From 31c8aa8d33630ab5129a5fcd263c9460da27cd23 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 2 Feb 2013 08:35:08 -0800 Subject: [PATCH] Imported Upstream version 1.1.0 --- .gitattributes | 18 + .gitignore | 61 + .mailmap | 8 + AUTHORS | 65 + CHANGELOG | 505 ++ LICENSE | 31 + PATENTS | 22 + README | 98 + args.c | 265 + args.h | 54 + build/.gitattributes | 2 + build/.gitignore | 1 + build/make/Android.mk | 199 + build/make/Makefile | 384 + build/make/ads2gas.pl | 178 + build/make/ads2gas_apple.pl | 214 + build/make/armlink_adapter.sh | 54 + build/make/configure.sh | 1187 ++++ build/make/gen_asm_deps.sh | 64 + build/make/gen_msvs_def.sh | 83 + build/make/gen_msvs_proj.sh | 573 ++ build/make/gen_msvs_sln.sh | 273 + build/make/obj_int_extract.c | 914 +++ build/make/rtcd.sh | 330 + build/make/version.sh | 76 + build/x86-msvs/obj_int_extract.bat | 15 + build/x86-msvs/yasm.rules | 115 + configure | 601 ++ docs.mk | 53 + example_xma.c | 214 + examples.mk | 285 + examples/decode_to_md5.txt | 48 + examples/decode_with_drops.txt | 73 + examples/decode_with_partial_drops.txt | 238 + examples/decoder_tmpl.c | 103 + examples/decoder_tmpl.txt | 62 + examples/encoder_tmpl.c | 186 + examples/encoder_tmpl.txt | 73 + examples/error_resilient.txt | 25 + examples/force_keyframe.txt | 28 + examples/gen_example_code.sh | 85 + examples/gen_example_doxy.php | 224 + examples/gen_example_text.sh | 84 + .../ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php | 218 + .../ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php | 1119 +++ examples/includes/ASCIIMathPHP-2.0/htmlMathML.js | 86 + examples/includes/HTML-Toc-0.91/.gitattributes | 1 + examples/includes/HTML-Toc-0.91/Changes | 26 + examples/includes/HTML-Toc-0.91/MANIFEST | 26 + examples/includes/HTML-Toc-0.91/Makefile.PL | 8 + examples/includes/HTML-Toc-0.91/Toc.pm | 549 ++ examples/includes/HTML-Toc-0.91/Toc.pod | 1710 +++++ examples/includes/HTML-Toc-0.91/TocGenerator.pm | 1793 +++++ examples/includes/HTML-Toc-0.91/TocInsertor.pm | 1066 +++ examples/includes/HTML-Toc-0.91/TocUpdator.pm | 693 ++ .../HTML-Toc-0.91/t/ManualTest/manualTest1.htm | 92 + .../t/SiteMap/SubDir1/SubSubDir1/index.htm | 5 + .../HTML-Toc-0.91/t/SiteMap/SubDir1/index.htm | 5 + .../t/SiteMap/SubDir2/SubSubDir1/index.htm | 5 + .../t/SiteMap/SubDir2/SubSubDir2/index.htm | 5 + .../HTML-Toc-0.91/t/SiteMap/SubDir2/index.htm | 5 + .../HTML-Toc-0.91/t/SiteMap/SubDir3/index.htm | 5 + .../includes/HTML-Toc-0.91/t/SiteMap/index.htm | 5 + examples/includes/HTML-Toc-0.91/t/extend.t | 87 + examples/includes/HTML-Toc-0.91/t/format.t | 157 + examples/includes/HTML-Toc-0.91/t/generate.t | 200 + examples/includes/HTML-Toc-0.91/t/insert.t | 336 + examples/includes/HTML-Toc-0.91/t/manualTest.t | 768 ++ examples/includes/HTML-Toc-0.91/t/options.t | 194 + examples/includes/HTML-Toc-0.91/t/podExamples.t | 709 ++ examples/includes/HTML-Toc-0.91/t/propagate.t | 176 + examples/includes/HTML-Toc-0.91/t/siteMap.t | 97 + examples/includes/HTML-Toc-0.91/t/update.t | 114 + .../includes/PHP-Markdown-Extra-1.2.3/License.text | 36 + .../PHP Markdown Extra Readme.text | 731 ++ .../includes/PHP-Markdown-Extra-1.2.3/markdown.php | 2909 ++++++++ .../PHP SmartyPants Readme.txt | 394 ++ .../PHP-SmartyPants-1.5.1e/smartypants.php | 860 +++ examples/includes/geshi/contrib/aliased.php | 124 + examples/includes/geshi/contrib/cssgen.php | 456 ++ examples/includes/geshi/contrib/cssgen2.php | 59 + examples/includes/geshi/contrib/example.php | 217 + examples/includes/geshi/contrib/langcheck.php | 666 ++ examples/includes/geshi/docs/BUGS | 29 + examples/includes/geshi/docs/CHANGES | 682 ++ examples/includes/geshi/docs/COPYING | 340 + examples/includes/geshi/docs/README | 33 + examples/includes/geshi/docs/THANKS | 163 + examples/includes/geshi/docs/TODO | 71 + .../__filesource/fsource_geshi_core_geshi.php.html | 4616 ++++++++++++ examples/includes/geshi/docs/api/blank.html | 13 + .../includes/geshi/docs/api/classtrees_geshi.html | 24 + examples/includes/geshi/docs/api/elementindex.html | 867 +++ .../geshi/docs/api/elementindex_geshi.html | 864 +++ examples/includes/geshi/docs/api/errors.html | 20 + .../includes/geshi/docs/api/geshi/core/GeSHi.html | 2676 +++++++ .../geshi/docs/api/geshi/core/_geshi.php.html | 478 ++ examples/includes/geshi/docs/api/index.html | 24 + examples/includes/geshi/docs/api/li_geshi.html | 46 + examples/includes/geshi/docs/api/media/banner.css | 33 + .../geshi/docs/api/media/images/AbstractClass.png | Bin 0 -> 620 bytes .../docs/api/media/images/AbstractClass_logo.png | Bin 0 -> 1232 bytes .../geshi/docs/api/media/images/AbstractMethod.png | Bin 0 -> 696 bytes .../docs/api/media/images/AbstractPrivateClass.png | Bin 0 -> 848 bytes .../api/media/images/AbstractPrivateClass_logo.png | Bin 0 -> 1615 bytes .../api/media/images/AbstractPrivateMethod.png | Bin 0 -> 874 bytes .../includes/geshi/docs/api/media/images/Class.png | Bin 0 -> 570 bytes .../geshi/docs/api/media/images/Class_logo.png | Bin 0 -> 1600 bytes .../geshi/docs/api/media/images/Constant.png | Bin 0 -> 752 bytes .../geshi/docs/api/media/images/Constructor.png | Bin 0 -> 865 bytes .../geshi/docs/api/media/images/Destructor.png | Bin 0 -> 956 bytes .../geshi/docs/api/media/images/Function.png | Bin 0 -> 596 bytes .../geshi/docs/api/media/images/Global.png | Bin 0 -> 712 bytes .../includes/geshi/docs/api/media/images/I.png | Bin 0 -> 148 bytes .../includes/geshi/docs/api/media/images/Index.png | Bin 0 -> 584 bytes .../geshi/docs/api/media/images/Interface.png | Bin 0 -> 1083 bytes .../geshi/docs/api/media/images/Interface_logo.png | Bin 0 -> 1600 bytes .../includes/geshi/docs/api/media/images/L.png | Bin 0 -> 153 bytes .../geshi/docs/api/media/images/Lminus.png | Bin 0 -> 219 bytes .../includes/geshi/docs/api/media/images/Lplus.png | Bin 0 -> 224 bytes .../geshi/docs/api/media/images/Method.png | Bin 0 -> 661 bytes .../includes/geshi/docs/api/media/images/Page.png | Bin 0 -> 592 bytes .../geshi/docs/api/media/images/Page_logo.png | Bin 0 -> 1369 bytes .../geshi/docs/api/media/images/PrivateClass.png | Bin 0 -> 790 bytes .../docs/api/media/images/PrivateClass_logo.png | Bin 0 -> 1836 bytes .../geshi/docs/api/media/images/PrivateMethod.png | Bin 0 -> 918 bytes .../docs/api/media/images/PrivateVariable.png | Bin 0 -> 772 bytes .../geshi/docs/api/media/images/StaticMethod.png | Bin 0 -> 661 bytes .../geshi/docs/api/media/images/StaticVariable.png | Bin 0 -> 688 bytes .../includes/geshi/docs/api/media/images/T.png | Bin 0 -> 152 bytes .../geshi/docs/api/media/images/Tminus.png | Bin 0 -> 207 bytes .../includes/geshi/docs/api/media/images/Tplus.png | Bin 0 -> 222 bytes .../geshi/docs/api/media/images/Variable.png | Bin 0 -> 688 bytes .../includes/geshi/docs/api/media/images/blank.png | Bin 0 -> 144 bytes .../geshi/docs/api/media/images/class_folder.png | Bin 0 -> 633 bytes .../includes/geshi/docs/api/media/images/empty.png | Bin 0 -> 90 bytes .../includes/geshi/docs/api/media/images/file.png | Bin 0 -> 462 bytes .../geshi/docs/api/media/images/folder.png | Bin 0 -> 492 bytes .../docs/api/media/images/function_folder.png | Bin 0 -> 605 bytes .../geshi/docs/api/media/images/next_button.png | Bin 0 -> 657 bytes .../docs/api/media/images/next_button_disabled.png | Bin 0 -> 543 bytes .../geshi/docs/api/media/images/package.png | Bin 0 -> 668 bytes .../geshi/docs/api/media/images/package_folder.png | Bin 0 -> 564 bytes .../docs/api/media/images/previous_button.png | Bin 0 -> 644 bytes .../api/media/images/previous_button_disabled.png | Bin 0 -> 541 bytes .../docs/api/media/images/private_class_logo.png | Bin 0 -> 1836 bytes .../geshi/docs/api/media/images/tutorial.png | Bin 0 -> 431 bytes .../docs/api/media/images/tutorial_folder.png | Bin 0 -> 572 bytes .../geshi/docs/api/media/images/up_button.png | Bin 0 -> 668 bytes .../includes/geshi/docs/api/media/stylesheet.css | 145 + examples/includes/geshi/docs/api/packages.html | 29 + examples/includes/geshi/docs/api/todolist.html | 42 + examples/includes/geshi/docs/geshi-doc.html | 4051 +++++++++++ examples/includes/geshi/docs/geshi-doc.txt | 1740 +++++ examples/includes/geshi/docs/phpdoc.ini | 90 + examples/includes/geshi/geshi.php | 4619 ++++++++++++ examples/includes/geshi/geshi/abap.php | 1419 ++++ examples/includes/geshi/geshi/actionscript.php | 197 + examples/includes/geshi/geshi/actionscript3.php | 467 ++ examples/includes/geshi/geshi/ada.php | 133 + examples/includes/geshi/geshi/apache.php | 206 + examples/includes/geshi/geshi/applescript.php | 157 + examples/includes/geshi/geshi/apt_sources.php | 144 + examples/includes/geshi/geshi/asm.php | 225 + examples/includes/geshi/geshi/asp.php | 164 + examples/includes/geshi/geshi/autoit.php | 1171 ++++ examples/includes/geshi/geshi/avisynth.php | 194 + examples/includes/geshi/geshi/bash.php | 282 + examples/includes/geshi/geshi/basic4gl.php | 341 + examples/includes/geshi/geshi/bf.php | 114 + examples/includes/geshi/geshi/blitzbasic.php | 185 + examples/includes/geshi/geshi/bnf.php | 110 + examples/includes/geshi/geshi/boo.php | 217 + examples/includes/geshi/geshi/c.php | 188 + examples/includes/geshi/geshi/c_mac.php | 212 + examples/includes/geshi/geshi/caddcl.php | 126 + examples/includes/geshi/geshi/cadlisp.php | 186 + examples/includes/geshi/geshi/cfdg.php | 124 + examples/includes/geshi/geshi/cfm.php | 299 + examples/includes/geshi/geshi/cil.php | 196 + examples/includes/geshi/geshi/cobol.php | 244 + examples/includes/geshi/geshi/cpp-qt.php | 315 + examples/includes/geshi/geshi/cpp.php | 226 + examples/includes/geshi/geshi/csharp.php | 249 + examples/includes/geshi/geshi/css.php | 212 + examples/includes/geshi/geshi/d.php | 272 + examples/includes/geshi/geshi/dcs.php | 185 + examples/includes/geshi/geshi/delphi.php | 289 + examples/includes/geshi/geshi/diff.php | 196 + examples/includes/geshi/geshi/div.php | 126 + examples/includes/geshi/geshi/dos.php | 198 + examples/includes/geshi/geshi/dot.php | 164 + examples/includes/geshi/geshi/eiffel.php | 395 ++ examples/includes/geshi/geshi/email.php | 209 + examples/includes/geshi/geshi/fortran.php | 160 + examples/includes/geshi/geshi/freebasic.php | 141 + examples/includes/geshi/geshi/genero.php | 463 ++ examples/includes/geshi/geshi/gettext.php | 97 + examples/includes/geshi/geshi/glsl.php | 205 + examples/includes/geshi/geshi/gml.php | 506 ++ examples/includes/geshi/geshi/gnuplot.php | 296 + examples/includes/geshi/geshi/groovy.php | 1011 +++ examples/includes/geshi/geshi/haskell.php | 198 + examples/includes/geshi/geshi/hq9plus.php | 104 + examples/includes/geshi/geshi/html4strict.php | 203 + examples/includes/geshi/geshi/idl.php | 123 + examples/includes/geshi/geshi/ini.php | 128 + examples/includes/geshi/geshi/inno.php | 212 + examples/includes/geshi/geshi/intercal.php | 122 + examples/includes/geshi/geshi/io.php | 138 + examples/includes/geshi/geshi/java.php | 983 +++ examples/includes/geshi/geshi/java5.php | 1031 +++ examples/includes/geshi/geshi/javascript.php | 150 + examples/includes/geshi/geshi/kixtart.php | 329 + examples/includes/geshi/geshi/klonec.php | 282 + examples/includes/geshi/geshi/klonecpp.php | 310 + examples/includes/geshi/geshi/latex.php | 209 + examples/includes/geshi/geshi/lisp.php | 144 + examples/includes/geshi/geshi/locobasic.php | 130 + examples/includes/geshi/geshi/lolcode.php | 152 + examples/includes/geshi/geshi/lotusformulas.php | 318 + examples/includes/geshi/geshi/lotusscript.php | 191 + examples/includes/geshi/geshi/lscript.php | 387 ++ examples/includes/geshi/geshi/lsl2.php | 898 +++ examples/includes/geshi/geshi/lua.php | 137 + examples/includes/geshi/geshi/m68k.php | 143 + examples/includes/geshi/geshi/make.php | 151 + examples/includes/geshi/geshi/matlab.php | 227 + examples/includes/geshi/geshi/mirc.php | 173 + examples/includes/geshi/geshi/modula3.php | 135 + examples/includes/geshi/geshi/mpasm.php | 164 + examples/includes/geshi/geshi/mxml.php | 145 + examples/includes/geshi/geshi/mysql.php | 475 ++ examples/includes/geshi/geshi/nsis.php | 351 + examples/includes/geshi/geshi/objc.php | 358 + examples/includes/geshi/geshi/ocaml-brief.php | 112 + examples/includes/geshi/geshi/ocaml.php | 174 + examples/includes/geshi/geshi/oobas.php | 135 + examples/includes/geshi/geshi/oracle11.php | 614 ++ examples/includes/geshi/geshi/oracle8.php | 496 ++ examples/includes/geshi/geshi/pascal.php | 152 + examples/includes/geshi/geshi/per.php | 302 + examples/includes/geshi/geshi/perl.php | 213 + examples/includes/geshi/geshi/php-brief.php | 202 + examples/includes/geshi/geshi/php.php | 1094 +++ examples/includes/geshi/geshi/pic16.php | 141 + examples/includes/geshi/geshi/pixelbender.php | 176 + examples/includes/geshi/geshi/plsql.php | 256 + examples/includes/geshi/geshi/povray.php | 199 + examples/includes/geshi/geshi/powershell.php | 279 + examples/includes/geshi/geshi/progress.php | 479 ++ examples/includes/geshi/geshi/prolog.php | 143 + examples/includes/geshi/geshi/providex.php | 299 + examples/includes/geshi/geshi/python.php | 237 + examples/includes/geshi/geshi/qbasic.php | 151 + examples/includes/geshi/geshi/rails.php | 406 ++ examples/includes/geshi/geshi/rebol.php | 196 + examples/includes/geshi/geshi/reg.php | 233 + examples/includes/geshi/geshi/robots.php | 98 + examples/includes/geshi/geshi/ruby.php | 226 + examples/includes/geshi/geshi/sas.php | 290 + examples/includes/geshi/geshi/scala.php | 122 + examples/includes/geshi/geshi/scheme.php | 170 + examples/includes/geshi/geshi/scilab.php | 295 + examples/includes/geshi/geshi/sdlbasic.php | 165 + examples/includes/geshi/geshi/smalltalk.php | 160 + examples/includes/geshi/geshi/smarty.php | 192 + examples/includes/geshi/geshi/sql.php | 140 + examples/includes/geshi/geshi/tcl.php | 194 + examples/includes/geshi/geshi/teraterm.php | 317 + examples/includes/geshi/geshi/text.php | 84 + examples/includes/geshi/geshi/thinbasic.php | 868 +++ examples/includes/geshi/geshi/tsql.php | 378 + examples/includes/geshi/geshi/typoscript.php | 300 + examples/includes/geshi/geshi/vb.php | 133 + examples/includes/geshi/geshi/vbnet.php | 201 + examples/includes/geshi/geshi/verilog.php | 173 + examples/includes/geshi/geshi/vhdl.php | 144 + examples/includes/geshi/geshi/vim.php | 185 + examples/includes/geshi/geshi/visualfoxpro.php | 456 ++ examples/includes/geshi/geshi/visualprolog.php | 129 + examples/includes/geshi/geshi/whitespace.php | 121 + examples/includes/geshi/geshi/winbatch.php | 369 + examples/includes/geshi/geshi/xml.php | 157 + examples/includes/geshi/geshi/xorg_conf.php | 124 + examples/includes/geshi/geshi/xpp.php | 436 ++ examples/includes/geshi/geshi/z80.php | 144 + examples/includes/vp8_doc_tools.php | 207 + examples/postproc.txt | 67 + examples/simple_decoder.txt | 96 + examples/simple_encoder.txt | 105 + examples/twopass_encoder.txt | 75 + examples/vp8_set_maps.txt | 96 + examples/vp8cx_set_ref.txt | 73 + keywords.dox | 51 + libmkv/EbmlBufferWriter.c | 60 + libmkv/EbmlBufferWriter.h | 21 + libmkv/EbmlIDs.h | 231 + libmkv/EbmlWriter.c | 171 + libmkv/EbmlWriter.h | 38 + libmkv/Makefile | 25 + libmkv/WebMElement.c | 220 + libmkv/WebMElement.h | 35 + libmkv/testlibmkv.c | 63 + libs.doxy_template | 1308 ++++ libs.mk | 437 ++ mainpage.dox | 53 + md5_utils.c | 251 + md5_utils.h | 42 + nestegg/.gitignore | 40 + nestegg/AUTHORS | 1 + nestegg/INSTALL | 8 + nestegg/LICENSE | 13 + nestegg/Makefile.am | 51 + nestegg/README | 6 + nestegg/TODO | 21 + nestegg/configure.ac | 124 + nestegg/docs/Doxyfile.in | 1551 +++++ nestegg/docs/Makefile.am | 38 + nestegg/halloc/README | 45 + nestegg/halloc/halloc.h | 43 + nestegg/halloc/src/align.h | 36 + nestegg/halloc/src/halloc.c | 254 + nestegg/halloc/src/hlist.h | 136 + nestegg/halloc/src/macros.h | 36 + nestegg/include/nestegg/nestegg.h | 292 + nestegg/m4/as-ac-expand.m4 | 43 + nestegg/m4/ax_create_stdint_h.m4 | 695 ++ nestegg/m4/pkg.m4 | 157 + nestegg/nestegg-uninstalled.pc.in | 13 + nestegg/nestegg.pc.in | 13 + nestegg/src/nestegg.c | 1938 ++++++ nestegg/test/test.c | 248 + solution.mk | 31 + third_party/googletest/README.webm | 15 + third_party/googletest/gtest.mk | 1 + third_party/googletest/src/CHANGES | 130 + third_party/googletest/src/CMakeLists.txt | 240 + third_party/googletest/src/CONTRIBUTORS | 37 + third_party/googletest/src/COPYING | 28 + third_party/googletest/src/Makefile.am | 302 + third_party/googletest/src/README | 424 ++ third_party/googletest/src/build-aux/.keep | 0 .../googletest/src/cmake/internal_utils.cmake | 216 + third_party/googletest/src/codegear/gtest.cbproj | 138 + .../googletest/src/codegear/gtest.groupproj | 54 + third_party/googletest/src/codegear/gtest_all.cc | 38 + third_party/googletest/src/codegear/gtest_link.cc | 40 + .../googletest/src/codegear/gtest_main.cbproj | 82 + .../googletest/src/codegear/gtest_unittest.cbproj | 88 + third_party/googletest/src/configure.ac | 68 + .../src/include/gtest/gtest-death-test.h | 283 + .../googletest/src/include/gtest/gtest-message.h | 230 + .../src/include/gtest/gtest-param-test.h | 1421 ++++ .../src/include/gtest/gtest-param-test.h.pump | 487 ++ .../googletest/src/include/gtest/gtest-printers.h | 796 +++ .../googletest/src/include/gtest/gtest-spi.h | 232 + .../googletest/src/include/gtest/gtest-test-part.h | 176 + .../src/include/gtest/gtest-typed-test.h | 259 + third_party/googletest/src/include/gtest/gtest.h | 2155 ++++++ .../googletest/src/include/gtest/gtest_pred_impl.h | 358 + .../googletest/src/include/gtest/gtest_prod.h | 58 + .../gtest/internal/gtest-death-test-internal.h | 308 + .../src/include/gtest/internal/gtest-filepath.h | 210 + .../src/include/gtest/internal/gtest-internal.h | 1226 ++++ .../src/include/gtest/internal/gtest-linked_ptr.h | 233 + .../gtest/internal/gtest-param-util-generated.h | 4822 +++++++++++++ .../internal/gtest-param-util-generated.h.pump | 301 + .../src/include/gtest/internal/gtest-param-util.h | 619 ++ .../src/include/gtest/internal/gtest-port.h | 1775 +++++ .../src/include/gtest/internal/gtest-string.h | 350 + .../src/include/gtest/internal/gtest-tuple.h | 968 +++ .../src/include/gtest/internal/gtest-tuple.h.pump | 336 + .../src/include/gtest/internal/gtest-type-util.h | 3330 +++++++++ .../include/gtest/internal/gtest-type-util.h.pump | 296 + third_party/googletest/src/m4/acx_pthread.m4 | 363 + third_party/googletest/src/m4/gtest.m4 | 74 + third_party/googletest/src/make/Makefile | 80 + third_party/googletest/src/msvc/gtest-md.sln | 45 + third_party/googletest/src/msvc/gtest-md.vcproj | 126 + third_party/googletest/src/msvc/gtest.sln | 45 + third_party/googletest/src/msvc/gtest.vcproj | 126 + .../googletest/src/msvc/gtest_main-md.vcproj | 129 + third_party/googletest/src/msvc/gtest_main.vcproj | 129 + .../googletest/src/msvc/gtest_prod_test-md.vcproj | 164 + .../googletest/src/msvc/gtest_prod_test.vcproj | 164 + .../googletest/src/msvc/gtest_unittest-md.vcproj | 147 + .../googletest/src/msvc/gtest_unittest.vcproj | 147 + third_party/googletest/src/samples/prime_tables.h | 123 + third_party/googletest/src/samples/sample1.cc | 68 + third_party/googletest/src/samples/sample1.h | 43 + .../googletest/src/samples/sample10_unittest.cc | 145 + .../googletest/src/samples/sample1_unittest.cc | 153 + third_party/googletest/src/samples/sample2.cc | 56 + third_party/googletest/src/samples/sample2.h | 86 + .../googletest/src/samples/sample2_unittest.cc | 109 + third_party/googletest/src/samples/sample3-inl.h | 173 + .../googletest/src/samples/sample3_unittest.cc | 151 + third_party/googletest/src/samples/sample4.cc | 46 + third_party/googletest/src/samples/sample4.h | 53 + .../googletest/src/samples/sample4_unittest.cc | 45 + .../googletest/src/samples/sample5_unittest.cc | 199 + .../googletest/src/samples/sample6_unittest.cc | 224 + .../googletest/src/samples/sample7_unittest.cc | 130 + .../googletest/src/samples/sample8_unittest.cc | 173 + .../googletest/src/samples/sample9_unittest.cc | 160 + .../googletest/src/scripts/fuse_gtest_files.py | 250 + .../googletest/src/scripts/gen_gtest_pred_impl.py | 730 ++ third_party/googletest/src/scripts/gtest-config.in | 274 + third_party/googletest/src/scripts/pump.py | 847 +++ third_party/googletest/src/scripts/test/Makefile | 59 + third_party/googletest/src/scripts/upload.py | 1387 ++++ third_party/googletest/src/scripts/upload_gtest.py | 78 + third_party/googletest/src/src/gtest-all.cc | 48 + third_party/googletest/src/src/gtest-death-test.cc | 1234 ++++ third_party/googletest/src/src/gtest-filepath.cc | 380 + .../googletest/src/src/gtest-internal-inl.h | 1038 +++ third_party/googletest/src/src/gtest-port.cc | 746 ++ third_party/googletest/src/src/gtest-printers.cc | 356 + third_party/googletest/src/src/gtest-test-part.cc | 110 + third_party/googletest/src/src/gtest-typed-test.cc | 110 + third_party/googletest/src/src/gtest.cc | 4898 +++++++++++++ third_party/googletest/src/src/gtest_main.cc | 39 + .../src/test/gtest-death-test_ex_test.cc | 93 + .../googletest/src/test/gtest-death-test_test.cc | 1296 ++++ .../googletest/src/test/gtest-filepath_test.cc | 696 ++ .../googletest/src/test/gtest-linked_ptr_test.cc | 155 + .../googletest/src/test/gtest-listener_test.cc | 313 + .../googletest/src/test/gtest-message_test.cc | 166 + .../googletest/src/test/gtest-options_test.cc | 212 + .../googletest/src/test/gtest-param-test2_test.cc | 65 + .../googletest/src/test/gtest-param-test_test.cc | 895 +++ .../googletest/src/test/gtest-param-test_test.h | 55 + third_party/googletest/src/test/gtest-port_test.cc | 1206 ++++ .../googletest/src/test/gtest-printers_test.cc | 1307 ++++ .../googletest/src/test/gtest-test-part_test.cc | 208 + .../googletest/src/test/gtest-tuple_test.cc | 320 + .../googletest/src/test/gtest-typed-test2_test.cc | 45 + .../googletest/src/test/gtest-typed-test_test.cc | 360 + .../googletest/src/test/gtest-typed-test_test.h | 66 + .../googletest/src/test/gtest-unittest-api_test.cc | 341 + third_party/googletest/src/test/gtest_all_test.cc | 47 + .../src/test/gtest_break_on_failure_unittest.py | 218 + .../src/test/gtest_break_on_failure_unittest_.cc | 88 + .../src/test/gtest_catch_exceptions_test.py | 220 + .../src/test/gtest_catch_exceptions_test_.cc | 308 + .../googletest/src/test/gtest_color_test.py | 130 + .../googletest/src/test/gtest_color_test_.cc | 71 + .../googletest/src/test/gtest_env_var_test.py | 103 + .../googletest/src/test/gtest_env_var_test_.cc | 126 + .../googletest/src/test/gtest_environment_test.cc | 191 + .../googletest/src/test/gtest_filter_unittest.py | 633 ++ .../googletest/src/test/gtest_filter_unittest_.cc | 140 + third_party/googletest/src/test/gtest_help_test.py | 172 + .../googletest/src/test/gtest_help_test_.cc | 46 + .../src/test/gtest_list_tests_unittest.py | 177 + .../src/test/gtest_list_tests_unittest_.cc | 85 + .../googletest/src/test/gtest_main_unittest.cc | 45 + .../googletest/src/test/gtest_no_test_unittest.cc | 57 + .../googletest/src/test/gtest_output_test.py | 335 + .../googletest/src/test/gtest_output_test_.cc | 1020 +++ .../src/test/gtest_output_test_golden_lin.txt | 711 ++ .../src/test/gtest_pred_impl_unittest.cc | 2427 +++++++ third_party/googletest/src/test/gtest_prod_test.cc | 57 + .../googletest/src/test/gtest_repeat_test.cc | 253 + .../googletest/src/test/gtest_shuffle_test.py | 325 + .../googletest/src/test/gtest_shuffle_test_.cc | 104 + .../googletest/src/test/gtest_sole_header_test.cc | 57 + .../googletest/src/test/gtest_stress_test.cc | 257 + .../googletest/src/test/gtest_test_utils.py | 305 + .../src/test/gtest_throw_on_failure_ex_test.cc | 92 + .../src/test/gtest_throw_on_failure_test.py | 171 + .../src/test/gtest_throw_on_failure_test_.cc | 56 + .../src/test/gtest_uninitialized_test.py | 70 + .../src/test/gtest_uninitialized_test_.cc | 43 + third_party/googletest/src/test/gtest_unittest.cc | 7337 ++++++++++++++++++++ .../src/test/gtest_xml_outfile1_test_.cc | 49 + .../src/test/gtest_xml_outfile2_test_.cc | 49 + .../googletest/src/test/gtest_xml_outfiles_test.py | 132 + .../src/test/gtest_xml_output_unittest.py | 242 + .../src/test/gtest_xml_output_unittest_.cc | 174 + .../googletest/src/test/gtest_xml_test_utils.py | 179 + third_party/googletest/src/test/production.cc | 36 + third_party/googletest/src/test/production.h | 55 + .../src/xcode/Config/DebugProject.xcconfig | 30 + .../src/xcode/Config/FrameworkTarget.xcconfig | 17 + .../googletest/src/xcode/Config/General.xcconfig | 41 + .../src/xcode/Config/ReleaseProject.xcconfig | 32 + .../src/xcode/Config/StaticLibraryTarget.xcconfig | 18 + .../src/xcode/Config/TestTarget.xcconfig | 8 + .../googletest/src/xcode/Resources/Info.plist | 30 + .../src/xcode/Samples/FrameworkSample/Info.plist | 28 + .../WidgetFramework.xcodeproj/project.pbxproj | 457 ++ .../src/xcode/Samples/FrameworkSample/runtests.sh | 62 + .../src/xcode/Samples/FrameworkSample/widget.cc | 63 + .../src/xcode/Samples/FrameworkSample/widget.h | 59 + .../xcode/Samples/FrameworkSample/widget_test.cc | 68 + .../googletest/src/xcode/Scripts/runtests.sh | 65 + .../src/xcode/Scripts/versiongenerate.py | 100 + .../src/xcode/gtest.xcodeproj/project.pbxproj | 1084 +++ third_party/libyuv/README.webm | 17 + third_party/libyuv/include/libyuv/basic_types.h | 73 + third_party/libyuv/include/libyuv/cpu_id.h | 49 + third_party/libyuv/include/libyuv/scale.h | 70 + third_party/libyuv/source/cpu_id.c | 81 + third_party/libyuv/source/row.h | 264 + third_party/libyuv/source/scale.c | 3884 +++++++++++ tools/author_first_release.sh | 15 + tools/ftfy.sh | 160 + tools/gen_authors.sh | 13 + tools/intersect-diffs.py | 188 + tools/wrap-commit-msg.py | 70 + tools_common.c | 30 + tools_common.h | 16 + usage.dox | 208 + usage_cx.dox | 13 + usage_dx.dox | 62 + vp8/common/alloccommon.c | 222 + vp8/common/alloccommon.h | 23 + vp8/common/arm/armv6/bilinearfilter_v6.asm | 237 + vp8/common/arm/armv6/copymem16x16_v6.asm | 186 + vp8/common/arm/armv6/copymem8x4_v6.asm | 128 + vp8/common/arm/armv6/copymem8x8_v6.asm | 128 + vp8/common/arm/armv6/dc_only_idct_add_v6.asm | 70 + vp8/common/arm/armv6/dequant_idct_v6.asm | 190 + vp8/common/arm/armv6/dequantize_v6.asm | 69 + vp8/common/arm/armv6/filter_v6.asm | 624 ++ vp8/common/arm/armv6/idct_blk_v6.c | 115 + vp8/common/arm/armv6/idct_v6.asm | 202 + vp8/common/arm/armv6/intra4x4_predict_v6.asm | 606 ++ vp8/common/arm/armv6/iwalsh_v6.asm | 136 + vp8/common/arm/armv6/loopfilter_v6.asm | 1282 ++++ vp8/common/arm/armv6/simpleloopfilter_v6.asm | 286 + vp8/common/arm/armv6/sixtappredict8x4_v6.asm | 273 + vp8/common/arm/armv6/vp8_sad16x16_armv6.asm | 96 + vp8/common/arm/armv6/vp8_variance16x16_armv6.asm | 154 + vp8/common/arm/armv6/vp8_variance8x8_armv6.asm | 101 + .../armv6/vp8_variance_halfpixvar16x16_h_armv6.asm | 182 + .../vp8_variance_halfpixvar16x16_hv_armv6.asm | 222 + .../armv6/vp8_variance_halfpixvar16x16_v_armv6.asm | 184 + vp8/common/arm/bilinearfilter_arm.c | 113 + vp8/common/arm/bilinearfilter_arm.h | 35 + vp8/common/arm/dequantize_arm.c | 42 + vp8/common/arm/filter_arm.c | 221 + vp8/common/arm/loopfilter_arm.c | 181 + vp8/common/arm/neon/bilinearpredict16x16_neon.asm | 357 + vp8/common/arm/neon/bilinearpredict4x4_neon.asm | 130 + vp8/common/arm/neon/bilinearpredict8x4_neon.asm | 135 + vp8/common/arm/neon/bilinearpredict8x8_neon.asm | 183 + .../arm/neon/buildintrapredictorsmby_neon.asm | 584 ++ vp8/common/arm/neon/copymem16x16_neon.asm | 59 + vp8/common/arm/neon/copymem8x4_neon.asm | 34 + vp8/common/arm/neon/copymem8x8_neon.asm | 43 + vp8/common/arm/neon/dc_only_idct_add_neon.asm | 54 + vp8/common/arm/neon/dequant_idct_neon.asm | 131 + vp8/common/arm/neon/dequantizeb_neon.asm | 34 + vp8/common/arm/neon/idct_blk_neon.c | 96 + vp8/common/arm/neon/idct_dequant_0_2x_neon.asm | 79 + vp8/common/arm/neon/idct_dequant_full_2x_neon.asm | 196 + vp8/common/arm/neon/iwalsh_neon.asm | 87 + vp8/common/arm/neon/loopfilter_neon.asm | 397 ++ .../neon/loopfiltersimplehorizontaledge_neon.asm | 117 + .../arm/neon/loopfiltersimpleverticaledge_neon.asm | 154 + vp8/common/arm/neon/mbloopfilter_neon.asm | 469 ++ vp8/common/arm/neon/sad16_neon.asm | 207 + vp8/common/arm/neon/sad8_neon.asm | 209 + vp8/common/arm/neon/save_reg_neon.asm | 36 + vp8/common/arm/neon/shortidct4x4llm_neon.asm | 139 + vp8/common/arm/neon/sixtappredict16x16_neon.asm | 490 ++ vp8/common/arm/neon/sixtappredict4x4_neon.asm | 422 ++ vp8/common/arm/neon/sixtappredict8x4_neon.asm | 473 ++ vp8/common/arm/neon/sixtappredict8x8_neon.asm | 524 ++ vp8/common/arm/neon/variance_neon.asm | 276 + .../arm/neon/vp8_subpixelvariance16x16_neon.asm | 423 ++ .../arm/neon/vp8_subpixelvariance16x16s_neon.asm | 572 ++ .../arm/neon/vp8_subpixelvariance8x8_neon.asm | 222 + vp8/common/arm/reconintra_arm.c | 58 + vp8/common/arm/variance_arm.c | 132 + vp8/common/asm_com_offsets.c | 71 + vp8/common/blockd.c | 22 + vp8/common/blockd.h | 296 + vp8/common/coefupdateprobs.h | 185 + vp8/common/common.h | 40 + vp8/common/context.c | 399 ++ vp8/common/debugmodes.c | 157 + vp8/common/default_coef_probs.h | 188 + vp8/common/dequantize.c | 43 + vp8/common/entropy.c | 189 + vp8/common/entropy.h | 101 + vp8/common/entropymode.c | 177 + vp8/common/entropymode.h | 75 + vp8/common/entropymv.c | 49 + vp8/common/entropymv.h | 44 + vp8/common/extend.c | 185 + vp8/common/extend.h | 25 + vp8/common/filter.c | 494 ++ vp8/common/filter.h | 22 + vp8/common/findnearmv.c | 193 + vp8/common/findnearmv.h | 182 + vp8/common/generic/systemdependent.c | 150 + vp8/common/header.h | 43 + vp8/common/idct_blk.c | 89 + vp8/common/idctllm.c | 204 + vp8/common/idctllm_test.cc | 31 + vp8/common/idctllm_test.h | 113 + vp8/common/invtrans.h | 62 + vp8/common/loopfilter.c | 575 ++ vp8/common/loopfilter.h | 92 + vp8/common/loopfilter_filters.c | 430 ++ vp8/common/mbpitch.c | 68 + vp8/common/mfqe.c | 385 + vp8/common/modecont.c | 40 + vp8/common/modecont.h | 17 + vp8/common/mv.h | 28 + vp8/common/onyx.h | 259 + vp8/common/onyxc_int.h | 194 + vp8/common/onyxd.h | 71 + vp8/common/postproc.c | 1173 ++++ vp8/common/postproc.h | 48 + vp8/common/ppc/copy_altivec.asm | 47 + vp8/common/ppc/filter_altivec.asm | 1013 +++ vp8/common/ppc/filter_bilinear_altivec.asm | 677 ++ vp8/common/ppc/idctllm_altivec.asm | 189 + vp8/common/ppc/loopfilter_altivec.c | 135 + vp8/common/ppc/loopfilter_filters_altivec.asm | 1253 ++++ vp8/common/ppc/platform_altivec.asm | 59 + vp8/common/ppc/recon_altivec.asm | 175 + vp8/common/ppc/sad_altivec.asm | 277 + vp8/common/ppc/systemdependent.c | 170 + vp8/common/ppc/variance_altivec.asm | 375 + vp8/common/ppc/variance_subpixel_altivec.asm | 865 +++ vp8/common/ppflags.h | 41 + vp8/common/pragmas.h | 19 + vp8/common/quant_common.c | 132 + vp8/common/quant_common.h | 21 + vp8/common/reconinter.c | 595 ++ vp8/common/reconinter.h | 35 + vp8/common/reconintra.c | 288 + vp8/common/reconintra4x4.c | 308 + vp8/common/reconintra4x4.h | 32 + vp8/common/rtcd.c | 12 + vp8/common/rtcd_defs.sh | 541 ++ vp8/common/sad_c.c | 395 ++ vp8/common/setupintrarecon.c | 32 + vp8/common/setupintrarecon.h | 13 + vp8/common/swapyv12buffer.c | 34 + vp8/common/swapyv12buffer.h | 19 + vp8/common/systemdependent.h | 21 + vp8/common/textblit.c | 130 + vp8/common/threading.h | 186 + vp8/common/treecoder.c | 143 + vp8/common/treecoder.h | 90 + vp8/common/variance.h | 115 + vp8/common/variance_c.c | 458 ++ vp8/common/vp8_entropymodedata.h | 242 + vp8/common/x86/dequantize_mmx.asm | 258 + vp8/common/x86/filter_x86.c | 35 + vp8/common/x86/filter_x86.h | 19 + vp8/common/x86/idct_blk_mmx.c | 127 + vp8/common/x86/idct_blk_sse2.c | 89 + vp8/common/x86/idctllm_mmx.asm | 295 + vp8/common/x86/idctllm_mmx_test.cc | 31 + vp8/common/x86/idctllm_sse2.asm | 708 ++ vp8/common/x86/iwalsh_mmx.asm | 140 + vp8/common/x86/iwalsh_sse2.asm | 121 + vp8/common/x86/loopfilter_block_sse2.asm | 813 +++ vp8/common/x86/loopfilter_mmx.asm | 1753 +++++ vp8/common/x86/loopfilter_sse2.asm | 1640 +++++ vp8/common/x86/loopfilter_x86.c | 198 + vp8/common/x86/mfqe_sse2.asm | 281 + vp8/common/x86/postproc_mmx.asm | 579 ++ vp8/common/x86/postproc_sse2.asm | 759 ++ vp8/common/x86/postproc_x86.c | 21 + vp8/common/x86/recon_mmx.asm | 274 + vp8/common/x86/recon_sse2.asm | 1080 +++ vp8/common/x86/recon_wrapper_sse2.c | 186 + vp8/common/x86/sad_mmx.asm | 427 ++ vp8/common/x86/sad_sse2.asm | 410 ++ vp8/common/x86/sad_sse3.asm | 960 +++ vp8/common/x86/sad_sse4.asm | 353 + vp8/common/x86/sad_ssse3.asm | 370 + vp8/common/x86/subpixel_mmx.asm | 702 ++ vp8/common/x86/subpixel_sse2.asm | 1372 ++++ vp8/common/x86/subpixel_ssse3.asm | 1507 ++++ vp8/common/x86/variance_impl_mmx.asm | 851 +++ vp8/common/x86/variance_impl_sse2.asm | 1359 ++++ vp8/common/x86/variance_impl_ssse3.asm | 364 + vp8/common/x86/variance_mmx.c | 398 ++ vp8/common/x86/variance_sse2.c | 557 ++ vp8/common/x86/variance_ssse3.c | 165 + vp8/common/x86/vp8_asm_stubs.c | 552 ++ vp8/decoder/asm_dec_offsets.c | 26 + vp8/decoder/dboolhuff.c | 52 + vp8/decoder/dboolhuff.h | 154 + vp8/decoder/decodemv.c | 666 ++ vp8/decoder/decodemv.h | 14 + vp8/decoder/decoderthreading.h | 26 + vp8/decoder/decodframe.c | 1192 ++++ vp8/decoder/detokenize.c | 244 + vp8/decoder/detokenize.h | 20 + vp8/decoder/ec_types.h | 51 + vp8/decoder/error_concealment.c | 597 ++ vp8/decoder/error_concealment.h | 41 + vp8/decoder/onyxd_if.c | 614 ++ vp8/decoder/onyxd_int.h | 132 + vp8/decoder/threading.c | 922 +++ vp8/decoder/treereader.h | 41 + vp8/encoder/arm/armv5te/boolhuff_armv5te.asm | 310 + vp8/encoder/arm/armv5te/vp8_packtokens_armv5.asm | 317 + .../arm/armv5te/vp8_packtokens_mbrow_armv5.asm | 352 + .../armv5te/vp8_packtokens_partitions_armv5.asm | 471 ++ .../arm/armv6/vp8_fast_quantize_b_armv6.asm | 225 + vp8/encoder/arm/armv6/vp8_mse16x16_armv6.asm | 138 + vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm | 262 + vp8/encoder/arm/armv6/vp8_subtract_armv6.asm | 272 + vp8/encoder/arm/armv6/walsh_v6.asm | 212 + vp8/encoder/arm/boolhuff_arm.c | 41 + vp8/encoder/arm/dct_arm.c | 22 + vp8/encoder/arm/neon/fastquantizeb_neon.asm | 258 + vp8/encoder/arm/neon/picklpf_arm.c | 46 + vp8/encoder/arm/neon/shortfdct_neon.asm | 221 + vp8/encoder/arm/neon/subtract_neon.asm | 199 + vp8/encoder/arm/neon/vp8_memcpy_neon.asm | 70 + vp8/encoder/arm/neon/vp8_mse16x16_neon.asm | 116 + vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm | 103 + vp8/encoder/arm/quantize_arm.c | 64 + vp8/encoder/asm_enc_offsets.c | 93 + vp8/encoder/bitstream.c | 1734 +++++ vp8/encoder/bitstream.h | 46 + vp8/encoder/block.h | 131 + vp8/encoder/boolhuff.c | 70 + vp8/encoder/boolhuff.h | 128 + vp8/encoder/dct.c | 116 + vp8/encoder/dct_value_cost.h | 358 + vp8/encoder/dct_value_tokens.h | 699 ++ vp8/encoder/defaultcoefcounts.h | 223 + vp8/encoder/denoising.c | 212 + vp8/encoder/denoising.h | 33 + vp8/encoder/encodeframe.c | 1352 ++++ vp8/encoder/encodeframe.h | 27 + vp8/encoder/encodeintra.c | 138 + vp8/encoder/encodeintra.h | 21 + vp8/encoder/encodemb.c | 648 ++ vp8/encoder/encodemb.h | 26 + vp8/encoder/encodemv.c | 417 ++ vp8/encoder/encodemv.h | 21 + vp8/encoder/ethreading.c | 588 ++ vp8/encoder/firstpass.c | 3198 +++++++++ vp8/encoder/firstpass.h | 24 + vp8/encoder/lookahead.c | 229 + vp8/encoder/lookahead.h | 109 + vp8/encoder/mcomp.c | 2003 ++++++ vp8/encoder/mcomp.h | 100 + vp8/encoder/modecosts.c | 47 + vp8/encoder/modecosts.h | 17 + vp8/encoder/mr_dissim.c | 201 + vp8/encoder/mr_dissim.h | 19 + vp8/encoder/onyx_if.c | 5369 ++++++++++++++ vp8/encoder/onyx_int.h | 720 ++ vp8/encoder/pickinter.c | 1176 ++++ vp8/encoder/pickinter.h | 23 + vp8/encoder/picklpf.c | 392 ++ vp8/encoder/ppc/csystemdependent.c | 160 + vp8/encoder/ppc/encodemb_altivec.asm | 153 + vp8/encoder/ppc/fdct_altivec.asm | 205 + vp8/encoder/ppc/rdopt_altivec.asm | 51 + vp8/encoder/psnr.c | 31 + vp8/encoder/psnr.h | 17 + vp8/encoder/quantize.c | 814 +++ vp8/encoder/quantize.h | 23 + vp8/encoder/ratectrl.c | 1569 +++++ vp8/encoder/ratectrl.h | 28 + vp8/encoder/rdopt.c | 2576 +++++++ vp8/encoder/rdopt.h | 133 + vp8/encoder/segmentation.c | 64 + vp8/encoder/segmentation.h | 16 + vp8/encoder/ssim.c | 233 + vp8/encoder/temporal_filter.c | 533 ++ vp8/encoder/tokenize.c | 598 ++ vp8/encoder/tokenize.h | 50 + vp8/encoder/treewriter.c | 43 + vp8/encoder/treewriter.h | 126 + vp8/encoder/x86/dct_mmx.asm | 241 + vp8/encoder/x86/dct_sse2.asm | 432 ++ vp8/encoder/x86/encodeopt.asm | 386 + vp8/encoder/x86/fwalsh_sse2.asm | 164 + vp8/encoder/x86/quantize_mmx.asm | 286 + vp8/encoder/x86/quantize_sse2.asm | 386 + vp8/encoder/x86/quantize_sse4.asm | 256 + vp8/encoder/x86/quantize_ssse3.asm | 138 + vp8/encoder/x86/ssim_opt.asm | 216 + vp8/encoder/x86/subtract_mmx.asm | 223 + vp8/encoder/x86/subtract_sse2.asm | 245 + vp8/encoder/x86/temporal_filter_apply_sse2.asm | 207 + vp8/encoder/x86/vp8_enc_stubs_mmx.c | 78 + vp8/encoder/x86/vp8_enc_stubs_sse2.c | 43 + vp8/exports_dec | 2 + vp8/exports_enc | 2 + vp8/vp8_common.mk | 187 + vp8/vp8_cx_iface.c | 1294 ++++ vp8/vp8_dx_iface.c | 787 +++ vp8/vp8cx.mk | 116 + vp8/vp8cx_arm.mk | 44 + vp8/vp8dx.mk | 64 + vp8_multi_resolution_encoder.c | 476 ++ vp8_scalable_patterns.c | 565 ++ vpx/exports_com | 16 + vpx/exports_dec | 9 + vpx/exports_enc | 8 + vpx/internal/vpx_codec_internal.h | 490 ++ vpx/src/vpx_codec.c | 150 + vpx/src/vpx_decoder.c | 247 + vpx/src/vpx_encoder.c | 423 ++ vpx/src/vpx_image.c | 305 + vpx/vp8.h | 123 + vpx/vp8cx.h | 317 + vpx/vp8dx.h | 83 + vpx/vpx_codec.h | 554 ++ vpx/vpx_codec.mk | 25 + vpx/vpx_codec_impl_bottom.h | 19 + vpx/vpx_codec_impl_top.h | 19 + vpx/vpx_decoder.h | 329 + vpx/vpx_encoder.h | 931 +++ vpx/vpx_image.h | 243 + vpx/vpx_integer.h | 54 + vpx_mem/include/vpx_mem_intrnl.h | 99 + vpx_mem/include/vpx_mem_tracker.h | 180 + vpx_mem/memory_manager/hmm_alloc.c | 60 + vpx_mem/memory_manager/hmm_base.c | 434 ++ vpx_mem/memory_manager/hmm_dflt_abort.c | 54 + vpx_mem/memory_manager/hmm_grow.c | 50 + vpx_mem/memory_manager/hmm_largest.c | 60 + vpx_mem/memory_manager/hmm_resize.c | 119 + vpx_mem/memory_manager/hmm_shrink.c | 111 + vpx_mem/memory_manager/hmm_true.c | 32 + vpx_mem/memory_manager/include/cavl_if.h | 227 + vpx_mem/memory_manager/include/cavl_impl.h | 1267 ++++ vpx_mem/memory_manager/include/heapmm.h | 153 + vpx_mem/memory_manager/include/hmm_cnfg.h | 116 + vpx_mem/memory_manager/include/hmm_intrnl.h | 161 + vpx_mem/vpx_mem.c | 722 ++ vpx_mem/vpx_mem.h | 179 + vpx_mem/vpx_mem.mk | 22 + vpx_mem/vpx_mem_tracker.c | 798 +++ vpx_ports/arm.h | 27 + vpx_ports/arm_cpudetect.c | 218 + vpx_ports/asm_offsets.h | 31 + vpx_ports/emms.asm | 38 + vpx_ports/mem.h | 46 + vpx_ports/mem_ops.h | 234 + vpx_ports/mem_ops_aligned.h | 157 + vpx_ports/vpx_timer.h | 120 + vpx_ports/vpxtypes.h | 167 + vpx_ports/x86.h | 247 + vpx_ports/x86_abi_support.asm | 334 + vpx_ports/x86_cpuid.c | 53 + vpx_scale/arm/neon/vp8_vpxyv12_copy_y_neon.asm | 122 + .../arm/neon/vp8_vpxyv12_copyframe_func_neon.asm | 233 + .../neon/vp8_vpxyv12_copysrcframe_func_neon.asm | 258 + .../neon/vp8_vpxyv12_extendframeborders_neon.asm | 308 + vpx_scale/arm/neon/yv12extend_arm.c | 25 + vpx_scale/generic/bicubic_scaler.c | 602 ++ vpx_scale/generic/gen_scalers.c | 956 +++ vpx_scale/generic/vpxscale.c | 1059 +++ vpx_scale/generic/yv12config.c | 100 + vpx_scale/generic/yv12extend.c | 277 + vpx_scale/generic/yv12extend_generic.h | 25 + vpx_scale/include/generic/vpxscale_arbitrary.h | 56 + vpx_scale/include/generic/vpxscale_depricated.h | 34 + vpx_scale/scale_mode.h | 29 + vpx_scale/vpx_scale.mk | 18 + vpx_scale/vpxscale.h | 42 + vpx_scale/win32/scaleopt.c | 1750 +++++ vpx_scale/win32/scalesystemdependent.c | 91 + vpx_scale/yv12config.h | 73 + vpxdec.c | 1154 +++ vpxenc.c | 2544 +++++++ y4minput.c | 871 +++ y4minput.h | 60 + 879 files changed, 279108 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .mailmap create mode 100644 AUTHORS create mode 100644 CHANGELOG create mode 100644 LICENSE create mode 100644 PATENTS create mode 100644 README create mode 100644 args.c create mode 100644 args.h create mode 100644 build/.gitattributes create mode 100644 build/.gitignore create mode 100644 build/make/Android.mk create mode 100644 build/make/Makefile create mode 100755 build/make/ads2gas.pl create mode 100755 build/make/ads2gas_apple.pl create mode 100755 build/make/armlink_adapter.sh create mode 100755 build/make/configure.sh create mode 100755 build/make/gen_asm_deps.sh create mode 100755 build/make/gen_msvs_def.sh create mode 100755 build/make/gen_msvs_proj.sh create mode 100755 build/make/gen_msvs_sln.sh create mode 100644 build/make/obj_int_extract.c create mode 100755 build/make/rtcd.sh create mode 100755 build/make/version.sh create mode 100644 build/x86-msvs/obj_int_extract.bat create mode 100644 build/x86-msvs/yasm.rules create mode 100755 configure create mode 100644 docs.mk create mode 100644 example_xma.c create mode 100644 examples.mk create mode 100644 examples/decode_to_md5.txt create mode 100644 examples/decode_with_drops.txt create mode 100644 examples/decode_with_partial_drops.txt create mode 100644 examples/decoder_tmpl.c create mode 100644 examples/decoder_tmpl.txt create mode 100644 examples/encoder_tmpl.c create mode 100644 examples/encoder_tmpl.txt create mode 100644 examples/error_resilient.txt create mode 100644 examples/force_keyframe.txt create mode 100755 examples/gen_example_code.sh create mode 100755 examples/gen_example_doxy.php create mode 100755 examples/gen_example_text.sh create mode 100644 examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php create mode 100644 examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php create mode 100644 examples/includes/ASCIIMathPHP-2.0/htmlMathML.js create mode 100644 examples/includes/HTML-Toc-0.91/.gitattributes create mode 100644 examples/includes/HTML-Toc-0.91/Changes create mode 100644 examples/includes/HTML-Toc-0.91/MANIFEST create mode 100644 examples/includes/HTML-Toc-0.91/Makefile.PL create mode 100644 examples/includes/HTML-Toc-0.91/Toc.pm create mode 100644 examples/includes/HTML-Toc-0.91/Toc.pod create mode 100644 examples/includes/HTML-Toc-0.91/TocGenerator.pm create mode 100644 examples/includes/HTML-Toc-0.91/TocInsertor.pm create mode 100644 examples/includes/HTML-Toc-0.91/TocUpdator.pm create mode 100644 examples/includes/HTML-Toc-0.91/t/ManualTest/manualTest1.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/SubDir1/SubSubDir1/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/SubDir1/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/SubDir2/SubSubDir1/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/SubDir2/SubSubDir2/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/SubDir2/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/SubDir3/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/SiteMap/index.htm create mode 100644 examples/includes/HTML-Toc-0.91/t/extend.t create mode 100644 examples/includes/HTML-Toc-0.91/t/format.t create mode 100644 examples/includes/HTML-Toc-0.91/t/generate.t create mode 100644 examples/includes/HTML-Toc-0.91/t/insert.t create mode 100644 examples/includes/HTML-Toc-0.91/t/manualTest.t create mode 100644 examples/includes/HTML-Toc-0.91/t/options.t create mode 100644 examples/includes/HTML-Toc-0.91/t/podExamples.t create mode 100644 examples/includes/HTML-Toc-0.91/t/propagate.t create mode 100644 examples/includes/HTML-Toc-0.91/t/siteMap.t create mode 100644 examples/includes/HTML-Toc-0.91/t/update.t create mode 100644 examples/includes/PHP-Markdown-Extra-1.2.3/License.text create mode 100644 examples/includes/PHP-Markdown-Extra-1.2.3/PHP Markdown Extra Readme.text create mode 100644 examples/includes/PHP-Markdown-Extra-1.2.3/markdown.php create mode 100644 examples/includes/PHP-SmartyPants-1.5.1e/PHP SmartyPants Readme.txt create mode 100644 examples/includes/PHP-SmartyPants-1.5.1e/smartypants.php create mode 100644 examples/includes/geshi/contrib/aliased.php create mode 100644 examples/includes/geshi/contrib/cssgen.php create mode 100644 examples/includes/geshi/contrib/cssgen2.php create mode 100644 examples/includes/geshi/contrib/example.php create mode 100644 examples/includes/geshi/contrib/langcheck.php create mode 100644 examples/includes/geshi/docs/BUGS create mode 100644 examples/includes/geshi/docs/CHANGES create mode 100644 examples/includes/geshi/docs/COPYING create mode 100644 examples/includes/geshi/docs/README create mode 100644 examples/includes/geshi/docs/THANKS create mode 100644 examples/includes/geshi/docs/TODO create mode 100644 examples/includes/geshi/docs/api/__filesource/fsource_geshi_core_geshi.php.html create mode 100644 examples/includes/geshi/docs/api/blank.html create mode 100644 examples/includes/geshi/docs/api/classtrees_geshi.html create mode 100644 examples/includes/geshi/docs/api/elementindex.html create mode 100644 examples/includes/geshi/docs/api/elementindex_geshi.html create mode 100644 examples/includes/geshi/docs/api/errors.html create mode 100644 examples/includes/geshi/docs/api/geshi/core/GeSHi.html create mode 100644 examples/includes/geshi/docs/api/geshi/core/_geshi.php.html create mode 100644 examples/includes/geshi/docs/api/index.html create mode 100644 examples/includes/geshi/docs/api/li_geshi.html create mode 100644 examples/includes/geshi/docs/api/media/banner.css create mode 100644 examples/includes/geshi/docs/api/media/images/AbstractClass.png create mode 100644 examples/includes/geshi/docs/api/media/images/AbstractClass_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/AbstractMethod.png create mode 100644 examples/includes/geshi/docs/api/media/images/AbstractPrivateClass.png create mode 100644 examples/includes/geshi/docs/api/media/images/AbstractPrivateClass_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/AbstractPrivateMethod.png create mode 100644 examples/includes/geshi/docs/api/media/images/Class.png create mode 100644 examples/includes/geshi/docs/api/media/images/Class_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/Constant.png create mode 100644 examples/includes/geshi/docs/api/media/images/Constructor.png create mode 100644 examples/includes/geshi/docs/api/media/images/Destructor.png create mode 100644 examples/includes/geshi/docs/api/media/images/Function.png create mode 100644 examples/includes/geshi/docs/api/media/images/Global.png create mode 100644 examples/includes/geshi/docs/api/media/images/I.png create mode 100644 examples/includes/geshi/docs/api/media/images/Index.png create mode 100644 examples/includes/geshi/docs/api/media/images/Interface.png create mode 100644 examples/includes/geshi/docs/api/media/images/Interface_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/L.png create mode 100644 examples/includes/geshi/docs/api/media/images/Lminus.png create mode 100644 examples/includes/geshi/docs/api/media/images/Lplus.png create mode 100644 examples/includes/geshi/docs/api/media/images/Method.png create mode 100644 examples/includes/geshi/docs/api/media/images/Page.png create mode 100644 examples/includes/geshi/docs/api/media/images/Page_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/PrivateClass.png create mode 100644 examples/includes/geshi/docs/api/media/images/PrivateClass_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/PrivateMethod.png create mode 100644 examples/includes/geshi/docs/api/media/images/PrivateVariable.png create mode 100644 examples/includes/geshi/docs/api/media/images/StaticMethod.png create mode 100644 examples/includes/geshi/docs/api/media/images/StaticVariable.png create mode 100644 examples/includes/geshi/docs/api/media/images/T.png create mode 100644 examples/includes/geshi/docs/api/media/images/Tminus.png create mode 100644 examples/includes/geshi/docs/api/media/images/Tplus.png create mode 100644 examples/includes/geshi/docs/api/media/images/Variable.png create mode 100644 examples/includes/geshi/docs/api/media/images/blank.png create mode 100644 examples/includes/geshi/docs/api/media/images/class_folder.png create mode 100644 examples/includes/geshi/docs/api/media/images/empty.png create mode 100644 examples/includes/geshi/docs/api/media/images/file.png create mode 100644 examples/includes/geshi/docs/api/media/images/folder.png create mode 100644 examples/includes/geshi/docs/api/media/images/function_folder.png create mode 100644 examples/includes/geshi/docs/api/media/images/next_button.png create mode 100644 examples/includes/geshi/docs/api/media/images/next_button_disabled.png create mode 100644 examples/includes/geshi/docs/api/media/images/package.png create mode 100644 examples/includes/geshi/docs/api/media/images/package_folder.png create mode 100644 examples/includes/geshi/docs/api/media/images/previous_button.png create mode 100644 examples/includes/geshi/docs/api/media/images/previous_button_disabled.png create mode 100644 examples/includes/geshi/docs/api/media/images/private_class_logo.png create mode 100644 examples/includes/geshi/docs/api/media/images/tutorial.png create mode 100644 examples/includes/geshi/docs/api/media/images/tutorial_folder.png create mode 100644 examples/includes/geshi/docs/api/media/images/up_button.png create mode 100644 examples/includes/geshi/docs/api/media/stylesheet.css create mode 100644 examples/includes/geshi/docs/api/packages.html create mode 100644 examples/includes/geshi/docs/api/todolist.html create mode 100644 examples/includes/geshi/docs/geshi-doc.html create mode 100644 examples/includes/geshi/docs/geshi-doc.txt create mode 100644 examples/includes/geshi/docs/phpdoc.ini create mode 100644 examples/includes/geshi/geshi.php create mode 100644 examples/includes/geshi/geshi/abap.php create mode 100644 examples/includes/geshi/geshi/actionscript.php create mode 100644 examples/includes/geshi/geshi/actionscript3.php create mode 100644 examples/includes/geshi/geshi/ada.php create mode 100644 examples/includes/geshi/geshi/apache.php create mode 100644 examples/includes/geshi/geshi/applescript.php create mode 100644 examples/includes/geshi/geshi/apt_sources.php create mode 100644 examples/includes/geshi/geshi/asm.php create mode 100644 examples/includes/geshi/geshi/asp.php create mode 100644 examples/includes/geshi/geshi/autoit.php create mode 100644 examples/includes/geshi/geshi/avisynth.php create mode 100644 examples/includes/geshi/geshi/bash.php create mode 100644 examples/includes/geshi/geshi/basic4gl.php create mode 100644 examples/includes/geshi/geshi/bf.php create mode 100644 examples/includes/geshi/geshi/blitzbasic.php create mode 100644 examples/includes/geshi/geshi/bnf.php create mode 100644 examples/includes/geshi/geshi/boo.php create mode 100644 examples/includes/geshi/geshi/c.php create mode 100644 examples/includes/geshi/geshi/c_mac.php create mode 100644 examples/includes/geshi/geshi/caddcl.php create mode 100644 examples/includes/geshi/geshi/cadlisp.php create mode 100644 examples/includes/geshi/geshi/cfdg.php create mode 100644 examples/includes/geshi/geshi/cfm.php create mode 100644 examples/includes/geshi/geshi/cil.php create mode 100644 examples/includes/geshi/geshi/cobol.php create mode 100644 examples/includes/geshi/geshi/cpp-qt.php create mode 100644 examples/includes/geshi/geshi/cpp.php create mode 100644 examples/includes/geshi/geshi/csharp.php create mode 100644 examples/includes/geshi/geshi/css.php create mode 100644 examples/includes/geshi/geshi/d.php create mode 100644 examples/includes/geshi/geshi/dcs.php create mode 100644 examples/includes/geshi/geshi/delphi.php create mode 100644 examples/includes/geshi/geshi/diff.php create mode 100644 examples/includes/geshi/geshi/div.php create mode 100644 examples/includes/geshi/geshi/dos.php create mode 100644 examples/includes/geshi/geshi/dot.php create mode 100644 examples/includes/geshi/geshi/eiffel.php create mode 100644 examples/includes/geshi/geshi/email.php create mode 100644 examples/includes/geshi/geshi/fortran.php create mode 100644 examples/includes/geshi/geshi/freebasic.php create mode 100644 examples/includes/geshi/geshi/genero.php create mode 100644 examples/includes/geshi/geshi/gettext.php create mode 100644 examples/includes/geshi/geshi/glsl.php create mode 100644 examples/includes/geshi/geshi/gml.php create mode 100644 examples/includes/geshi/geshi/gnuplot.php create mode 100644 examples/includes/geshi/geshi/groovy.php create mode 100644 examples/includes/geshi/geshi/haskell.php create mode 100644 examples/includes/geshi/geshi/hq9plus.php create mode 100644 examples/includes/geshi/geshi/html4strict.php create mode 100644 examples/includes/geshi/geshi/idl.php create mode 100644 examples/includes/geshi/geshi/ini.php create mode 100644 examples/includes/geshi/geshi/inno.php create mode 100644 examples/includes/geshi/geshi/intercal.php create mode 100644 examples/includes/geshi/geshi/io.php create mode 100644 examples/includes/geshi/geshi/java.php create mode 100644 examples/includes/geshi/geshi/java5.php create mode 100644 examples/includes/geshi/geshi/javascript.php create mode 100644 examples/includes/geshi/geshi/kixtart.php create mode 100644 examples/includes/geshi/geshi/klonec.php create mode 100644 examples/includes/geshi/geshi/klonecpp.php create mode 100644 examples/includes/geshi/geshi/latex.php create mode 100644 examples/includes/geshi/geshi/lisp.php create mode 100644 examples/includes/geshi/geshi/locobasic.php create mode 100644 examples/includes/geshi/geshi/lolcode.php create mode 100644 examples/includes/geshi/geshi/lotusformulas.php create mode 100644 examples/includes/geshi/geshi/lotusscript.php create mode 100644 examples/includes/geshi/geshi/lscript.php create mode 100644 examples/includes/geshi/geshi/lsl2.php create mode 100644 examples/includes/geshi/geshi/lua.php create mode 100644 examples/includes/geshi/geshi/m68k.php create mode 100644 examples/includes/geshi/geshi/make.php create mode 100644 examples/includes/geshi/geshi/matlab.php create mode 100644 examples/includes/geshi/geshi/mirc.php create mode 100644 examples/includes/geshi/geshi/modula3.php create mode 100644 examples/includes/geshi/geshi/mpasm.php create mode 100644 examples/includes/geshi/geshi/mxml.php create mode 100644 examples/includes/geshi/geshi/mysql.php create mode 100644 examples/includes/geshi/geshi/nsis.php create mode 100644 examples/includes/geshi/geshi/objc.php create mode 100644 examples/includes/geshi/geshi/ocaml-brief.php create mode 100644 examples/includes/geshi/geshi/ocaml.php create mode 100644 examples/includes/geshi/geshi/oobas.php create mode 100644 examples/includes/geshi/geshi/oracle11.php create mode 100644 examples/includes/geshi/geshi/oracle8.php create mode 100644 examples/includes/geshi/geshi/pascal.php create mode 100644 examples/includes/geshi/geshi/per.php create mode 100644 examples/includes/geshi/geshi/perl.php create mode 100644 examples/includes/geshi/geshi/php-brief.php create mode 100644 examples/includes/geshi/geshi/php.php create mode 100644 examples/includes/geshi/geshi/pic16.php create mode 100644 examples/includes/geshi/geshi/pixelbender.php create mode 100644 examples/includes/geshi/geshi/plsql.php create mode 100644 examples/includes/geshi/geshi/povray.php create mode 100644 examples/includes/geshi/geshi/powershell.php create mode 100644 examples/includes/geshi/geshi/progress.php create mode 100644 examples/includes/geshi/geshi/prolog.php create mode 100644 examples/includes/geshi/geshi/providex.php create mode 100644 examples/includes/geshi/geshi/python.php create mode 100644 examples/includes/geshi/geshi/qbasic.php create mode 100644 examples/includes/geshi/geshi/rails.php create mode 100644 examples/includes/geshi/geshi/rebol.php create mode 100644 examples/includes/geshi/geshi/reg.php create mode 100644 examples/includes/geshi/geshi/robots.php create mode 100644 examples/includes/geshi/geshi/ruby.php create mode 100644 examples/includes/geshi/geshi/sas.php create mode 100644 examples/includes/geshi/geshi/scala.php create mode 100644 examples/includes/geshi/geshi/scheme.php create mode 100644 examples/includes/geshi/geshi/scilab.php create mode 100644 examples/includes/geshi/geshi/sdlbasic.php create mode 100644 examples/includes/geshi/geshi/smalltalk.php create mode 100644 examples/includes/geshi/geshi/smarty.php create mode 100644 examples/includes/geshi/geshi/sql.php create mode 100644 examples/includes/geshi/geshi/tcl.php create mode 100644 examples/includes/geshi/geshi/teraterm.php create mode 100644 examples/includes/geshi/geshi/text.php create mode 100644 examples/includes/geshi/geshi/thinbasic.php create mode 100644 examples/includes/geshi/geshi/tsql.php create mode 100644 examples/includes/geshi/geshi/typoscript.php create mode 100644 examples/includes/geshi/geshi/vb.php create mode 100644 examples/includes/geshi/geshi/vbnet.php create mode 100644 examples/includes/geshi/geshi/verilog.php create mode 100644 examples/includes/geshi/geshi/vhdl.php create mode 100644 examples/includes/geshi/geshi/vim.php create mode 100644 examples/includes/geshi/geshi/visualfoxpro.php create mode 100644 examples/includes/geshi/geshi/visualprolog.php create mode 100644 examples/includes/geshi/geshi/whitespace.php create mode 100644 examples/includes/geshi/geshi/winbatch.php create mode 100644 examples/includes/geshi/geshi/xml.php create mode 100644 examples/includes/geshi/geshi/xorg_conf.php create mode 100644 examples/includes/geshi/geshi/xpp.php create mode 100644 examples/includes/geshi/geshi/z80.php create mode 100644 examples/includes/vp8_doc_tools.php create mode 100644 examples/postproc.txt create mode 100644 examples/simple_decoder.txt create mode 100644 examples/simple_encoder.txt create mode 100644 examples/twopass_encoder.txt create mode 100644 examples/vp8_set_maps.txt create mode 100644 examples/vp8cx_set_ref.txt create mode 100644 keywords.dox create mode 100644 libmkv/EbmlBufferWriter.c create mode 100644 libmkv/EbmlBufferWriter.h create mode 100644 libmkv/EbmlIDs.h create mode 100644 libmkv/EbmlWriter.c create mode 100644 libmkv/EbmlWriter.h create mode 100644 libmkv/Makefile create mode 100644 libmkv/WebMElement.c create mode 100644 libmkv/WebMElement.h create mode 100644 libmkv/testlibmkv.c create mode 100644 libs.doxy_template create mode 100644 libs.mk create mode 100644 mainpage.dox create mode 100644 md5_utils.c create mode 100644 md5_utils.h create mode 100644 nestegg/.gitignore create mode 100644 nestegg/AUTHORS create mode 100644 nestegg/INSTALL create mode 100644 nestegg/LICENSE create mode 100644 nestegg/Makefile.am create mode 100644 nestegg/README create mode 100644 nestegg/TODO create mode 100644 nestegg/configure.ac create mode 100644 nestegg/docs/Doxyfile.in create mode 100644 nestegg/docs/Makefile.am create mode 100644 nestegg/halloc/README create mode 100644 nestegg/halloc/halloc.h create mode 100644 nestegg/halloc/src/align.h create mode 100644 nestegg/halloc/src/halloc.c create mode 100644 nestegg/halloc/src/hlist.h create mode 100644 nestegg/halloc/src/macros.h create mode 100644 nestegg/include/nestegg/nestegg.h create mode 100644 nestegg/m4/as-ac-expand.m4 create mode 100644 nestegg/m4/ax_create_stdint_h.m4 create mode 100644 nestegg/m4/pkg.m4 create mode 100644 nestegg/nestegg-uninstalled.pc.in create mode 100644 nestegg/nestegg.pc.in create mode 100644 nestegg/src/nestegg.c create mode 100644 nestegg/test/test.c create mode 100644 solution.mk create mode 100644 third_party/googletest/README.webm create mode 100644 third_party/googletest/gtest.mk create mode 100644 third_party/googletest/src/CHANGES create mode 100644 third_party/googletest/src/CMakeLists.txt create mode 100644 third_party/googletest/src/CONTRIBUTORS create mode 100644 third_party/googletest/src/COPYING create mode 100644 third_party/googletest/src/Makefile.am create mode 100644 third_party/googletest/src/README create mode 100644 third_party/googletest/src/build-aux/.keep create mode 100644 third_party/googletest/src/cmake/internal_utils.cmake create mode 100644 third_party/googletest/src/codegear/gtest.cbproj create mode 100644 third_party/googletest/src/codegear/gtest.groupproj create mode 100644 third_party/googletest/src/codegear/gtest_all.cc create mode 100644 third_party/googletest/src/codegear/gtest_link.cc create mode 100644 third_party/googletest/src/codegear/gtest_main.cbproj create mode 100644 third_party/googletest/src/codegear/gtest_unittest.cbproj create mode 100644 third_party/googletest/src/configure.ac create mode 100644 third_party/googletest/src/include/gtest/gtest-death-test.h create mode 100644 third_party/googletest/src/include/gtest/gtest-message.h create mode 100644 third_party/googletest/src/include/gtest/gtest-param-test.h create mode 100644 third_party/googletest/src/include/gtest/gtest-param-test.h.pump create mode 100644 third_party/googletest/src/include/gtest/gtest-printers.h create mode 100644 third_party/googletest/src/include/gtest/gtest-spi.h create mode 100644 third_party/googletest/src/include/gtest/gtest-test-part.h create mode 100644 third_party/googletest/src/include/gtest/gtest-typed-test.h create mode 100644 third_party/googletest/src/include/gtest/gtest.h create mode 100644 third_party/googletest/src/include/gtest/gtest_pred_impl.h create mode 100644 third_party/googletest/src/include/gtest/gtest_prod.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-death-test-internal.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-filepath.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-internal.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-linked_ptr.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h.pump create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-param-util.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-port.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-string.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-tuple.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-tuple.h.pump create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-type-util.h create mode 100644 third_party/googletest/src/include/gtest/internal/gtest-type-util.h.pump create mode 100644 third_party/googletest/src/m4/acx_pthread.m4 create mode 100644 third_party/googletest/src/m4/gtest.m4 create mode 100644 third_party/googletest/src/make/Makefile create mode 100644 third_party/googletest/src/msvc/gtest-md.sln create mode 100644 third_party/googletest/src/msvc/gtest-md.vcproj create mode 100644 third_party/googletest/src/msvc/gtest.sln create mode 100644 third_party/googletest/src/msvc/gtest.vcproj create mode 100644 third_party/googletest/src/msvc/gtest_main-md.vcproj create mode 100644 third_party/googletest/src/msvc/gtest_main.vcproj create mode 100644 third_party/googletest/src/msvc/gtest_prod_test-md.vcproj create mode 100644 third_party/googletest/src/msvc/gtest_prod_test.vcproj create mode 100644 third_party/googletest/src/msvc/gtest_unittest-md.vcproj create mode 100644 third_party/googletest/src/msvc/gtest_unittest.vcproj create mode 100644 third_party/googletest/src/samples/prime_tables.h create mode 100644 third_party/googletest/src/samples/sample1.cc create mode 100644 third_party/googletest/src/samples/sample1.h create mode 100644 third_party/googletest/src/samples/sample10_unittest.cc create mode 100644 third_party/googletest/src/samples/sample1_unittest.cc create mode 100644 third_party/googletest/src/samples/sample2.cc create mode 100644 third_party/googletest/src/samples/sample2.h create mode 100644 third_party/googletest/src/samples/sample2_unittest.cc create mode 100644 third_party/googletest/src/samples/sample3-inl.h create mode 100644 third_party/googletest/src/samples/sample3_unittest.cc create mode 100644 third_party/googletest/src/samples/sample4.cc create mode 100644 third_party/googletest/src/samples/sample4.h create mode 100644 third_party/googletest/src/samples/sample4_unittest.cc create mode 100644 third_party/googletest/src/samples/sample5_unittest.cc create mode 100644 third_party/googletest/src/samples/sample6_unittest.cc create mode 100644 third_party/googletest/src/samples/sample7_unittest.cc create mode 100644 third_party/googletest/src/samples/sample8_unittest.cc create mode 100644 third_party/googletest/src/samples/sample9_unittest.cc create mode 100755 third_party/googletest/src/scripts/fuse_gtest_files.py create mode 100755 third_party/googletest/src/scripts/gen_gtest_pred_impl.py create mode 100644 third_party/googletest/src/scripts/gtest-config.in create mode 100755 third_party/googletest/src/scripts/pump.py create mode 100644 third_party/googletest/src/scripts/test/Makefile create mode 100755 third_party/googletest/src/scripts/upload.py create mode 100755 third_party/googletest/src/scripts/upload_gtest.py create mode 100644 third_party/googletest/src/src/gtest-all.cc create mode 100644 third_party/googletest/src/src/gtest-death-test.cc create mode 100644 third_party/googletest/src/src/gtest-filepath.cc create mode 100644 third_party/googletest/src/src/gtest-internal-inl.h create mode 100644 third_party/googletest/src/src/gtest-port.cc create mode 100644 third_party/googletest/src/src/gtest-printers.cc create mode 100644 third_party/googletest/src/src/gtest-test-part.cc create mode 100644 third_party/googletest/src/src/gtest-typed-test.cc create mode 100644 third_party/googletest/src/src/gtest.cc create mode 100644 third_party/googletest/src/src/gtest_main.cc create mode 100644 third_party/googletest/src/test/gtest-death-test_ex_test.cc create mode 100644 third_party/googletest/src/test/gtest-death-test_test.cc create mode 100644 third_party/googletest/src/test/gtest-filepath_test.cc create mode 100644 third_party/googletest/src/test/gtest-linked_ptr_test.cc create mode 100644 third_party/googletest/src/test/gtest-listener_test.cc create mode 100644 third_party/googletest/src/test/gtest-message_test.cc create mode 100644 third_party/googletest/src/test/gtest-options_test.cc create mode 100644 third_party/googletest/src/test/gtest-param-test2_test.cc create mode 100644 third_party/googletest/src/test/gtest-param-test_test.cc create mode 100644 third_party/googletest/src/test/gtest-param-test_test.h create mode 100644 third_party/googletest/src/test/gtest-port_test.cc create mode 100644 third_party/googletest/src/test/gtest-printers_test.cc create mode 100644 third_party/googletest/src/test/gtest-test-part_test.cc create mode 100644 third_party/googletest/src/test/gtest-tuple_test.cc create mode 100644 third_party/googletest/src/test/gtest-typed-test2_test.cc create mode 100644 third_party/googletest/src/test/gtest-typed-test_test.cc create mode 100644 third_party/googletest/src/test/gtest-typed-test_test.h create mode 100644 third_party/googletest/src/test/gtest-unittest-api_test.cc create mode 100644 third_party/googletest/src/test/gtest_all_test.cc create mode 100755 third_party/googletest/src/test/gtest_break_on_failure_unittest.py create mode 100644 third_party/googletest/src/test/gtest_break_on_failure_unittest_.cc create mode 100755 third_party/googletest/src/test/gtest_catch_exceptions_test.py create mode 100644 third_party/googletest/src/test/gtest_catch_exceptions_test_.cc create mode 100755 third_party/googletest/src/test/gtest_color_test.py create mode 100644 third_party/googletest/src/test/gtest_color_test_.cc create mode 100755 third_party/googletest/src/test/gtest_env_var_test.py create mode 100644 third_party/googletest/src/test/gtest_env_var_test_.cc create mode 100644 third_party/googletest/src/test/gtest_environment_test.cc create mode 100755 third_party/googletest/src/test/gtest_filter_unittest.py create mode 100644 third_party/googletest/src/test/gtest_filter_unittest_.cc create mode 100755 third_party/googletest/src/test/gtest_help_test.py create mode 100644 third_party/googletest/src/test/gtest_help_test_.cc create mode 100755 third_party/googletest/src/test/gtest_list_tests_unittest.py create mode 100644 third_party/googletest/src/test/gtest_list_tests_unittest_.cc create mode 100644 third_party/googletest/src/test/gtest_main_unittest.cc create mode 100644 third_party/googletest/src/test/gtest_no_test_unittest.cc create mode 100755 third_party/googletest/src/test/gtest_output_test.py create mode 100644 third_party/googletest/src/test/gtest_output_test_.cc create mode 100644 third_party/googletest/src/test/gtest_output_test_golden_lin.txt create mode 100644 third_party/googletest/src/test/gtest_pred_impl_unittest.cc create mode 100644 third_party/googletest/src/test/gtest_prod_test.cc create mode 100644 third_party/googletest/src/test/gtest_repeat_test.cc create mode 100755 third_party/googletest/src/test/gtest_shuffle_test.py create mode 100644 third_party/googletest/src/test/gtest_shuffle_test_.cc create mode 100644 third_party/googletest/src/test/gtest_sole_header_test.cc create mode 100644 third_party/googletest/src/test/gtest_stress_test.cc create mode 100755 third_party/googletest/src/test/gtest_test_utils.py create mode 100644 third_party/googletest/src/test/gtest_throw_on_failure_ex_test.cc create mode 100755 third_party/googletest/src/test/gtest_throw_on_failure_test.py create mode 100644 third_party/googletest/src/test/gtest_throw_on_failure_test_.cc create mode 100755 third_party/googletest/src/test/gtest_uninitialized_test.py create mode 100644 third_party/googletest/src/test/gtest_uninitialized_test_.cc create mode 100644 third_party/googletest/src/test/gtest_unittest.cc create mode 100644 third_party/googletest/src/test/gtest_xml_outfile1_test_.cc create mode 100644 third_party/googletest/src/test/gtest_xml_outfile2_test_.cc create mode 100755 third_party/googletest/src/test/gtest_xml_outfiles_test.py create mode 100755 third_party/googletest/src/test/gtest_xml_output_unittest.py create mode 100644 third_party/googletest/src/test/gtest_xml_output_unittest_.cc create mode 100755 third_party/googletest/src/test/gtest_xml_test_utils.py create mode 100644 third_party/googletest/src/test/production.cc create mode 100644 third_party/googletest/src/test/production.h create mode 100644 third_party/googletest/src/xcode/Config/DebugProject.xcconfig create mode 100644 third_party/googletest/src/xcode/Config/FrameworkTarget.xcconfig create mode 100644 third_party/googletest/src/xcode/Config/General.xcconfig create mode 100644 third_party/googletest/src/xcode/Config/ReleaseProject.xcconfig create mode 100644 third_party/googletest/src/xcode/Config/StaticLibraryTarget.xcconfig create mode 100644 third_party/googletest/src/xcode/Config/TestTarget.xcconfig create mode 100644 third_party/googletest/src/xcode/Resources/Info.plist create mode 100644 third_party/googletest/src/xcode/Samples/FrameworkSample/Info.plist create mode 100644 third_party/googletest/src/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj create mode 100755 third_party/googletest/src/xcode/Samples/FrameworkSample/runtests.sh create mode 100644 third_party/googletest/src/xcode/Samples/FrameworkSample/widget.cc create mode 100644 third_party/googletest/src/xcode/Samples/FrameworkSample/widget.h create mode 100644 third_party/googletest/src/xcode/Samples/FrameworkSample/widget_test.cc create mode 100755 third_party/googletest/src/xcode/Scripts/runtests.sh create mode 100755 third_party/googletest/src/xcode/Scripts/versiongenerate.py create mode 100644 third_party/googletest/src/xcode/gtest.xcodeproj/project.pbxproj create mode 100644 third_party/libyuv/README.webm create mode 100644 third_party/libyuv/include/libyuv/basic_types.h create mode 100644 third_party/libyuv/include/libyuv/cpu_id.h create mode 100644 third_party/libyuv/include/libyuv/scale.h create mode 100644 third_party/libyuv/source/cpu_id.c create mode 100644 third_party/libyuv/source/row.h create mode 100644 third_party/libyuv/source/scale.c create mode 100755 tools/author_first_release.sh create mode 100755 tools/ftfy.sh create mode 100755 tools/gen_authors.sh create mode 100755 tools/intersect-diffs.py create mode 100755 tools/wrap-commit-msg.py create mode 100644 tools_common.c create mode 100644 tools_common.h create mode 100644 usage.dox create mode 100644 usage_cx.dox create mode 100644 usage_dx.dox create mode 100644 vp8/common/alloccommon.c create mode 100644 vp8/common/alloccommon.h create mode 100644 vp8/common/arm/armv6/bilinearfilter_v6.asm create mode 100644 vp8/common/arm/armv6/copymem16x16_v6.asm create mode 100644 vp8/common/arm/armv6/copymem8x4_v6.asm create mode 100644 vp8/common/arm/armv6/copymem8x8_v6.asm create mode 100644 vp8/common/arm/armv6/dc_only_idct_add_v6.asm create mode 100644 vp8/common/arm/armv6/dequant_idct_v6.asm create mode 100644 vp8/common/arm/armv6/dequantize_v6.asm create mode 100644 vp8/common/arm/armv6/filter_v6.asm create mode 100644 vp8/common/arm/armv6/idct_blk_v6.c create mode 100644 vp8/common/arm/armv6/idct_v6.asm create mode 100644 vp8/common/arm/armv6/intra4x4_predict_v6.asm create mode 100644 vp8/common/arm/armv6/iwalsh_v6.asm create mode 100644 vp8/common/arm/armv6/loopfilter_v6.asm create mode 100644 vp8/common/arm/armv6/simpleloopfilter_v6.asm create mode 100644 vp8/common/arm/armv6/sixtappredict8x4_v6.asm create mode 100644 vp8/common/arm/armv6/vp8_sad16x16_armv6.asm create mode 100644 vp8/common/arm/armv6/vp8_variance16x16_armv6.asm create mode 100644 vp8/common/arm/armv6/vp8_variance8x8_armv6.asm create mode 100644 vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_h_armv6.asm create mode 100644 vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_hv_armv6.asm create mode 100644 vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_v_armv6.asm create mode 100644 vp8/common/arm/bilinearfilter_arm.c create mode 100644 vp8/common/arm/bilinearfilter_arm.h create mode 100644 vp8/common/arm/dequantize_arm.c create mode 100644 vp8/common/arm/filter_arm.c create mode 100644 vp8/common/arm/loopfilter_arm.c create mode 100644 vp8/common/arm/neon/bilinearpredict16x16_neon.asm create mode 100644 vp8/common/arm/neon/bilinearpredict4x4_neon.asm create mode 100644 vp8/common/arm/neon/bilinearpredict8x4_neon.asm create mode 100644 vp8/common/arm/neon/bilinearpredict8x8_neon.asm create mode 100644 vp8/common/arm/neon/buildintrapredictorsmby_neon.asm create mode 100644 vp8/common/arm/neon/copymem16x16_neon.asm create mode 100644 vp8/common/arm/neon/copymem8x4_neon.asm create mode 100644 vp8/common/arm/neon/copymem8x8_neon.asm create mode 100644 vp8/common/arm/neon/dc_only_idct_add_neon.asm create mode 100644 vp8/common/arm/neon/dequant_idct_neon.asm create mode 100644 vp8/common/arm/neon/dequantizeb_neon.asm create mode 100644 vp8/common/arm/neon/idct_blk_neon.c create mode 100644 vp8/common/arm/neon/idct_dequant_0_2x_neon.asm create mode 100644 vp8/common/arm/neon/idct_dequant_full_2x_neon.asm create mode 100644 vp8/common/arm/neon/iwalsh_neon.asm create mode 100644 vp8/common/arm/neon/loopfilter_neon.asm create mode 100644 vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm create mode 100644 vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm create mode 100644 vp8/common/arm/neon/mbloopfilter_neon.asm create mode 100644 vp8/common/arm/neon/sad16_neon.asm create mode 100644 vp8/common/arm/neon/sad8_neon.asm create mode 100644 vp8/common/arm/neon/save_reg_neon.asm create mode 100644 vp8/common/arm/neon/shortidct4x4llm_neon.asm create mode 100644 vp8/common/arm/neon/sixtappredict16x16_neon.asm create mode 100644 vp8/common/arm/neon/sixtappredict4x4_neon.asm create mode 100644 vp8/common/arm/neon/sixtappredict8x4_neon.asm create mode 100644 vp8/common/arm/neon/sixtappredict8x8_neon.asm create mode 100644 vp8/common/arm/neon/variance_neon.asm create mode 100644 vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm create mode 100644 vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm create mode 100644 vp8/common/arm/neon/vp8_subpixelvariance8x8_neon.asm create mode 100644 vp8/common/arm/reconintra_arm.c create mode 100644 vp8/common/arm/variance_arm.c create mode 100644 vp8/common/asm_com_offsets.c create mode 100644 vp8/common/blockd.c create mode 100644 vp8/common/blockd.h create mode 100644 vp8/common/coefupdateprobs.h create mode 100644 vp8/common/common.h create mode 100644 vp8/common/context.c create mode 100644 vp8/common/debugmodes.c create mode 100644 vp8/common/default_coef_probs.h create mode 100644 vp8/common/dequantize.c create mode 100644 vp8/common/entropy.c create mode 100644 vp8/common/entropy.h create mode 100644 vp8/common/entropymode.c create mode 100644 vp8/common/entropymode.h create mode 100644 vp8/common/entropymv.c create mode 100644 vp8/common/entropymv.h create mode 100644 vp8/common/extend.c create mode 100644 vp8/common/extend.h create mode 100644 vp8/common/filter.c create mode 100644 vp8/common/filter.h create mode 100644 vp8/common/findnearmv.c create mode 100644 vp8/common/findnearmv.h create mode 100644 vp8/common/generic/systemdependent.c create mode 100644 vp8/common/header.h create mode 100644 vp8/common/idct_blk.c create mode 100644 vp8/common/idctllm.c create mode 100755 vp8/common/idctllm_test.cc create mode 100755 vp8/common/idctllm_test.h create mode 100644 vp8/common/invtrans.h create mode 100644 vp8/common/loopfilter.c create mode 100644 vp8/common/loopfilter.h create mode 100644 vp8/common/loopfilter_filters.c create mode 100644 vp8/common/mbpitch.c create mode 100644 vp8/common/mfqe.c create mode 100644 vp8/common/modecont.c create mode 100644 vp8/common/modecont.h create mode 100644 vp8/common/mv.h create mode 100644 vp8/common/onyx.h create mode 100644 vp8/common/onyxc_int.h create mode 100644 vp8/common/onyxd.h create mode 100644 vp8/common/postproc.c create mode 100644 vp8/common/postproc.h create mode 100644 vp8/common/ppc/copy_altivec.asm create mode 100644 vp8/common/ppc/filter_altivec.asm create mode 100644 vp8/common/ppc/filter_bilinear_altivec.asm create mode 100644 vp8/common/ppc/idctllm_altivec.asm create mode 100644 vp8/common/ppc/loopfilter_altivec.c create mode 100644 vp8/common/ppc/loopfilter_filters_altivec.asm create mode 100644 vp8/common/ppc/platform_altivec.asm create mode 100644 vp8/common/ppc/recon_altivec.asm create mode 100644 vp8/common/ppc/sad_altivec.asm create mode 100644 vp8/common/ppc/systemdependent.c create mode 100644 vp8/common/ppc/variance_altivec.asm create mode 100644 vp8/common/ppc/variance_subpixel_altivec.asm create mode 100644 vp8/common/ppflags.h create mode 100644 vp8/common/pragmas.h create mode 100644 vp8/common/quant_common.c create mode 100644 vp8/common/quant_common.h create mode 100644 vp8/common/reconinter.c create mode 100644 vp8/common/reconinter.h create mode 100644 vp8/common/reconintra.c create mode 100644 vp8/common/reconintra4x4.c create mode 100644 vp8/common/reconintra4x4.h create mode 100644 vp8/common/rtcd.c create mode 100644 vp8/common/rtcd_defs.sh create mode 100644 vp8/common/sad_c.c create mode 100644 vp8/common/setupintrarecon.c create mode 100644 vp8/common/setupintrarecon.h create mode 100644 vp8/common/swapyv12buffer.c create mode 100644 vp8/common/swapyv12buffer.h create mode 100644 vp8/common/systemdependent.h create mode 100644 vp8/common/textblit.c create mode 100644 vp8/common/threading.h create mode 100644 vp8/common/treecoder.c create mode 100644 vp8/common/treecoder.h create mode 100644 vp8/common/variance.h create mode 100644 vp8/common/variance_c.c create mode 100755 vp8/common/vp8_entropymodedata.h create mode 100644 vp8/common/x86/dequantize_mmx.asm create mode 100644 vp8/common/x86/filter_x86.c create mode 100644 vp8/common/x86/filter_x86.h create mode 100644 vp8/common/x86/idct_blk_mmx.c create mode 100644 vp8/common/x86/idct_blk_sse2.c create mode 100644 vp8/common/x86/idctllm_mmx.asm create mode 100755 vp8/common/x86/idctllm_mmx_test.cc create mode 100644 vp8/common/x86/idctllm_sse2.asm create mode 100644 vp8/common/x86/iwalsh_mmx.asm create mode 100644 vp8/common/x86/iwalsh_sse2.asm create mode 100644 vp8/common/x86/loopfilter_block_sse2.asm create mode 100644 vp8/common/x86/loopfilter_mmx.asm create mode 100644 vp8/common/x86/loopfilter_sse2.asm create mode 100644 vp8/common/x86/loopfilter_x86.c create mode 100644 vp8/common/x86/mfqe_sse2.asm create mode 100644 vp8/common/x86/postproc_mmx.asm create mode 100644 vp8/common/x86/postproc_sse2.asm create mode 100644 vp8/common/x86/postproc_x86.c create mode 100644 vp8/common/x86/recon_mmx.asm create mode 100644 vp8/common/x86/recon_sse2.asm create mode 100644 vp8/common/x86/recon_wrapper_sse2.c create mode 100644 vp8/common/x86/sad_mmx.asm create mode 100644 vp8/common/x86/sad_sse2.asm create mode 100644 vp8/common/x86/sad_sse3.asm create mode 100644 vp8/common/x86/sad_sse4.asm create mode 100644 vp8/common/x86/sad_ssse3.asm create mode 100644 vp8/common/x86/subpixel_mmx.asm create mode 100644 vp8/common/x86/subpixel_sse2.asm create mode 100644 vp8/common/x86/subpixel_ssse3.asm create mode 100644 vp8/common/x86/variance_impl_mmx.asm create mode 100644 vp8/common/x86/variance_impl_sse2.asm create mode 100644 vp8/common/x86/variance_impl_ssse3.asm create mode 100644 vp8/common/x86/variance_mmx.c create mode 100644 vp8/common/x86/variance_sse2.c create mode 100644 vp8/common/x86/variance_ssse3.c create mode 100644 vp8/common/x86/vp8_asm_stubs.c create mode 100644 vp8/decoder/asm_dec_offsets.c create mode 100644 vp8/decoder/dboolhuff.c create mode 100644 vp8/decoder/dboolhuff.h create mode 100644 vp8/decoder/decodemv.c create mode 100644 vp8/decoder/decodemv.h create mode 100644 vp8/decoder/decoderthreading.h create mode 100644 vp8/decoder/decodframe.c create mode 100644 vp8/decoder/detokenize.c create mode 100644 vp8/decoder/detokenize.h create mode 100644 vp8/decoder/ec_types.h create mode 100644 vp8/decoder/error_concealment.c create mode 100644 vp8/decoder/error_concealment.h create mode 100644 vp8/decoder/onyxd_if.c create mode 100644 vp8/decoder/onyxd_int.h create mode 100644 vp8/decoder/threading.c create mode 100644 vp8/decoder/treereader.h create mode 100644 vp8/encoder/arm/armv5te/boolhuff_armv5te.asm create mode 100644 vp8/encoder/arm/armv5te/vp8_packtokens_armv5.asm create mode 100644 vp8/encoder/arm/armv5te/vp8_packtokens_mbrow_armv5.asm create mode 100644 vp8/encoder/arm/armv5te/vp8_packtokens_partitions_armv5.asm create mode 100644 vp8/encoder/arm/armv6/vp8_fast_quantize_b_armv6.asm create mode 100644 vp8/encoder/arm/armv6/vp8_mse16x16_armv6.asm create mode 100644 vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm create mode 100644 vp8/encoder/arm/armv6/vp8_subtract_armv6.asm create mode 100644 vp8/encoder/arm/armv6/walsh_v6.asm create mode 100644 vp8/encoder/arm/boolhuff_arm.c create mode 100644 vp8/encoder/arm/dct_arm.c create mode 100644 vp8/encoder/arm/neon/fastquantizeb_neon.asm create mode 100644 vp8/encoder/arm/neon/picklpf_arm.c create mode 100644 vp8/encoder/arm/neon/shortfdct_neon.asm create mode 100644 vp8/encoder/arm/neon/subtract_neon.asm create mode 100644 vp8/encoder/arm/neon/vp8_memcpy_neon.asm create mode 100644 vp8/encoder/arm/neon/vp8_mse16x16_neon.asm create mode 100644 vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm create mode 100644 vp8/encoder/arm/quantize_arm.c create mode 100644 vp8/encoder/asm_enc_offsets.c create mode 100644 vp8/encoder/bitstream.c create mode 100644 vp8/encoder/bitstream.h create mode 100644 vp8/encoder/block.h create mode 100644 vp8/encoder/boolhuff.c create mode 100644 vp8/encoder/boolhuff.h create mode 100644 vp8/encoder/dct.c create mode 100644 vp8/encoder/dct_value_cost.h create mode 100644 vp8/encoder/dct_value_tokens.h create mode 100644 vp8/encoder/defaultcoefcounts.h create mode 100644 vp8/encoder/denoising.c create mode 100644 vp8/encoder/denoising.h create mode 100644 vp8/encoder/encodeframe.c create mode 100644 vp8/encoder/encodeframe.h create mode 100644 vp8/encoder/encodeintra.c create mode 100644 vp8/encoder/encodeintra.h create mode 100644 vp8/encoder/encodemb.c create mode 100644 vp8/encoder/encodemb.h create mode 100644 vp8/encoder/encodemv.c create mode 100644 vp8/encoder/encodemv.h create mode 100644 vp8/encoder/ethreading.c create mode 100644 vp8/encoder/firstpass.c create mode 100644 vp8/encoder/firstpass.h create mode 100644 vp8/encoder/lookahead.c create mode 100644 vp8/encoder/lookahead.h create mode 100644 vp8/encoder/mcomp.c create mode 100644 vp8/encoder/mcomp.h create mode 100644 vp8/encoder/modecosts.c create mode 100644 vp8/encoder/modecosts.h create mode 100644 vp8/encoder/mr_dissim.c create mode 100644 vp8/encoder/mr_dissim.h create mode 100644 vp8/encoder/onyx_if.c create mode 100644 vp8/encoder/onyx_int.h create mode 100644 vp8/encoder/pickinter.c create mode 100644 vp8/encoder/pickinter.h create mode 100644 vp8/encoder/picklpf.c create mode 100644 vp8/encoder/ppc/csystemdependent.c create mode 100644 vp8/encoder/ppc/encodemb_altivec.asm create mode 100644 vp8/encoder/ppc/fdct_altivec.asm create mode 100644 vp8/encoder/ppc/rdopt_altivec.asm create mode 100644 vp8/encoder/psnr.c create mode 100644 vp8/encoder/psnr.h create mode 100644 vp8/encoder/quantize.c create mode 100644 vp8/encoder/quantize.h create mode 100644 vp8/encoder/ratectrl.c create mode 100644 vp8/encoder/ratectrl.h create mode 100644 vp8/encoder/rdopt.c create mode 100644 vp8/encoder/rdopt.h create mode 100644 vp8/encoder/segmentation.c create mode 100644 vp8/encoder/segmentation.h create mode 100644 vp8/encoder/ssim.c create mode 100644 vp8/encoder/temporal_filter.c create mode 100644 vp8/encoder/tokenize.c create mode 100644 vp8/encoder/tokenize.h create mode 100644 vp8/encoder/treewriter.c create mode 100644 vp8/encoder/treewriter.h create mode 100644 vp8/encoder/x86/dct_mmx.asm create mode 100644 vp8/encoder/x86/dct_sse2.asm create mode 100644 vp8/encoder/x86/encodeopt.asm create mode 100644 vp8/encoder/x86/fwalsh_sse2.asm create mode 100644 vp8/encoder/x86/quantize_mmx.asm create mode 100644 vp8/encoder/x86/quantize_sse2.asm create mode 100644 vp8/encoder/x86/quantize_sse4.asm create mode 100644 vp8/encoder/x86/quantize_ssse3.asm create mode 100644 vp8/encoder/x86/ssim_opt.asm create mode 100644 vp8/encoder/x86/subtract_mmx.asm create mode 100644 vp8/encoder/x86/subtract_sse2.asm create mode 100644 vp8/encoder/x86/temporal_filter_apply_sse2.asm create mode 100644 vp8/encoder/x86/vp8_enc_stubs_mmx.c create mode 100644 vp8/encoder/x86/vp8_enc_stubs_sse2.c create mode 100644 vp8/exports_dec create mode 100644 vp8/exports_enc create mode 100644 vp8/vp8_common.mk create mode 100644 vp8/vp8_cx_iface.c create mode 100644 vp8/vp8_dx_iface.c create mode 100644 vp8/vp8cx.mk create mode 100644 vp8/vp8cx_arm.mk create mode 100644 vp8/vp8dx.mk create mode 100644 vp8_multi_resolution_encoder.c create mode 100644 vp8_scalable_patterns.c create mode 100644 vpx/exports_com create mode 100644 vpx/exports_dec create mode 100644 vpx/exports_enc create mode 100644 vpx/internal/vpx_codec_internal.h create mode 100644 vpx/src/vpx_codec.c create mode 100644 vpx/src/vpx_decoder.c create mode 100644 vpx/src/vpx_encoder.c create mode 100644 vpx/src/vpx_image.c create mode 100644 vpx/vp8.h create mode 100644 vpx/vp8cx.h create mode 100644 vpx/vp8dx.h create mode 100644 vpx/vpx_codec.h create mode 100644 vpx/vpx_codec.mk create mode 100644 vpx/vpx_codec_impl_bottom.h create mode 100644 vpx/vpx_codec_impl_top.h create mode 100644 vpx/vpx_decoder.h create mode 100644 vpx/vpx_encoder.h create mode 100644 vpx/vpx_image.h create mode 100644 vpx/vpx_integer.h create mode 100644 vpx_mem/include/vpx_mem_intrnl.h create mode 100644 vpx_mem/include/vpx_mem_tracker.h create mode 100644 vpx_mem/memory_manager/hmm_alloc.c create mode 100644 vpx_mem/memory_manager/hmm_base.c create mode 100644 vpx_mem/memory_manager/hmm_dflt_abort.c create mode 100644 vpx_mem/memory_manager/hmm_grow.c create mode 100644 vpx_mem/memory_manager/hmm_largest.c create mode 100644 vpx_mem/memory_manager/hmm_resize.c create mode 100644 vpx_mem/memory_manager/hmm_shrink.c create mode 100644 vpx_mem/memory_manager/hmm_true.c create mode 100644 vpx_mem/memory_manager/include/cavl_if.h create mode 100644 vpx_mem/memory_manager/include/cavl_impl.h create mode 100644 vpx_mem/memory_manager/include/heapmm.h create mode 100644 vpx_mem/memory_manager/include/hmm_cnfg.h create mode 100644 vpx_mem/memory_manager/include/hmm_intrnl.h create mode 100644 vpx_mem/vpx_mem.c create mode 100644 vpx_mem/vpx_mem.h create mode 100644 vpx_mem/vpx_mem.mk create mode 100644 vpx_mem/vpx_mem_tracker.c create mode 100644 vpx_ports/arm.h create mode 100644 vpx_ports/arm_cpudetect.c create mode 100644 vpx_ports/asm_offsets.h create mode 100644 vpx_ports/emms.asm create mode 100644 vpx_ports/mem.h create mode 100644 vpx_ports/mem_ops.h create mode 100644 vpx_ports/mem_ops_aligned.h create mode 100644 vpx_ports/vpx_timer.h create mode 100644 vpx_ports/vpxtypes.h create mode 100644 vpx_ports/x86.h create mode 100644 vpx_ports/x86_abi_support.asm create mode 100644 vpx_ports/x86_cpuid.c create mode 100644 vpx_scale/arm/neon/vp8_vpxyv12_copy_y_neon.asm create mode 100644 vpx_scale/arm/neon/vp8_vpxyv12_copyframe_func_neon.asm create mode 100644 vpx_scale/arm/neon/vp8_vpxyv12_copysrcframe_func_neon.asm create mode 100644 vpx_scale/arm/neon/vp8_vpxyv12_extendframeborders_neon.asm create mode 100644 vpx_scale/arm/neon/yv12extend_arm.c create mode 100644 vpx_scale/generic/bicubic_scaler.c create mode 100644 vpx_scale/generic/gen_scalers.c create mode 100644 vpx_scale/generic/vpxscale.c create mode 100644 vpx_scale/generic/yv12config.c create mode 100644 vpx_scale/generic/yv12extend.c create mode 100644 vpx_scale/generic/yv12extend_generic.h create mode 100644 vpx_scale/include/generic/vpxscale_arbitrary.h create mode 100644 vpx_scale/include/generic/vpxscale_depricated.h create mode 100644 vpx_scale/scale_mode.h create mode 100644 vpx_scale/vpx_scale.mk create mode 100644 vpx_scale/vpxscale.h create mode 100644 vpx_scale/win32/scaleopt.c create mode 100644 vpx_scale/win32/scalesystemdependent.c create mode 100644 vpx_scale/yv12config.h create mode 100644 vpxdec.c create mode 100644 vpxenc.c create mode 100644 y4minput.c create mode 100644 y4minput.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ffc6912 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,18 @@ +*.[chs] filter=fixtabswsp +*.[ch]pp filter=fixtabswsp +*.[ch]xx filter=fixtabswsp +*.asm filter=fixtabswsp +*.php filter=fixtabswsp +*.pl filter=fixtabswsp +*.sh filter=fixtabswsp +*.txt filter=fixwsp +[Mm]akefile filter=fixwsp +*.mk filter=fixwsp +*.rc -crlf +*.ds[pw] -crlf +*.bat -crlf +*.mmp -crlf +*.dpj -crlf +*.pjt -crlf +*.vcp -crlf +*.inf -crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..110146d --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +*.a +*.asm.s +*.d +*.o +*~ +/*-*.mk +/*.asm +/*.doxy +/.bins +/.deps +/.docs +/.install-* +/.libs +/Makefile +/config.err +/config.mk +/decode_to_md5 +/decode_to_md5.c +/decode_to_md5.dox +/decode_with_drops +/decode_with_drops.c +/decode_with_drops.dox +/docs/ +/doxyfile +/error_resilient +/error_resilient.c +/error_resilient.dox +/force_keyframe +/force_keyframe.c +/force_keyframe.dox +/ivfdec +/ivfdec.dox +/ivfenc +/ivfenc.dox +/obj_int_extract +/postproc +/postproc.c +/postproc.dox +/samples.dox +/simple_decoder +/simple_decoder.c +/simple_decoder.dox +/simple_encoder +/simple_encoder.c +/simple_encoder.dox +/twopass_encoder +/twopass_encoder.c +/twopass_encoder.dox +/vp8_api1_migration.dox +/vp8_scalable_patterns +/vp8_scalable_patterns.dox +/vp8_set_maps +/vp8_set_maps.c +/vp8_set_maps.dox +/vp8cx_set_ref +/vp8cx_set_ref.c +/vp8cx_set_ref.dox +/vpx_config.c +/vpx_config.h +/vpx_version.h +TAGS diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..ba1279b --- /dev/null +++ b/.mailmap @@ -0,0 +1,8 @@ +Adrian Grange +Johann Koenig +Tero Rintaluoma +Tom Finegan +Ralph Giles +Ralph Giles +Alpha Lam +Deb Mukherjee diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..0937d5d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,65 @@ +# This file is automatically generated from the git commit history +# by tools/gen_authors.sh. + +Aaron Watry +Adrian Grange +Alex Converse +Alexis Ballier +Alok Ahuja +Alpha Lam +Andoni Morales Alastruey +Andres Mejia +Aron Rosenberg +Attila Nagy +Deb Mukherjee +Fabio Pedretti +Frank Galligan +Fredrik Söderquist +Fritz Koenig +Gaute Strokkenes +Giuseppe Scrivano +Guillermo Ballester Valor +Henrik Lundin +James Berry +James Zern +Jan Kratochvil +Jeff Faust +Jeff Muizelaar +Jim Bankoski +Johann Koenig +John Koleszar +Joshua Bleecher Snyder +Justin Clift +Justin Lebar +KO Myung-Hun +Lou Quillio +Luca Barbato +Makoto Kato +Marco Paniconi +Martin Ettl +Michael Kohler +Mike Hommey +Mikhal Shemer +Pascal Massimino +Patrik Westin +Paul Wilkins +Pavol Rusnak +Philip Jägenstedt +Priit Laes +Rafael Ávila de Espíndola +Rafaël Carré +Ralph Giles +Ronald S. Bultje +Scott LaVarnway +Stefan Holmer +Taekhyun Kim +Takanori MATSUURA +Tero Rintaluoma +Thijs Vermeir +Timothy B. Terriberry +Tom Finegan +Yaowu Xu +Yunqing Wang +Google Inc. +The Mozilla Foundation +The Xiph.Org Foundation diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..dcb9f73 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,505 @@ +2012-05-09 v1.1.0 "Eider" + This introduces a number of enhancements, mostly focused on real-time + encoding. In addition, it fixes a decoder bug (first introduced in + Duclair) so all users of that release are encouraged to upgrade. + + - Upgrading: + This release is ABI and API compatible with Duclair (v1.0.0). Users + of older releases should refer to the Upgrading notes in this + document for that release. + + This release introduces a new temporal denoiser, controlled by the + VP8E_SET_NOISE_SENSITIVITY control. The temporal denoiser does not + currently take a strength parameter, so the control is effectively + a boolean - zero (off) or non-zero (on). For compatibility with + existing applications, the values accepted are the same as those + for the spatial denoiser (0-6). The temporal denoiser is enabled + by default, and the older spatial denoiser may be restored by + configuring with --disable-temporal-denoising. The temporal denoiser + is more computationally intensive than the spatial one. + + This release removes support for a legacy, decode only API that was + supported, but deprecated, at the initial release of libvpx + (v0.9.0). This is not expected to have any impact. If you are + impacted, you can apply a reversion to commit 2bf8fb58 locally. + Please update to the latest libvpx API if you are affected. + + - Enhancements: + Adds a motion compensated temporal denoiser to the encoder, which + gives higher quality than the older spatial denoiser. (See above + for notes on upgrading). + + In addition, support for new compilers and platforms were added, + including: + improved support for XCode + Android x86 NDK build + OS/2 support + SunCC support + + Changing resolution with vpx_codec_enc_config_set() is now + supported. Previously, reinitializing the codec was required to + change the input resolution. + + The vpxenc application has initial support for producing multiple + encodes from the same input in one call. Resizing is not yet + supported, but varying other codec parameters is. Use -- to + delineate output streams. Options persist from one stream to the + next. + + Also, the vpxenc application will now use a keyframe interval of + 5 seconds by default. Use the --kf-max-dist option to override. + + - Speed: + Decoder performance improved 2.5% versus Duclair. Encoder speed is + consistent with Duclair for most material. Two pass encoding of + slideshow-like material will see significant improvements. + + Large realtime encoding speed gains at a small quality expense are + possible by configuring the on-the-fly bitpacking experiment with + --enable-onthefly-bitpacking. Realtime encoder can be up to 13% + faster (ARM) depending on the number of threads and bitrate + settings. This technique sees constant gain over the 5-16 speed + range. For VC style input the loss seen is up to 0.2dB. See commit + 52cf4dca for further details. + + - Quality: + On the whole, quality is consistent with the Duclair release. Some + tweaks: + + Reduced blockiness in easy sections by applying a penalty to + intra modes. + + Improved quality of static sections (like slideshows) with + two pass encoding. + + Improved keyframe sizing with multiple temporal layers + + - Bug Fixes: + Corrected alt-ref contribution to frame rate for visible updates + to the alt-ref buffer. This affected applications making manual + usage of the frame reference flags, or temporal layers. + + Additional constraints were added to disable multi-frame quality + enhancement (MFQE) in sections of the frame where there is motion. + (#392) + + Fixed corruption issues when vpx_codec_enc_config_set() was called + with spatial resampling enabled. + + Fixed a decoder error introduced in Duclair where the segmentation + map was not being reinitialized on keyframes (#378) + + +2012-01-27 v1.0.0 "Duclair" + Our fourth named release, focused on performance and features related to + real-time encoding. It also fixes a decoder crash bug introduced in + v0.9.7, so all users of that release are encouraged to upgrade. + + - Upgrading: + This release is ABI incompatible with prior releases of libvpx, so the + "major" version number has been bumped to 1. You must recompile your + applications against the latest version of the libvpx headers. The + API remains compatible, and this should not require code changes in most + applications. + + - Enhancements: + This release introduces several substantial new features to the encoder, + of particular interest to real time streaming applications. + + Temporal scalability allows the encoder to produce a stream that can + be decimated to different frame rates, with independent rate targetting + for each substream. + + Multiframe quality enhancement postprocessing can make visual quality + more consistent in the presence of frames that are substantially + different quality than the surrounding frames, as in the temporal + scalability case and in some forced keyframe scenarios. + + Multiple-resolution encoding support allows the encoding of the + same content at different resolutions faster than encoding them + separately. + + - Speed: + Optimization targets for this release included the decoder and the real- + time modes of the encoder. Decoder speed on x86 has improved 10.5% with + this release. Encoder improvements followed a curve where speeds 1-3 + improved 4.0%-1.5%, speeds 4-8 improved <1%, and speeds 9-16 improved + 1.5% to 10.5%, respectively. "Best" mode speed is consistent with the + Cayuga release. + + - Quality: + Encoder quality in the single stream case is consistent with the Cayuga + release. + + - Bug Fixes: + This release fixes an OOB read decoder crash bug present in v0.9.7 + related to the clamping of motion vectors in SPLITMV blocks. This + behavior could be triggered by corrupt input or by starting + decoding from a P-frame. + + +2011-08-15 v0.9.7-p1 "Cayuga" patch 1 + This is an incremental bugfix release against Cayuga. All users of that + release are strongly encouraged to upgrade. + + - Fix potential OOB reads (cdae03a) + + An unbounded out of bounds read was discovered when the + decoder was requested to perform error concealment (new in + Cayuga) given a frame with corrupt partition sizes. + + A bounded out of bounds read was discovered affecting all + versions of libvpx. Given an multipartition input frame that + is truncated between the mode/mv partition and the first + residiual paritition (in the block of partition offsets), up + to 3 extra bytes could have been read from the source buffer. + The code will not take any action regardless of the contents + of these undefined bytes, as the truncated buffer is detected + immediately following the read based on the calculated + starting position of the coefficient partition. + + - Fix potential error concealment crash when the very first frame + is missing or corrupt (a609be5) + + - Fix significant artifacts in error concealment (a4c2211, 99d870a) + + - Revert 1-pass CBR rate control changes (e961317) + Further testing showed this change produced undesirable visual + artifacts, rolling back for now. + + +2011-08-02 v0.9.7 "Cayuga" + Our third named release, focused on a faster, higher quality, encoder. + + - Upgrading: + This release is backwards compatible with Aylesbury (v0.9.5) and + Bali (v0.9.6). Users of older releases should refer to the Upgrading + notes in this document for that release. + + - Enhancements: + Stereo 3D format support for vpxenc + Runtime detection of available processor cores. + Allow specifying --end-usage by enum name + vpxdec: test for frame corruption + vpxenc: add quantizer histogram display + vpxenc: add rate histogram display + Set VPX_FRAME_IS_DROPPABLE + update configure for ios sdk 4.3 + Avoid text relocations in ARM vp8 decoder + Generate a vpx.pc file for pkg-config. + New ways of passing encoded data between encoder and decoder. + + - Speed: + This release includes across-the-board speed improvements to the + encoder. On x86, these measure at approximately 11.5% in Best mode, + 21.5% in Good mode (speed 0), and 22.5% in Realtime mode (speed 6). + On ARM Cortex A9 with Neon extensions, real-time encoding of video + telephony content is 35% faster than Bali on single core and 48% + faster on multi-core. On the NVidia Tegra2 platform, real time + encoding is 40% faster than Bali. + + Decoder speed was not a priority for this release, but improved + approximately 8.4% on x86. + + Reduce motion vector search on alt-ref frame. + Encoder loopfilter running in its own thread + Reworked loopfilter to precalculate more parameters + SSE2/SSSE3 optimizations for build_predictors_mbuv{,_s}(). + Make hor UV predict ~2x faster (73 vs 132 cycles) using SSSE3. + Removed redundant checks + Reduced structure sizes + utilize preload in ARMv6 MC/LPF/Copy routines + ARM optimized quantization, dfct, variance, subtract + Increase chrow row alignment to 16 bytes. + disable trellis optimization for first pass + Write SSSE3 sub-pixel filter function + Improve SSE2 half-pixel filter funtions + Add vp8_sub_pixel_variance16x8_ssse3 function + Reduce unnecessary distortion computation + Use diamond search to replace full search + Preload reference area in sub-pixel motion search (real-time mode) + + - Quality: + This release focused primarily on one-pass use cases, including + video conferencing. Low latency data rate control was significantly + improved, improving streamability over bandwidth constrained links. + Added support for error concealment, allowing frames to maintain + visual quality in the presence of substantial packet loss. + + Add rc_max_intra_bitrate_pct control + Limit size of initial keyframe in one-pass. + Improve framerate adaptation + Improved 1-pass CBR rate control + Improved KF insertion after fades to still. + Improved key frame detection. + Improved activity masking (lower PSNR impact for same SSIM boost) + Improved interaction between GF and ARFs + Adding error-concealment to the decoder. + Adding support for independent partitions + Adjusted rate-distortion constants + + + - Bug Fixes: + Removed firstpass motion map + Fix parallel make install + Fix multithreaded encoding for 1 MB wide frame + Fixed iwalsh_neon build problems with RVDS4.1 + Fix semaphore emulation, spin-wait intrinsics on Windows + Fix build with xcode4 and simplify GLOBAL. + Mark ARM asm objects as allowing a non-executable stack. + Fix vpxenc encoding incorrect webm file header on big endian + + +2011-03-07 v0.9.6 "Bali" + Our second named release, focused on a faster, higher quality, encoder. + + - Upgrading: + This release is backwards compatible with Aylesbury (v0.9.5). Users + of older releases should refer to the Upgrading notes in this + document for that release. + + - Enhancements: + vpxenc --psnr shows a summary when encode completes + --tune=ssim option to enable activity masking + improved postproc visualizations for development + updated support for Apple iOS to SDK 4.2 + query decoder to determine which reference frames were updated + implemented error tracking in the decoder + fix pipe support on windows + + - Speed: + Primary focus was on good quality mode, speed 0. Average improvement + on x86 about 40%, up to 100% on user-generated content at that speed. + Best quality mode speed improved 35%, and realtime speed 10-20%. This + release also saw significant improvement in realtime encoding speed + on ARM platforms. + + Improved encoder threading + Dont pick encoder filter level when loopfilter is disabled. + Avoid double copying of key frames into alt and golden buffer + FDCT optimizations. + x86 sse2 temporal filter + SSSE3 version of fast quantizer + vp8_rd_pick_best_mbsegmentation code restructure + Adjusted breakout RD for SPLITMV + Changed segmentation check order + Improved rd_pick_intra4x4block + Adds armv6 optimized variance calculation + ARMv6 optimized sad16x16 + ARMv6 optimized half pixel variance calculations + Full search SAD function optimization in SSE4.1 + Improve MV prediction accuracy to achieve performance gain + Improve MV prediction in vp8_pick_inter_mode() for speed>3 + + - Quality: + Best quality mode improved PSNR 6.3%, and SSIM 6.1%. This release + also includes support for "activity masking," which greatly improves + SSIM at the expense of PSNR. For now, this feature is available with + the --tune=ssim option. Further experimentation in this area + is ongoing. This release also introduces a new rate control mode + called "CQ," which changes the allocation of bits within a clip to + the sections where they will have the most visual impact. + + Tuning for the more exact quantizer. + Relax rate control for last few frames + CQ Mode + Limit key frame quantizer for forced key frames. + KF/GF Pulsing + Add simple version of activity masking. + make rdmult adaptive for intra in quantizer RDO + cap the best quantizer for 2nd order DC + change the threshold of DC check for encode breakout + + - Bug Fixes: + Fix crash on Sparc Solaris. + Fix counter of fixed keyframe distance + ARNR filter pointer update bug fix + Fixed use of motion percentage in KF/GF group calc + Changed condition for using RD in Intra Mode + Fix encoder real-time only configuration. + Fix ARM encoder crash with multiple token partitions + Fixed bug first cluster timecode of webm file is wrong. + Fixed various encoder bugs with odd-sized images + vp8e_get_preview fixed when spatial resampling enabled + quantizer: fix assertion in fast quantizer path + Allocate source buffers to be multiples of 16 + Fix for manual Golden frame frequency + Fix drastic undershoot in long form content + + +2010-10-28 v0.9.5 "Aylesbury" + Our first named release, focused on a faster decoder, and a better encoder. + + - Upgrading: + This release incorporates backwards-incompatible changes to the + ivfenc and ivfdec tools. These tools are now called vpxenc and vpxdec. + + vpxdec + * the -q (quiet) option has been removed, and replaced with + -v (verbose). the output is quiet by default. Use -v to see + the version number of the binary. + + * The default behavior is now to write output to a single file + instead of individual frames. The -y option has been removed. + Y4M output is the default. + + * For raw I420/YV12 output instead of Y4M, the --i420 or --yv12 + options must be specified. + + $ ivfdec -o OUTPUT INPUT + $ vpxdec --i420 -o OUTPUT INPUT + + * If an output file is not specified, the default is to write + Y4M to stdout. This makes piping more natural. + + $ ivfdec -y -o - INPUT | ... + $ vpxdec INPUT | ... + + * The output file has additional flexibility for formatting the + filename. It supports escape characters for constructing a + filename from the width, height, and sequence number. This + replaces the -p option. To get the equivalent: + + $ ivfdec -p frame INPUT + $ vpxdec --i420 -o frame-%wx%h-%4.i420 INPUT + + vpxenc + * The output file must be specified with -o, rather than as the + last argument. + + $ ivfenc INPUT OUTPUT + $ vpxenc -o OUTPUT INPUT + + * The output defaults to webm. To get IVF output, use the --ivf + option. + + $ ivfenc INPUT OUTPUT.ivf + $ vpxenc -o OUTPUT.ivf --ivf INPUT + + + - Enhancements: + ivfenc and ivfdec have been renamed to vpxenc, vpxdec. + vpxdec supports .webm input + vpxdec writes .y4m by default + vpxenc writes .webm output by default + vpxenc --psnr now shows the average/overall PSNR at the end + ARM platforms now support runtime cpu detection + vpxdec visualizations added for motion vectors, block modes, references + vpxdec now silent by default + vpxdec --progress shows frame-by-frame timing information + vpxenc supports the distinction between --fps and --timebase + NASM is now a supported assembler + configure: enable PIC for shared libs by default + configure: add --enable-small + configure: support for ppc32-linux-gcc + configure: support for sparc-solaris-gcc + + - Bugs: + Improve handling of invalid frames + Fix valgrind errors in the NEON loop filters. + Fix loopfilter delta zero transitions + Fix valgrind errors in vp8_sixtap_predict8x4_armv6(). + Build fixes for darwin-icc + + - Speed: + 20-40% (average 28%) improvement in libvpx decoder speed, + including: + Rewrite vp8_short_walsh4x4_sse2() + Optimizations on the loopfilters. + Miscellaneous improvements for Atom + Add 4-tap version of 2nd-pass ARMv6 MC filter. + Improved multithread utilization + Better instruction choices on x86 + reorder data to use wider instructions + Update NEON wide idcts + Make block access to frame buffer sequential + Improved subset block search + Bilinear subpixel optimizations for ssse3. + Decrease memory footprint + + Encoder speed improvements (percentage gain not measured): + Skip unnecessary search of identical frames + Add SSE2 subtract functions + Improve bounds checking in vp8_diamond_search_sadx4() + Added vp8_fast_quantize_b_sse2 + + - Quality: + Over 7% overall PSNR improvement (6.3% SSIM) in "best" quality + encoding mode, and up to 60% improvement on very noisy, still + or slow moving source video + + Motion compensated temporal filter for Alt-Ref Noise Reduction + Improved use of trellis quantization on 2nd order Y blocks + Tune effect of motion on KF/GF boost in two pass + Allow coefficient optimization for good quality speed 0. + Improved control of active min quantizer for two pass. + Enable ARFs for non-lagged compress + +2010-09-02 v0.9.2 + - Enhancements: + Disable frame dropping by default + Improved multithreaded performance + Improved Force Key Frame Behaviour + Increased rate control buffer level precision + Fix bug in 1st pass motion compensation + ivfenc: correct fixed kf interval, --disable-kf + - Speed: + Changed above and left context data layout + Rework idct calling structure. + Removed unnecessary MB_MODE_INFO copies + x86: SSSE3 sixtap prediction + Reworked IDCT to include reconstruction (add) step + Swap alt/gold/new/last frame buffer ptrs instead of copying. + Improve SSE2 loopfilter functions + Change bitreader to use a larger window. + Avoid loopfilter reinitialization when possible + - Quality: + Normalize quantizer's zero bin and rounding factors + Add trellis quantization. + Make the quantizer exact. + Updates to ARNR filtering algorithm + Fix breakout thresh computation for golden & AltRef frames + Redo the forward 4x4 dct + Improve the accuracy of forward walsh-hadamard transform + Further adjustment of RD behaviour with Q and Zbin. + - Build System: + Allow linking of libs built with MinGW to MSVC + Fix target auto-detection on mingw32 + Allow --cpu= to work for x86. + configure: pass original arguments through to make dist + Fix builds without runtime CPU detection + msvs: fix install of codec sources + msvs: Change devenv.com command line for better msys support + msvs: Add vs9 targets. + Add x86_64-linux-icc target + - Bugs: + Potential crashes on older MinGW builds + Fix two-pass framrate for Y4M input. + Fixed simple loop filter, other crashes on ARM v6 + arm: fix missing dependency with --enable-shared + configure: support directories containing .o + Replace pinsrw (SSE) with MMX instructions + apple: include proper mach primatives + Fixed rate control bug with long key frame interval. + Fix DSO link errors on x86-64 when not using a version script + Fixed buffer selection for UV in AltRef filtering + + +2010-06-17 v0.9.1 + - Enhancements: + * ivfenc/ivfdec now support YUV4MPEG2 input and pipe I/O + * Speed optimizations + - Bugfixes: + * Rate control + * Prevent out-of-bounds accesses on invalid data + - Build system updates: + * Detect toolchain to be used automatically for native builds + * Support building shared libraries + * Better autotools emulation (--prefix, --libdir, DESTDIR) + - Updated LICENSE + * http://webmproject.blogspot.com/2010/06/changes-to-webm-open-source-license.html + + +2010-05-18 v0.9.0 + - Initial open source release. Welcome to WebM and VP8! + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1ce4434 --- /dev/null +++ b/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2010, The WebM Project authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google, nor the WebM Project, nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER 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. + diff --git a/PATENTS b/PATENTS new file mode 100644 index 0000000..4414d83 --- /dev/null +++ b/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the WebM Project. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer, and otherwise run, modify and propagate the contents of this +implementation of VP8, where such license applies only to those patent +claims, both currently owned by Google and acquired in the future, +licensable by Google that are necessarily infringed by this +implementation of VP8. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of VP8 or any code incorporated within this +implementation of VP8 constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of VP8 +shall terminate as of the date such litigation is filed. diff --git a/README b/README new file mode 100644 index 0000000..0dfb0fe --- /dev/null +++ b/README @@ -0,0 +1,98 @@ +vpx Multi-Format Codec SDK +README - 19 May 2010 + +Welcome to the WebM VP8 Codec SDK! + +COMPILING THE APPLICATIONS/LIBRARIES: + The build system used is similar to autotools. Building generally consists of + "configuring" with your desired build options, then using GNU make to build + the application. + + 1. Prerequisites + + * All x86 targets require the Yasm[1] assembler be installed. + * All Windows builds require that Cygwin[2] be installed. + * Building the documentation requires PHP[3] and Doxygen[4]. If you do not + have these packages, you must pass --disable-install-docs to the + configure script. + + [1]: http://www.tortall.net/projects/yasm + [2]: http://www.cygwin.com + [3]: http://php.net + [4]: http://www.doxygen.org + + 2. Out-of-tree builds + Out of tree builds are a supported method of building the application. For + an out of tree build, the source tree is kept separate from the object + files produced during compilation. For instance: + + $ mkdir build + $ cd build + $ ../libvpx/configure + $ make + + 3. Configuration options + The 'configure' script supports a number of options. The --help option can be + used to get a list of supported options: + $ ../libvpx/configure --help + + 4. Cross development + For cross development, the most notable option is the --target option. The + most up-to-date list of supported targets can be found at the bottom of the + --help output of the configure script. As of this writing, the list of + available targets is: + + armv5te-android-gcc + armv5te-linux-rvct + armv5te-linux-gcc + armv6-darwin-gcc + armv6-linux-rvct + armv6-linux-gcc + armv7-android-gcc + armv7-linux-rvct + armv7-linux-gcc + mips32-linux-gcc + ppc32-darwin8-gcc + ppc32-darwin9-gcc + ppc64-darwin8-gcc + ppc64-darwin9-gcc + ppc64-linux-gcc + x86-darwin8-gcc + x86-darwin8-icc + x86-darwin9-gcc + x86-darwin9-icc + x86-linux-gcc + x86-linux-icc + x86-solaris-gcc + x86-win32-vs7 + x86-win32-vs8 + x86_64-darwin9-gcc + x86_64-linux-gcc + x86_64-solaris-gcc + x86_64-win64-vs8 + universal-darwin8-gcc + universal-darwin9-gcc + generic-gnu + + The generic-gnu target, in conjunction with the CROSS environment variable, + can be used to cross compile architectures that aren't explicitly listed, if + the toolchain is a cross GNU (gcc/binutils) toolchain. Other POSIX toolchains + will likely work as well. For instance, to build using the mipsel-linux-uclibc + toolchain, the following command could be used (note, POSIX SH syntax, adapt + to your shell as necessary): + + $ CROSS=mipsel-linux-uclibc- ../libvpx/configure + + In addition, the executables to be invoked can be overridden by specifying the + environment variables: CC, AR, LD, AS, STRIP, NM. Additional flags can be + passed to these executables with CFLAGS, LDFLAGS, and ASFLAGS. + + 5. Configuration errors + If the configuration step fails, the first step is to look in the error log. + This defaults to config.err. This should give a good indication of what went + wrong. If not, contact us for support. + +SUPPORT + This library is an open source project supported by its community. Please + please email webm-users@webmproject.org for help. + diff --git a/args.c b/args.c new file mode 100644 index 0000000..37ba778 --- /dev/null +++ b/args.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include +#include "args.h" + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +#if defined(__GNUC__) && __GNUC__ +extern void die(const char *fmt, ...) __attribute__((noreturn)); +#else +extern void die(const char *fmt, ...); +#endif + + +struct arg arg_init(char **argv) +{ + struct arg a; + + a.argv = argv; + a.argv_step = 1; + a.name = NULL; + a.val = NULL; + a.def = NULL; + return a; +} + +int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) +{ + struct arg arg; + + if (!argv[0] || argv[0][0] != '-') + return 0; + + arg = arg_init(argv); + + if (def->short_name + && strlen(arg.argv[0]) == strlen(def->short_name) + 1 + && !strcmp(arg.argv[0] + 1, def->short_name)) + { + + arg.name = arg.argv[0] + 1; + arg.val = def->has_val ? arg.argv[1] : NULL; + arg.argv_step = def->has_val ? 2 : 1; + } + else if (def->long_name) + { + const size_t name_len = strlen(def->long_name); + + if (strlen(arg.argv[0]) >= name_len + 2 + && arg.argv[0][1] == '-' + && !strncmp(arg.argv[0] + 2, def->long_name, name_len) + && (arg.argv[0][name_len+2] == '=' + || arg.argv[0][name_len+2] == '\0')) + { + + arg.name = arg.argv[0] + 2; + arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL; + arg.argv_step = 1; + } + } + + if (arg.name && !arg.val && def->has_val) + die("Error: option %s requires argument.\n", arg.name); + + if (arg.name && arg.val && !def->has_val) + die("Error: option %s requires no argument.\n", arg.name); + + if (arg.name + && (arg.val || !def->has_val)) + { + arg.def = def; + *arg_ = arg; + return 1; + } + + return 0; +} + + +const char *arg_next(struct arg *arg) +{ + if (arg->argv[0]) + arg->argv += arg->argv_step; + + return *arg->argv; +} + + +char **argv_dup(int argc, const char **argv) +{ + char **new_argv = malloc((argc + 1) * sizeof(*argv)); + + memcpy(new_argv, argv, argc * sizeof(*argv)); + new_argv[argc] = NULL; + return new_argv; +} + + +void arg_show_usage(FILE *fp, const struct arg_def *const *defs) +{ + char option_text[40] = {0}; + + for (; *defs; defs++) + { + const struct arg_def *def = *defs; + char *short_val = def->has_val ? " " : ""; + char *long_val = def->has_val ? "=" : ""; + + if (def->short_name && def->long_name) + { + char *comma = def->has_val ? "," : ", "; + + snprintf(option_text, 37, "-%s%s%s --%s%6s", + def->short_name, short_val, comma, + def->long_name, long_val); + } + else if (def->short_name) + snprintf(option_text, 37, "-%s%s", + def->short_name, short_val); + else if (def->long_name) + snprintf(option_text, 37, " --%s%s", + def->long_name, long_val); + + fprintf(fp, " %-37s\t%s\n", option_text, def->desc); + + if(def->enums) + { + const struct arg_enum_list *listptr; + + fprintf(fp, " %-37s\t ", ""); + + for(listptr = def->enums; listptr->name; listptr++) + fprintf(fp, "%s%s", listptr->name, + listptr[1].name ? ", " : "\n"); + } + } +} + + +unsigned int arg_parse_uint(const struct arg *arg) +{ + long int rawval; + char *endptr; + + rawval = strtol(arg->val, &endptr, 10); + + if (arg->val[0] != '\0' && endptr[0] == '\0') + { + if (rawval >= 0 && rawval <= UINT_MAX) + return rawval; + + die("Option %s: Value %ld out of range for unsigned int\n", + arg->name, rawval); + } + + die("Option %s: Invalid character '%c'\n", arg->name, *endptr); + return 0; +} + + +int arg_parse_int(const struct arg *arg) +{ + long int rawval; + char *endptr; + + rawval = strtol(arg->val, &endptr, 10); + + if (arg->val[0] != '\0' && endptr[0] == '\0') + { + if (rawval >= INT_MIN && rawval <= INT_MAX) + return rawval; + + die("Option %s: Value %ld out of range for signed int\n", + arg->name, rawval); + } + + die("Option %s: Invalid character '%c'\n", arg->name, *endptr); + return 0; +} + + +struct vpx_rational +{ + int num; /**< fraction numerator */ + int den; /**< fraction denominator */ +}; +struct vpx_rational arg_parse_rational(const struct arg *arg) +{ + long int rawval; + char *endptr; + struct vpx_rational rat; + + /* parse numerator */ + rawval = strtol(arg->val, &endptr, 10); + + if (arg->val[0] != '\0' && endptr[0] == '/') + { + if (rawval >= INT_MIN && rawval <= INT_MAX) + rat.num = rawval; + else die("Option %s: Value %ld out of range for signed int\n", + arg->name, rawval); + } + else die("Option %s: Expected / at '%c'\n", arg->name, *endptr); + + /* parse denominator */ + rawval = strtol(endptr + 1, &endptr, 10); + + if (arg->val[0] != '\0' && endptr[0] == '\0') + { + if (rawval >= INT_MIN && rawval <= INT_MAX) + rat.den = rawval; + else die("Option %s: Value %ld out of range for signed int\n", + arg->name, rawval); + } + else die("Option %s: Invalid character '%c'\n", arg->name, *endptr); + + return rat; +} + + +int arg_parse_enum(const struct arg *arg) +{ + const struct arg_enum_list *listptr; + long int rawval; + char *endptr; + + /* First see if the value can be parsed as a raw value */ + rawval = strtol(arg->val, &endptr, 10); + if (arg->val[0] != '\0' && endptr[0] == '\0') + { + /* Got a raw value, make sure it's valid */ + for(listptr = arg->def->enums; listptr->name; listptr++) + if(listptr->val == rawval) + return rawval; + } + + /* Next see if it can be parsed as a string */ + for(listptr = arg->def->enums; listptr->name; listptr++) + if(!strcmp(arg->val, listptr->name)) + return listptr->val; + + die("Option %s: Invalid value '%s'\n", arg->name, arg->val); + return 0; +} + + +int arg_parse_enum_or_int(const struct arg *arg) +{ + if(arg->def->enums) + return arg_parse_enum(arg); + return arg_parse_int(arg); +} diff --git a/args.h b/args.h new file mode 100644 index 0000000..7963fa6 --- /dev/null +++ b/args.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef ARGS_H +#define ARGS_H +#include + +struct arg +{ + char **argv; + const char *name; + const char *val; + unsigned int argv_step; + const struct arg_def *def; +}; + +struct arg_enum_list +{ + const char *name; + int val; +}; +#define ARG_ENUM_LIST_END {0} + +typedef struct arg_def +{ + const char *short_name; + const char *long_name; + int has_val; + const char *desc; + const struct arg_enum_list *enums; +} arg_def_t; +#define ARG_DEF(s,l,v,d) {s,l,v,d, NULL} +#define ARG_DEF_ENUM(s,l,v,d,e) {s,l,v,d,e} +#define ARG_DEF_LIST_END {0} + +struct arg arg_init(char **argv); +int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); +const char *arg_next(struct arg *arg); +void arg_show_usage(FILE *fp, const struct arg_def *const *defs); +char **argv_dup(int argc, const char **argv); + +unsigned int arg_parse_uint(const struct arg *arg); +int arg_parse_int(const struct arg *arg); +struct vpx_rational arg_parse_rational(const struct arg *arg); +int arg_parse_enum_or_int(const struct arg *arg); +#endif diff --git a/build/.gitattributes b/build/.gitattributes new file mode 100644 index 0000000..03db79b --- /dev/null +++ b/build/.gitattributes @@ -0,0 +1,2 @@ +*-vs8/*.rules -crlf +*-msvs/*.rules -crlf diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..1350fcb --- /dev/null +++ b/build/.gitignore @@ -0,0 +1 @@ +x86*-win32-vs* diff --git a/build/make/Android.mk b/build/make/Android.mk new file mode 100644 index 0000000..6fcd4ae --- /dev/null +++ b/build/make/Android.mk @@ -0,0 +1,199 @@ +## +## Copyright (c) 2012 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + +# +# This file is to be used for compiling libvpx for Android using the NDK. +# In an Android project place a libvpx checkout in the jni directory. +# Run the configure script from the jni directory. Base libvpx +# encoder/decoder configuration will look similar to: +# ./libvpx/configure --target=armv7-android-gcc --disable-examples \ +# --sdk-path=/opt/android-ndk-r6b/ +# +# When targeting Android, realtime-only is enabled by default. This can +# be overridden by adding the command line flag: +# --disable-realtime-only +# +# This will create .mk files that contain variables that contain the +# source files to compile. +# +# Place an Android.mk file in the jni directory that references the +# Android.mk file in the libvpx directory: +# LOCAL_PATH := $(call my-dir) +# include $(CLEAR_VARS) +# include libvpx/build/make/Android.mk +# +# There are currently two TARGET_ARCH_ABI targets for ARM. +# armeabi and armeabi-v7a. armeabi-v7a is selected by creating an +# Application.mk in the jni directory that contains: +# APP_ABI := armeabi-v7a +# +# To change to building armeabi, run ./libvpx/configure again, but with +# --target=arm5te-android-gcc and and modify the Application.mk file to +# set APP_ABI := armeabi +# +# Running ndk-build will build libvpx and include it in your project. +# + +CONFIG_DIR := $(LOCAL_PATH) +LIBVPX_PATH := $(LOCAL_PATH)/libvpx +ASM_CNV_PATH_LOCAL := $(TARGET_ARCH_ABI)/ads2gas +ASM_CNV_PATH := $(LOCAL_PATH)/$(ASM_CNV_PATH_LOCAL) + +# Makefiles created by the libvpx configure process +# This will need to be fixed to handle x86. +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + include $(CONFIG_DIR)/libs-armv7-android-gcc.mk +else + include $(CONFIG_DIR)/libs-armv5te-android-gcc.mk +endif + +# Rule that is normally in Makefile created by libvpx +# configure. Used to filter out source files based on configuration. +enabled=$(filter-out $($(1)-no),$($(1)-yes)) + +# Override the relative path that is defined by the libvpx +# configure process +SRC_PATH_BARE := $(LIBVPX_PATH) + +# Include the list of files to be built +include $(LIBVPX_PATH)/libs.mk + +# Want arm, not thumb, optimized +LOCAL_ARM_MODE := arm +LOCAL_CFLAGS := -O3 + +# ----------------------------------------------------------------------------- +# Template : asm_offsets_template +# Arguments : 1: assembly offsets file to be created +# 2: c file to base assembly offsets on +# Returns : None +# Usage : $(eval $(call asm_offsets_template,, +# Rationale : Create offsets at compile time using for structures that are +# defined in c, but used in assembly functions. +# ----------------------------------------------------------------------------- +define asm_offsets_template + +_SRC:=$(2) +_OBJ:=$(ASM_CNV_PATH)/$$(notdir $(2)).S + +_FLAGS = $$($$(my)CFLAGS) \ + $$(call get-src-file-target-cflags,$(2)) \ + $$(call host-c-includes,$$(LOCAL_C_INCLUDES) $$(CONFIG_DIR)) \ + $$(LOCAL_CFLAGS) \ + $$(NDK_APP_CFLAGS) \ + $$(call host-c-includes,$$($(my)C_INCLUDES)) \ + -DINLINE_ASM \ + -S \ + +_TEXT = "Compile $$(call get-src-file-text,$(2))" +_CC = $$(TARGET_CC) + +$$(eval $$(call ev-build-file)) + +$(1) : $$(_OBJ) $(2) + @mkdir -p $$(dir $$@) + @grep $(OFFSET_PATTERN) $$< | tr -d '\#' | $(CONFIG_DIR)/$(ASM_CONVERSION) > $$@ +endef + +# Use ads2gas script to convert from RVCT format to GAS format. This passes +# puts the processed file under $(ASM_CNV_PATH). Local clean rule +# to handle removing these +ASM_CNV_OFFSETS_DEPEND = $(ASM_CNV_PATH)/asm_com_offsets.asm +ifeq ($(CONFIG_VP8_DECODER), yes) + ASM_CNV_OFFSETS_DEPEND += $(ASM_CNV_PATH)/asm_dec_offsets.asm +endif +ifeq ($(CONFIG_VP8_ENCODER), yes) + ASM_CNV_OFFSETS_DEPEND += $(ASM_CNV_PATH)/asm_enc_offsets.asm +endif + +.PRECIOUS: %.asm.s +$(ASM_CNV_PATH)/libvpx/%.asm.s: $(LIBVPX_PATH)/%.asm $(ASM_CNV_OFFSETS_DEPEND) + @mkdir -p $(dir $@) + @$(CONFIG_DIR)/$(ASM_CONVERSION) <$< > $@ + +# For building vpx_rtcd.h, which has a rule in libs.mk +TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN))) +target := libs + +LOCAL_SRC_FILES += vpx_config.c + +# Remove duplicate entries +CODEC_SRCS_UNIQUE = $(sort $(CODEC_SRCS)) + +# Pull out C files. vpx_config.c is in the immediate directory and +# so it does not need libvpx/ prefixed like the rest of the source files. +CODEC_SRCS_C = $(filter %.c, $(CODEC_SRCS_UNIQUE)) +LOCAL_CODEC_SRCS_C = $(filter-out vpx_config.c, $(CODEC_SRCS_C)) + +LOCAL_SRC_FILES += $(foreach file, $(LOCAL_CODEC_SRCS_C), libvpx/$(file)) + +# Pull out assembly files, splitting NEON from the rest. This is +# done to specify that the NEON assembly files use NEON assembler flags. +CODEC_SRCS_ASM_ALL = $(filter %.asm.s, $(CODEC_SRCS_UNIQUE)) +CODEC_SRCS_ASM = $(foreach v, \ + $(CODEC_SRCS_ASM_ALL), \ + $(if $(findstring neon,$(v)),,$(v))) +CODEC_SRCS_ASM_ADS2GAS = $(patsubst %.s, \ + $(ASM_CNV_PATH_LOCAL)/libvpx/%.s, \ + $(CODEC_SRCS_ASM)) +LOCAL_SRC_FILES += $(CODEC_SRCS_ASM_ADS2GAS) + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + CODEC_SRCS_ASM_NEON = $(foreach v, \ + $(CODEC_SRCS_ASM_ALL),\ + $(if $(findstring neon,$(v)),$(v),)) + CODEC_SRCS_ASM_NEON_ADS2GAS = $(patsubst %.s, \ + $(ASM_CNV_PATH_LOCAL)/libvpx/%.s, \ + $(CODEC_SRCS_ASM_NEON)) + LOCAL_SRC_FILES += $(patsubst %.s, \ + %.s.neon, \ + $(CODEC_SRCS_ASM_NEON_ADS2GAS)) +endif + +LOCAL_CFLAGS += \ + -DHAVE_CONFIG_H=vpx_config.h \ + -I$(LIBVPX_PATH) \ + -I$(ASM_CNV_PATH) + +LOCAL_MODULE := libvpx + +LOCAL_LDLIBS := -llog + +LOCAL_STATIC_LIBRARIES := cpufeatures + +$(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vpx_rtcd.h + +.PHONY: clean +clean: + @echo "Clean: ads2gas files [$(TARGET_ARCH_ABI)]" + @$(RM) $(CODEC_SRCS_ASM_ADS2GAS) $(CODEC_SRCS_ASM_NEON_ADS2GAS) + @$(RM) $(patsubst %.asm, %.*, $(ASM_CNV_OFFSETS_DEPEND)) + @$(RM) -r $(ASM_CNV_PATH) + @$(RM) $(CLEAN-OBJS) + +include $(BUILD_SHARED_LIBRARY) + +$(eval $(call asm_offsets_template,\ + $(ASM_CNV_PATH)/asm_com_offsets.asm, \ + $(LIBVPX_PATH)/vp8/common/asm_com_offsets.c)) + +ifeq ($(CONFIG_VP8_DECODER), yes) + $(eval $(call asm_offsets_template,\ + $(ASM_CNV_PATH)/asm_dec_offsets.asm, \ + $(LIBVPX_PATH)/vp8/decoder/asm_dec_offsets.c)) +endif + +ifeq ($(CONFIG_VP8_ENCODER), yes) + $(eval $(call asm_offsets_template,\ + $(ASM_CNV_PATH)/asm_enc_offsets.asm, \ + $(LIBVPX_PATH)/vp8/encoder/asm_enc_offsets.c)) +endif + +$(call import-module,cpufeatures) diff --git a/build/make/Makefile b/build/make/Makefile new file mode 100644 index 0000000..b6cf320 --- /dev/null +++ b/build/make/Makefile @@ -0,0 +1,384 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +include config.mk +quiet?=true +ifeq ($(target),) +# If a target wasn't specified, invoke for all enabled targets. +.DEFAULT: + @for t in $(ALL_TARGETS); do \ + $(MAKE) --no-print-directory target=$$t $(MAKECMDGOALS) || exit $$?;\ + done +all: .DEFAULT +clean:: .DEFAULT +install:: .DEFAULT +test:: .DEFAULT + + +# Note: md5sum is not installed on OS X, but openssl is. Openssl may not be +# installed on cygwin, so we need to autodetect here. +md5sum := $(firstword $(wildcard \ + $(foreach e,md5sum openssl,\ + $(foreach p,$(subst :, ,$(PATH)),$(p)/$(e)*))\ + )) +md5sum := $(if $(filter %openssl,$(md5sum)),$(md5sum) dgst -md5,$(md5sum)) + +TGT_CC:=$(word 3, $(subst -, ,$(TOOLCHAIN))) +dist: + @for t in $(ALL_TARGETS); do \ + $(MAKE) --no-print-directory target=$$t $(MAKECMDGOALS) || exit $$?;\ + done + # Run configure for the user with the current toolchain. + @if [ -d "$(DIST_DIR)/src" ]; then \ + mkdir -p "$(DIST_DIR)/build"; \ + cd "$(DIST_DIR)/build"; \ + echo "Rerunning configure $(CONFIGURE_ARGS)"; \ + ../src/configure $(CONFIGURE_ARGS); \ + $(if $(filter vs%,$(TGT_CC)),make NO_LAUNCH_DEVENV=1;) \ + fi + @if [ -d "$(DIST_DIR)" ]; then \ + echo " [MD5SUM] $(DIST_DIR)"; \ + cd $(DIST_DIR) && \ + $(md5sum) `find . -name md5sums.txt -prune -o -type f -print` \ + | sed -e 's/MD5(\(.*\))= \([0-9a-f]\{32\}\)/\2 \1/' \ + > md5sums.txt;\ + fi + + +endif + +ifneq ($(target),) +# Normally, we want to build the filename from the target and the toolchain. +# This disambiguates from the $(target).mk file that exists in the source tree. +# However, the toolchain is part of the target in universal builds, so we +# don't want to include TOOLCHAIN in that case. FAT_ARCHS is used to test +# if we're in the universal case. +include $(target)$(if $(FAT_ARCHS),,-$(TOOLCHAIN)).mk +endif +BUILD_ROOT?=. +VPATH=$(SRC_PATH_BARE) +CFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH) +ASFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT)/ -I$(SRC_PATH)/ +DIST_DIR?=dist +HOSTCC?=gcc +TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN))) +TGT_OS:=$(word 2, $(subst -, ,$(TOOLCHAIN))) +TGT_CC:=$(word 3, $(subst -, ,$(TOOLCHAIN))) +quiet:=$(if $(verbose),,yes) +qexec=$(if $(quiet),@) + +# Cancel built-in implicit rules +%: %.o +%.asm: +%.a: +%: %.cc + +# +# Common rules" +# +.PHONY: all +all: + +.PHONY: clean +clean:: + rm -f $(OBJS-yes) $(OBJS-yes:.o=.d) $(OBJS-yes:.asm.s.o=.asm.s) + rm -f $(CLEAN-OBJS) + +.PHONY: dist +dist: +.PHONY: install +install:: +.PHONY: test +test:: + +$(BUILD_PFX)%.c.d: %.c + $(if $(quiet),@echo " [DEP] $@") + $(qexec)mkdir -p $(dir $@) + $(qexec)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -M $< | $(fmt_deps) > $@ + +$(BUILD_PFX)%.c.o: %.c + $(if $(quiet),@echo " [CC] $@") + $(qexec)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -c -o $@ $< + +$(BUILD_PFX)%.cc.d: %.cc + $(if $(quiet),@echo " [DEP] $@") + $(qexec)mkdir -p $(dir $@) + $(qexec)g++ $(INTERNAL_CFLAGS) $(CFLAGS) -M $< | $(fmt_deps) > $@ + +$(BUILD_PFX)%.cc.o: %.cc + $(if $(quiet),@echo " [CXX] $@") + $(qexec)g++ $(INTERNAL_CFLAGS) $(CFLAGS) -c -o $@ $< + +$(BUILD_PFX)%.asm.d: %.asm + $(if $(quiet),@echo " [DEP] $@") + $(qexec)mkdir -p $(dir $@) + $(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \ + --build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@ + +$(BUILD_PFX)%.asm.o: %.asm + $(if $(quiet),@echo " [AS] $@") + $(qexec)$(AS) $(ASFLAGS) -o $@ $< + +$(BUILD_PFX)%.s.d: %.s + $(if $(quiet),@echo " [DEP] $@") + $(qexec)mkdir -p $(dir $@) + $(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \ + --build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@ + +$(BUILD_PFX)%.s.o: %.s + $(if $(quiet),@echo " [AS] $@") + $(qexec)$(AS) $(ASFLAGS) -o $@ $< + +.PRECIOUS: %.c.S +%.c.S: CFLAGS += -DINLINE_ASM +$(BUILD_PFX)%.c.S: %.c + $(if $(quiet),@echo " [GEN] $@") + $(qexec)$(CC) -S $(CFLAGS) -o $@ $< + +.PRECIOUS: %.asm.s +$(BUILD_PFX)%.asm.s: %.asm + $(if $(quiet),@echo " [ASM CONVERSION] $@") + $(qexec)mkdir -p $(dir $@) + $(qexec)$(ASM_CONVERSION) <$< >$@ + +# If we're in debug mode, pretend we don't have GNU strip, to fall back to +# the copy implementation +HAVE_GNU_STRIP := $(if $(CONFIG_DEBUG),,$(HAVE_GNU_STRIP)) +ifeq ($(HAVE_GNU_STRIP),yes) +# Older binutils strip global sybols not needed for relocation processing +# when given --strip-unneeded. Use nm and awk to identify globals and +# keep them. +%.a: %_g.a + $(if $(quiet),@echo " [STRIP] $@ < $<") + $(qexec)$(STRIP) --strip-unneeded \ + `$(NM) $< | grep ' [A-TV-Z] ' | awk '{print "-K"$$3'}`\ + -o $@ $< +else +%.a: %_g.a + $(if $(quiet),@echo " [CP] $@ < $<") + $(qexec)cp $< $@ +endif + +# +# Rule to extract assembly constants from C sources +# +obj_int_extract: build/make/obj_int_extract.c + $(if $(quiet),@echo " [HOSTCC] $@") + $(qexec)$(HOSTCC) -I. -I$(SRC_PATH_BARE) -o $@ $< +CLEAN-OBJS += obj_int_extract + +# +# Utility functions +# +pairmap=$(if $(strip $(2)),\ + $(call $(1),$(word 1,$(2)),$(word 2,$(2)))\ + $(call pairmap,$(1),$(wordlist 3,$(words $(2)),$(2)))\ +) + +enabled=$(filter-out $($(1)-no),$($(1)-yes)) +cond_enabled=$(if $(filter yes,$($(1))), $(call enabled,$(2))) + +find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2))))) +find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) ) +obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o +objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) )) + +install_map_templates=$(eval $(call install_map_template,$(1),$(2))) + +not=$(subst yes,no,$(1)) + +ifeq ($(CONFIG_MSVS),yes) +lib_file_name=$(1).lib +else +lib_file_name=lib$(1).a +endif +# +# Rule Templates +# +define linker_template +$(1): $(filter-out -%,$(2)) +$(1): + $(if $(quiet),@echo " [LD] $$@") + $(qexec)$$(LD) $$(strip $$(INTERNAL_LDFLAGS) $$(LDFLAGS) -o $$@ $(2) $(3) $$(extralibs)) +endef +define linkerxx_template +$(1): $(filter-out -%,$(2)) +$(1): + $(if $(quiet),@echo " [LD] $$@") + $(qexec)g++ $$(strip $$(INTERNAL_LDFLAGS) $$(LDFLAGS) -o $$@ $(2) $(3) $$(extralibs)) +endef +# make-3.80 has a bug with expanding large input strings to the eval function, +# which was triggered in some cases by the following component of +# linker_template: +# $(1): $$(call find_file, $(patsubst -l%,lib%.a,$(filter -l%,$(2))),\ +# $$(patsubst -L%,%,$$(filter -L%,$$(LDFLAGS) $(2)))) +# This may be useful to revisit in the future (it tries to locate libraries +# in a search path and add them as prerequisites + +define install_map_template +$(DIST_DIR)/$(1): $(2) + $(if $(quiet),@echo " [INSTALL] $$@") + $(qexec)mkdir -p $$(dir $$@) + $(qexec)cp -p $$< $$@ +endef + +define archive_template +# Not using a pattern rule here because we don't want to generate empty +# archives when they are listed as a dependency in files not responsible +# for creating them. +$(1): + $(if $(quiet),@echo " [AR] $$@") + $(qexec)$$(AR) $$(ARFLAGS) $$@ $$? +endef + +define so_template +# Not using a pattern rule here because we don't want to generate empty +# archives when they are listed as a dependency in files not responsible +# for creating them. +# +# This needs further abstraction for dealing with non-GNU linkers. +$(1): + $(if $(quiet),@echo " [LD] $$@") + $(qexec)$$(LD) -shared $$(LDFLAGS) \ + -Wl,--no-undefined -Wl,-soname,$$(SONAME) \ + -Wl,--version-script,$$(SO_VERSION_SCRIPT) -o $$@ \ + $$(filter %.o,$$?) $$(extralibs) +endef + +define lipo_lib_template +$(1): $(addsuffix /$(1),$(FAT_ARCHS)) + $(if $(quiet),@echo " [LIPO] $$@") + $(qexec)libtool -static -o $$@ $$? +endef + +define lipo_bin_template +$(1): $(addsuffix /$(1),$(FAT_ARCHS)) + $(if $(quiet),@echo " [LIPO] $$@") + $(qexec)lipo -output $$@ -create $$? +endef + + +# +# Get current configuration +# +ifneq ($(target),) +include $(SRC_PATH_BARE)/$(target:-$(TOOLCHAIN)=).mk +endif +ifeq ($(filter clean,$(MAKECMDGOALS)),) + # Older versions of make don't like -include directives with no arguments + ifneq ($(filter %.d,$(OBJS-yes:.o=.d)),) + -include $(filter %.d,$(OBJS-yes:.o=.d)) + endif +endif + +# +# Configuration dependent rules +# +$(call pairmap,install_map_templates,$(INSTALL_MAPS)) + +DOCS=$(call cond_enabled,CONFIG_INSTALL_DOCS,DOCS) +.docs: $(DOCS) + @touch $@ + +INSTALL-DOCS=$(call cond_enabled,CONFIG_INSTALL_DOCS,INSTALL-DOCS) +ifeq ($(MAKECMDGOALS),dist) +INSTALL-DOCS+=$(call cond_enabled,CONFIG_INSTALL_DOCS,DIST-DOCS) +endif +.install-docs: .docs $(addprefix $(DIST_DIR)/,$(INSTALL-DOCS)) + @touch $@ + +clean:: + rm -f .docs .install-docs $(DOCS) + +BINS=$(call enabled,BINS) +.bins: $(BINS) + @touch $@ + +INSTALL-BINS=$(call cond_enabled,CONFIG_INSTALL_BINS,INSTALL-BINS) +ifeq ($(MAKECMDGOALS),dist) +INSTALL-BINS+=$(call cond_enabled,CONFIG_INSTALL_BINS,DIST-BINS) +endif +.install-bins: .bins $(addprefix $(DIST_DIR)/,$(INSTALL-BINS)) + @touch $@ + +clean:: + rm -f .bins .install-bins $(BINS) + +LIBS=$(call enabled,LIBS) +.libs: $(LIBS) + @touch $@ +$(foreach lib,$(filter %_g.a,$(LIBS)),$(eval $(call archive_template,$(lib)))) +$(foreach lib,$(filter %so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH),$(LIBS)),$(eval $(call so_template,$(lib)))) + +INSTALL-LIBS=$(call cond_enabled,CONFIG_INSTALL_LIBS,INSTALL-LIBS) +ifeq ($(MAKECMDGOALS),dist) +INSTALL-LIBS+=$(call cond_enabled,CONFIG_INSTALL_LIBS,DIST-LIBS) +endif +.install-libs: .libs $(addprefix $(DIST_DIR)/,$(INSTALL-LIBS)) + @touch $@ + +clean:: + rm -f .libs .install-libs $(LIBS) + +ifeq ($(CONFIG_EXTERNAL_BUILD),yes) +PROJECTS=$(call enabled,PROJECTS) +.projects: $(PROJECTS) + @touch $@ + +INSTALL-PROJECTS=$(call cond_enabled,CONFIG_INSTALL_PROJECTS,INSTALL-PROJECTS) +ifeq ($(MAKECMDGOALS),dist) +INSTALL-PROJECTS+=$(call cond_enabled,CONFIG_INSTALL_PROJECTS,DIST-PROJECTS) +endif +.install-projects: .projects $(addprefix $(DIST_DIR)/,$(INSTALL-PROJECTS)) + @touch $@ + +clean:: + rm -f .projects .install-projects $(PROJECTS) +endif + +# If there are any source files to be distributed, then include the build +# system too. +ifneq ($(call enabled,DIST-SRCS),) + DIST-SRCS-yes += configure + DIST-SRCS-yes += build/make/configure.sh + DIST-SRCS-yes += build/make/gen_asm_deps.sh + DIST-SRCS-yes += build/make/Makefile + DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_def.sh + DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_proj.sh + DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_sln.sh + DIST-SRCS-$(CONFIG_MSVS) += build/x86-msvs/yasm.rules + DIST-SRCS-$(CONFIG_MSVS) += build/x86-msvs/obj_int_extract.bat + DIST-SRCS-$(CONFIG_RVCT) += build/make/armlink_adapter.sh + # Include obj_int_extract if we use offsets from asm_*_offsets + DIST-SRCS-$(ARCH_ARM)$(ARCH_X86)$(ARCH_X86_64) += build/make/obj_int_extract.c + DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas.pl + DIST-SRCS-yes += $(target:-$(TOOLCHAIN)=).mk +endif +INSTALL-SRCS := $(call cond_enabled,CONFIG_INSTALL_SRCS,INSTALL-SRCS) +ifeq ($(MAKECMDGOALS),dist) +INSTALL-SRCS += $(call cond_enabled,CONFIG_INSTALL_SRCS,DIST-SRCS) +endif +.install-srcs: $(addprefix $(DIST_DIR)/src/,$(INSTALL-SRCS)) + @touch $@ + +clean:: + rm -f .install-srcs + +ifeq ($(CONFIG_EXTERNAL_BUILD),yes) + BUILD_TARGETS += .projects + INSTALL_TARGETS += .install-projects +endif +BUILD_TARGETS += .docs .libs .bins +INSTALL_TARGETS += .install-docs .install-srcs .install-libs .install-bins +all: $(BUILD_TARGETS) +install:: $(INSTALL_TARGETS) +dist: $(INSTALL_TARGETS) +test:: diff --git a/build/make/ads2gas.pl b/build/make/ads2gas.pl new file mode 100755 index 0000000..c55ed0f --- /dev/null +++ b/build/make/ads2gas.pl @@ -0,0 +1,178 @@ +#!/usr/bin/perl +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# ads2gas.pl +# Author: Eric Fung (efung (at) acm.org) +# +# Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format +# +# Usage: cat inputfile | perl ads2gas.pl > outputfile +# +print "@ This file was created from a .asm file\n"; +print "@ using the ads2gas.pl script.\n"; +print "\t.equ DO1STROUNDING, 0\n"; + +# Stack of procedure names. +@proc_stack = (); + +while () +{ + # Load and store alignment + s/@/,:/g; + + # Comment character + s/;/@/g; + + # Hexadecimal constants prefaced by 0x + s/#&/#0x/g; + + # Convert :OR: to | + s/:OR:/ | /g; + + # Convert :AND: to & + s/:AND:/ & /g; + + # Convert :NOT: to ~ + s/:NOT:/ ~ /g; + + # Convert :SHL: to << + s/:SHL:/ << /g; + + # Convert :SHR: to >> + s/:SHR:/ >> /g; + + # Convert ELSE to .else + s/ELSE/.else/g; + + # Convert ENDIF to .endif + s/ENDIF/.endif/g; + + # Convert ELSEIF to .elseif + s/ELSEIF/.elseif/g; + + # Convert LTORG to .ltorg + s/LTORG/.ltorg/g; + + # Convert IF :DEF:to .if + # gcc doesn't have the ability to do a conditional + # if defined variable that is set by IF :DEF: on + # armasm, so convert it to a normal .if and then + # make sure to define a value elesewhere + if (s/\bIF :DEF:\b/.if /g) + { + s/=/==/g; + } + + # Convert IF to .if + if (s/\bIF\b/.if/g) + { + s/=+/==/g; + } + + # Convert INCLUDE to .INCLUDE "file" + s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/; + + # Code directive (ARM vs Thumb) + s/CODE([0-9][0-9])/.code $1/; + + # No AREA required + # But ALIGNs in AREA must be obeyed + s/^\s*AREA.*ALIGN=([0-9])$/.text\n.p2align $1/; + # If no ALIGN, strip the AREA and align to 4 bytes + s/^\s*AREA.*$/.text\n.p2align 2/; + + # DCD to .word + # This one is for incoming symbols + s/DCD\s+\|(\w*)\|/.long $1/; + + # DCW to .short + s/DCW\s+\|(\w*)\|/.short $1/; + s/DCW(.*)/.short $1/; + + # Constants defined in scope + s/DCD(.*)/.long $1/; + s/DCB(.*)/.byte $1/; + + # RN to .req + if (s/RN\s+([Rr]\d+|lr)/.req $1/) + { + print; + next; + } + + # Make function visible to linker, and make additional symbol with + # prepended underscore + s/EXPORT\s+\|([\$\w]*)\|/.global $1 \n\t.type $1, function/; + s/IMPORT\s+\|([\$\w]*)\|/.global $1/; + + # No vertical bars required; make additional symbol with prepended + # underscore + s/^\|(\$?\w+)\|/_$1\n\t$1:/g; + + # Labels need trailing colon +# s/^(\w+)/$1:/ if !/EQU/; + # put the colon at the end of the line in the macro + s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/; + + # ALIGN directive + s/ALIGN/.balign/g; + + # ARM code + s/\sARM/.arm/g; + + # eabi_attributes numerical equivalents can be found in the + # "ARM IHI 0045C" document. + + # REQUIRE8 Stack is required to be 8-byte aligned + s/\sREQUIRE8/.eabi_attribute 24, 1 \@Tag_ABI_align_needed/g; + + # PRESERVE8 Stack 8-byte align is preserved + s/\sPRESERVE8/.eabi_attribute 25, 1 \@Tag_ABI_align_preserved/g; + + # Use PROC and ENDP to give the symbols a .size directive. + # This makes them show up properly in debugging tools like gdb and valgrind. + if (/\bPROC\b/) + { + my $proc; + /^_([\.0-9A-Z_a-z]\w+)\b/; + $proc = $1; + push(@proc_stack, $proc) if ($proc); + s/\bPROC\b/@ $&/; + } + if (/\bENDP\b/) + { + my $proc; + s/\bENDP\b/@ $&/; + $proc = pop(@proc_stack); + $_ = "\t.size $proc, .-$proc".$_ if ($proc); + } + + # EQU directive + s/(.*)EQU(.*)/.equ $1, $2/; + + # Begin macro definition + if (/MACRO/) { + $_ = ; + s/^/.macro/; + s/\$//g; # remove formal param reference + s/;/@/g; # change comment characters + } + + # For macros, use \ to reference formal params + s/\$/\\/g; # End macro definition + s/MEND/.endm/; # No need to tell it where to stop assembling + next if /^\s*END\s*$/; + print; +} + +# Mark that this object doesn't need an executable stack. +printf ("\t.section\t.note.GNU-stack,\"\",\%\%progbits\n"); diff --git a/build/make/ads2gas_apple.pl b/build/make/ads2gas_apple.pl new file mode 100755 index 0000000..81280bf --- /dev/null +++ b/build/make/ads2gas_apple.pl @@ -0,0 +1,214 @@ +#!/usr/bin/env perl +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# ads2gas.pl +# Author: Eric Fung (efung (at) acm.org) +# +# Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format +# +# Usage: cat inputfile | perl ads2gas.pl > outputfile +# +print "@ This file was created from a .asm file\n"; +print "@ using the ads2gas_apple.pl script.\n\n"; +print "\t.set WIDE_REFERENCE, 0\n"; +print "\t.set ARCHITECTURE, 5\n"; +print "\t.set DO1STROUNDING, 0\n"; + +my %register_aliases; +my %macro_aliases; + +my @mapping_list = ("\$0", "\$1", "\$2", "\$3", "\$4", "\$5", "\$6", "\$7", "\$8", "\$9"); + +my @incoming_array; + +my @imported_functions; + +# Perl trim function to remove whitespace from the start and end of the string +sub trim($) +{ + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +while () +{ + # Load and store alignment + s/@/,:/g; + + # Comment character + s/;/@/g; + + # Hexadecimal constants prefaced by 0x + s/#&/#0x/g; + + # Convert :OR: to | + s/:OR:/ | /g; + + # Convert :AND: to & + s/:AND:/ & /g; + + # Convert :NOT: to ~ + s/:NOT:/ ~ /g; + + # Convert :SHL: to << + s/:SHL:/ << /g; + + # Convert :SHR: to >> + s/:SHR:/ >> /g; + + # Convert ELSE to .else + s/ELSE/.else/g; + + # Convert ENDIF to .endif + s/ENDIF/.endif/g; + + # Convert ELSEIF to .elseif + s/ELSEIF/.elseif/g; + + # Convert LTORG to .ltorg + s/LTORG/.ltorg/g; + + # Convert IF :DEF:to .if + # gcc doesn't have the ability to do a conditional + # if defined variable that is set by IF :DEF: on + # armasm, so convert it to a normal .if and then + # make sure to define a value elesewhere + if (s/\bIF :DEF:\b/.if /g) + { + s/=/==/g; + } + + # Convert IF to .if + if (s/\bIF\b/.if/g) + { + s/=/==/g; + } + + # Convert INCLUDE to .INCLUDE "file" + s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/; + + # Code directive (ARM vs Thumb) + s/CODE([0-9][0-9])/.code $1/; + + # No AREA required + # But ALIGNs in AREA must be obeyed + s/^\s*AREA.*ALIGN=([0-9])$/.text\n.p2align $1/; + # If no ALIGN, strip the AREA and align to 4 bytes + s/^\s*AREA.*$/.text\n.p2align 2/; + + # DCD to .word + # This one is for incoming symbols + s/DCD\s+\|(\w*)\|/.long $1/; + + # DCW to .short + s/DCW\s+\|(\w*)\|/.short $1/; + s/DCW(.*)/.short $1/; + + # Constants defined in scope + s/DCD(.*)/.long $1/; + s/DCB(.*)/.byte $1/; + + # Build a hash of all the register - alias pairs. + if (s/(.*)RN(.*)/$1 .req $2/g) + { + $register_aliases{trim($1)} = trim($2); + next; + } + + while (($key, $value) = each(%register_aliases)) + { + s/\b$key\b/$value/g; + } + + # Make function visible to linker, and make additional symbol with + # prepended underscore + s/EXPORT\s+\|([\$\w]*)\|/.globl _$1\n\t.globl $1/; + + # Prepend imported functions with _ + if (s/IMPORT\s+\|([\$\w]*)\|/.globl $1/) + { + $function = trim($1); + push(@imported_functions, $function); + } + + foreach $function (@imported_functions) + { + s/$function/_$function/; + } + + # No vertical bars required; make additional symbol with prepended + # underscore + s/^\|(\$?\w+)\|/_$1\n\t$1:/g; + + # Labels need trailing colon +# s/^(\w+)/$1:/ if !/EQU/; + # put the colon at the end of the line in the macro + s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/; + + # ALIGN directive + s/ALIGN/.balign/g; + + # Strip ARM + s/\sARM/@ ARM/g; + + # Strip REQUIRE8 + #s/\sREQUIRE8/@ REQUIRE8/g; + s/\sREQUIRE8/@ /g; + + # Strip PRESERVE8 + s/\sPRESERVE8/@ PRESERVE8/g; + + # Strip PROC and ENDPROC + s/\bPROC\b/@/g; + s/\bENDP\b/@/g; + + # EQU directive + s/(.*)EQU(.*)/.set $1, $2/; + + # Begin macro definition + if (/MACRO/) + { + # Process next line down, which will be the macro definition + $_ = ; + + $trimmed = trim($_); + + # remove commas that are separating list + $trimmed =~ s/,//g; + + # string to array + @incoming_array = split(/ /, $trimmed); + + print ".macro @incoming_array[0]\n"; + + # remove the first element, as that is the name of the macro + shift (@incoming_array); + + @macro_aliases{@incoming_array} = @mapping_list; + + next; + } + + while (($key, $value) = each(%macro_aliases)) + { + $key =~ s/\$/\\\$/; + s/$key\b/$value/g; + } + + # For macros, use \ to reference formal params +# s/\$/\\/g; # End macro definition + s/MEND/.endm/; # No need to tell it where to stop assembling + next if /^\s*END\s*$/; + print; +} diff --git a/build/make/armlink_adapter.sh b/build/make/armlink_adapter.sh new file mode 100755 index 0000000..b53669c --- /dev/null +++ b/build/make/armlink_adapter.sh @@ -0,0 +1,54 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +verbose=0 +set -- $* +for i; do + if [ "$i" == "-o" ]; then + on_of=1 + elif [ "$i" == "-v" ]; then + verbose=1 + elif [ "$i" == "-g" ]; then + args="${args} --debug" + elif [ "$on_of" == "1" ]; then + outfile=$i + on_of=0 + elif [ -f "$i" ]; then + infiles="$infiles $i" + elif [ "${i:0:2}" == "-l" ]; then + libs="$libs ${i#-l}" + elif [ "${i:0:2}" == "-L" ]; then + libpaths="${libpaths} ${i#-L}" + else + args="${args} ${i}" + fi + shift +done + +# Absolutize library file names +for f in $libs; do + found=0 + for d in $libpaths; do + [ -f "$d/$f" ] && infiles="$infiles $d/$f" && found=1 && break + [ -f "$d/lib${f}.so" ] && infiles="$infiles $d/lib${f}.so" && found=1 && break + [ -f "$d/lib${f}.a" ] && infiles="$infiles $d/lib${f}.a" && found=1 && break + done + [ $found -eq 0 ] && infiles="$infiles $f" +done +for d in $libpaths; do + [ -n "$libsearchpath" ] && libsearchpath="${libsearchpath}," + libsearchpath="${libsearchpath}$d" +done + +cmd="armlink $args --userlibpath=$libsearchpath --output=$outfile $infiles" +[ $verbose -eq 1 ] && echo $cmd +$cmd diff --git a/build/make/configure.sh b/build/make/configure.sh new file mode 100755 index 0000000..3c772e5 --- /dev/null +++ b/build/make/configure.sh @@ -0,0 +1,1187 @@ +#!/bin/bash +## +## configure.sh +## +## This script is sourced by the main configure script and contains +## utility functions and other common bits that aren't strictly libvpx +## related. +## +## This build system is based in part on the FFmpeg configure script. +## + + +# +# Logging / Output Functions +# +die_unknown(){ + echo "Unknown option \"$1\"." + echo "See $0 --help for available options." + clean_temp_files + exit 1 +} + + +die() { + echo "$@" + echo + echo "Configuration failed. This could reflect a misconfiguration of your" + echo "toolchains, improper options selected, or another problem. If you" + echo "don't see any useful error messages above, the next step is to look" + echo "at the configure error log file ($logfile) to determine what" + echo "configure was trying to do when it died." + clean_temp_files + exit 1 +} + + +log(){ + echo "$@" >>$logfile +} + + +log_file(){ + log BEGIN $1 + pr -n -t $1 >>$logfile + log END $1 +} + + +log_echo() { + echo "$@" + log "$@" +} + + +fwrite () { + outfile=$1 + shift + echo "$@" >> ${outfile} +} + + +show_help_pre(){ + for opt in ${CMDLINE_SELECT}; do + opt2=`echo $opt | sed -e 's;_;-;g'` + if enabled $opt; then + eval "toggle_${opt}=\"--disable-${opt2}\"" + else + eval "toggle_${opt}=\"--enable-${opt2} \"" + fi + done + + cat <>${logfile} 2>&1 +} + +check_cc() { + log check_cc "$@" + cat >${TMP_C} + log_file ${TMP_C} + check_cmd ${CC} ${CFLAGS} "$@" -c -o ${TMP_O} ${TMP_C} +} + +check_cpp() { + log check_cpp "$@" + cat > ${TMP_C} + log_file ${TMP_C} + check_cmd ${CC} ${CFLAGS} "$@" -E -o ${TMP_O} ${TMP_C} +} + +check_ld() { + log check_ld "$@" + check_cc $@ \ + && check_cmd ${LD} ${LDFLAGS} "$@" -o ${TMP_X} ${TMP_O} ${extralibs} +} + +check_header(){ + log check_header "$@" + header=$1 + shift + var=`echo $header | sed 's/[^A-Za-z0-9_]/_/g'` + disable $var + check_cpp "$@" <${TMP_ASM} <${TMP_X} + log_file ${TMP_X} + if ! grep -q '\.rodata .* 16$' ${TMP_X}; then + die "${AS} ${ASFLAGS} does not support section alignment (nasm <=2.08?)" + fi +} + +write_common_config_banner() { + print_webm_license config.mk "##" "" + echo '# This file automatically generated by configure. Do not edit!' >> config.mk + echo "TOOLCHAIN := ${toolchain}" >> config.mk + + case ${toolchain} in + *-linux-rvct) + echo "ALT_LIBC := ${alt_libc}" >> config.mk + ;; + esac +} + +write_common_config_targets() { + for t in ${all_targets}; do + if enabled ${t}; then + if enabled universal || enabled child; then + fwrite config.mk "ALL_TARGETS += ${t}-${toolchain}" + else + fwrite config.mk "ALL_TARGETS += ${t}" + fi + fi + true; + done +true +} + +write_common_target_config_mk() { + local CC=${CC} + enabled ccache && CC="ccache ${CC}" + print_webm_license $1 "##" "" + + cat >> $1 << EOF +# This file automatically generated by configure. Do not edit! +SRC_PATH="$source_path" +SRC_PATH_BARE=$source_path +BUILD_PFX=${BUILD_PFX} +TOOLCHAIN=${toolchain} +ASM_CONVERSION=${asm_conversion_cmd:-${source_path}/build/make/ads2gas.pl} + +CC=${CC} +AR=${AR} +LD=${LD} +AS=${AS} +STRIP=${STRIP} +NM=${NM} + +CFLAGS = ${CFLAGS} +ARFLAGS = -rus\$(if \$(quiet),c,v) +LDFLAGS = ${LDFLAGS} +ASFLAGS = ${ASFLAGS} +extralibs = ${extralibs} +AS_SFX = ${AS_SFX:-.asm} +EXE_SFX = ${EXE_SFX} +RTCD_OPTIONS = ${RTCD_OPTIONS} +EOF + + if enabled rvct; then cat >> $1 << EOF +fmt_deps = sed -e 's;^__image.axf;\$(dir \$@)\$(notdir \$<).o \$@;' #hide +EOF + else cat >> $1 << EOF +fmt_deps = sed -e 's;^\([a-zA-Z0-9_]*\)\.o;\$(dir \$@)\1\$(suffix \$<).o \$@;' +EOF + fi + + print_config_mk ARCH "${1}" ${ARCH_LIST} + print_config_mk HAVE "${1}" ${HAVE_LIST} + print_config_mk CONFIG "${1}" ${CONFIG_LIST} + print_config_mk HAVE "${1}" gnu_strip + + enabled msvs && echo "CONFIG_VS_VERSION=${vs_version}" >> "${1}" + +} + + +write_common_target_config_h() { + print_webm_license ${TMP_H} "/*" " */" + cat >> ${TMP_H} << EOF +/* This file automatically generated by configure. Do not edit! */ +#ifndef VPX_CONFIG_H +#define VPX_CONFIG_H +#define RESTRICT ${RESTRICT} +EOF + print_config_h ARCH "${TMP_H}" ${ARCH_LIST} + print_config_h HAVE "${TMP_H}" ${HAVE_LIST} + print_config_h CONFIG "${TMP_H}" ${CONFIG_LIST} + echo "#endif /* VPX_CONFIG_H */" >> ${TMP_H} + mkdir -p `dirname "$1"` + cmp "$1" ${TMP_H} >/dev/null 2>&1 || mv ${TMP_H} "$1" +} + +process_common_cmdline() { + for opt in "$@"; do + optval="${opt#*=}" + case "$opt" in + --child) enable child + ;; + --log*) + logging="$optval" + if ! disabled logging ; then + enabled logging || logfile="$logging" + else + logfile=/dev/null + fi + ;; + --target=*) toolchain="${toolchain:-${optval}}" + ;; + --force-target=*) toolchain="${toolchain:-${optval}}"; enable force_toolchain + ;; + --cpu) + ;; + --cpu=*) tune_cpu="$optval" + ;; + --extra-cflags=*) + extra_cflags="${optval}" + ;; + --enable-?*|--disable-?*) + eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'` + if echo "${ARCH_EXT_LIST}" | grep "^ *$option\$" >/dev/null; then + [ $action = "disable" ] && RTCD_OPTIONS="${RTCD_OPTIONS}${opt} " + elif [ $action = "disable" ] && ! disabled $option ; then + echo "${CMDLINE_SELECT}" | grep "^ *$option\$" >/dev/null || + die_unknown $opt + elif [ $action = "enable" ] && ! enabled $option ; then + echo "${CMDLINE_SELECT}" | grep "^ *$option\$" >/dev/null || + die_unknown $opt + fi + $action $option + ;; + --require-?*) + eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'` + if echo "${ARCH_EXT_LIST}" none | grep "^ *$option\$" >/dev/null; then + RTCD_OPTIONS="${RTCD_OPTIONS}${opt} " + else + die_unknown $opt + fi + ;; + --force-enable-?*|--force-disable-?*) + eval `echo "$opt" | sed 's/--force-/action=/;s/-/ option=/;s/-/_/g'` + $action $option + ;; + --libc=*) + [ -d "${optval}" ] || die "Not a directory: ${optval}" + disable builtin_libc + alt_libc="${optval}" + ;; + --as=*) + [ "${optval}" = yasm -o "${optval}" = nasm -o "${optval}" = auto ] \ + || die "Must be yasm, nasm or auto: ${optval}" + alt_as="${optval}" + ;; + --prefix=*) + prefix="${optval}" + ;; + --libdir=*) + libdir="${optval}" + ;; + --sdk-path=*) + [ -d "${optval}" ] || die "Not a directory: ${optval}" + sdk_path="${optval}" + ;; + --libc|--as|--prefix|--libdir|--sdk-path) + die "Option ${opt} requires argument" + ;; + --help|-h) show_help + ;; + *) die_unknown $opt + ;; + esac + done +} + +process_cmdline() { + for opt do + optval="${opt#*=}" + case "$opt" in + *) process_common_cmdline $opt + ;; + esac + done +} + + +post_process_common_cmdline() { + prefix="${prefix:-/usr/local}" + prefix="${prefix%/}" + libdir="${libdir:-${prefix}/lib}" + libdir="${libdir%/}" + if [ "${libdir#${prefix}}" = "${libdir}" ]; then + die "Libdir ${libdir} must be a subdirectory of ${prefix}" + fi +} + + +post_process_cmdline() { + true; +} + +setup_gnu_toolchain() { + CC=${CC:-${CROSS}gcc} + AR=${AR:-${CROSS}ar} + LD=${LD:-${CROSS}${link_with_cc:-ld}} + AS=${AS:-${CROSS}as} + STRIP=${STRIP:-${CROSS}strip} + NM=${NM:-${CROSS}nm} + AS_SFX=.s + EXE_SFX= +} + +process_common_toolchain() { + if [ -z "$toolchain" ]; then + gcctarget="$(gcc -dumpmachine 2> /dev/null)" + + # detect tgt_isa + case "$gcctarget" in + *x86_64*|*amd64*) + tgt_isa=x86_64 + ;; + *i[3456]86*) + tgt_isa=x86 + ;; + *powerpc64*) + tgt_isa=ppc64 + ;; + *powerpc*) + tgt_isa=ppc32 + ;; + *sparc*) + tgt_isa=sparc + ;; + esac + + # detect tgt_os + case "$gcctarget" in + *darwin8*) + tgt_isa=universal + tgt_os=darwin8 + ;; + *darwin9*) + tgt_isa=universal + tgt_os=darwin9 + ;; + *darwin10*) + tgt_isa=x86_64 + tgt_os=darwin10 + ;; + *darwin11*) + tgt_isa=x86_64 + tgt_os=darwin11 + ;; + *darwin12*) + tgt_isa=x86_64 + tgt_os=darwin12 + ;; + *mingw32*|*cygwin*) + [ -z "$tgt_isa" ] && tgt_isa=x86 + tgt_os=win32 + ;; + *linux*|*bsd*) + tgt_os=linux + ;; + *solaris2.10) + tgt_os=solaris + ;; + *os2*) + tgt_os=os2 + ;; + esac + + if [ -n "$tgt_isa" ] && [ -n "$tgt_os" ]; then + toolchain=${tgt_isa}-${tgt_os}-gcc + fi + fi + + toolchain=${toolchain:-generic-gnu} + + is_in ${toolchain} ${all_platforms} || enabled force_toolchain \ + || die "Unrecognized toolchain '${toolchain}'" + + enabled child || log_echo "Configuring for target '${toolchain}'" + + # + # Set up toolchain variables + # + tgt_isa=$(echo ${toolchain} | awk 'BEGIN{FS="-"}{print $1}') + tgt_os=$(echo ${toolchain} | awk 'BEGIN{FS="-"}{print $2}') + tgt_cc=$(echo ${toolchain} | awk 'BEGIN{FS="-"}{print $3}') + + # Mark the specific ISA requested as enabled + soft_enable ${tgt_isa} + enable ${tgt_os} + enable ${tgt_cc} + + # Enable the architecture family + case ${tgt_isa} in + arm*) enable arm;; + mips*) enable mips;; + esac + + # PIC is probably what we want when building shared libs + enabled shared && soft_enable pic + + # Handle darwin variants. Newer SDKs allow targeting older + # platforms, so find the newest SDK available. + case ${toolchain} in + *-darwin*) + if [ -z "${DEVELOPER_DIR}" ]; then + DEVELOPER_DIR=`xcode-select -print-path 2> /dev/null` + [ $? -ne 0 ] && OSX_SKIP_DIR_CHECK=1 + fi + if [ -z "${OSX_SKIP_DIR_CHECK}" ]; then + OSX_SDK_ROOTS="${DEVELOPER_DIR}/SDKs" + OSX_SDK_VERSIONS="MacOSX10.4u.sdk MacOSX10.5.sdk MacOSX10.6.sdk" + OSX_SDK_VERSIONS="${OSX_SDK_VERSIONS} MacOSX10.7.sdk" + for v in ${OSX_SDK_VERSIONS}; do + if [ -d "${OSX_SDK_ROOTS}/${v}" ]; then + osx_sdk_dir="${OSX_SDK_ROOTS}/${v}" + fi + done + fi + ;; + esac + + if [ -d "${osx_sdk_dir}" ]; then + add_cflags "-isysroot ${osx_sdk_dir}" + add_ldflags "-isysroot ${osx_sdk_dir}" + fi + + case ${toolchain} in + *-darwin8-*) + add_cflags "-mmacosx-version-min=10.4" + add_ldflags "-mmacosx-version-min=10.4" + ;; + *-darwin9-*) + add_cflags "-mmacosx-version-min=10.5" + add_ldflags "-mmacosx-version-min=10.5" + ;; + *-darwin10-*) + add_cflags "-mmacosx-version-min=10.6" + add_ldflags "-mmacosx-version-min=10.6" + ;; + *-darwin11-*) + add_cflags "-mmacosx-version-min=10.7" + add_ldflags "-mmacosx-version-min=10.7" + ;; + *-darwin12-*) + add_cflags "-mmacosx-version-min=10.8" + add_ldflags "-mmacosx-version-min=10.8" + ;; + esac + + # Handle Solaris variants. Solaris 10 needs -lposix4 + case ${toolchain} in + sparc-solaris-*) + add_extralibs -lposix4 + disable fast_unaligned + ;; + *-solaris-*) + add_extralibs -lposix4 + ;; + esac + + # Process ARM architecture variants + case ${toolchain} in + arm*) + # on arm, isa versions are supersets + case ${tgt_isa} in + armv7) + soft_enable neon + soft_enable media + soft_enable edsp + soft_enable fast_unaligned + ;; + armv6) + soft_enable media + soft_enable edsp + soft_enable fast_unaligned + ;; + armv5te) + soft_enable edsp + ;; + esac + + asm_conversion_cmd="cat" + + case ${tgt_cc} in + gcc) + CROSS=${CROSS:-arm-none-linux-gnueabi-} + link_with_cc=gcc + setup_gnu_toolchain + arch_int=${tgt_isa##armv} + arch_int=${arch_int%%te} + check_add_asflags --defsym ARCHITECTURE=${arch_int} + tune_cflags="-mtune=" + if [ ${tgt_isa} == "armv7" ]; then + if enabled neon + then + check_add_cflags -mfpu=neon #-ftree-vectorize + check_add_asflags -mfpu=neon + fi + check_add_cflags -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp + check_add_asflags -mcpu=cortex-a8 -mfloat-abi=softfp #-march=armv7-a + else + check_add_cflags -march=${tgt_isa} + check_add_asflags -march=${tgt_isa} + fi + enabled debug && add_asflags -g + asm_conversion_cmd="${source_path}/build/make/ads2gas.pl" + ;; + rvct) + CC=armcc + AR=armar + AS=armasm + LD=${source_path}/build/make/armlink_adapter.sh + STRIP=arm-none-linux-gnueabi-strip + NM=arm-none-linux-gnueabi-nm + tune_cflags="--cpu=" + tune_asflags="--cpu=" + if [ -z "${tune_cpu}" ]; then + if [ ${tgt_isa} == "armv7" ]; then + if enabled neon + then + check_add_cflags --fpu=softvfp+vfpv3 + check_add_asflags --fpu=softvfp+vfpv3 + fi + check_add_cflags --cpu=Cortex-A8 + check_add_asflags --cpu=Cortex-A8 + else + check_add_cflags --cpu=${tgt_isa##armv} + check_add_asflags --cpu=${tgt_isa##armv} + fi + fi + arch_int=${tgt_isa##armv} + arch_int=${arch_int%%te} + check_add_asflags --pd "\"ARCHITECTURE SETA ${arch_int}\"" + enabled debug && add_asflags -g + add_cflags --gnu + add_cflags --enum_is_int + add_cflags --wchar32 + ;; + esac + + case ${tgt_os} in + none*) + disable multithread + disable os_support + ;; + + android*) + SDK_PATH=${sdk_path} + COMPILER_LOCATION=`find "${SDK_PATH}" \ + -name "arm-linux-androideabi-gcc*" -print -quit` + TOOLCHAIN_PATH=${COMPILER_LOCATION%/*}/arm-linux-androideabi- + CC=${TOOLCHAIN_PATH}gcc + AR=${TOOLCHAIN_PATH}ar + LD=${TOOLCHAIN_PATH}gcc + AS=${TOOLCHAIN_PATH}as + STRIP=${TOOLCHAIN_PATH}strip + NM=${TOOLCHAIN_PATH}nm + + if [ -z "${alt_libc}" ]; then + alt_libc=`find "${SDK_PATH}" -name arch-arm -print | \ + awk '{n = split($0,a,"/"); \ + split(a[n-1],b,"-"); \ + print $0 " " b[2]}' | \ + sort -g -k 2 | \ + awk '{ print $1 }' | tail -1` + fi + + add_cflags "--sysroot=${alt_libc}" + add_ldflags "--sysroot=${alt_libc}" + + add_cflags "-I${SDK_PATH}/sources/android/cpufeatures/" + + enable pic + soft_enable realtime_only + if [ ${tgt_isa} == "armv7" ]; then + enable runtime_cpu_detect + fi + ;; + + darwin*) + if [ -z "${sdk_path}" ]; then + SDK_PATH=`xcode-select -print-path 2> /dev/null` + SDK_PATH=${SDK_PATH}/Platforms/iPhoneOS.platform/Developer + else + SDK_PATH=${sdk_path} + fi + TOOLCHAIN_PATH=${SDK_PATH}/usr/bin + CC=${TOOLCHAIN_PATH}/gcc + AR=${TOOLCHAIN_PATH}/ar + LD=${TOOLCHAIN_PATH}/arm-apple-darwin10-llvm-gcc-4.2 + AS=${TOOLCHAIN_PATH}/as + STRIP=${TOOLCHAIN_PATH}/strip + NM=${TOOLCHAIN_PATH}/nm + AS_SFX=.s + + # ASFLAGS is written here instead of using check_add_asflags + # because we need to overwrite all of ASFLAGS and purge the + # options that were put in above + ASFLAGS="-version -arch ${tgt_isa} -g" + + add_cflags -arch ${tgt_isa} + add_ldflags -arch_only ${tgt_isa} + + if [ -z "${alt_libc}" ]; then + alt_libc=${SDK_PATH}/SDKs/iPhoneOS5.1.sdk + fi + + add_cflags "-isysroot ${alt_libc}" + + # Add the paths for the alternate libc + for d in usr/include; do + try_dir="${alt_libc}/${d}" + [ -d "${try_dir}" ] && add_cflags -I"${try_dir}" + done + + for d in lib usr/lib usr/lib/system; do + try_dir="${alt_libc}/${d}" + [ -d "${try_dir}" ] && add_ldflags -L"${try_dir}" + done + + asm_conversion_cmd="${source_path}/build/make/ads2gas_apple.pl" + ;; + + linux*) + enable linux + if enabled rvct; then + # Check if we have CodeSourcery GCC in PATH. Needed for + # libraries + hash arm-none-linux-gnueabi-gcc 2>&- || \ + die "Couldn't find CodeSourcery GCC from PATH" + + # Use armcc as a linker to enable translation of + # some gcc specific options such as -lm and -lpthread. + LD="armcc --translate_gcc" + + # create configuration file (uses path to CodeSourcery GCC) + armcc --arm_linux_configure --arm_linux_config_file=arm_linux.cfg + + add_cflags --arm_linux_paths --arm_linux_config_file=arm_linux.cfg + add_asflags --no_hide_all --apcs=/interwork + add_ldflags --arm_linux_paths --arm_linux_config_file=arm_linux.cfg + enabled pic && add_cflags --apcs=/fpic + enabled pic && add_asflags --apcs=/fpic + enabled shared && add_cflags --shared + fi + ;; + + esac + ;; + mips*) + CROSS=${CROSS:-mipsel-linux-uclibc-} + link_with_cc=gcc + setup_gnu_toolchain + tune_cflags="-mtune=" + check_add_cflags -march=${tgt_isa} + check_add_asflags -march=${tgt_isa} + check_add_asflags -KPIC + ;; + ppc*) + enable ppc + bits=${tgt_isa##ppc} + link_with_cc=gcc + setup_gnu_toolchain + add_asflags -force_cpusubtype_ALL -I"\$(dir \$<)darwin" + soft_enable altivec + enabled altivec && add_cflags -maltivec + + case "$tgt_os" in + linux*) + add_asflags -maltivec -mregnames -I"\$(dir \$<)linux" + ;; + darwin*) + darwin_arch="-arch ppc" + enabled ppc64 && darwin_arch="${darwin_arch}64" + add_cflags ${darwin_arch} -m${bits} -fasm-blocks + add_asflags ${darwin_arch} -force_cpusubtype_ALL -I"\$(dir \$<)darwin" + add_ldflags ${darwin_arch} -m${bits} + enabled altivec && add_cflags -faltivec + ;; + esac + ;; + x86*) + bits=32 + enabled x86_64 && bits=64 + soft_enable runtime_cpu_detect + soft_enable mmx + soft_enable sse + soft_enable sse2 + soft_enable sse3 + soft_enable ssse3 + soft_enable sse4_1 + + case ${tgt_os} in + win*) + enabled gcc && add_cflags -fno-common + ;; + solaris*) + CC=${CC:-${CROSS}gcc} + LD=${LD:-${CROSS}gcc} + CROSS=${CROSS:-g} + ;; + os2) + AS=${AS:-nasm} + ;; + esac + + AS="${alt_as:-${AS:-auto}}" + case ${tgt_cc} in + icc*) + CC=${CC:-icc} + LD=${LD:-icc} + setup_gnu_toolchain + add_cflags -use-msasm -use-asm + add_ldflags -i-static + enabled x86_64 && add_cflags -ipo -no-prec-div -static -xSSE2 -axSSE2 + enabled x86_64 && AR=xiar + case ${tune_cpu} in + atom*) + tune_cflags="-x" + tune_cpu="SSE3_ATOM" + ;; + *) + tune_cflags="-march=" + ;; + esac + ;; + gcc*) + add_cflags -m${bits} + add_ldflags -m${bits} + link_with_cc=gcc + tune_cflags="-march=" + setup_gnu_toolchain + #for 32 bit x86 builds, -O3 did not turn on this flag + enabled optimizations && check_add_cflags -fomit-frame-pointer + ;; + esac + + case "${AS}" in + auto|"") + which nasm >/dev/null 2>&1 && AS=nasm + which yasm >/dev/null 2>&1 && AS=yasm + [ "${AS}" = auto -o -z "${AS}" ] \ + && die "Neither yasm nor nasm have been found" + ;; + esac + log_echo " using $AS" + [ "${AS##*/}" = nasm ] && add_asflags -Ox + AS_SFX=.asm + case ${tgt_os} in + win32) + add_asflags -f win32 + enabled debug && add_asflags -g cv8 + ;; + win64) + add_asflags -f x64 + enabled debug && add_asflags -g cv8 + ;; + linux*|solaris*) + add_asflags -f elf${bits} + enabled debug && [ "${AS}" = yasm ] && add_asflags -g dwarf2 + enabled debug && [ "${AS}" = nasm ] && add_asflags -g + [ "${AS##*/}" = nasm ] && check_asm_align + ;; + darwin*) + add_asflags -f macho${bits} + enabled x86 && darwin_arch="-arch i386" || darwin_arch="-arch x86_64" + add_cflags ${darwin_arch} + add_ldflags ${darwin_arch} + # -mdynamic-no-pic is still a bit of voodoo -- it was required at + # one time, but does not seem to be now, and it breaks some of the + # code that still relies on inline assembly. + # enabled icc && ! enabled pic && add_cflags -fno-pic -mdynamic-no-pic + enabled icc && ! enabled pic && add_cflags -fno-pic + ;; + os2) + add_asflags -f aout + enabled debug && add_asflags -g + EXE_SFX=.exe + ;; + *) log "Warning: Unknown os $tgt_os while setting up $AS flags" + ;; + esac + ;; + universal*|*-gcc|generic-gnu) + link_with_cc=gcc + enable gcc + setup_gnu_toolchain + ;; + esac + + # Try to enable CPU specific tuning + if [ -n "${tune_cpu}" ]; then + if [ -n "${tune_cflags}" ]; then + check_add_cflags ${tune_cflags}${tune_cpu} || \ + die "Requested CPU '${tune_cpu}' not supported by compiler" + fi + if [ -n "${tune_asflags}" ]; then + check_add_asflags ${tune_asflags}${tune_cpu} || \ + die "Requested CPU '${tune_cpu}' not supported by assembler" + fi + if [ -z "${tune_cflags}${tune_asflags}" ]; then + log_echo "Warning: CPU tuning not supported by this toolchain" + fi + fi + + enabled debug && check_add_cflags -g && check_add_ldflags -g + enabled gprof && check_add_cflags -pg && check_add_ldflags -pg + enabled gcov && + check_add_cflags -fprofile-arcs -ftest-coverage && + check_add_ldflags -fprofile-arcs -ftest-coverage + + if enabled optimizations; then + if enabled rvct; then + enabled small && check_add_cflags -Ospace || check_add_cflags -Otime + else + enabled small && check_add_cflags -O2 || check_add_cflags -O3 + fi + fi + + # Position Independent Code (PIC) support, for building relocatable + # shared objects + enabled gcc && enabled pic && check_add_cflags -fPIC + + # Work around longjmp interception on glibc >= 2.11, to improve binary + # compatibility. See http://code.google.com/p/webm/issues/detail?id=166 + enabled linux && check_add_cflags -D_FORTIFY_SOURCE=0 + + # Check for strip utility variant + ${STRIP} -V 2>/dev/null | grep GNU >/dev/null && enable gnu_strip + + # Try to determine target endianness + check_cc </dev/null 2>&1 && enable big_endian + + # Almost every platform uses pthreads. + if enabled multithread; then + case ${toolchain} in + *-win*);; + *-android-gcc);; + *) check_header pthread.h && add_extralibs -lpthread + esac + fi + + # for sysconf(3) and friends. + check_header unistd.h + + # glibc needs these + if enabled linux; then + add_cflags -D_LARGEFILE_SOURCE + add_cflags -D_FILE_OFFSET_BITS=64 + fi + + # append any user defined extra cflags + if [ -n "${extra_cflags}" ] ; then + check_add_cflags ${extra_cflags} || \ + die "Requested extra CFLAGS '${extra_cflags}' not supported by compiler" + fi +} + +process_toolchain() { + process_common_toolchain +} + +print_config_mk() { + local prefix=$1 + local makefile=$2 + shift 2 + for cfg; do + upname="`toupper $cfg`" + if enabled $cfg; then + echo "${prefix}_${upname}=yes" >> $makefile + fi + done +} + +print_config_h() { + local prefix=$1 + local header=$2 + shift 2 + for cfg; do + upname="`toupper $cfg`" + if enabled $cfg; then + echo "#define ${prefix}_${upname} 1" >> $header + else + echo "#define ${prefix}_${upname} 0" >> $header + fi + done +} + +print_webm_license() { + local destination=$1 + local prefix=$2 + local suffix=$3 + shift 3 + cat < ${destination} +${prefix} Copyright (c) 2011 The WebM project authors. All Rights Reserved.${suffix} +${prefix} ${suffix} +${prefix} Use of this source code is governed by a BSD-style license${suffix} +${prefix} that can be found in the LICENSE file in the root of the source${suffix} +${prefix} tree. An additional intellectual property rights grant can be found${suffix} +${prefix} in the file PATENTS. All contributing project authors may${suffix} +${prefix} be found in the AUTHORS file in the root of the source tree.${suffix} +EOF +} + +process_targets() { + true; +} + +process_detect() { + true; +} + +enable logging +logfile="config.err" +self=$0 +process() { + cmdline_args="$@" + process_cmdline "$@" + if enabled child; then + echo "# ${self} $@" >> ${logfile} + else + echo "# ${self} $@" > ${logfile} + fi + post_process_common_cmdline + post_process_cmdline + process_toolchain + process_detect + process_targets + + OOT_INSTALLS="${OOT_INSTALLS}" + if enabled source_path_used; then + # Prepare the PWD for building. + for f in ${OOT_INSTALLS}; do + install -D ${source_path}/$f $f + done + fi + cp ${source_path}/build/make/Makefile . + + clean_temp_files + true +} diff --git a/build/make/gen_asm_deps.sh b/build/make/gen_asm_deps.sh new file mode 100755 index 0000000..717f870 --- /dev/null +++ b/build/make/gen_asm_deps.sh @@ -0,0 +1,64 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +self=$0 +show_help() { + echo "usage: $self [options] " + echo + echo "Generate Makefile dependency information from assembly code source" + echo + exit 1 +} +die_unknown(){ + echo "Unknown option \"$1\"." + echo "See $0 --help for available options." + exit 1 +} +for opt do + optval="${opt#*=}" + case "$opt" in + --build-pfx=*) pfx="${optval}" + ;; + --depfile=*) out="${optval}" + ;; + -I*) raw_inc_paths="${raw_inc_paths} ${opt}" + inc_path="${inc_path} ${opt#-I}" + ;; + -h|--help) show_help + ;; + *) [ -f "$opt" ] && srcfile="$opt" + ;; + esac +done + +[ -n "$srcfile" ] || show_help +sfx=${sfx:-asm} +includes=$(LC_ALL=C egrep -i "include +\"?+[a-z0-9_/]+\.${sfx}" $srcfile | + perl -p -e "s;.*?([a-z0-9_/]+.${sfx}).*;\1;") +#" restore editor state +for inc in ${includes}; do + found_inc_path= + for idir in ${inc_path}; do + [ -f "${idir}/${inc}" ] && found_inc_path="${idir}" && break + done + if [ -f `dirname $srcfile`/$inc ]; then + # Handle include files in the same directory as the source + $self --build-pfx=$pfx --depfile=$out ${raw_inc_paths} `dirname $srcfile`/$inc + elif [ -n "${found_inc_path}" ]; then + # Handle include files on the include path + $self --build-pfx=$pfx --depfile=$out ${raw_inc_paths} "${found_inc_path}/$inc" + else + # Handle generated includes in the build root (which may not exist yet) + echo ${out} ${out%d}o: "${pfx}${inc}" + fi +done +echo ${out} ${out%d}o: $srcfile diff --git a/build/make/gen_msvs_def.sh b/build/make/gen_msvs_def.sh new file mode 100755 index 0000000..4defcc2 --- /dev/null +++ b/build/make/gen_msvs_def.sh @@ -0,0 +1,83 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +self=$0 +self_basename=${self##*/} +EOL=$'\n' + +show_help() { + cat < symbol1 [symbol2, symbol3, ...] + +where is either 'text' or 'data' + + +Options: + --help Print this message + --out=filename Write output to a file [stdout] + --name=project_name Name of the library (required) +EOF + exit 1 +} + +die() { + echo "${self_basename}: $@" + exit 1 +} + +die_unknown(){ + echo "Unknown option \"$1\"." + echo "See ${self_basename} --help for available options." + exit 1 +} + +text() { + for sym in "$@"; do + echo " $sym" >> ${outfile} + done +} + +data() { + for sym in "$@"; do + printf " %-40s DATA\n" "$sym" >> ${outfile} + done +} + +# Process command line +for opt in "$@"; do + optval="${opt#*=}" + case "$opt" in + --help|-h) show_help + ;; + --out=*) outfile="$optval" + ;; + --name=*) name="${optval}" + ;; + -*) die_unknown $opt + ;; + *) file_list[${#file_list[@]}]="$opt" + esac +done +outfile=${outfile:-/dev/stdout} +[ -n "$name" ] || die "Library name (--name) must be specified!" + +echo "LIBRARY ${name}" > ${outfile} +echo "EXPORTS" >> ${outfile} +for f in "${file_list[@]}"; do + . $f +done diff --git a/build/make/gen_msvs_proj.sh b/build/make/gen_msvs_proj.sh new file mode 100755 index 0000000..6d42941 --- /dev/null +++ b/build/make/gen_msvs_proj.sh @@ -0,0 +1,573 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +self=$0 +self_basename=${self##*/} +self_dirname=$(dirname "$0") +EOL=$'\n' + +show_help() { + cat <&2 + exit 1 +} + +die_unknown(){ + echo "Unknown option \"$1\"." >&2 + echo "See ${self_basename} --help for available options." >&2 + exit 1 +} + +generate_uuid() { + local hex="0123456789ABCDEF" + local i + local uuid="" + local j + #93995380-89BD-4b04-88EB-625FBE52EBFB + for ((i=0; i<32; i++)); do + (( j = $RANDOM % 16 )) + uuid="${uuid}${hex:$j:1}" + done + echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}" +} + +indent1=" " +indent="" +indent_push() { + indent="${indent}${indent1}" +} +indent_pop() { + indent="${indent%${indent1}}" +} + +tag_attributes() { + for opt in "$@"; do + optval="${opt#*=}" + [ -n "${optval}" ] || + die "Missing attribute value in '$opt' while generating $tag tag" + echo "${indent}${opt%%=*}=\"${optval}\"" + done +} + +open_tag() { + local tag=$1 + shift + if [ $# -ne 0 ]; then + echo "${indent}<${tag}" + indent_push + tag_attributes "$@" + echo "${indent}>" + else + echo "${indent}<${tag}>" + indent_push + fi +} + +close_tag() { + local tag=$1 + indent_pop + echo "${indent}" +} + +tag() { + local tag=$1 + shift + if [ $# -ne 0 ]; then + echo "${indent}<${tag}" + indent_push + tag_attributes "$@" + indent_pop + echo "${indent}/>" + else + echo "${indent}<${tag}/>" + fi +} + +generate_filter() { + local var=$1 + local name=$2 + local pats=$3 + local file_list_sz + local i + local f + local saveIFS="$IFS" + local pack + echo "generating filter '$name' from ${#file_list[@]} files" >&2 + IFS=* + + open_tag Filter \ + Name=$name \ + Filter=$pats \ + UniqueIdentifier=`generate_uuid` \ + + file_list_sz=${#file_list[@]} + for i in ${!file_list[@]}; do + f=${file_list[i]} + for pat in ${pats//;/$IFS}; do + if [ "${f##*.}" == "$pat" ]; then + unset file_list[i] + + open_tag File RelativePath="./$f" + if [ "$pat" == "asm" ] && $asm_use_custom_step; then + for plat in "${platforms[@]}"; do + for cfg in Debug Release; do + open_tag FileConfiguration \ + Name="${cfg}|${plat}" \ + + tag Tool \ + Name="VCCustomBuildTool" \ + Description="Assembling \$(InputFileName)" \ + CommandLine="$(eval echo \$asm_${cfg}_cmdline)" \ + Outputs="\$(InputName).obj" \ + + close_tag FileConfiguration + done + done + fi + + close_tag File + + break + fi + done + done + + close_tag Filter + IFS="$saveIFS" +} + +# Process command line +unset target +for opt in "$@"; do + optval="${opt#*=}" + case "$opt" in + --help|-h) show_help + ;; + --target=*) target="${optval}" + ;; + --out=*) outfile="$optval" + ;; + --name=*) name="${optval}" + ;; + --proj-guid=*) guid="${optval}" + ;; + --module-def=*) link_opts="${link_opts} ModuleDefinitionFile=${optval}" + ;; + --exe) proj_kind="exe" + ;; + --lib) proj_kind="lib" + ;; + --src-path-bare=*) src_path_bare="$optval" + ;; + --static-crt) use_static_runtime=true + ;; + --ver=*) + vs_ver="$optval" + case "$optval" in + [789]) + ;; + *) die Unrecognized Visual Studio Version in $opt + ;; + esac + ;; + -I*) + opt="${opt%/}" + incs="${incs}${incs:+;}"${opt##-I}"" + yasmincs="${yasmincs} ${opt}" + ;; + -D*) defines="${defines}${defines:+;}${opt##-D}" + ;; + -L*) # fudge . to $(OutDir) + if [ "${opt##-L}" == "." ]; then + libdirs="${libdirs}${libdirs:+;}"\$(OutDir)"" + else + # Also try directories for this platform/configuration + libdirs="${libdirs}${libdirs:+;}"${opt##-L}"" + libdirs="${libdirs}${libdirs:+;}"${opt##-L}/\$(PlatformName)/\$(ConfigurationName)"" + libdirs="${libdirs}${libdirs:+;}"${opt##-L}/\$(PlatformName)"" + fi + ;; + -l*) libs="${libs}${libs:+ }${opt##-l}.lib" + ;; + -*) die_unknown $opt + ;; + *) + file_list[${#file_list[@]}]="$opt" + case "$opt" in + *.asm) uses_asm=true + ;; + esac + ;; + esac +done +outfile=${outfile:-/dev/stdout} +guid=${guid:-`generate_uuid`} +asm_use_custom_step=false +uses_asm=${uses_asm:-false} +case "${vs_ver:-8}" in + 7) vs_ver_id="7.10" + asm_use_custom_step=$uses_asm + ;; + 8) vs_ver_id="8.00" + ;; + 9) vs_ver_id="9.00" + ;; +esac + +[ -n "$name" ] || die "Project name (--name) must be specified!" +[ -n "$target" ] || die "Target (--target) must be specified!" + +if ${use_static_runtime:-false}; then + release_runtime=0 + debug_runtime=1 + lib_sfx=mt +else + release_runtime=2 + debug_runtime=3 + lib_sfx=md +fi + +# Calculate debug lib names: If a lib ends in ${lib_sfx}.lib, then rename +# it to ${lib_sfx}d.lib. This precludes linking to release libs from a +# debug exe, so this may need to be refactored later. +for lib in ${libs}; do + if [ "$lib" != "${lib%${lib_sfx}.lib}" ]; then + lib=${lib%.lib}d.lib + fi + debug_libs="${debug_libs}${debug_libs:+ }${lib}" +done + + +# List Keyword for this target +case "$target" in + x86*) keyword="ManagedCProj" + ;; + *) die "Unsupported target $target!" +esac + +# List of all platforms supported for this target +case "$target" in + x86_64*) + platforms[0]="x64" + ;; + x86*) + platforms[0]="Win32" + # these are only used by vs7 + asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "\$(InputPath)"" + asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "\$(InputPath)"" + ;; + *) die "Unsupported target $target!" + ;; +esac + +generate_vcproj() { + case "$proj_kind" in + exe) vs_ConfigurationType=1 + ;; + *) vs_ConfigurationType=4 + ;; + esac + + echo "" + open_tag VisualStudioProject \ + ProjectType="Visual C++" \ + Version="${vs_ver_id}" \ + Name="${name}" \ + ProjectGUID="{${guid}}" \ + RootNamespace="${name}" \ + Keyword="${keyword}" \ + + open_tag Platforms + for plat in "${platforms[@]}"; do + tag Platform Name="$plat" + done + close_tag Platforms + + open_tag ToolFiles + case "$target" in + x86*) $uses_asm && tag ToolFile RelativePath="$self_dirname/../x86-msvs/yasm.rules" + ;; + esac + close_tag ToolFiles + + open_tag Configurations + for plat in "${platforms[@]}"; do + plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'` + open_tag Configuration \ + Name="Debug|$plat" \ + OutputDirectory="\$(SolutionDir)$plat_no_ws/\$(ConfigurationName)" \ + IntermediateDirectory="$plat_no_ws/\$(ConfigurationName)/${name}" \ + ConfigurationType="$vs_ConfigurationType" \ + CharacterSet="1" \ + + case "$target" in + x86*) + case "$name" in + obj_int_extract) + tag Tool \ + Name="VCCLCompilerTool" \ + Optimization="0" \ + AdditionalIncludeDirectories="$incs" \ + PreprocessorDefinitions="WIN32;DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE" \ + RuntimeLibrary="$debug_runtime" \ + WarningLevel="3" \ + Detect64BitPortabilityProblems="true" \ + DebugInformationFormat="1" \ + ;; + vpx) + tag Tool \ + Name="VCPreBuildEventTool" \ + CommandLine="call obj_int_extract.bat $src_path_bare" \ + + tag Tool \ + Name="VCCLCompilerTool" \ + Optimization="0" \ + AdditionalIncludeDirectories="$incs" \ + PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \ + RuntimeLibrary="$debug_runtime" \ + UsePrecompiledHeader="0" \ + WarningLevel="3" \ + DebugInformationFormat="1" \ + Detect64BitPortabilityProblems="true" \ + + $uses_asm && tag Tool Name="YASM" IncludePaths="$incs" Debug="true" + ;; + *) + tag Tool \ + Name="VCCLCompilerTool" \ + Optimization="0" \ + AdditionalIncludeDirectories="$incs" \ + PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \ + RuntimeLibrary="$debug_runtime" \ + UsePrecompiledHeader="0" \ + WarningLevel="3" \ + DebugInformationFormat="1" \ + Detect64BitPortabilityProblems="true" \ + + $uses_asm && tag Tool Name="YASM" IncludePaths="$incs" Debug="true" + ;; + esac + ;; + esac + + case "$proj_kind" in + exe) + case "$target" in + x86*) + case "$name" in + obj_int_extract) + tag Tool \ + Name="VCLinkerTool" \ + OutputFile="${name}.exe" \ + GenerateDebugInformation="true" \ + ;; + *) + tag Tool \ + Name="VCLinkerTool" \ + AdditionalDependencies="$debug_libs \$(NoInherit)" \ + AdditionalLibraryDirectories="$libdirs" \ + GenerateDebugInformation="true" \ + ProgramDatabaseFile="\$(OutDir)/${name}.pdb" \ + ;; + esac + ;; + esac + ;; + lib) + case "$target" in + x86*) + tag Tool \ + Name="VCLibrarianTool" \ + OutputFile="\$(OutDir)/${name}${lib_sfx}d.lib" \ + + ;; + esac + ;; + dll) + tag Tool \ + Name="VCLinkerTool" \ + AdditionalDependencies="\$(NoInherit)" \ + LinkIncremental="2" \ + GenerateDebugInformation="true" \ + AssemblyDebug="1" \ + TargetMachine="1" \ + $link_opts \ + + ;; + esac + + close_tag Configuration + + open_tag Configuration \ + Name="Release|$plat" \ + OutputDirectory="\$(SolutionDir)$plat_no_ws/\$(ConfigurationName)" \ + IntermediateDirectory="$plat_no_ws/\$(ConfigurationName)/${name}" \ + ConfigurationType="$vs_ConfigurationType" \ + CharacterSet="1" \ + WholeProgramOptimization="0" \ + + case "$target" in + x86*) + case "$name" in + obj_int_extract) + tag Tool \ + Name="VCCLCompilerTool" \ + Optimization="2" \ + FavorSizeorSpeed="1" \ + AdditionalIncludeDirectories="$incs" \ + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE" \ + RuntimeLibrary="$release_runtime" \ + UsePrecompiledHeader="0" \ + WarningLevel="3" \ + Detect64BitPortabilityProblems="true" \ + DebugInformationFormat="0" \ + ;; + vpx) + tag Tool \ + Name="VCPreBuildEventTool" \ + CommandLine="call obj_int_extract.bat $src_path_bare" \ + + tag Tool \ + Name="VCCLCompilerTool" \ + Optimization="2" \ + FavorSizeorSpeed="1" \ + AdditionalIncludeDirectories="$incs" \ + PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \ + RuntimeLibrary="$release_runtime" \ + UsePrecompiledHeader="0" \ + WarningLevel="3" \ + DebugInformationFormat="0" \ + Detect64BitPortabilityProblems="true" \ + + $uses_asm && tag Tool Name="YASM" IncludePaths="$incs" + ;; + *) + tag Tool \ + Name="VCCLCompilerTool" \ + AdditionalIncludeDirectories="$incs" \ + Optimization="2" \ + FavorSizeorSpeed="1" \ + PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \ + RuntimeLibrary="$release_runtime" \ + UsePrecompiledHeader="0" \ + WarningLevel="3" \ + DebugInformationFormat="0" \ + Detect64BitPortabilityProblems="true" \ + + $uses_asm && tag Tool Name="YASM" IncludePaths="$incs" + ;; + esac + ;; + esac + + case "$proj_kind" in + exe) + case "$target" in + x86*) + case "$name" in + obj_int_extract) + tag Tool \ + Name="VCLinkerTool" \ + OutputFile="${name}.exe" \ + GenerateDebugInformation="true" \ + ;; + *) + tag Tool \ + Name="VCLinkerTool" \ + AdditionalDependencies="$libs \$(NoInherit)" \ + AdditionalLibraryDirectories="$libdirs" \ + + ;; + esac + ;; + esac + ;; + lib) + case "$target" in + x86*) + tag Tool \ + Name="VCLibrarianTool" \ + OutputFile="\$(OutDir)/${name}${lib_sfx}.lib" \ + + ;; + esac + ;; + dll) # note differences to debug version: LinkIncremental, AssemblyDebug + tag Tool \ + Name="VCLinkerTool" \ + AdditionalDependencies="\$(NoInherit)" \ + LinkIncremental="1" \ + GenerateDebugInformation="true" \ + TargetMachine="1" \ + $link_opts \ + + ;; + esac + + close_tag Configuration + done + close_tag Configurations + + open_tag Files + generate_filter srcs "Source Files" "c;cc;def;odl;idl;hpj;bat;asm;asmx" + generate_filter hdrs "Header Files" "h;hm;inl;inc;xsd" + generate_filter resrcs "Resource Files" "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + generate_filter resrcs "Build Files" "mk" + close_tag Files + + tag Globals + close_tag VisualStudioProject + + # This must be done from within the {} subshell + echo "Ignored files list (${#file_list[@]} items) is:" >&2 + for f in "${file_list[@]}"; do + echo " $f" >&2 + done +} + +generate_vcproj | + sed -e '/"/s;\([^ "]\)/;\1\\;g' > ${outfile} + +exit + diff --git a/build/make/gen_msvs_sln.sh b/build/make/gen_msvs_sln.sh new file mode 100755 index 0000000..240678b --- /dev/null +++ b/build/make/gen_msvs_sln.sh @@ -0,0 +1,273 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +self=$0 +self_basename=${self##*/} +EOL=$'\n' +EOLDOS=$'\r' + +show_help() { + cat <&2 + [ -f "${outfile}" ] && rm -f ${outfile}{,.mk} + exit 1 +} + +die_unknown(){ + echo "Unknown option \"$1\"." >&2 + echo "See ${self_basename} --help for available options." >&2 + [ -f "${outfile}" ] && rm -f ${outfile}{,.mk} + exit 1 +} + +indent1=$'\t' +indent="" +indent_push() { + indent="${indent}${indent1}" +} +indent_pop() { + indent="${indent%${indent1}}" +} + +parse_project() { + local file=$1 + local name=`grep Name "$file" | awk 'BEGIN {FS="\""}{if (NR==1) print $2}'` + local guid=`grep ProjectGUID "$file" | awk 'BEGIN {FS="\""}{if (NR==1) print $2}'` + + # save the project GUID to a varaible, normalizing to the basename of the + # vcproj file without the extension + local var + var=${file##*/} + var=${var%%.vcproj} + eval "${var}_file=\"$1\"" + eval "${var}_name=$name" + eval "${var}_guid=$guid" + + # assume that all projects have the same list of possible configurations, + # so overwriting old config_lists is not a problem + config_list=`grep -A1 '/dev/null 2>&1 && echo yes) +.nodevenv.once: +${TAB}@echo " * devenv.com not found in path." +${TAB}@echo " * " +${TAB}@echo " * You will have to build all configurations manually using the" +${TAB}@echo " * Visual Studio IDE. To allow make to build them automatically," +${TAB}@echo " * add the Common7/IDE directory of your Visual Studio" +${TAB}@echo " * installation to your path, eg:" +${TAB}@echo " * C:\Program Files\Microsoft Visual Studio 8\Common7\IDE" +${TAB}@echo " * " +${TAB}@touch \$@ +CLEAN-OBJS += \$(if \$(found_devenv),,.nodevenv.once) + +EOF + + for sln_config in ${config_list}; do + local config=${sln_config%%|*} + local platform=${sln_config##*|} + local nows_sln_config=`echo $sln_config | sed -e 's/[^a-zA-Z0-9]/_/g'` + cat <${outfile} <>${outfile} +done +process_global >>${outfile} +process_makefile >${mkoutfile} diff --git a/build/make/obj_int_extract.c b/build/make/obj_int_extract.c new file mode 100644 index 0000000..04e14a6 --- /dev/null +++ b/build/make/obj_int_extract.c @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include +#include + +#include "vpx_config.h" +#include "vpx/vpx_integer.h" + +typedef enum +{ + OUTPUT_FMT_PLAIN, + OUTPUT_FMT_RVDS, + OUTPUT_FMT_GAS, +} output_fmt_t; + +int log_msg(const char *fmt, ...) +{ + int res; + va_list ap; + va_start(ap, fmt); + res = vfprintf(stderr, fmt, ap); + va_end(ap); + return res; +} + +#if defined(__GNUC__) && __GNUC__ +#if defined(__MACH__) + +#include +#include + +int parse_macho(uint8_t *base_buf, size_t sz) +{ + int i, j; + struct mach_header header; + uint8_t *buf = base_buf; + int base_data_section = 0; + int bits = 0; + + /* We can read in mach_header for 32 and 64 bit architectures + * because it's identical to mach_header_64 except for the last + * element (uint32_t reserved), which we don't use. Then, when + * we know which architecture we're looking at, increment buf + * appropriately. + */ + memcpy(&header, buf, sizeof(struct mach_header)); + + if (header.magic == MH_MAGIC) + { + if (header.cputype == CPU_TYPE_ARM + || header.cputype == CPU_TYPE_X86) + { + bits = 32; + buf += sizeof(struct mach_header); + } + else + { + log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_[ARM|X86].\n"); + goto bail; + } + } + else if (header.magic == MH_MAGIC_64) + { + if (header.cputype == CPU_TYPE_X86_64) + { + bits = 64; + buf += sizeof(struct mach_header_64); + } + else + { + log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_X86_64.\n"); + goto bail; + } + } + else + { + log_msg("Bad magic number for object file. 0x%x or 0x%x expected, 0x%x found.\n", + MH_MAGIC, MH_MAGIC_64, header.magic); + goto bail; + } + + if (header.filetype != MH_OBJECT) + { + log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n"); + goto bail; + } + + for (i = 0; i < header.ncmds; i++) + { + struct load_command lc; + + memcpy(&lc, buf, sizeof(struct load_command)); + + if (lc.cmd == LC_SEGMENT) + { + uint8_t *seg_buf = buf; + struct section s; + struct segment_command seg_c; + + memcpy(&seg_c, seg_buf, sizeof(struct segment_command)); + seg_buf += sizeof(struct segment_command); + + /* Although each section is given it's own offset, nlist.n_value + * references the offset of the first section. This isn't + * apparent without debug information because the offset of the + * data section is the same as the first section. However, with + * debug sections mixed in, the offset of the debug section + * increases but n_value still references the first section. + */ + if (seg_c.nsects < 1) + { + log_msg("Not enough sections\n"); + goto bail; + } + + memcpy(&s, seg_buf, sizeof(struct section)); + base_data_section = s.offset; + } + else if (lc.cmd == LC_SEGMENT_64) + { + uint8_t *seg_buf = buf; + struct section_64 s; + struct segment_command_64 seg_c; + + memcpy(&seg_c, seg_buf, sizeof(struct segment_command_64)); + seg_buf += sizeof(struct segment_command_64); + + /* Explanation in LG_SEGMENT */ + if (seg_c.nsects < 1) + { + log_msg("Not enough sections\n"); + goto bail; + } + + memcpy(&s, seg_buf, sizeof(struct section_64)); + base_data_section = s.offset; + } + else if (lc.cmd == LC_SYMTAB) + { + if (base_data_section != 0) + { + struct symtab_command sc; + uint8_t *sym_buf = base_buf; + uint8_t *str_buf = base_buf; + + memcpy(&sc, buf, sizeof(struct symtab_command)); + + if (sc.cmdsize != sizeof(struct symtab_command)) + { + log_msg("Can't find symbol table!\n"); + goto bail; + } + + sym_buf += sc.symoff; + str_buf += sc.stroff; + + for (j = 0; j < sc.nsyms; j++) + { + /* Location of string is cacluated each time from the + * start of the string buffer. On darwin the symbols + * are prefixed by "_", so we bump the pointer by 1. + * The target value is defined as an int in asm_*_offsets.c, + * which is 4 bytes on all targets we currently use. + */ + if (bits == 32) + { + struct nlist nl; + int val; + + memcpy(&nl, sym_buf, sizeof(struct nlist)); + sym_buf += sizeof(struct nlist); + + memcpy(&val, base_buf + base_data_section + nl.n_value, + sizeof(val)); + printf("%-40s EQU %5d\n", + str_buf + nl.n_un.n_strx + 1, val); + } + else /* if (bits == 64) */ + { + struct nlist_64 nl; + int val; + + memcpy(&nl, sym_buf, sizeof(struct nlist_64)); + sym_buf += sizeof(struct nlist_64); + + memcpy(&val, base_buf + base_data_section + nl.n_value, + sizeof(val)); + printf("%-40s EQU %5d\n", + str_buf + nl.n_un.n_strx + 1, val); + } + } + } + } + + buf += lc.cmdsize; + } + + return 0; +bail: + return 1; + +} + +#elif defined(__ELF__) +#include "elf.h" + +#define COPY_STRUCT(dst, buf, ofst, sz) do {\ + if(ofst + sizeof((*(dst))) > sz) goto bail;\ + memcpy(dst, buf+ofst, sizeof((*(dst))));\ + } while(0) + +#define ENDIAN_ASSIGN(val, memb) do {\ + if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\ + (val) = (memb);\ + } while(0) + +#define ENDIAN_ASSIGN_IN_PLACE(memb) do {\ + ENDIAN_ASSIGN(memb, memb);\ + } while(0) + +typedef struct +{ + uint8_t *buf; /* Buffer containing ELF data */ + size_t sz; /* Buffer size */ + int le_data; /* Data is little-endian */ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + int bits; /* 32 or 64 */ + Elf32_Ehdr hdr32; + Elf64_Ehdr hdr64; +} elf_obj_t; + +int parse_elf_header(elf_obj_t *elf) +{ + int res; + /* Verify ELF Magic numbers */ + COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz); + res = elf->e_ident[EI_MAG0] == ELFMAG0; + res &= elf->e_ident[EI_MAG1] == ELFMAG1; + res &= elf->e_ident[EI_MAG2] == ELFMAG2; + res &= elf->e_ident[EI_MAG3] == ELFMAG3; + res &= elf->e_ident[EI_CLASS] == ELFCLASS32 + || elf->e_ident[EI_CLASS] == ELFCLASS64; + res &= elf->e_ident[EI_DATA] == ELFDATA2LSB; + + if (!res) goto bail; + + elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB; + + /* Read in relevant values */ + if (elf->e_ident[EI_CLASS] == ELFCLASS32) + { + elf->bits = 32; + COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz); + + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx); + } + else /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */ + { + elf->bits = 64; + COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz); + + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx); + } + + return 0; +bail: + log_msg("Failed to parse ELF file header"); + return 1; +} + +int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) +{ + if (hdr32) + { + if (idx >= elf->hdr32.e_shnum) + goto bail; + + COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize, + elf->sz); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize); + } + else /* if (hdr64) */ + { + if (idx >= elf->hdr64.e_shnum) + goto bail; + + COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize, + elf->sz); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize); + } + + return 0; +bail: + return 1; +} + +char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) +{ + if (elf->bits == 32) + { + Elf32_Shdr shdr; + + if (parse_elf_section(elf, s_idx, &shdr, NULL)) + { + log_msg("Failed to parse ELF string table: section %d, index %d\n", + s_idx, idx); + return ""; + } + + return (char *)(elf->buf + shdr.sh_offset + idx); + } + else /* if (elf->bits == 64) */ + { + Elf64_Shdr shdr; + + if (parse_elf_section(elf, s_idx, NULL, &shdr)) + { + log_msg("Failed to parse ELF string table: section %d, index %d\n", + s_idx, idx); + return ""; + } + + return (char *)(elf->buf + shdr.sh_offset + idx); + } +} + +int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) +{ + if (sym32) + { + COPY_STRUCT(sym32, elf->buf, ofst, elf->sz); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_name); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_value); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_size); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_info); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_other); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx); + } + else /* if (sym64) */ + { + COPY_STRUCT(sym64, elf->buf, ofst, elf->sz); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_name); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_value); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_size); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_info); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_other); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx); + } + return 0; +bail: + return 1; +} + +int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) +{ + elf_obj_t elf; + unsigned int ofst; + int i; + Elf32_Off strtab_off32; + Elf64_Off strtab_off64; /* save String Table offset for later use */ + + memset(&elf, 0, sizeof(elf)); + elf.buf = buf; + elf.sz = sz; + + /* Parse Header */ + if (parse_elf_header(&elf)) + goto bail; + + if (elf.bits == 32) + { + Elf32_Shdr shdr; + for (i = 0; i < elf.hdr32.e_shnum; i++) + { + parse_elf_section(&elf, i, &shdr, NULL); + + if (shdr.sh_type == SHT_STRTAB) + { + char strtsb_name[128]; + + strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); + + if (!(strcmp(strtsb_name, ".shstrtab"))) + { + /* log_msg("found section: %s\n", strtsb_name); */ + strtab_off32 = shdr.sh_offset; + break; + } + } + } + } + else /* if (elf.bits == 64) */ + { + Elf64_Shdr shdr; + for (i = 0; i < elf.hdr64.e_shnum; i++) + { + parse_elf_section(&elf, i, NULL, &shdr); + + if (shdr.sh_type == SHT_STRTAB) + { + char strtsb_name[128]; + + strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); + + if (!(strcmp(strtsb_name, ".shstrtab"))) + { + /* log_msg("found section: %s\n", strtsb_name); */ + strtab_off64 = shdr.sh_offset; + break; + } + } + } + } + + /* Parse all Symbol Tables */ + if (elf.bits == 32) + { + Elf32_Shdr shdr; + for (i = 0; i < elf.hdr32.e_shnum; i++) + { + parse_elf_section(&elf, i, &shdr, NULL); + + if (shdr.sh_type == SHT_SYMTAB) + { + for (ofst = shdr.sh_offset; + ofst < shdr.sh_offset + shdr.sh_size; + ofst += shdr.sh_entsize) + { + Elf32_Sym sym; + + parse_elf_symbol(&elf, ofst, &sym, NULL); + + /* For all OBJECTS (data objects), extract the value from the + * proper data segment. + */ + /* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) + log_msg("found data object %s\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name)); + */ + + if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT + && sym.st_size == 4) + { + Elf32_Shdr dhdr; + int val = 0; + char section_name[128]; + + parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL); + + /* For explanition - refer to _MSC_VER version of code */ + strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name)); + /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ + + if (strcmp(section_name, ".bss")) + { + if (sizeof(val) != sym.st_size) + { + /* The target value is declared as an int in + * asm_*_offsets.c, which is 4 bytes on all + * targets we currently use. Complain loudly if + * this is not true. + */ + log_msg("Symbol size is wrong\n"); + goto bail; + } + + memcpy(&val, + elf.buf + dhdr.sh_offset + sym.st_value, + sym.st_size); + } + + if (!elf.le_data) + { + log_msg("Big Endian data not supported yet!\n"); + goto bail; + } + + switch (mode) + { + case OUTPUT_FMT_RVDS: + printf("%-40s EQU %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + case OUTPUT_FMT_GAS: + printf(".equ %-40s, %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + default: + printf("%s = %d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + } + } + } + } + } + } + else /* if (elf.bits == 64) */ + { + Elf64_Shdr shdr; + for (i = 0; i < elf.hdr64.e_shnum; i++) + { + parse_elf_section(&elf, i, NULL, &shdr); + + if (shdr.sh_type == SHT_SYMTAB) + { + for (ofst = shdr.sh_offset; + ofst < shdr.sh_offset + shdr.sh_size; + ofst += shdr.sh_entsize) + { + Elf64_Sym sym; + + parse_elf_symbol(&elf, ofst, NULL, &sym); + + /* For all OBJECTS (data objects), extract the value from the + * proper data segment. + */ + /* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) + log_msg("found data object %s\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name)); + */ + + if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT + && sym.st_size == 4) + { + Elf64_Shdr dhdr; + int val = 0; + char section_name[128]; + + parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr); + + /* For explanition - refer to _MSC_VER version of code */ + strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name)); + /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ + + if ((strcmp(section_name, ".bss"))) + { + if (sizeof(val) != sym.st_size) + { + /* The target value is declared as an int in + * asm_*_offsets.c, which is 4 bytes on all + * targets we currently use. Complain loudly if + * this is not true. + */ + log_msg("Symbol size is wrong\n"); + goto bail; + } + + memcpy(&val, + elf.buf + dhdr.sh_offset + sym.st_value, + sym.st_size); + } + + if (!elf.le_data) + { + log_msg("Big Endian data not supported yet!\n"); + goto bail; + } + + switch (mode) + { + case OUTPUT_FMT_RVDS: + printf("%-40s EQU %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + case OUTPUT_FMT_GAS: + printf(".equ %-40s, %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + default: + printf("%s = %d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + } + } + } + } + } + } + + if (mode == OUTPUT_FMT_RVDS) + printf(" END\n"); + + return 0; +bail: + log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n"); + return 1; +} + +#endif +#endif /* defined(__GNUC__) && __GNUC__ */ + + +#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) +/* See "Microsoft Portable Executable and Common Object File Format Specification" + for reference. +*/ +#define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 ) +#define get_le16(x) ((*(x)) | (*(x+1)) << 8) + +int parse_coff(uint8_t *buf, size_t sz) +{ + unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr; + unsigned int sectionrawdata_ptr; + unsigned int i; + uint8_t *ptr; + uint32_t symoffset; + + char **sectionlist; //this array holds all section names in their correct order. + //it is used to check if the symbol is in .bss or .data section. + + nsections = get_le16(buf + 2); + symtab_ptr = get_le32(buf + 8); + symtab_sz = get_le32(buf + 12); + strtab_ptr = symtab_ptr + symtab_sz * 18; + + if (nsections > 96) + { + log_msg("Too many sections\n"); + return 1; + } + + sectionlist = malloc(nsections * sizeof(sectionlist)); + + if (sectionlist == NULL) + { + log_msg("Allocating first level of section list failed\n"); + return 1; + } + + //log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections); + + /* + The size of optional header is always zero for an obj file. So, the section header + follows the file header immediately. + */ + + ptr = buf + 20; //section header + + for (i = 0; i < nsections; i++) + { + char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + strncpy(sectionname, ptr, 8); + //log_msg("COFF: Parsing section %s\n",sectionname); + + sectionlist[i] = malloc(strlen(sectionname) + 1); + + if (sectionlist[i] == NULL) + { + log_msg("Allocating storage for %s failed\n", sectionname); + goto bail; + } + strcpy(sectionlist[i], sectionname); + + if (!strcmp(sectionname, ".data")) sectionrawdata_ptr = get_le32(ptr + 20); + + ptr += 40; + } + + //log_msg("COFF: Symbol table at offset %u\n", symtab_ptr); + //log_msg("COFF: raw data pointer ofset for section .data is %u\n", sectionrawdata_ptr); + + /* The compiler puts the data with non-zero offset in .data section, but puts the data with + zero offset in .bss section. So, if the data in in .bss section, set offset=0. + Note from Wiki: In an object module compiled from C, the bss section contains + the local variables (but not functions) that were declared with the static keyword, + except for those with non-zero initial values. (In C, static variables are initialized + to zero by default.) It also contains the non-local (both extern and static) variables + that are also initialized to zero (either explicitly or by default). + */ + //move to symbol table + /* COFF symbol table: + offset field + 0 Name(*) + 8 Value + 12 SectionNumber + 14 Type + 16 StorageClass + 17 NumberOfAuxSymbols + */ + ptr = buf + symtab_ptr; + + for (i = 0; i < symtab_sz; i++) + { + int16_t section = get_le16(ptr + 12); //section number + + if (section > 0 && ptr[16] == 2) + { + //if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) { + + if (get_le32(ptr)) + { + char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + strncpy(name, ptr, 8); + //log_msg("COFF: Parsing symbol %s\n",name); + /* The 64bit Windows compiler doesn't prefix with an _. + * Check what's there, and bump if necessary + */ + if (name[0] == '_') + printf("%-40s EQU ", name + 1); + else + printf("%-40s EQU ", name); + } + else + { + //log_msg("COFF: Parsing symbol %s\n", + // buf + strtab_ptr + get_le32(ptr+4)); + if ((buf + strtab_ptr + get_le32(ptr + 4))[0] == '_') + printf("%-40s EQU ", + buf + strtab_ptr + get_le32(ptr + 4) + 1); + else + printf("%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4)); + } + + if (!(strcmp(sectionlist[section-1], ".bss"))) + { + symoffset = 0; + } + else + { + symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8)); + } + + //log_msg(" Section: %d\n",section); + //log_msg(" Class: %d\n",ptr[16]); + //log_msg(" Address: %u\n",get_le32(ptr+8)); + //log_msg(" Offset: %u\n", symoffset); + + printf("%5d\n", symoffset); + } + + ptr += 18; + } + + printf(" END\n"); + + for (i = 0; i < nsections; i++) + { + free(sectionlist[i]); + } + + free(sectionlist); + + return 0; +bail: + + for (i = 0; i < nsections; i++) + { + free(sectionlist[i]); + } + + free(sectionlist); + + return 1; +} +#endif /* defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) */ + +int main(int argc, char **argv) +{ + output_fmt_t mode = OUTPUT_FMT_PLAIN; + const char *f; + uint8_t *file_buf; + int res; + FILE *fp; + long int file_size; + + if (argc < 2 || argc > 3) + { + fprintf(stderr, "Usage: %s [output format] \n\n", argv[0]); + fprintf(stderr, " \tobject file to parse\n"); + fprintf(stderr, "Output Formats:\n"); + fprintf(stderr, " gas - compatible with GNU assembler\n"); + fprintf(stderr, " rvds - compatible with armasm\n"); + goto bail; + } + + f = argv[2]; + + if (!strcmp(argv[1], "rvds")) + mode = OUTPUT_FMT_RVDS; + else if (!strcmp(argv[1], "gas")) + mode = OUTPUT_FMT_GAS; + else + f = argv[1]; + + fp = fopen(f, "rb"); + + if (!fp) + { + perror("Unable to open file"); + goto bail; + } + + if (fseek(fp, 0, SEEK_END)) + { + perror("stat"); + goto bail; + } + + file_size = ftell(fp); + file_buf = malloc(file_size); + + if (!file_buf) + { + perror("malloc"); + goto bail; + } + + rewind(fp); + + if (fread(file_buf, sizeof(char), file_size, fp) != file_size) + { + perror("read"); + goto bail; + } + + if (fclose(fp)) + { + perror("close"); + goto bail; + } + +#if defined(__GNUC__) && __GNUC__ +#if defined(__MACH__) + res = parse_macho(file_buf, file_size); +#elif defined(__ELF__) + res = parse_elf(file_buf, file_size, mode); +#endif +#endif +#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) + res = parse_coff(file_buf, file_size); +#endif + + free(file_buf); + + if (!res) + return EXIT_SUCCESS; + +bail: + return EXIT_FAILURE; +} diff --git a/build/make/rtcd.sh b/build/make/rtcd.sh new file mode 100755 index 0000000..1dffde5 --- /dev/null +++ b/build/make/rtcd.sh @@ -0,0 +1,330 @@ +#!/bin/sh +self=$0 + +usage() { + cat <&2 +Usage: $self [options] FILE + +Reads the Run Time CPU Detections definitions from FILE and generates a +C header file on stdout. + +Options: + --arch=ARCH Architecture to generate defs for (required) + --disable-EXT Disable support for EXT extensions + --require-EXT Require support for EXT extensions + --sym=SYMBOL Unique symbol to use for RTCD initialization function + --config=FILE File with CONFIG_FOO=yes lines to parse +EOF + exit 1 +} + +die() { + echo "$@" >&2 + exit 1 +} + +die_argument_required() { + die "Option $opt requires argument" +} + +for opt; do + optval="${opt#*=}" + case "$opt" in + --arch) die_argument_required;; + --arch=*) arch=${optval};; + --disable-*) eval "disable_${opt#--disable-}=true";; + --require-*) REQUIRES="${REQUIRES}${opt#--require-} ";; + --sym) die_argument_required;; + --sym=*) symbol=${optval};; + --config=*) config_file=${optval};; + -h|--help) + usage + ;; + -*) + die "Unrecognized option: ${opt%%=*}" + ;; + *) + defs_file="$defs_file $opt" + ;; + esac + shift +done +for f in $defs_file; do [ -f "$f" ] || usage; done +[ -n "$arch" ] || usage + +# Import the configuration +[ -f "$config_file" ] && eval $(grep CONFIG_ "$config_file") + +# +# Routines for the RTCD DSL to call +# +prototype() { + local rtyp + case "$1" in + unsigned) rtyp="$1 "; shift;; + esac + rtyp="${rtyp}$1" + local fn="$2" + local args="$3" + + eval "${2}_rtyp='$rtyp'" + eval "${2}_args='$3'" + ALL_FUNCS="$ALL_FUNCS $fn" + specialize $fn c +} + +specialize() { + local fn="$1" + shift + for opt in "$@"; do + eval "${fn}_${opt}=${fn}_${opt}" + done +} + +require() { + for fn in $ALL_FUNCS; do + for opt in "$@"; do + local ofn=$(eval "echo \$${fn}_${opt}") + [ -z "$ofn" ] && continue + + # if we already have a default, then we can disable it, as we know + # we can do better. + local best=$(eval "echo \$${fn}_default") + local best_ofn=$(eval "echo \$${best}") + [ -n "$best" ] && [ "$best_ofn" != "$ofn" ] && eval "${best}_link=false" + eval "${fn}_default=${fn}_${opt}" + eval "${fn}_${opt}_link=true" + done + done +} + +forward_decls() { + ALL_FORWARD_DECLS="$ALL_FORWARD_DECLS $1" +} + +# +# Include the user's directives +# +for f in $defs_file; do + . $f +done + +# +# Process the directives according to the command line +# +process_forward_decls() { + for fn in $ALL_FORWARD_DECLS; do + eval $fn + done +} + +determine_indirection() { + [ "$CONFIG_RUNTIME_CPU_DETECT" = "yes" ] || require $ALL_ARCHS + for fn in $ALL_FUNCS; do + local n="" + local rtyp="$(eval "echo \$${fn}_rtyp")" + local args="$(eval "echo \"\$${fn}_args\"")" + local dfn="$(eval "echo \$${fn}_default")" + dfn=$(eval "echo \$${dfn}") + for opt in "$@"; do + local ofn=$(eval "echo \$${fn}_${opt}") + [ -z "$ofn" ] && continue + local link=$(eval "echo \$${fn}_${opt}_link") + [ "$link" = "false" ] && continue + n="${n}x" + done + if [ "$n" = "x" ]; then + eval "${fn}_indirect=false" + else + eval "${fn}_indirect=true" + fi + done +} + +declare_function_pointers() { + for fn in $ALL_FUNCS; do + local rtyp="$(eval "echo \$${fn}_rtyp")" + local args="$(eval "echo \"\$${fn}_args\"")" + local dfn="$(eval "echo \$${fn}_default")" + dfn=$(eval "echo \$${dfn}") + for opt in "$@"; do + local ofn=$(eval "echo \$${fn}_${opt}") + [ -z "$ofn" ] && continue + echo "$rtyp ${ofn}($args);" + done + if [ "$(eval "echo \$${fn}_indirect")" = "false" ]; then + echo "#define ${fn} ${dfn}" + else + echo "RTCD_EXTERN $rtyp (*${fn})($args);" + fi + echo + done +} + +set_function_pointers() { + for fn in $ALL_FUNCS; do + local n="" + local rtyp="$(eval "echo \$${fn}_rtyp")" + local args="$(eval "echo \"\$${fn}_args\"")" + local dfn="$(eval "echo \$${fn}_default")" + dfn=$(eval "echo \$${dfn}") + if $(eval "echo \$${fn}_indirect"); then + echo " $fn = $dfn;" + for opt in "$@"; do + local ofn=$(eval "echo \$${fn}_${opt}") + [ -z "$ofn" ] && continue + [ "$ofn" = "$dfn" ] && continue; + local link=$(eval "echo \$${fn}_${opt}_link") + [ "$link" = "false" ] && continue + local cond="$(eval "echo \$have_${opt}")" + echo " if (${cond}) $fn = $ofn;" + done + fi + echo + done +} + +filter() { + local filtered + for opt in "$@"; do + [ -z $(eval "echo \$disable_${opt}") ] && filtered="$filtered $opt" + done + echo $filtered +} + +# +# Helper functions for generating the arch specific RTCD files +# +common_top() { + local outfile_basename=$(basename ${symbol:-rtcd.h}) + local include_guard=$(echo $outfile_basename | tr '[a-z]' '[A-Z]' | tr -c '[A-Z]' _) + cat </dev/null` +fi + +changelog_version="" +for p in "${source_path}" "${source_path}/.."; do + if [ -z "$git_version_id" -a -f "${p}/CHANGELOG" ]; then + changelog_version=`head -n1 "${p}/CHANGELOG" | awk '{print $2}'` + changelog_version="${changelog_version}" + break + fi +done +version_str="${changelog_version}${git_version_id}" +bare_version=${version_str#v} +major_version=${bare_version%%.*} +bare_version=${bare_version#*.} +minor_version=${bare_version%%.*} +bare_version=${bare_version#*.} +patch_version=${bare_version%%-*} +bare_version=${bare_version#${patch_version}} +extra_version=${bare_version##-} + +#since they'll be used as integers below make sure they are or force to 0 +for v in major_version minor_version patch_version; do + if eval echo \$$v |grep -E -q '[^[:digit:]]'; then + eval $v=0 + fi +done + +if [ ${bare} ]; then + echo "${changelog_version}${git_version_id}" > $$.tmp +else + cat<$$.tmp +#define VERSION_MAJOR $major_version +#define VERSION_MINOR $minor_version +#define VERSION_PATCH $patch_version +#define VERSION_EXTRA "$extra_version" +#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) +#define ${id}_NOSP "${version_str}" +#define ${id} " ${version_str}" +EOF +fi +if [ -n "$out_file" ]; then +diff $$.tmp ${out_file} >/dev/null 2>&1 || cat $$.tmp > ${out_file} +else +cat $$.tmp +fi +rm $$.tmp diff --git a/build/x86-msvs/obj_int_extract.bat b/build/x86-msvs/obj_int_extract.bat new file mode 100644 index 0000000..1bb8653 --- /dev/null +++ b/build/x86-msvs/obj_int_extract.bat @@ -0,0 +1,15 @@ +REM Copyright (c) 2011 The WebM project authors. All Rights Reserved. +REM +REM Use of this source code is governed by a BSD-style license +REM that can be found in the LICENSE file in the root of the source +REM tree. An additional intellectual property rights grant can be found +REM in the file PATENTS. All contributing project authors may +REM be found in the AUTHORS file in the root of the source tree. +echo on + +cl /I "./" /I "%1" /nologo /c "%1/vp8/common/asm_com_offsets.c" +cl /I "./" /I "%1" /nologo /c "%1/vp8/decoder/asm_dec_offsets.c" +cl /I "./" /I "%1" /nologo /c "%1/vp8/encoder/asm_enc_offsets.c" +obj_int_extract.exe rvds "asm_com_offsets.obj" > "asm_com_offsets.asm" +obj_int_extract.exe rvds "asm_dec_offsets.obj" > "asm_dec_offsets.asm" +obj_int_extract.exe rvds "asm_enc_offsets.obj" > "asm_enc_offsets.asm" diff --git a/build/x86-msvs/yasm.rules b/build/x86-msvs/yasm.rules new file mode 100644 index 0000000..ee1fefb --- /dev/null +++ b/build/x86-msvs/yasm.rules @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/configure b/configure new file mode 100755 index 0000000..62e1ffb --- /dev/null +++ b/configure @@ -0,0 +1,601 @@ +#!/bin/bash +## +## configure +## +## This script is the front-end to the build system. It provides a similar +## interface to standard configure scripts with some extra bits for dealing +## with toolchains that differ from the standard POSIX interface and +## for extracting subsets of the source tree. In theory, reusable parts +## of this script were intended to live in build/make/configure.sh, +## but in practice, the line is pretty blurry. +## +## This build system is based in part on the FFmpeg configure script. +## + +#source_path="`dirname \"$0\"`" +source_path=${0%/*} +. "${source_path}/build/make/configure.sh" + +show_help(){ + show_help_pre + cat << EOF +Advanced options: + ${toggle_libs} don't build libraries + ${toggle_examples} don't build examples + ${toggle_unit_tests} build unit tests + --libc=PATH path to alternate libc + --as={yasm|nasm|auto} use specified assembler [auto, yasm preferred] + --sdk-path=PATH path to root of sdk (iOS, android builds only) + ${toggle_fast_unaligned} don't use unaligned accesses, even when + supported by hardware [auto] + ${toggle_codec_srcs} in/exclude codec library source code + ${toggle_debug_libs} in/exclude debug version of libraries + ${toggle_md5} support for output of checksum data + ${toggle_static_msvcrt} use static MSVCRT (VS builds only) + ${toggle_vp8} VP8 codec support + ${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders) + ${toggle_mem_tracker} track memory usage + ${toggle_postproc} postprocessing + ${toggle_multithread} multithreaded encoding and decoding + ${toggle_spatial_resampling} spatial sampling (scaling) support + ${toggle_realtime_only} enable this option while building for real-time encoding + ${toggle_onthefly_bitpacking} enable on-the-fly bitpacking in real-time encoding + ${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses + ${toggle_runtime_cpu_detect} runtime cpu detection + ${toggle_shared} shared library support + ${toggle_static} static library support + ${toggle_small} favor smaller size over speed + ${toggle_postproc_visualizer} macro block / block level visualizers + ${toggle_multi_res_encoding} enable multiple-resolution encoding + ${toggle_temporal_denoising} enable temporal denoising and disable the spatial denoiser + +Codecs: + Codecs can be selectively enabled or disabled individually, or by family: + --disable- + is equivalent to: + --disable--encoder + --disable--decoder + + Codecs available in this distribution: +EOF +#restore editor state ' + + local family; + local last_family; + local c; + local str; + for c in ${CODECS}; do + family=${c%_*} + if [ "${family}" != "${last_family}" ]; then + [ -z "${str}" ] || echo "${str}" + str="$(printf ' %10s:' ${family})" + fi + str="${str} $(printf '%10s' ${c#*_})" + last_family=${family} + done + echo "${str}" + show_help_post +} + +## +## BEGIN APPLICATION SPECIFIC CONFIGURATION +## + +# all_platforms is a list of all supported target platforms. Maintain +# alphabetically by architecture, generic-gnu last. +all_platforms="${all_platforms} armv5te-android-gcc" +all_platforms="${all_platforms} armv5te-linux-rvct" +all_platforms="${all_platforms} armv5te-linux-gcc" +all_platforms="${all_platforms} armv5te-none-rvct" +all_platforms="${all_platforms} armv6-darwin-gcc" +all_platforms="${all_platforms} armv6-linux-rvct" +all_platforms="${all_platforms} armv6-linux-gcc" +all_platforms="${all_platforms} armv6-none-rvct" +all_platforms="${all_platforms} armv7-android-gcc" #neon Cortex-A8 +all_platforms="${all_platforms} armv7-darwin-gcc" #neon Cortex-A8 +all_platforms="${all_platforms} armv7-linux-rvct" #neon Cortex-A8 +all_platforms="${all_platforms} armv7-linux-gcc" #neon Cortex-A8 +all_platforms="${all_platforms} armv7-none-rvct" #neon Cortex-A8 +all_platforms="${all_platforms} mips32-linux-gcc" +all_platforms="${all_platforms} ppc32-darwin8-gcc" +all_platforms="${all_platforms} ppc32-darwin9-gcc" +all_platforms="${all_platforms} ppc32-linux-gcc" +all_platforms="${all_platforms} ppc64-darwin8-gcc" +all_platforms="${all_platforms} ppc64-darwin9-gcc" +all_platforms="${all_platforms} ppc64-linux-gcc" +all_platforms="${all_platforms} sparc-solaris-gcc" +all_platforms="${all_platforms} x86-darwin8-gcc" +all_platforms="${all_platforms} x86-darwin8-icc" +all_platforms="${all_platforms} x86-darwin9-gcc" +all_platforms="${all_platforms} x86-darwin9-icc" +all_platforms="${all_platforms} x86-darwin10-gcc" +all_platforms="${all_platforms} x86-darwin11-gcc" +all_platforms="${all_platforms} x86-darwin12-gcc" +all_platforms="${all_platforms} x86-linux-gcc" +all_platforms="${all_platforms} x86-linux-icc" +all_platforms="${all_platforms} x86-os2-gcc" +all_platforms="${all_platforms} x86-solaris-gcc" +all_platforms="${all_platforms} x86-win32-gcc" +all_platforms="${all_platforms} x86-win32-vs7" +all_platforms="${all_platforms} x86-win32-vs8" +all_platforms="${all_platforms} x86-win32-vs9" +all_platforms="${all_platforms} x86_64-darwin9-gcc" +all_platforms="${all_platforms} x86_64-darwin10-gcc" +all_platforms="${all_platforms} x86_64-darwin11-gcc" +all_platforms="${all_platforms} x86_64-darwin12-gcc" +all_platforms="${all_platforms} x86_64-linux-gcc" +all_platforms="${all_platforms} x86_64-linux-icc" +all_platforms="${all_platforms} x86_64-solaris-gcc" +all_platforms="${all_platforms} x86_64-win64-gcc" +all_platforms="${all_platforms} x86_64-win64-vs8" +all_platforms="${all_platforms} x86_64-win64-vs9" +all_platforms="${all_platforms} universal-darwin8-gcc" +all_platforms="${all_platforms} universal-darwin9-gcc" +all_platforms="${all_platforms} universal-darwin10-gcc" +all_platforms="${all_platforms} universal-darwin11-gcc" +all_platforms="${all_platforms} universal-darwin12-gcc" +all_platforms="${all_platforms} generic-gnu" + +# all_targets is a list of all targets that can be configured +# note that these should be in dependency order for now. +all_targets="libs examples docs" + +# all targets available are enabled, by default. +for t in ${all_targets}; do + [ -f ${source_path}/${t}.mk ] && enable ${t} +done + +# check installed doxygen version +doxy_version=$(doxygen --version 2>/dev/null) +doxy_major=${doxy_version%%.*} +if [ ${doxy_major:-0} -ge 1 ]; then + doxy_version=${doxy_version#*.} + doxy_minor=${doxy_version%%.*} + doxy_patch=${doxy_version##*.} + + [ $doxy_major -gt 1 ] && enable doxygen + [ $doxy_minor -gt 5 ] && enable doxygen + [ $doxy_minor -eq 5 ] && [ $doxy_patch -ge 3 ] && enable doxygen +fi + +# install everything except the sources, by default. sources will have +# to be enabled when doing dist builds, since that's no longer a common +# case. +enabled doxygen && php -v >/dev/null 2>&1 && enable install_docs +enable install_bins +enable install_libs + +enable static +enable optimizations +enable fast_unaligned #allow unaligned accesses, if supported by hw +enable md5 +enable spatial_resampling +enable multithread +enable os_support +enable temporal_denoising + +[ -d ${source_path}/../include ] && enable alt_tree_layout +for d in vp8; do + [ -d ${source_path}/${d} ] && disable alt_tree_layout; +done + +if ! enabled alt_tree_layout; then +# development environment +[ -d ${source_path}/vp8 ] && CODECS="${CODECS} vp8_encoder vp8_decoder" +else +# customer environment +[ -f ${source_path}/../include/vpx/vp8cx.h ] && CODECS="${CODECS} vp8_encoder" +[ -f ${source_path}/../include/vpx/vp8dx.h ] && CODECS="${CODECS} vp8_decoder" +[ -f ${source_path}/../include/vpx/vp8cx.h ] || disable vp8_encoder +[ -f ${source_path}/../include/vpx/vp8dx.h ] || disable vp8_decoder + +[ -f ${source_path}/../lib/*/*mt.lib ] && soft_enable static_msvcrt +fi + +CODECS="$(echo ${CODECS} | tr ' ' '\n')" +CODEC_FAMILIES="$(for c in ${CODECS}; do echo ${c%_*}; done | sort | uniq)" + +ARCH_LIST=" + arm + mips + x86 + x86_64 + ppc32 + ppc64 +" +ARCH_EXT_LIST=" + edsp + media + neon + + mips32 + + mmx + sse + sse2 + sse3 + ssse3 + sse4_1 + + altivec +" +HAVE_LIST=" + ${ARCH_EXT_LIST} + vpx_ports + stdint_h + alt_tree_layout + pthread_h + sys_mman_h + unistd_h +" +CONFIG_LIST=" + external_build + install_docs + install_bins + install_libs + install_srcs + debug + gprof + gcov + rvct + gcc + msvs + pic + big_endian + + codec_srcs + debug_libs + fast_unaligned + mem_manager + mem_tracker + mem_checks + md5 + + dequant_tokens + dc_recon + runtime_cpu_detect + postproc + multithread + internal_stats + ${CODECS} + ${CODEC_FAMILIES} + encoders + decoders + static_msvcrt + spatial_resampling + realtime_only + onthefly_bitpacking + error_concealment + shared + static + small + postproc_visualizer + os_support + unit_tests + multi_res_encoding + temporal_denoising +" +CMDLINE_SELECT=" + extra_warnings + werror + install_docs + install_bins + install_libs + install_srcs + debug + gprof + gcov + pic + optimizations + ccache + runtime_cpu_detect + + libs + examples + libc + as + fast_unaligned + codec_srcs + debug_libs + md5 + + dequant_tokens + dc_recon + postproc + multithread + internal_stats + ${CODECS} + ${CODEC_FAMILIES} + static_msvcrt + mem_tracker + spatial_resampling + realtime_only + onthefly_bitpacking + error_concealment + shared + static + small + postproc_visualizer + unit_tests + multi_res_encoding + temporal_denoising +" + +process_cmdline() { + for opt do + optval="${opt#*=}" + case "$opt" in + --disable-codecs) for c in ${CODECS}; do disable $c; done ;; + *) process_common_cmdline "$opt" + ;; + esac + done +} + +post_process_cmdline() { + local c + + # If the codec family is disabled, disable all components of that family. + # If the codec family is enabled, enable all components of that family. + log_echo "Configuring selected codecs" + for c in ${CODECS}; do + disabled ${c%%_*} && disable ${c} + enabled ${c%%_*} && enable ${c} + done + + # Enable all detected codecs, if they haven't been disabled + for c in ${CODECS}; do soft_enable $c; done + + # Enable the codec family if any component of that family is enabled + for c in ${CODECS}; do + enabled $c && enable ${c%_*} + done + + # Set the {en,de}coders variable if any algorithm in that class is enabled + for c in ${CODECS}; do + enabled ${c} && enable ${c##*_}s + done +} + + +process_targets() { + enabled child || write_common_config_banner + enabled universal || write_common_target_config_h ${BUILD_PFX}vpx_config.h + + # TODO: add host tools target (obj_int_extract, etc) + + # For fat binaries, call configure recursively to configure for each + # binary architecture to be included. + if enabled universal; then + # Call configure (ourselves) for each subarchitecture + for arch in $fat_bin_archs; do + BUILD_PFX=${arch}/ toolchain=${arch} $self --child $cmdline_args || exit $? + done + fi + + # The write_common_config (config.mk) logic is deferred until after the + # recursive calls to configure complete, becuase we want our universal + # targets to be executed last. + write_common_config_targets + enabled universal && echo "FAT_ARCHS=${fat_bin_archs}" >> config.mk + + # Calculate the default distribution name, based on the enabled features + local cf + local DIST_DIR=vpx + for cf in $CODEC_FAMILIES; do + if enabled ${cf}_encoder && enabled ${cf}_decoder; then + DIST_DIR="${DIST_DIR}-${cf}" + elif enabled ${cf}_encoder; then + DIST_DIR="${DIST_DIR}-${cf}cx" + elif enabled ${cf}_decoder; then + DIST_DIR="${DIST_DIR}-${cf}dx" + fi + done + enabled debug_libs && DIST_DIR="${DIST_DIR}-debug" + enabled codec_srcs && DIST_DIR="${DIST_DIR}-src" + ! enabled postproc && DIST_DIR="${DIST_DIR}-nopost" + ! enabled multithread && DIST_DIR="${DIST_DIR}-nomt" + ! enabled install_docs && DIST_DIR="${DIST_DIR}-nodocs" + DIST_DIR="${DIST_DIR}-${tgt_isa}-${tgt_os}" + case "${tgt_os}" in + win*) enabled static_msvcrt && DIST_DIR="${DIST_DIR}mt" || DIST_DIR="${DIST_DIR}md" + DIST_DIR="${DIST_DIR}-${tgt_cc}" + ;; + esac + if [ -f "${source_path}/build/make/version.sh" ]; then + local ver=`"$source_path/build/make/version.sh" --bare $source_path` + DIST_DIR="${DIST_DIR}-${ver}" + VERSION_STRING=${ver} + ver=${ver%%-*} + VERSION_PATCH=${ver##*.} + ver=${ver%.*} + VERSION_MINOR=${ver##*.} + ver=${ver#v} + VERSION_MAJOR=${ver%.*} + fi + enabled child || cat <> config.mk + +PREFIX=${prefix} +ifeq (\$(MAKECMDGOALS),dist) +DIST_DIR?=${DIST_DIR} +else +DIST_DIR?=\$(DESTDIR)${prefix} +endif +LIBSUBDIR=${libdir##${prefix}/} + +VERSION_STRING=${VERSION_STRING} + +VERSION_MAJOR=${VERSION_MAJOR} +VERSION_MINOR=${VERSION_MINOR} +VERSION_PATCH=${VERSION_PATCH} + +CONFIGURE_ARGS=${CONFIGURE_ARGS} +EOF + enabled child || echo "CONFIGURE_ARGS?=${CONFIGURE_ARGS}" >> config.mk + + # + # Write makefiles for all enabled targets + # + for tgt in libs examples docs solution; do + local tgt_fn="$tgt-$toolchain.mk" + + if enabled $tgt; then + echo "Creating makefiles for ${toolchain} ${tgt}" + write_common_target_config_mk $tgt_fn ${BUILD_PFX}vpx_config.h + #write_${tgt}_config + fi + done + +} + +process_detect() { + if enabled shared; then + # Can only build shared libs on a subset of platforms. Doing this check + # here rather than at option parse time because the target auto-detect + # magic happens after the command line has been parsed. + enabled linux || die "--enable-shared only supported on ELF for now" + fi + if [ -z "$CC" ]; then + echo "Bypassing toolchain for environment detection." + enable external_build + check_header() { + log fake_check_header "$@" + header=$1 + shift + var=`echo $header | sed 's/[^A-Za-z0-9_]/_/g'` + disable $var + case $header in + stdio.h) + true; + ;; + *) + local result=false + for d in "$@"; do + [ -f "${d##-I}/$header" ] && result=true && break + done + ${result:-true} + esac && enable $var + } + check_ld() { + true + } + fi + check_header stdio.h || die "Unable to invoke compiler: ${CC} ${CFLAGS}" + check_ld <> ${BUILD_PFX}vpx_config.c +static const char* const cfg = "$CONFIGURE_ARGS"; +const char *vpx_codec_build_config(void) {return cfg;} +EOF diff --git a/docs.mk b/docs.mk new file mode 100644 index 0000000..cfe57ed --- /dev/null +++ b/docs.mk @@ -0,0 +1,53 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +INSTALL_MAPS += docs/% docs/% +INSTALL_MAPS += src/% % +INSTALL_MAPS += % % + +# Static documentation authored in doxygen +CODEC_DOX := mainpage.dox \ + keywords.dox \ + usage.dox \ + usage_cx.dox \ + usage_dx.dox \ + +# Other doxy files sourced in Markdown +TXT_DOX = $(call enabled,TXT_DOX) + +%.dox: %.txt + @echo " [DOXY] $@" + @$(SRC_PATH_BARE)/examples/gen_example_doxy.php \ + $(@:.dox=) "$($@.DESC)" > $@ < $< + + +EXAMPLE_PATH += $(SRC_PATH_BARE) #for CHANGELOG, README, etc + +doxyfile: $(if $(findstring examples, $(ALL_TARGETS)),examples.doxy) +doxyfile: libs.doxy_template libs.doxy + @echo " [CREATE] $@" + @cat $^ > $@ + @echo "STRIP_FROM_PATH += $(SRC_PATH_BARE) $(BUILD_ROOT)" >> $@ + @echo "INPUT += $(addprefix $(SRC_PATH_BARE)/,$(CODEC_DOX))" >> $@; + @echo "INPUT += $(TXT_DOX)" >> $@; + @echo "EXAMPLE_PATH += $(EXAMPLE_PATH)" >> $@ + +CLEAN-OBJS += doxyfile $(wildcard docs/html/*) +docs/html/index.html: doxyfile $(CODEC_DOX) $(TXT_DOX) + @echo " [DOXYGEN] $<" + @doxygen $< +DOCS-yes += docs/html/index.html + +DIST-DOCS-yes = $(wildcard docs/html/*) +DIST-DOCS-$(CONFIG_CODEC_SRCS) += $(addprefix src/,$(CODEC_DOX)) +DIST-DOCS-$(CONFIG_CODEC_SRCS) += src/libs.doxy_template +DIST-DOCS-yes += CHANGELOG +DIST-DOCS-yes += README diff --git a/example_xma.c b/example_xma.c new file mode 100644 index 0000000..72eb470 --- /dev/null +++ b/example_xma.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This is a simple program showing how to initialize the decoder in XMA mode */ +#include +#include +#include +#include +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx_config.h" +#include "vpx/vpx_decoder.h" +#include "vpx/vpx_integer.h" +#if CONFIG_VP8_DECODER +#include "vpx/vp8dx.h" +#endif + +static char *exec_name; +static int verbose = 0; + +static const struct +{ + const char *name; + const vpx_codec_iface_t *iface; +} ifaces[] = +{ +#if CONFIG_VP8_DECODER + {"vp8", &vpx_codec_vp8_dx_algo}, +#endif +}; + +static void usage_exit(void) +{ + int i; + + printf("Usage: %s \n\n" + "Options:\n" + "\t--codec \tCodec to use (default=%s)\n" + "\t-h \tHeight of the simulated video frame, in pixels\n" + "\t-w \tWidth of the simulated video frame, in pixels\n" + "\t-v \tVerbose mode (show individual segment sizes)\n" + "\t--help \tShow this message\n" + "\n" + "Included decoders:\n" + "\n", + exec_name, + ifaces[0].name); + + for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) + printf(" %-6s - %s\n", + ifaces[i].name, + vpx_codec_iface_name(ifaces[i].iface)); + + exit(EXIT_FAILURE); +} + +static void usage_error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + printf("\n"); + usage_exit(); +} + +void my_mem_dtor(vpx_codec_mmap_t *mmap) +{ + if (verbose) + printf("freeing segment %d\n", mmap->id); + + free(mmap->priv); +} + +int main(int argc, char **argv) +{ + vpx_codec_ctx_t decoder; + vpx_codec_iface_t *iface = ifaces[0].iface; + vpx_codec_iter_t iter; + vpx_codec_dec_cfg_t cfg; + vpx_codec_err_t res = VPX_CODEC_OK; + unsigned int alloc_sz = 0; + unsigned int w = 352; + unsigned int h = 288; + int i; + + exec_name = argv[0]; + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "--codec")) + { + if (i + 1 < argc) + { + int j, k = -1; + + i++; + + for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) + if (!strcmp(ifaces[j].name, argv[i])) + k = j; + + if (k >= 0) + iface = ifaces[k].iface; + else + usage_error("Error: Unrecognized argument (%s) to --codec\n", + argv[i]); + } + else + usage_error("Error: Option --codec requires argument.\n"); + } + else if (!strcmp(argv[i], "-v")) + verbose = 1; + else if (!strcmp(argv[i], "-h")) + if (i + 1 < argc) + { + h = atoi(argv[++i]); + } + else + usage_error("Error: Option -h requires argument.\n"); + else if (!strcmp(argv[i], "-w")) + if (i + 1 < argc) + { + w = atoi(argv[++i]); + } + else + usage_error("Error: Option -w requires argument.\n"); + else if (!strcmp(argv[i], "--help")) + usage_exit(); + else + usage_error("Error: Unrecognized option %s\n\n", argv[i]); + } + + if (argc == 1) + printf("Using built-in defaults. For options, rerun with --help\n\n"); + + /* XMA mode is not supported on all decoders! */ + if (!(vpx_codec_get_caps(iface) & VPX_CODEC_CAP_XMA)) + { + printf("%s does not support XMA mode!\n", vpx_codec_iface_name(iface)); + return EXIT_FAILURE; + } + + /* The codec knows how much memory to allocate based on the size of the + * encoded frames. This data can be parsed from the bitstream with + * vpx_codec_peek_stream_info() if a bitstream is available. Otherwise, + * a fixed size can be used that will be the upper limit on the frame + * size the decoder can decode. + */ + cfg.w = w; + cfg.h = h; + + /* Initialize the decoder in XMA mode. */ + if (vpx_codec_dec_init(&decoder, iface, &cfg, VPX_CODEC_USE_XMA)) + { + printf("Failed to initialize decoder in XMA mode: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + /* Iterate through the list of memory maps, allocating them with the + * requested alignment. + */ + iter = NULL; + + do + { + vpx_codec_mmap_t mmap; + unsigned int align; + + res = vpx_codec_get_mem_map(&decoder, &mmap, &iter); + align = mmap.align ? mmap.align - 1 : 0; + + if (!res) + { + if (verbose) + printf("Allocating segment %u, size %lu, align %u %s\n", + mmap.id, mmap.sz, mmap.align, + mmap.flags & VPX_CODEC_MEM_ZERO ? "(ZEROED)" : ""); + + if (mmap.flags & VPX_CODEC_MEM_ZERO) + mmap.priv = calloc(1, mmap.sz + align); + else + mmap.priv = malloc(mmap.sz + align); + + mmap.base = (void *)((((uintptr_t)mmap.priv) + align) & ~(uintptr_t)align); + mmap.dtor = my_mem_dtor; + alloc_sz += mmap.sz + align; + + if (vpx_codec_set_mem_map(&decoder, &mmap, 1)) + { + printf("Failed to set mmap: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + } + else if (res != VPX_CODEC_LIST_END) + { + printf("Failed to get mmap: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + } + while (res != VPX_CODEC_LIST_END); + + printf("%s\n %d bytes external memory required for %dx%d.\n", + decoder.name, alloc_sz, cfg.w, cfg.h); + vpx_codec_destroy(&decoder); + return EXIT_SUCCESS; + +} diff --git a/examples.mk b/examples.mk new file mode 100644 index 0000000..b93a16b --- /dev/null +++ b/examples.mk @@ -0,0 +1,285 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# List of examples to build. UTILS are files that are taken from the source +# tree directly, and GEN_EXAMPLES are files that are created from the +# examples folder. +UTILS-$(CONFIG_DECODERS) += vpxdec.c +vpxdec.SRCS += md5_utils.c md5_utils.h +vpxdec.SRCS += vpx_ports/vpx_timer.h +vpxdec.SRCS += vpx/vpx_integer.h +vpxdec.SRCS += args.c args.h +vpxdec.SRCS += tools_common.c tools_common.h +vpxdec.SRCS += nestegg/halloc/halloc.h +vpxdec.SRCS += nestegg/halloc/src/align.h +vpxdec.SRCS += nestegg/halloc/src/halloc.c +vpxdec.SRCS += nestegg/halloc/src/hlist.h +vpxdec.SRCS += nestegg/halloc/src/macros.h +vpxdec.SRCS += nestegg/include/nestegg/nestegg.h +vpxdec.SRCS += nestegg/src/nestegg.c +vpxdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950 +vpxdec.DESCRIPTION = Full featured decoder +UTILS-$(CONFIG_ENCODERS) += vpxenc.c +vpxenc.SRCS += args.c args.h y4minput.c y4minput.h +vpxenc.SRCS += tools_common.c tools_common.h +vpxenc.SRCS += vpx_ports/mem_ops.h +vpxenc.SRCS += vpx_ports/mem_ops_aligned.h +vpxenc.SRCS += vpx_ports/vpx_timer.h +vpxenc.SRCS += libmkv/EbmlIDs.h +vpxenc.SRCS += libmkv/EbmlWriter.c +vpxenc.SRCS += libmkv/EbmlWriter.h +vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 +vpxenc.DESCRIPTION = Full featured encoder +UTILS-$(CONFIG_ENCODERS) += vp8_scalable_patterns.c +vp8_scalable_patterns.GUID = 0D6A210B-F482-4D6F-8570-4A9C01ACC88C +vp8_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder + +# Clean up old ivfenc, ivfdec binaries. +ifeq ($(CONFIG_MSVS),yes) +CLEAN-OBJS += $(foreach p,$(VS_PLATFORMS),$(p)/Release/ivfenc.exe) +CLEAN-OBJS += $(foreach p,$(VS_PLATFORMS),$(p)/Release/ivfdec.exe) +else +CLEAN-OBJS += ivfenc{.c.o,.c.d,.dox,.exe,} +CLEAN-OBJS += ivfdec{.c.o,.c.d,.dox,.exe,} +endif + +# XMA example disabled for now, not used in VP8 +#UTILS-$(CONFIG_DECODERS) += example_xma.c +#example_xma.GUID = A955FC4A-73F1-44F7-135E-30D84D32F022 +#example_xma.DESCRIPTION = External Memory Allocation mode usage + +GEN_EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c +simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC +simple_decoder.DESCRIPTION = Simplified decoder loop +GEN_EXAMPLES-$(CONFIG_DECODERS) += postproc.c +postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7 +postproc.DESCRIPTION = Decoder postprocessor control +GEN_EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c +decode_to_md5.SRCS += md5_utils.h md5_utils.c +decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42 +decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum + +GEN_EXAMPLES-$(CONFIG_ENCODERS) += simple_encoder.c +simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD +simple_encoder.DESCRIPTION = Simplified encoder loop +GEN_EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c +twopass_encoder.GUID = 73494FA6-4AF9-4763-8FBB-265C92402FD8 +twopass_encoder.DESCRIPTION = Two-pass encoder loop +GEN_EXAMPLES-$(CONFIG_ENCODERS) += force_keyframe.c +force_keyframe.GUID = 3C67CADF-029F-4C86-81F5-D6D4F51177F0 +force_keyframe.DESCRIPTION = Force generation of keyframes +ifeq ($(CONFIG_DECODERS),yes) +GEN_EXAMPLES-$(CONFIG_ENCODERS) += decode_with_drops.c +endif +decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26 +decode_with_drops.DESCRIPTION = Drops frames while decoding +ifeq ($(CONFIG_DECODERS),yes) +GEN_EXAMPLES-$(CONFIG_ERROR_CONCEALMENT) += decode_with_partial_drops.c +endif +decode_with_partial_drops.GUID = 61C2D026-5754-46AC-916F-1343ECC5537E +decode_with_partial_drops.DESCRIPTION = Drops parts of frames while decoding +GEN_EXAMPLES-$(CONFIG_ENCODERS) += error_resilient.c +error_resilient.GUID = DF5837B9-4145-4F92-A031-44E4F832E00C +error_resilient.DESCRIPTION = Error Resiliency Feature + +GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_set_maps.c +vp8_set_maps.GUID = ECB2D24D-98B8-4015-A465-A4AF3DCC145F +vp8_set_maps.DESCRIPTION = VP8 set active and ROI maps +GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c +vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A +vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame + +# C file is provided, not generated automatically. +GEN_EXAMPLES-$(CONFIG_MULTI_RES_ENCODING) += vp8_multi_resolution_encoder.c +vp8_multi_resolution_encoder.SRCS \ + += third_party/libyuv/include/libyuv/basic_types.h \ + third_party/libyuv/include/libyuv/cpu_id.h \ + third_party/libyuv/include/libyuv/scale.h \ + third_party/libyuv/source/row.h \ + third_party/libyuv/source/scale.c \ + third_party/libyuv/source/cpu_id.c +vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de +vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding + +# Handle extra library flags depending on codec configuration + +# We should not link to math library (libm) on RVCT +# when building for bare-metal targets +ifeq ($(CONFIG_OS_SUPPORT), yes) +CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m +else + ifeq ($(CONFIG_GCC), yes) + CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m + endif +endif +# +# End of specified files. The rest of the build rules should happen +# automagically from here. +# + + +# Examples need different flags based on whether we're building +# from an installed tree or a version controlled tree. Determine +# the proper paths. +ifeq ($(HAVE_ALT_TREE_LAYOUT),yes) + LIB_PATH := $(SRC_PATH_BARE)/../lib + INC_PATH := $(SRC_PATH_BARE)/../include +else + LIB_PATH-yes += $(if $(BUILD_PFX),$(BUILD_PFX),.) + INC_PATH-$(CONFIG_VP8_DECODER) += $(SRC_PATH_BARE)/vp8 + INC_PATH-$(CONFIG_VP8_ENCODER) += $(SRC_PATH_BARE)/vp8 + LIB_PATH := $(call enabled,LIB_PATH) + INC_PATH := $(call enabled,INC_PATH) +endif +INTERNAL_CFLAGS = $(addprefix -I,$(INC_PATH)) +INTERNAL_LDFLAGS += $(addprefix -L,$(LIB_PATH)) + + +# Expand list of selected examples to build (as specified above) +UTILS = $(call enabled,UTILS) +GEN_EXAMPLES = $(call enabled,GEN_EXAMPLES) +ALL_EXAMPLES = $(UTILS) $(GEN_EXAMPLES) +UTIL_SRCS = $(foreach ex,$(UTILS),$($(ex:.c=).SRCS)) +ALL_SRCS = $(foreach ex,$(ALL_EXAMPLES),$($(ex:.c=).SRCS)) +CODEC_EXTRA_LIBS=$(sort $(call enabled,CODEC_EXTRA_LIBS)) + + +# Expand all example sources into a variable containing all sources +# for that example (not just them main one specified in UTILS/GEN_EXAMPLES) +# and add this file to the list (for MSVS workspace generation) +$(foreach ex,$(ALL_EXAMPLES),$(eval $(ex:.c=).SRCS += $(ex) examples.mk)) + + +# If this is a universal (fat) binary, then all the subarchitectures have +# already been built and our job is to stitch them together. The +# BUILD_OBJS variable indicates whether we should be building +# (compiling, linking) the library. The LIPO_OBJS variable indicates +# that we're stitching. +$(eval $(if $(filter universal%,$(TOOLCHAIN)),LIPO_OBJS,BUILD_OBJS):=yes) + + +# Create build/install dependencies for all examples. The common case +# is handled here. The MSVS case is handled below. +NOT_MSVS = $(if $(CONFIG_MSVS),,yes) +DIST-BINS-$(NOT_MSVS) += $(addprefix bin/,$(ALL_EXAMPLES:.c=$(EXE_SFX))) +INSTALL-BINS-$(NOT_MSVS) += $(addprefix bin/,$(UTILS:.c=$(EXE_SFX))) +DIST-SRCS-yes += $(ALL_SRCS) +INSTALL-SRCS-yes += $(UTIL_SRCS) +OBJS-$(NOT_MSVS) += $(if $(BUILD_OBJS),$(call objs,$(ALL_SRCS))) +BINS-$(NOT_MSVS) += $(addprefix $(BUILD_PFX),$(ALL_EXAMPLES:.c=$(EXE_SFX))) + + +# Instantiate linker template for all examples. +CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx) +CODEC_LIB_SUF=$(if $(CONFIG_SHARED),.so,.a) +$(foreach bin,$(BINS-yes),\ + $(if $(BUILD_OBJS),$(eval $(bin):\ + $(LIB_PATH)/lib$(CODEC_LIB)$(CODEC_LIB_SUF)))\ + $(if $(BUILD_OBJS),$(eval $(call linker_template,$(bin),\ + $(call objs,$($(notdir $(bin:$(EXE_SFX)=)).SRCS)) \ + -l$(CODEC_LIB) $(addprefix -l,$(CODEC_EXTRA_LIBS))\ + )))\ + $(if $(LIPO_OBJS),$(eval $(call lipo_bin_template,$(bin))))\ + ) + + +# Rules to generate the GEN_EXAMPLES sources +.PRECIOUS: %.c +CLEAN-OBJS += $(GEN_EXAMPLES) +%.c: examples/%.txt + @echo " [EXAMPLE] $@" + @$(SRC_PATH_BARE)/examples/gen_example_code.sh $< > $@ + + +# The following pairs define a mapping of locations in the distribution +# tree to locations in the source/build trees. +INSTALL_MAPS += src/%.c %.c +INSTALL_MAPS += src/% $(SRC_PATH_BARE)/% +INSTALL_MAPS += bin/% % +INSTALL_MAPS += % % + + +# Set up additional MSVS environment +ifeq ($(CONFIG_MSVS),yes) +CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd) +# This variable uses deferred expansion intentionally, since the results of +# $(wildcard) may change during the course of the Make. +VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d)))) +INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),bin/$(p)/% $(p)/Release/%) +endif + +# Build Visual Studio Projects. We use a template here to instantiate +# explicit rules rather than using an implicit rule because we want to +# leverage make's VPATH searching rather than specifying the paths on +# each file in ALL_EXAMPLES. This has the unfortunate side effect that +# touching the source files trigger a rebuild of the project files +# even though there is no real dependency there (the dependency is on +# the makefiles). We may want to revisit this. +define vcproj_template +$(1): $($(1:.vcproj=).SRCS) + @echo " [vcproj] $$@" + $$(SRC_PATH_BARE)/build/make/gen_msvs_proj.sh\ + --exe\ + --target=$$(TOOLCHAIN)\ + --name=$$(@:.vcproj=)\ + --ver=$$(CONFIG_VS_VERSION)\ + --proj-guid=$$($$(@:.vcproj=).GUID)\ + $$(if $$(CONFIG_STATIC_MSVCRT),--static-crt) \ + --out=$$@ $$(INTERNAL_CFLAGS) $$(CFLAGS) \ + $$(INTERNAL_LDFLAGS) $$(LDFLAGS) -l$$(CODEC_LIB) -lwinmm $$^ +endef +PROJECTS-$(CONFIG_MSVS) += $(ALL_EXAMPLES:.c=.vcproj) +INSTALL-BINS-$(CONFIG_MSVS) += $(foreach p,$(VS_PLATFORMS),\ + $(addprefix bin/$(p)/,$(ALL_EXAMPLES:.c=.exe))) +$(foreach proj,$(call enabled,PROJECTS),\ + $(eval $(call vcproj_template,$(proj)))) + + + +# +# Documentation Rules +# +%.dox: examples/%.txt + @echo " [DOXY] $@" + @$(SRC_PATH_BARE)/examples/gen_example_text.sh $< | \ + $(SRC_PATH_BARE)/examples/gen_example_doxy.php \ + example_$(@:.dox=) $(@:.dox=.c) > $@ + +%.dox: %.c + @echo " [DOXY] $@" + @echo "/*!\page example_$(@:.dox=) $(@:.dox=)" > $@ + @echo " \includelineno $(notdir $<)" >> $@ + @echo "*/" >> $@ + +samples.dox: examples.mk + @echo " [DOXY] $@" + @echo "/*!\page samples Sample Code" > $@ + @echo " This SDK includes a number of sample applications."\ + "each sample documents a feature of the SDK in both prose"\ + "and the associated C code. In general, later samples"\ + "build upon prior samples, so it is best to work through the"\ + "list in order. The following samples are included: ">>$@ + @$(foreach ex,$(GEN_EXAMPLES:.c=),\ + echo " - \subpage example_$(ex) $($(ex).DESCRIPTION)" >> $@;) + @echo >> $@ + @echo " In addition, the SDK contains a number of utilities."\ + "Since these utilities are built upon the concepts described"\ + "in the sample code listed above, they are not documented in"\ + "pieces like the samples are. Thir sourcre is included here"\ + "for reference. The following utilities are included:" >> $@ + @$(foreach ex,$(UTILS:.c=),\ + echo " - \subpage example_$(ex) $($(ex).DESCRIPTION)" >> $@;) + @echo "*/" >> $@ + +CLEAN-OBJS += examples.doxy samples.dox $(ALL_EXAMPLES:.c=.dox) +DOCS-yes += examples.doxy samples.dox $(ALL_EXAMPLES:.c=.dox) +examples.doxy: samples.dox $(ALL_EXAMPLES:.c=.dox) + @echo "INPUT += $^" > $@ diff --git a/examples/decode_to_md5.txt b/examples/decode_to_md5.txt new file mode 100644 index 0000000..ea0eb69 --- /dev/null +++ b/examples/decode_to_md5.txt @@ -0,0 +1,48 @@ +@TEMPLATE decoder_tmpl.c +Frame-by-frame MD5 Checksum +=========================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This example builds upon the simple decoder loop to show how checksums +of the decoded output can be generated. These are used for validating +decoder implementations against the reference implementation, for example. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + +MD5 algorithm +------------- +The Message-Digest 5 (MD5) is a well known hash function. We have provided +an implementation derived from the RSA Data Security, Inc. MD5 Message-Digest +Algorithm for your use. Our implmentation only changes the interface of this +reference code. You must include the `md5_utils.h` header for access to these +functions. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES +#include "md5_utils.h" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES + + +Processing The Decoded Data +--------------------------- +Each row of the image is passed to the MD5 accumulator. First the Y plane +is processed, then U, then V. It is important to honor the image's `stride` +values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX +unsigned char md5_sum[16]; +MD5Context md5; +int i; + +MD5Init(&md5); + +for(plane=0; plane < 3; plane++) { + unsigned char *buf =img->planes[plane]; + + for(y=0; y < (plane ? (img->d_h + 1) >> 1 : img->d_h); y++) { + MD5Update(&md5, buf, (plane ? (img->d_w + 1) >> 1 : img->d_w)); + buf += img->stride[plane]; + } +} + +MD5Final(md5_sum, &md5); +for(i=0; i<16; i++) + fprintf(outfile, "%02x",md5_sum[i]); +fprintf(outfile, " img-%dx%d-%04d.i420\n", img->d_w, img->d_h, + frame_cnt); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX diff --git a/examples/decode_with_drops.txt b/examples/decode_with_drops.txt new file mode 100644 index 0000000..fb77a7e --- /dev/null +++ b/examples/decode_with_drops.txt @@ -0,0 +1,73 @@ +@TEMPLATE decoder_tmpl.c +Decode With Drops Example +========================= +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example utility which drops a series of frames, as specified +on the command line. This is useful for observing the error recovery +features of the codec. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + +Usage +----- +This example adds a single argument to the `simple_decoder` example, +which specifies the range or pattern of frames to drop. The parameter is +parsed as follows: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE +if(argc!=4) + die("Usage: %s \n", argv[0]); +{ + char *nptr; + n = strtol(argv[3], &nptr, 0); + m = strtol(nptr+1, NULL, 0); + is_range = *nptr == '-'; + if(!n || !m || (*nptr != '-' && *nptr != '/')) + die("Couldn't parse pattern %s\n", argv[3]); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE + + +Dropping A Range Of Frames +-------------------------- +To drop a range of frames, specify the starting frame and the ending +frame to drop, separated by a dash. The following command will drop +frames 5 through 10 (base 1). + + $ ./decode_with_drops in.ivf out.i420 5-10 + + +Dropping A Pattern Of Frames +---------------------------- +To drop a pattern of frames, specify the number of frames to drop and +the number of frames after which to repeat the pattern, separated by +a forward-slash. The following command will drop 3 of 7 frames. +Specifically, it will decode 4 frames, then drop 3 frames, and then +repeat. + + $ ./decode_with_drops in.ivf out.i420 3/7 + + +Extra Variables +--------------- +This example maintains the pattern passed on the command line in the +`n`, `m`, and `is_range` variables: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS +int n, m, is_range; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS + + +Making The Drop Decision +------------------------ +The example decides whether to drop the frame based on the current +frame number, immediately before decoding the frame. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE +if((is_range && frame_cnt >= n && frame_cnt <= m) + ||(!is_range && m - (frame_cnt-1)%m <= n)) { + putc('X', stdout); + continue; +} +putc('.', stdout); +fflush(stdout); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE diff --git a/examples/decode_with_partial_drops.txt b/examples/decode_with_partial_drops.txt new file mode 100644 index 0000000..7b0d3d2 --- /dev/null +++ b/examples/decode_with_partial_drops.txt @@ -0,0 +1,238 @@ +@TEMPLATE decoder_tmpl.c +Decode With Partial Drops Example +========================= +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example utility which drops a series of frames (or parts of frames), +as specified on the command line. This is useful for observing the error +recovery features of the codec. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES +#include +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS +struct parsed_header +{ + char key_frame; + int version; + char show_frame; + int first_part_size; +}; + +int next_packet(struct parsed_header* hdr, int pos, int length, int mtu) +{ + int size = 0; + int remaining = length - pos; + /* Uncompressed part is 3 bytes for P frames and 10 bytes for I frames */ + int uncomp_part_size = (hdr->key_frame ? 10 : 3); + /* number of bytes yet to send from header and the first partition */ + int remainFirst = uncomp_part_size + hdr->first_part_size - pos; + if (remainFirst > 0) + { + if (remainFirst <= mtu) + { + size = remainFirst; + } + else + { + size = mtu; + } + + return size; + } + + /* second partition; just slot it up according to MTU */ + if (remaining <= mtu) + { + size = remaining; + return size; + } + return mtu; +} + +void throw_packets(unsigned char* frame, int* size, int loss_rate, + int* thrown, int* kept) +{ + unsigned char loss_frame[256*1024]; + int pkg_size = 1; + int pos = 0; + int loss_pos = 0; + struct parsed_header hdr; + unsigned int tmp; + int mtu = 1500; + + if (*size < 3) + { + return; + } + putc('|', stdout); + /* parse uncompressed 3 bytes */ + tmp = (frame[2] << 16) | (frame[1] << 8) | frame[0]; + hdr.key_frame = !(tmp & 0x1); /* inverse logic */ + hdr.version = (tmp >> 1) & 0x7; + hdr.show_frame = (tmp >> 4) & 0x1; + hdr.first_part_size = (tmp >> 5) & 0x7FFFF; + + /* don't drop key frames */ + if (hdr.key_frame) + { + int i; + *kept = *size/mtu + ((*size % mtu > 0) ? 1 : 0); /* approximate */ + for (i=0; i < *kept; i++) + putc('.', stdout); + return; + } + + while ((pkg_size = next_packet(&hdr, pos, *size, mtu)) > 0) + { + int loss_event = ((rand() + 1.0)/(RAND_MAX + 1.0) < loss_rate/100.0); + if (*thrown == 0 && !loss_event) + { + memcpy(loss_frame + loss_pos, frame + pos, pkg_size); + loss_pos += pkg_size; + (*kept)++; + putc('.', stdout); + } + else + { + (*thrown)++; + putc('X', stdout); + } + pos += pkg_size; + } + memcpy(frame, loss_frame, loss_pos); + memset(frame + loss_pos, 0, *size - loss_pos); + *size = loss_pos; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT +/* Initialize codec */ +flags = VPX_CODEC_USE_ERROR_CONCEALMENT; +res = vpx_codec_dec_init(&codec, interface, &dec_cfg, flags); +if(res) + die_codec(&codec, "Failed to initialize decoder"); + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT + +Usage +----- +This example adds a single argument to the `simple_decoder` example, +which specifies the range or pattern of frames to drop. The parameter is +parsed as follows: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE +if(argc < 4 || argc > 6) + die("Usage: %s [-t ] \n", + argv[0]); +{ + char *nptr; + int arg_num = 3; + if (argc == 6 && strncmp(argv[arg_num++], "-t", 2) == 0) + dec_cfg.threads = strtol(argv[arg_num++], NULL, 0); + n = strtol(argv[arg_num], &nptr, 0); + mode = (*nptr == '\0' || *nptr == ',') ? 2 : (*nptr == '-') ? 1 : 0; + + m = strtol(nptr+1, NULL, 0); + if((!n && !m) || (*nptr != '-' && *nptr != '/' && + *nptr != '\0' && *nptr != ',')) + die("Couldn't parse pattern %s\n", argv[3]); +} +seed = (m > 0) ? m : (unsigned int)time(NULL); +srand(seed);thrown_frame = 0; +printf("Seed: %u\n", seed); +printf("Threads: %d\n", dec_cfg.threads); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE + + +Dropping A Range Of Frames +-------------------------- +To drop a range of frames, specify the starting frame and the ending +frame to drop, separated by a dash. The following command will drop +frames 5 through 10 (base 1). + + $ ./decode_with_partial_drops in.ivf out.i420 5-10 + + +Dropping A Pattern Of Frames +---------------------------- +To drop a pattern of frames, specify the number of frames to drop and +the number of frames after which to repeat the pattern, separated by +a forward-slash. The following command will drop 3 of 7 frames. +Specifically, it will decode 4 frames, then drop 3 frames, and then +repeat. + + $ ./decode_with_partial_drops in.ivf out.i420 3/7 + +Dropping Random Parts Of Frames +------------------------------- +A third argument tuple is available to split the frame into 1500 bytes pieces +and randomly drop pieces rather than frames. The frame will be split at +partition boundaries where possible. The following example will seed the RNG +with the seed 123 and drop approximately 5% of the pieces. Pieces which +are depending on an already dropped piece will also be dropped. + + $ ./decode_with_partial_drops in.ivf out.i420 5,123 + + +Extra Variables +--------------- +This example maintains the pattern passed on the command line in the +`n`, `m`, and `is_range` variables: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS +int n, m, mode; +unsigned int seed; +int thrown=0, kept=0; +int thrown_frame=0, kept_frame=0; +vpx_codec_dec_cfg_t dec_cfg = {0}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS + + +Making The Drop Decision +------------------------ +The example decides whether to drop the frame based on the current +frame number, immediately before decoding the frame. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE +/* Decide whether to throw parts of the frame or the whole frame + depending on the drop mode */ +thrown_frame = 0; +kept_frame = 0; +switch (mode) +{ +case 0: + if (m - (frame_cnt-1)%m <= n) + { + frame_sz = 0; + } + break; +case 1: + if (frame_cnt >= n && frame_cnt <= m) + { + frame_sz = 0; + } + break; +case 2: + throw_packets(frame, &frame_sz, n, &thrown_frame, &kept_frame); + break; +default: break; +} +if (mode < 2) +{ + if (frame_sz == 0) + { + putc('X', stdout); + thrown_frame++; + } + else + { + putc('.', stdout); + kept_frame++; + } +} +thrown += thrown_frame; +kept += kept_frame; +fflush(stdout); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE diff --git a/examples/decoder_tmpl.c b/examples/decoder_tmpl.c new file mode 100644 index 0000000..8194f0a --- /dev/null +++ b/examples/decoder_tmpl.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* +@*INTRODUCTION + */ +#include +#include +#include +#include +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx/vpx_decoder.h" +#include "vpx/vp8dx.h" +#define interface (vpx_codec_vp8_dx()) +@EXTRA_INCLUDES + + +#define IVF_FILE_HDR_SZ (32) +#define IVF_FRAME_HDR_SZ (12) + +static unsigned int mem_get_le32(const unsigned char *mem) { + return (mem[3] << 24)|(mem[2] << 16)|(mem[1] << 8)|(mem[0]); +} + +static void die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + if(fmt[strlen(fmt)-1] != '\n') + printf("\n"); + exit(EXIT_FAILURE); +} + +@DIE_CODEC + +@HELPERS + +int main(int argc, char **argv) { + FILE *infile, *outfile; + vpx_codec_ctx_t codec; + int flags = 0, frame_cnt = 0; + unsigned char file_hdr[IVF_FILE_HDR_SZ]; + unsigned char frame_hdr[IVF_FRAME_HDR_SZ]; + unsigned char frame[256*1024]; + vpx_codec_err_t res; +@@@@EXTRA_VARS + + (void)res; + /* Open files */ +@@@@USAGE + if(!(infile = fopen(argv[1], "rb"))) + die("Failed to open %s for reading", argv[1]); + if(!(outfile = fopen(argv[2], "wb"))) + die("Failed to open %s for writing", argv[2]); + + /* Read file header */ + if(!(fread(file_hdr, 1, IVF_FILE_HDR_SZ, infile) == IVF_FILE_HDR_SZ + && file_hdr[0]=='D' && file_hdr[1]=='K' && file_hdr[2]=='I' + && file_hdr[3]=='F')) + die("%s is not an IVF file.", argv[1]); + + printf("Using %s\n",vpx_codec_iface_name(interface)); +@@@@DEC_INIT + + /* Read each frame */ + while(fread(frame_hdr, 1, IVF_FRAME_HDR_SZ, infile) == IVF_FRAME_HDR_SZ) { + int frame_sz = mem_get_le32(frame_hdr); + vpx_codec_iter_t iter = NULL; + vpx_image_t *img; + + + frame_cnt++; + if(frame_sz > sizeof(frame)) + die("Frame %d data too big for example code buffer", frame_sz); + if(fread(frame, 1, frame_sz, infile) != frame_sz) + die("Frame %d failed to read complete frame", frame_cnt); + +@@@@@@@@PRE_DECODE +@@@@@@@@DECODE + + /* Write decoded data to disk */ +@@@@@@@@GET_FRAME + unsigned int plane, y; + +@@@@@@@@@@@@PROCESS_DX + } + } + printf("Processed %d frames.\n",frame_cnt); +@@@@DESTROY + + fclose(outfile); + fclose(infile); + return EXIT_SUCCESS; +} diff --git a/examples/decoder_tmpl.txt b/examples/decoder_tmpl.txt new file mode 100644 index 0000000..92a2c30 --- /dev/null +++ b/examples/decoder_tmpl.txt @@ -0,0 +1,62 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INCLUDES +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx/vpx_decoder.h" +#include "vpx/vp8dx.h" +#define interface (vpx_codec_vp8_dx()) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INCLUDES + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC +static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { + const char *detail = vpx_codec_error_detail(ctx); + + printf("%s: %s\n", s, vpx_codec_error(ctx)); + if(detail) + printf(" %s\n",detail); + exit(EXIT_FAILURE); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE +if(argc!=3) + die("Usage: %s \n", argv[0]); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT +/* Initialize codec */ +if(vpx_codec_dec_init(&codec, interface, NULL, flags)) + die_codec(&codec, "Failed to initialize decoder"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE +/* Decode the frame */ +if(vpx_codec_decode(&codec, frame, frame_sz, NULL, 0)) + die_codec(&codec, "Failed to decode frame"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GET_FRAME +while((img = vpx_codec_get_frame(&codec, &iter))) { +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GET_FRAME + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX +for(plane=0; plane < 3; plane++) { + unsigned char *buf =img->planes[plane]; + + for(y=0; y < (plane ? (img->d_h + 1) >> 1 : img->d_h); y++) { + if(fwrite(buf, 1, (plane ? (img->d_w + 1) >> 1 : img->d_w), + outfile)); + buf += img->stride[plane]; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY +if(vpx_codec_destroy(&codec)) + die_codec(&codec, "Failed to destroy codec"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY diff --git a/examples/encoder_tmpl.c b/examples/encoder_tmpl.c new file mode 100644 index 0000000..cc70b00 --- /dev/null +++ b/examples/encoder_tmpl.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* +@*INTRODUCTION + */ +#include +#include +#include +#include +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx/vpx_encoder.h" +#include "vpx/vp8cx.h" +#define interface (vpx_codec_vp8_cx()) +#define fourcc 0x30385056 +@EXTRA_INCLUDES + +#define IVF_FILE_HDR_SZ (32) +#define IVF_FRAME_HDR_SZ (12) + +static void mem_put_le16(char *mem, unsigned int val) { + mem[0] = val; + mem[1] = val>>8; +} + +static void mem_put_le32(char *mem, unsigned int val) { + mem[0] = val; + mem[1] = val>>8; + mem[2] = val>>16; + mem[3] = val>>24; +} + +static void die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + if(fmt[strlen(fmt)-1] != '\n') + printf("\n"); + exit(EXIT_FAILURE); +} + +@DIE_CODEC + +static int read_frame(FILE *f, vpx_image_t *img) { + size_t nbytes, to_read; + int res = 1; + + to_read = img->w*img->h*3/2; + nbytes = fread(img->planes[0], 1, to_read, f); + if(nbytes != to_read) { + res = 0; + if(nbytes > 0) + printf("Warning: Read partial frame. Check your width & height!\n"); + } + return res; +} + +static void write_ivf_file_header(FILE *outfile, + const vpx_codec_enc_cfg_t *cfg, + int frame_cnt) { + char header[32]; + + if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) + return; + header[0] = 'D'; + header[1] = 'K'; + header[2] = 'I'; + header[3] = 'F'; + mem_put_le16(header+4, 0); /* version */ + mem_put_le16(header+6, 32); /* headersize */ + mem_put_le32(header+8, fourcc); /* headersize */ + mem_put_le16(header+12, cfg->g_w); /* width */ + mem_put_le16(header+14, cfg->g_h); /* height */ + mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ + mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ + mem_put_le32(header+24, frame_cnt); /* length */ + mem_put_le32(header+28, 0); /* unused */ + + if(fwrite(header, 1, 32, outfile)); +} + + +static void write_ivf_frame_header(FILE *outfile, + const vpx_codec_cx_pkt_t *pkt) +{ + char header[12]; + vpx_codec_pts_t pts; + + if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) + return; + + pts = pkt->data.frame.pts; + mem_put_le32(header, pkt->data.frame.sz); + mem_put_le32(header+4, pts&0xFFFFFFFF); + mem_put_le32(header+8, pts >> 32); + + if(fwrite(header, 1, 12, outfile)); +} + +int main(int argc, char **argv) { + FILE *infile, *outfile; + vpx_codec_ctx_t codec; + vpx_codec_enc_cfg_t cfg; + int frame_cnt = 0; + vpx_image_t raw; + vpx_codec_err_t res; + long width; + long height; + int frame_avail; + int got_data; + int flags = 0; +@@@@TWOPASS_VARS + + /* Open files */ +@@@@USAGE + width = strtol(argv[1], NULL, 0); + height = strtol(argv[2], NULL, 0); + if(width < 16 || width%2 || height <16 || height%2) + die("Invalid resolution: %ldx%ld", width, height); + if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1)) + die("Faile to allocate image", width, height); + if(!(outfile = fopen(argv[4], "wb"))) + die("Failed to open %s for writing", argv[4]); + + printf("Using %s\n",vpx_codec_iface_name(interface)); + +@@@@ENC_DEF_CFG + +@@@@ENC_SET_CFG +@@@@ENC_SET_CFG2 + + write_ivf_file_header(outfile, &cfg, 0); + +@@@@TWOPASS_LOOP_BEGIN + + /* Open input file for this encoding pass */ + if(!(infile = fopen(argv[3], "rb"))) + die("Failed to open %s for reading", argv[3]); + +@@@@@@@@ENC_INIT + + frame_avail = 1; + got_data = 0; + while(frame_avail || got_data) { + vpx_codec_iter_t iter = NULL; + const vpx_codec_cx_pkt_t *pkt; + +@@@@@@@@@@@@PER_FRAME_CFG +@@@@@@@@@@@@ENCODE_FRAME + got_data = 0; + while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { + got_data = 1; + switch(pkt->kind) { +@@@@@@@@@@@@@@@@PROCESS_FRAME +@@@@@@@@@@@@@@@@PROCESS_STATS + default: + break; + } + printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT + && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); + fflush(stdout); + } + frame_cnt++; + } + printf("\n"); + fclose(infile); +@@@@TWOPASS_LOOP_END + + printf("Processed %d frames.\n",frame_cnt-1); +@@@@DESTROY + + /* Try to rewrite the file header with the actual frame count */ + if(!fseek(outfile, 0, SEEK_SET)) + write_ivf_file_header(outfile, &cfg, frame_cnt-1); + fclose(outfile); + return EXIT_SUCCESS; +} diff --git a/examples/encoder_tmpl.txt b/examples/encoder_tmpl.txt new file mode 100644 index 0000000..0042071 --- /dev/null +++ b/examples/encoder_tmpl.txt @@ -0,0 +1,73 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INCLUDES +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx/vpx_encoder.h" +#include "vpx/vp8cx.h" +#define interface (vpx_codec_vp8_cx()) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INCLUDES + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC +static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { + const char *detail = vpx_codec_error_detail(ctx); + + printf("%s: %s\n", s, vpx_codec_error(ctx)); + if(detail) + printf(" %s\n",detail); + exit(EXIT_FAILURE); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE +if(argc!=5) + die("Usage: %s \n", argv[0]); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_DEF_CFG +/* Populate encoder configuration */ +res = vpx_codec_enc_config_default(interface, &cfg, 0); +if(res) { + printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); + return EXIT_FAILURE; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_DEF_CFG + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG +/* Update the default configuration with our settings */ +cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate + / cfg.g_w / cfg.g_h; +cfg.g_w = width; +cfg.g_h = height; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INIT +/* Initialize codec */ +if(vpx_codec_enc_init(&codec, interface, &cfg, 0)) + die_codec(&codec, "Failed to initialize encoder"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INIT + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME +frame_avail = read_frame(infile, &raw); +if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, + 1, flags, VPX_DL_REALTIME)) + die_codec(&codec, "Failed to encode frame"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_FRAME +case VPX_CODEC_CX_FRAME_PKT: + write_ivf_frame_header(outfile, pkt); + if(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, + outfile)); + break; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_FRAME + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY +if(vpx_codec_destroy(&codec)) + die_codec(&codec, "Failed to destroy codec"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY diff --git a/examples/error_resilient.txt b/examples/error_resilient.txt new file mode 100644 index 0000000..e9d0949 --- /dev/null +++ b/examples/error_resilient.txt @@ -0,0 +1,25 @@ +@TEMPLATE encoder_tmpl.c +Error Resiliency Features +========================= +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example demonstrating how to enable the error resiliency +features of the codec. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Configuration +------------- +Error resiliency is controlled by the g_error_resilient member of the +configuration structure. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG2 + +/* Enable error resilient mode */ +cfg.g_error_resilient = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG2 + + +Observing The Effects +--------------------- +Use the `decode_with_drops` example to decode with frames 5-10 dropped. +Compare the output for a file encoded with this example versus one +encoded with the `simple_encoder` example. diff --git a/examples/force_keyframe.txt b/examples/force_keyframe.txt new file mode 100644 index 0000000..a9c16be --- /dev/null +++ b/examples/force_keyframe.txt @@ -0,0 +1,28 @@ +@TEMPLATE encoder_tmpl.c +Forcing A Keyframe +================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example demonstrating how to control placement of keyframes +on a frame-by-frame basis. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Configuration +------------- +Keyframes can be forced by setting the VPX_EFLAG_FORCE_KF bit of the +flags passed to `vpx_codec_control()`. In this example, we force a +keyframe every 8 frames. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PER_FRAME_CFG +if(!(frame_cnt & 7)) + flags |= VPX_EFLAG_FORCE_KF; +else + flags &= ~VPX_EFLAG_FORCE_KF; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PER_FRAME_CFG + + +Observing The Effects +--------------------- +The output of the encoder examples shows a 'K' rather than a dot '.' +when the encoder generates a keyframe. Note that every 8 frames a 'K' +is output. diff --git a/examples/gen_example_code.sh b/examples/gen_example_code.sh new file mode 100755 index 0000000..1133b49 --- /dev/null +++ b/examples/gen_example_code.sh @@ -0,0 +1,85 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# gen_example_code.sh + +self=$0 + +die_usage() { + echo "Usage: $self " + exit 1 +} + +die() { + echo "$@" + exit 1 +} + +include_block() { + show_bar=$1 + block_name=${line##*@} + indent=${line%%${block_name}} + indent=${#indent} + [ $indent -eq 1 ] && indent=0 + local on_block + while IFS=$'\n' read -r t_line; do + case "$t_line" in + \~*\ ${block_name}) + if [ "x$on_block" == "xyes" ]; then + return 0; + else + on_block=yes + fi + ;; + @DEFAULT) + if [ "x$on_block" == "xyes" ]; then + include_block $show_bar < "${template%.c}.txt" + return 0 + fi + ;; + *) + if [ "x$on_block" == "xyes" ]; then + local rem + (( rem = 78 - indent )) + case "$block_name" in + \**) printf "%${indent}s * %s\n" "" "$t_line" ;; + *) + if [ "$show_bar" == "yes" ]; then + printf "%${indent}s%-${rem}s//\n" "" "$t_line" + else + printf "%${indent}s%s\n" "" "$t_line" + fi + ;; + esac + fi + esac + done + return 1 +} + +txt=$1 +[ -f "$txt" ] || die_usage +read -r template < "$txt" +case "$template" in + @TEMPLATE*) template=${txt%/*}/${template##@TEMPLATE } ;; + *) die "Failed to parse template name from '$template'" ;; +esac + +while IFS=$'\n' read -r line; do + case "$line" in + @*) include_block yes < "$txt" \ + || include_block < "${template%.c}.txt" \ + #|| echo "WARNING: failed to find text for block $block_name" >&2 + ;; + *) echo "$line" ;; + esac +done < "$template" diff --git a/examples/gen_example_doxy.php b/examples/gen_example_doxy.php new file mode 100755 index 0000000..701bbd3 --- /dev/null +++ b/examples/gen_example_doxy.php @@ -0,0 +1,224 @@ +#!/usr/bin/env php +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + + "" + */ + + +$geshi_path = dirname($argv[0])."/includes/geshi/geshi/"; // Language files +$tmp_token = ''; + +// Include prerequisites or exit +if(!include_once('includes/PHP-Markdown-Extra-1.2.3/markdown.php')) + die("Cannot load Markdown transformer.\n"); +if(!include_once('includes/PHP-SmartyPants-1.5.1e/smartypants.php')) + die("Cannot load SmartyPants transformer.\n"); +if(!include_once('includes/geshi/geshi.php')) + die("Cannot load GeSHi transformer.\n"); +// ASCIIMathPHP? +// HTML::Toc? +// Tidy? +// Prince? + +/** + * Generate XHTML body + * + */ + +$page_body = file_get_contents('php://stdin'); + +// Transform any MathML expressions in the body text +$regexp = '/\[\[(.*?)\]\]/'; // Double square bracket delimiters +$page_body = preg_replace_callback($regexp, 'ASCIIMathPHPCallback', $page_body); + +// Fix ASCIIMathPHP's output +$page_body = fix_asciiMath($page_body); + +// Wrap block-style elements in

, since Markdown doesn't. +$page_body = preg_replace('/\n()\n/', '

$1

', $page_body); + +// Transform the body text to HTML +$page_body = Markdown($page_body); + +// Preprocess code blocks +// Decode XML entities. GeSHi doesn't anticipate that +// Markdown has already done this. +$regexp = '|
(.*?)<\/code><\/pre>|si';
+while (preg_match($regexp, $page_body, $matches) > 0)
+{
+  // Replace 1st match with token
+  $page_body = preg_replace($regexp, $tmp_token, $page_body, 1);
+  $block_new = $matches[1];
+  // Un-encode ampersand entities
+  $block_new = decode_markdown($block_new);
+  // Replace token with revised string
+  $page_body = preg_replace("|$tmp_token|", '
'.$block_new.'
', $page_body); +} + +// Run GeSHi over code blocks +$regexp = '|
(.*?)<\/div>|si'; +$language = 'c'; + +while (preg_match($regexp, $page_body, $matches)) +{ + $geshi = new GeSHi($matches[1], $language); + $geshi->set_language_path($geshi_path); + $block_new = $geshi->parse_code(); + // Strip annoying final newline + $block_new = preg_replace('|\n <\/pre>|', '
' , $block_new); + // Remove style attribute (TODO: Research this in GeSHi) + $block_new = preg_replace('| style="font-family:monospace;"|', '' , $block_new); + $page_body = preg_replace($regexp, $block_new, $page_body, 1); + unset($geshi); // Clean up +} +unset($block_new); // Clean up + +// Apply typographic flourishes +$page_body = SmartyPants($page_body); + + +/** + * Generate Doxygen Body + * + */ +$page_id=(isset($argv[1]))?$argv[1]:""; +$page_desc=(isset($argv[2]))?$argv[2]:""; +print "/*!\\page ".$page_id." ".$page_desc."\n\\htmlonly\n"; +print $page_body; +print "\\endhtmlonly\n*/\n"; + +// --------------------------------------------------------- + +/** + * decode_markdown() + * + * Markdown encodes '&', '<' and '>' in detected code + * blocks, as a convenience. This will restore the + * encoded entities to ordinary characters, since a + * downstream transformer (like GeSHi) may not + * anticipate this. + * + **********************************************************/ + +function decode_markdown($input) +{ + $out = FALSE; + + $entities = array ('|&|' + ,'|<|' + ,'|>|' + ); + $characters = array ('&' + ,'<' + ,'>' + ); + $input = preg_replace($entities, $characters, $input); + $out = $input; + + return $out; +} + + +/** + * ASCIIMathML parser + * http://tinyurl.com/ASCIIMathPHP + * + * @PARAM mtch_arr array - Array of ASCIIMath expressions + * as returned by preg_replace_callback([pattern]). First + * dimension is the full matched string (with delimiter); + * 2nd dimension is the undelimited contents (typically + * a capture group). + * + **********************************************************/ + +function ASCIIMathPHPCallback($mtch_arr) +{ + $txt = trim($mtch_arr[1]); + + include('includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php'); + require_once('includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php'); + + static $asciimath; + + if (!isset($asciimath)) $asciimath = new ASCIIMathPHP($symbol_arr); + + $math_attr_arr = array('displaystyle' => 'true'); + + $asciimath->setExpr($txt); + $asciimath->genMathML($math_attr_arr); + + return($asciimath->getMathML()); +} + +/** + * fix_asciiMath() + * + * ASCIIMath pretty-prints its output, with linefeeds + * and tabs. Causes unexpected behavior in some renderers. + * This flattens blocks. + * + * @PARAM page_body str - The element of an + * XHTML page to transform. + * + **********************************************************/ + +function fix_asciiMath($page_body) +{ + $out = FALSE; + + // Remove linefeeds and whitespace in elements + $tags_bad = array('/()\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mstyle>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mrow>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mo>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mi>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mn>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mtext>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/msqrt>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mfrac>)\n*\s*/' + ); + $tags_good = array( '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + ); + $out = preg_replace($tags_bad, $tags_good, $page_body); + + return $out; + +} diff --git a/examples/gen_example_text.sh b/examples/gen_example_text.sh new file mode 100755 index 0000000..9a8703d --- /dev/null +++ b/examples/gen_example_text.sh @@ -0,0 +1,84 @@ +#!/bin/bash +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# gen_example_text.sh + +self=$0 + +die_usage() { + echo "Usage: $self " + exit 1 +} + +die() { + echo "$@" + exit 1 +} + +include_block() { + local on_block + while IFS=$'\n' read -r t_line; do + case "$t_line" in + \~*\ ${block_name}) + if [ "x$on_block" == "xyes" ]; then + return 0; + else + on_block=yes + fi + ;; + *) + if [ "x$on_block" == "xyes" ]; then + echo "$t_line" + fi + ;; + esac + done + echo "WARNING: failed to find text for block $block_name" >&2 + return 1 +} + +txt=$1 +[ -f "$txt" ] || die_usage +read -r template < "$txt" +case "$template" in + @TEMPLATE*) template=${txt%/*}/${template##@TEMPLATE } ;; + *) die "Failed to parse template name from '$template'" ;; +esac + +fence="~~~~~~~~~" +fence="${fence}${fence}" +fence="${fence}${fence}" +fence="${fence}${fence}" +while IFS=$'\n' read -r line; do + case "$line" in + @TEMPLATE*) + template=${template##@TEMPLATE } + template=${template%.c}.txt + ;; + @DEFAULT) + include_block < "$template" + ;; + ~~~*) + block_name=${line##~* } + [ "$block_name" == "INTRODUCTION" ] || echo "$fence" + ;; + *) echo "$line" + ;; + esac +done < "$txt" + +echo +echo "Putting It All Together" +echo "=======================" +echo "${fence}" +${self%/*}/gen_example_code.sh "${txt}" +echo "${fence}" diff --git a/examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php b/examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php new file mode 100644 index 0000000..06f7979 --- /dev/null +++ b/examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php @@ -0,0 +1,218 @@ + array( 'input'=>'alpha','tag'=>'mi', 'output'=>'&#' . hexdec('03B1') . ';'), +'beta' => array( 'input'=>'beta','tag'=>'mi', 'output'=>'&#' . hexdec('03B2') . ';'), +'chi' => array( 'input'=>'chi','tag'=>'mi', 'output'=>'&#' . hexdec('03C7') . ';'), +'delta' => array( 'input'=>'delta','tag'=>'mi', 'output'=>'&#' . hexdec('03B4') . ';'), +'Delta' => array( 'input'=>'Delta','tag'=>'mo', 'output'=>'&#' . hexdec('0394') . ';'), +'epsi' => array( 'input'=>'epsi','tag'=>'mi', 'output'=>'&#' . hexdec('03B5') . ';'), +'varepsilon' => array( 'input'=>'varepsilon','tag'=>'mi', 'output'=>'&#' . hexdec('025B') . ';'), +'eta' => array( 'input'=>'eta','tag'=>'mi', 'output'=>'&#' . hexdec('03B7') . ';'), +'gamma' => array( 'input'=>'gamma','tag'=>'mi', 'output'=>'&#' . hexdec('03B3') . ';'), +'Gamma' => array( 'input'=>'Gamma','tag'=>'mi', 'output'=>'&#' . hexdec('0393') . ';'), +'iota' => array( 'input'=>'iota','tag'=>'mi', 'output'=>'&#' . hexdec('03B9') . ';'), +'kappa' => array( 'input'=>'kappa','tag'=>'mi', 'output'=>'&#' . hexdec('03BA') . ';'), +'lambda' => array( 'input'=>'lambda','tag'=>'mi', 'output'=>'&#' . hexdec('03BB') . ';'), +'Lambda' => array( 'input'=>'Lambda','tag'=>'mo', 'output'=>'&#' . hexdec('039B') . ';'), +'mu' => array( 'input'=>'mu','tag'=>'mi', 'output'=>'&#' . hexdec('03BC') . ';'), +'nu' => array( 'input'=>'nu','tag'=>'mi', 'output'=>'&#' . hexdec('03BD') . ';'), +'omega' => array( 'input'=>'omega','tag'=>'mi', 'output'=>'&#' . hexdec('03C9') . ';'), +'Omega' => array( 'input'=>'Omega','tag'=>'mo', 'output'=>'&#' . hexdec('03A9') . ';'), +'phi' => array( 'input'=>'phi','tag'=>'mi', 'output'=>'&#' . hexdec('03C6') . ';'), +'varphi' => array( 'input'=>'varphi','tag'=>'mi', 'output'=>'&#' . hexdec('03D5') . ';'), +'Phi' => array( 'input'=>'Phi','tag'=>'mo', 'output'=>'&#' . hexdec('03A6') . ';'), +'pi' => array( 'input'=>'pi','tag'=>'mi', 'output'=>'&#' . hexdec('03C0') . ';'), +'Pi' => array( 'input'=>'Pi','tag'=>'mo', 'output'=>'&#' . hexdec('03A0') . ';'), +'psi' => array( 'input'=>'psi','tag'=>'mi', 'output'=>'&#' . hexdec('03C8') . ';'), +'rho' => array( 'input'=>'rho','tag'=>'mi', 'output'=>'&#' . hexdec('03C1') . ';'), +'sigma' => array( 'input'=>'sigma','tag'=>'mi', 'output'=>'&#' . hexdec('03C3') . ';'), +'Sigma' => array( 'input'=>'Sigma','tag'=>'mo', 'output'=>'&#' . hexdec('03A3') . ';'), +'tau' => array( 'input'=>'tau','tag'=>'mi', 'output'=>'&#' . hexdec('03C4') . ';'), +'theta' => array( 'input'=>'theta','tag'=>'mi', 'output'=>'&#' . hexdec('03B8') . ';'), +'vartheta' => array( 'input'=>'vartheta','tag'=>'mi', 'output'=>'&#' . hexdec('03D1') . ';'), +'Theta' => array( 'input'=>'Theta','tag'=>'mo', 'output'=>'&#' . hexdec('0398') . ';'), +'upsilon' => array( 'input'=>'upsilon','tag'=>'mi', 'output'=>'&#' . hexdec('03C5') . ';'), +'xi' => array( 'input'=>'xi','tag'=>'mi', 'output'=>'&#' . hexdec('03BE') . ';'), +'Xi' => array( 'input'=>'alpha','tag'=>'mo', 'output'=>'&#' . hexdec('039E') . ';'), +'zeta' => array( 'input'=>'zeta','tag'=>'mi', 'output'=>'&#' . hexdec('03B6') . ';'), + +// Binary operation symbols +'*' => array( 'input'=>'*','tag'=>'mo', 'output'=>'&#' . hexdec('22C5') . ';'), +'**' => array( 'input'=>'**','tag'=>'mo', 'output'=>'&#' . hexdec('22C6') . ';'), +'//' => array( 'input'=>'//','tag'=>'mo', 'output'=>'/'), +'\\\\' => array( 'input'=>'\\\\','tag'=>'mo', 'output'=>'\\'), +'xx' => array( 'input'=>'xx','tag'=>'mo', 'output'=>'&#' . hexdec('00D7') . ';'), +'-:' => array( 'input'=>'-:','tag'=>'mo', 'output'=>'&#' . hexdec('00F7') . ';'), +'@' => array( 'input'=>'@','tag'=>'mo', 'output'=>'&#' . hexdec('2218') . ';'), +'o+' => array( 'input'=>'o+','tag'=>'mo', 'output'=>'&#' . hexdec('2295') . ';'), +'ox' => array( 'input'=>'ox','tag'=>'mo', 'output'=>'&#' . hexdec('2297') . ';'), +'sum' => array( 'input'=>'sum','tag'=>'mo', 'output'=>'&#' . hexdec('2211') . ';', 'underover'=>TRUE), +'prod' => array( 'input'=>'prod','tag'=>'mo', 'output'=>'&#' . hexdec('220F') . ';', 'underover'=>TRUE), +'^^' => array( 'input'=>'^^','tag'=>'mo', 'output'=>'&#' . hexdec('2227') . ';'), +'^^^' => array( 'input'=>'^^^','tag'=>'mo', 'output'=>'&#' . hexdec('22C0') . ';', 'underover'=>TRUE), +'vv' => array( 'input'=>'vv','tag'=>'mo', 'output'=>'&#' . hexdec('2228') . ';'), +'vvv' => array( 'input'=>'vvv','tag'=>'mo', 'output'=>'&#' . hexdec('22C1') . ';', 'underover'=>TRUE), +'nn' => array( 'input'=>'nn','tag'=>'mo', 'output'=>'&#' . hexdec('2229') . ';'), +'nnn' => array( 'input'=>'nnn','tag'=>'mo', 'output'=>'&#' . hexdec('22C5') . ';', 'underover'=>TRUE), +'uu' => array( 'input'=>'uu','tag'=>'mo', 'output'=>'&#' . hexdec('222A') . ';'), +'uuu' => array( 'input'=>'uuu','tag'=>'mo', 'output'=>'&#' . hexdec('22C3') . ';', 'underover'=>TRUE), + +// Binary relation symbols +'!=' => array( 'input'=>'!=','tag'=>'mo', 'output'=>'&#' . hexdec('2260') . ';'), +':=' => array( 'input'=>':=','tag'=>'mo', 'output'=>':=' ), /* 2005-06-05 wes */ +'<' => array( 'input'=>'<','tag'=>'mo', 'output'=>'<'), +'lt' => array( 'input'=>'lt','tag'=>'mo', 'output'=>'<'), /* 2005-06-05 wes */ +'<=' => array( 'input'=>'<=','tag'=>'mo', 'output'=>'&#' . hexdec('2264') . ';'), +'lt=' => array( 'input'=>'lt=','tag'=>'mo', 'output'=>'&#' . hexdec('2264') . ';'), +'le' => array( 'input'=>'le','tag'=>'mo', 'output'=>'&#' . hexdec('2264') . ';'), /* 2005-06-05 wes */ +'>' => array( 'input'=>'>','tag'=>'mo', 'output'=>'>'), +'>=' => array( 'input'=>'>=','tag'=>'mo', 'output'=>'&#' . hexdec('2265') . ';'), +'qeq' => array( 'input'=>'geq','tag'=>'mo', 'output'=>'&#' . hexdec('2265') . ';'), +'-<' => array( 'input'=>'-<','tag'=>'mo', 'output'=>'&#' . hexdec('227A') . ';'), +'-lt' => array( 'input'=>'-lt','tag'=>'mo', 'output'=>'&#' . hexdec('227A') . ';'), +'>-' => array( 'input'=>'>-','tag'=>'mo', 'output'=>'&#' . hexdec('227B') . ';'), +'in' => array( 'input'=>'in','tag'=>'mo', 'output'=>'&#' . hexdec('2208') . ';'), +'!in' => array( 'input'=>'!in','tag'=>'mo', 'output'=>'&#' . hexdec('2209') . ';'), +'sub' => array( 'input'=>'sub','tag'=>'mo', 'output'=>'&#' . hexdec('2282') . ';'), +'sup' => array( 'input'=>'sup','tag'=>'mo', 'output'=>'&#' . hexdec('2283') . ';'), +'sube' => array( 'input'=>'sube','tag'=>'mo', 'output'=>'&#' . hexdec('2286') . ';'), +'supe' => array( 'input'=>'supe','tag'=>'mo', 'output'=>'&#' . hexdec('2287') . ';'), +'-=' => array( 'input'=>'-=','tag'=>'mo', 'output'=>'&#' . hexdec('2261') . ';'), +'~=' => array( 'input'=>'~=','tag'=>'mo', 'output'=>'&#' . hexdec('2245') . ';'), +'~~' => array( 'input'=>'~~','tag'=>'mo', 'output'=>'&#' . hexdec('2248') . ';'), +'prop' => array( 'input'=>'prop','tag'=>'mo', 'output'=>'&#' . hexdec('221D') . ';'), + +// Logical symbols +'and' => array( 'input'=>'and','tag'=>'mtext', 'output'=>'and', 'space'=>'1ex'), +'or' => array( 'input'=>'or','tag'=>'mtext', 'output'=>'or', 'space'=>'1ex'), +'not' => array( 'input'=>'not','tag'=>'mo', 'output'=>'&#' . hexdec('00AC') . ';'), +'=>' => array( 'input'=>'=>','tag'=>'mo', 'output'=>'&#' . hexdec('21D2') . ';'), +'if' => array( 'input'=>'if','tag'=>'mo', 'output'=>'if', 'space'=>'1ex'), +'iff' => array( 'input'=>'iff','tag'=>'mo', 'output'=>'&#' . hexdec('21D4') . ';'), +'<=>' => array( 'input'=>'iff','tag'=>'mo', 'output'=>'&#' . hexdec('21D4') . ';'), /* 2005-06-07 wes */ +'AA' => array( 'input'=>'AA','tag'=>'mo', 'output'=>'&#' . hexdec('2200') . ';'), +'EE' => array( 'input'=>'EE','tag'=>'mo', 'output'=>'&#' . hexdec('2203') . ';'), +'_|_' => array( 'input'=>'_|_','tag'=>'mo', 'output'=>'&#' . hexdec('22A5') . ';'), +'TT' => array( 'input'=>'TT','tag'=>'mo', 'output'=>'&#' . hexdec('22A4') . ';'), +'|-' => array( 'input'=>'|-','tag'=>'mo', 'output'=>'&#' . hexdec('22A2') . ';'), +'|=' => array( 'input'=>'|=','tag'=>'mo', 'output'=>'&#' . hexdec('22A8') . ';'), + +// Miscellaneous symbols +'ang' => array('input'=>'ang','tag'=>'mo','output'=>'&#' . hexdec('2220') . ';'), +'deg' => array('input'=>'deg','tag'=>'mo','output'=>'&#' . hexdec('00B0') . ';'), +'int' => array( 'input'=>'int','tag'=>'mo', 'output'=>'&#' . hexdec('222B') . ';'), +'dx' => array( 'input'=>'dx','tag'=>'mi', 'output'=>'{:d x:}', 'definition'=>TRUE), /* 2005-06-11 wes */ +'dy' => array( 'input'=>'dy','tag'=>'mi', 'output'=>'{:d y:}', 'definition'=>TRUE), /* 2005-06-11 wes */ +'dz' => array( 'input'=>'dz','tag'=>'mi', 'output'=>'{:d z:}', 'definition'=>TRUE), /* 2005-06-11 wes */ +'dt' => array( 'input'=>'dt','tag'=>'mi', 'output'=>'{:d t:}', 'definition'=>TRUE), /* 2005-06-11 wes */ +'oint' => array( 'input'=>'oint','tag'=>'mo', 'output'=>'&#' . hexdec('222E') . ';'), +'del' => array( 'input'=>'del','tag'=>'mo', 'output'=>'&#' . hexdec('2202') . ';'), +'grad' => array( 'input'=>'grad','tag'=>'mo', 'output'=>'&#' . hexdec('2207') . ';'), +'+-' => array( 'input'=>'+-','tag'=>'mo', 'output'=>'&#' . hexdec('00B1') . ';'), +'O/' => array( 'input'=>'0/','tag'=>'mo', 'output'=>'&#' . hexdec('2205') . ';'), +'oo' => array( 'input'=>'oo','tag'=>'mo', 'output'=>'&#' . hexdec('221E') . ';'), +'aleph' => array( 'input'=>'aleph','tag'=>'mo', 'output'=>'&#' . hexdec('2135') . ';'), +'...' => array( 'input'=>'int','tag'=>'mo', 'output'=>'...'), +'~' => array( 'input'=>'!~','tag'=>'mo', 'output'=>'&#' . hexdec('0020') . ';'), +'\\ ' => array( 'input'=>'~','tag'=>'mo', 'output'=>'&#' . hexdec('00A0') . ';'), +'quad' => array( 'input'=>'quad','tag'=>'mo', 'output'=>'&#' . hexdec('00A0') . ';&#' . hexdec('00A0') . ';'), +'qquad' => array( 'input'=>'qquad','tag'=>'mo', 'output'=> '&#' . hexdec('00A0') . ';&#' . hexdec('00A0') . ';&#' . hexdec('00A0') . ';'), +'cdots' => array( 'input'=>'cdots','tag'=>'mo', 'output'=>'&#' . hexdec('22EF') . ';'), +'vdots' => array( 'input'=>'vdots','tag'=>'mo', 'output'=>'&#' . hexdec('22EE') . ';'), /* 2005-06-11 wes */ +'ddots' => array( 'input'=>'ddots','tag'=>'mo', 'output'=>'&#' . hexdec('22F1') . ';'), /* 2005-06-11 wes */ +'diamond' => array( 'input'=>'diamond','tag'=>'mo', 'output'=>'&#' . hexdec('22C4') . ';'), +'square' => array( 'input'=>'square','tag'=>'mo', 'output'=>'&#' . hexdec('25A1') . ';'), +'|_' => array( 'input'=>'|_','tag'=>'mo', 'output'=>'&#' . hexdec('230A') . ';'), +'_|' => array( 'input'=>'_|','tag'=>'mo', 'output'=>'&#' . hexdec('230B') . ';'), +'|~' => array( 'input'=>'|~','tag'=>'mo', 'output'=>'&#' . hexdec('2308') . ';'), +'~|' => array( 'input'=>'~|','tag'=>'mo', 'output'=>'&#' . hexdec('2309') . ';'), +'CC' => array( 'input'=>'CC','tag'=>'mo', 'output'=>'&#' . hexdec('2102') . ';'), +'NN' => array( 'input'=>'NN','tag'=>'mo', 'output'=>'&#' . hexdec('2115') . ';'), +'QQ' => array( 'input'=>'QQ','tag'=>'mo', 'output'=>'&#' . hexdec('211A') . ';'), +'RR' => array( 'input'=>'RR','tag'=>'mo', 'output'=>'&#' . hexdec('211D') . ';'), +'ZZ' => array( 'input'=>'ZZ','tag'=>'mo', 'output'=>'&#' . hexdec('2124') . ';'), + +// Standard functions +'lim' => array( 'input'=>'lim','tag'=>'mo', 'output'=>'lim', 'underover'=>TRUE), +'Lim' => array( 'input'=>'Lim','tag'=>'mo', 'output'=>'Lim', 'underover'=>TRUE), /* 2005-06-11 wes */ +'sin' => array( 'input'=>'sin','tag'=>'mo', 'output'=>'sin', 'unary'=>TRUE, 'func'=>TRUE), +'cos' => array( 'input'=>'cos', 'tag'=>'mo', 'output'=>'cos', 'unary'=>TRUE, 'func'=>TRUE), +'tan' => array( 'input'=>'tan', 'tag'=>'mo', 'output'=>'tan', 'unary'=>TRUE, 'func'=>TRUE), +'arcsin' => array( 'input'=>'arcsin','tag'=>'mo', 'output'=>'arcsin', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL +'arccos' => array( 'input'=>'arccos', 'tag'=>'mo', 'output'=>'arccos', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL +'arctan' => array( 'input'=>'arctan', 'tag'=>'mo', 'output'=>'arctan', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL +'sinh' => array( 'input'=>'sinh','tag'=>'mo', 'output'=>'sinh', 'unary'=>TRUE, 'func'=>TRUE), +'cosh' => array( 'input'=>'cosh', 'tag'=>'mo', 'output'=>'cosh', 'unary'=>TRUE, 'func'=>TRUE), +'tanh' => array( 'input'=>'tanh', 'tag'=>'mo', 'output'=>'tanh', 'unary'=>TRUE, 'func'=>TRUE), +'cot' => array( 'input'=>'cot','tag'=>'mo', 'output'=>'cot', 'unary'=>TRUE, 'func'=>TRUE), +'sec' => array( 'input'=>'sec', 'tag'=>'mo', 'output'=>'sec', 'unary'=>TRUE, 'func'=>TRUE), +'csc' => array( 'input'=>'csc', 'tag'=>'mo', 'output'=>'csc', 'unary'=>TRUE, 'func'=>TRUE), +'coth' => array( 'input'=>'coth','tag'=>'mo', 'output'=>'coth', 'unary'=>TRUE, 'func'=>TRUE), +'sech' => array( 'input'=>'sech', 'tag'=>'mo', 'output'=>'sech', 'unary'=>TRUE, 'func'=>TRUE), +'csch' => array( 'input'=>'csch', 'tag'=>'mo', 'output'=>'csch', 'unary'=>TRUE, 'func'=>TRUE), +'log' => array( 'input'=>'log', 'tag'=>'mo', 'output'=>'log', 'unary'=>TRUE, 'func'=>TRUE), +'ln' => array( 'input'=>'ln', 'tag'=>'mo', 'output'=>'ln', 'unary'=>TRUE, 'func'=>TRUE), +'det' => array( 'input'=>'det', 'tag'=>'mo', 'output'=>'det', 'unary'=>TRUE, 'func'=>TRUE), +'dim' => array( 'input'=>'dim', 'tag'=>'mo', 'output'=>'dim'), +'mod' => array( 'input'=>'mod', 'tag'=>'mo', 'output'=>'mod'), +'gcd' => array( 'input'=>'gcd', 'tag'=>'mo', 'output'=>'gcd', 'unary'=>TRUE, 'func'=>TRUE), +'lcm' => array( 'input'=>'lcm', 'tag'=>'mo', 'output'=>'lcm', 'unary'=>TRUE, 'func'=>TRUE), +'lub' => array( 'input'=>'lub', 'tag'=>'mo', 'output'=>'lub'), /* 2005-06-11 wes */ +'glb' => array( 'input'=>'glb', 'tag'=>'mo', 'output'=>'glb'), /* 2005-06-11 wes */ +'min' => array( 'input'=>'min', 'tag'=>'mo', 'output'=>'min', 'underover'=>TRUE), /* 2005-06-11 wes */ +'max' => array( 'input'=>'max', 'tag'=>'mo', 'output'=>'max', 'underover'=>TRUE), /* 2005-06-11 wes */ +'f' => array( 'input'=>'f','tag'=>'mi', 'output'=>'f', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL +'g' => array( 'input'=>'g', 'tag'=>'mi', 'output'=>'g', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL + +// Arrows +'uarr' => array( 'input'=>'uarr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2191') . ';'), +'darr' => array( 'input'=>'darr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2193') . ';'), +'rarr' => array( 'input'=>'rarr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2192') . ';'), +'->' => array( 'input'=>'->', 'tag'=>'mo', 'output'=>'&#' . hexdec('2192') . ';'), +'|->' => array( 'input'=>'|->', 'tag'=>'mo', 'output'=>'&#' . hexdec('21A6') . ';'), /* 2005-06-11 wes */ +'larr' => array( 'input'=>'larr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2190') . ';'), +'harr' => array( 'input'=>'harr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2194') . ';'), +'rArr' => array( 'input'=>'rArr', 'tag'=>'mo', 'output'=>'&#' . hexdec('21D2') . ';'), +'lArr' => array( 'input'=>'lArr', 'tag'=>'mo', 'output'=>'&#' . hexdec('21D0') . ';'), +'hArr' => array( 'input'=>'hArr', 'tag'=>'mo', 'output'=>'&#' . hexdec('21D4') . ';'), + +// Commands with argument +'sqrt' => array( 'input'=>'sqrt', 'tag'=>'msqrt', 'output'=>'sqrt', 'unary'=>TRUE ), +'root' => array( 'input'=>'root', 'tag'=>'mroot', 'output'=>'root', 'binary'=>TRUE ), +'frac' => array( 'input'=>'frac', 'tag'=>'mfrac', 'output'=>'/', 'binary'=>TRUE), +'/' => array( 'input'=>'/', 'tag'=>'mfrac', 'output'=>'/', 'infix'=>TRUE), +'_' => array( 'input'=>'_', 'tag'=>'msub', 'output'=>'_', 'infix'=>TRUE), +'^' => array( 'input'=>'^', 'tag'=>'msup', 'output'=>'^', 'infix'=>TRUE), +'hat' => array( 'input'=>'hat', 'tag'=>'mover', 'output'=>'&#' . hexdec('005E') . ';', 'unary'=>TRUE, 'acc'=>TRUE), +'bar' => array( 'input'=>'bar', 'tag'=>'mover', 'output'=>'&#' . hexdec('00AF') . ';', 'unary'=>TRUE, 'acc'=>TRUE), +'vec' => array( 'input'=>'vec', 'tag'=>'mover', 'output'=>'&#' . hexdec('2192') . ';', 'unary'=>TRUE, 'acc'=>TRUE), +'dot' => array( 'input'=>'dot', 'tag'=>'mover', 'output'=>'.', 'unary'=>TRUE, 'acc'=>TRUE), +'ddot' => array( 'input'=>'ddot', 'tag'=>'mover', 'output'=>'..', 'unary'=>TRUE, 'acc'=>TRUE), +'ul' => array( 'input'=>'ul', 'tag'=>'munder', 'output'=>'&#' . hexdec('0332') . ';', 'unary'=>TRUE, 'acc'=>TRUE), +'avec' => array( 'input'=>'avec', 'tag'=>'munder', 'output'=>'~', 'unary'=>TRUE, 'acc'=>TRUE), +'text' => array( 'input'=>'text', 'tag'=>'mtext', 'output'=>'text', 'unary'=>TRUE), +'mbox' => array( 'input'=>'mbox', 'tag'=>'mtext', 'output'=>'mbox', 'unary'=>TRUE), +'"' => array( 'input'=>'"', 'tag'=>'mtext','output'=>'mbox', 'unary'=>TRUE), + +/* 2005-06-05 wes: added stackrel */ +'stackrel' => array( 'input'=>'stackrel', 'tag'=>'mover', 'output'=>'stackrel', 'binary'=>TRUE), + +// Grouping brackets +'(' => array( 'input'=>'(', 'tag'=>'mo', 'output'=>'(', 'left_bracket'=>TRUE), +')' => array( 'input'=>')', 'tag'=>'mo', 'output'=>')', 'right_bracket'=>TRUE), +'[' => array( 'input'=>'[', 'tag'=>'mo', 'output'=>'[', 'left_bracket'=>TRUE), +']' => array( 'input'=>']', 'tag'=>'mo', 'output'=>']', 'right_bracket'=>TRUE), +'{' => array( 'input'=>'{', 'tag'=>'mo', 'output'=>'{', 'left_bracket'=>TRUE), +'}' => array( 'input'=>'}', 'tag'=>'mo', 'output'=>'}', 'right_bracket'=>TRUE), +'(:' => array( 'input'=>'(:', 'tag'=>'mo', 'output'=>'&#' . hexdec('2329') . ';', 'left_bracket'=>TRUE), +':)' => array( 'input'=>':)', 'tag'=>'mo', 'output'=>'&#' . hexdec('232A') . ';', 'right_bracket'=>TRUE), +'{:' => array( 'input'=>'{:', 'tag'=>'mo', 'output'=>'{:', 'left_bracket'=>TRUE, 'invisible'=>TRUE), +':}' => array( 'input'=>':}', 'tag'=>'mo', 'output'=>':}', 'right_bracket'=>TRUE ,'invisible'=>TRUE), +'<<' => array( 'input'=>'<<', 'tag'=>'mo', 'output'=>'&#' . hexdec('2329') . ';', 'left_bracket'=>TRUE), // 2005-06-07 wes +'>>' => array( 'input'=>'>>', 'tag'=>'mo', 'output'=>'&#' . hexdec('232A') . ';', 'right_bracket'=>TRUE) // 2005-06-07 wes +); + +?> \ No newline at end of file diff --git a/examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php b/examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php new file mode 100644 index 0000000..5fb1060 --- /dev/null +++ b/examples/includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php @@ -0,0 +1,1119 @@ + made to bring ASCIIMathPHP up to + * ASCIIMath 1.4.7 functionality. + * -- Added parseIntExpr, for intermediate expression parsing rule, allowing x^2/x^3 to render as (x^2)/(x^3) + * -- Added quotes as another way of designating text; "hello" is equivalent to text(hello) + * -- Added FUNC designator to allow sin, cos, etc to act as functions, so sin(x)/x renders as {sin(x)}/x + * + * Ver 1.11 + * -- Fixed bug that stopped script execution for incomplete expressions + * -- Changed the algorithm for parsing expressions so that it matches the longest string possible (greedy) + * + * Ver 1.10 + * -- Added definition support + * -- Added stackrel support + * -- Added a bunch of different symbols etc. >>, << and definitions like dx, dy, dz etc. + * + * Ver 1.02 + * -- Fixed bug with mbox and text + * -- Fixed spacing bug with mbox and text + * + * Ver 1.01 + * -- Fixed Bug that did not parse symbols greater than a single character + * correctly when appearing at end of expression. + * + ***/ + +class XMLNode +{ + // Private variables + var $_id; + var $_name; + var $_content; + var $_mt_elem_flg; + var $_attr_arr; + var $_child_arr; + var $_nmspc; + var $_nmspc_alias; + var $_parent_id; + var $_parent_node; + + function XMLNode($id = NULL) + { + $this->_id = isset($id) ? $id : md5(uniqid(rand(),1)); + $this->_name = ''; + $this->_content = ''; + $this->_mt_elem_flg = FALSE; + $this->_attr_arr = array(); + $this->_child_arr = array(); + $this->_nmspc = ''; + $this->_nmspc_alias = ''; + $this->_parent_id = FALSE; + $this->_parent_node = NULL; + } + + function addChild(&$node) + { + $this->_child_arr[$node->getId()] = $node; + $node->setParentId($this->_id); + $node->setParentNode($this); + } + + function addChildArr(&$node_arr) + { + $key_arr = array_keys($node_arr); + $num_key = count($key_arr); + + for ($i = 0; $i < $num_key; $i++) { + $node = $node_arr[$key_arr[$i]]; + $this->addChild($node); + } + } + + function insertChildBefore($idx,&$node) + { + $key_arr = array_keys($this->_child_arr); + $num_key = count($key_arr); + $tmp_arr = arry(); + + for ($i = 0;$i < $num_key;$i++) { + if ($i == $idx) { + $tmp_arr[$node->getId()] = $node; + } + $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]]; + } + $this->_child_arr = $tmp_arr; + } + + function insertChildAfter($idx,&$node) + { + $key_arr = array_keys($this->_child_arr); + $num_key = count($key_arr); + $tmp_arr = arry(); + + for ($i = 0;$i < $num_key;$i++) { + $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]]; + if ($i == $idx) { + $tmp_arr[$node->getId()] = $node; + } + } + $this->_child_arr = $tmp_arr; + } + + function setId($id) + { + $this->_id = $id; + } + + function setName($name) + { + $this->_name = $name; + } + + function setNamepace($nmspc) + { + $this->_nmspc = $nmspc; + } + + function setNamespaceAlias($nmspc_alias) + { + $this->_nmspc_alias = $nmspc_alias; + } + + function setContent($content) + { + $this->_content = $content; + } + + function setEmptyElem($mt_elem_flg) + { + $this->_mt_elem_flg = $mt_elem_flg; + } + + function setAttr($attr_nm,$attr_val) + { + $this->_attr_arr[$attr_nm] = $attr_val; + } + + function setAttrArr($attr_arr) + { + $this->_attr_arr = $attr_arr; + } + + function setParentId($id) + { + $this->_parent_id = $id; + } + + function setParentNode(&$node) + { + $this->_parent_node = $node; + } + + function getId() + { + return($this->_id); + } + + function getName() + { + return($this->_name); + } + + function getNamespace() + { + return($this->_nmspc); + } + + function getNamespaceAlias() + { + return($this->_nmspc_alias); + } + + function getContent() + { + return($this->_content); + } + + function getAttr($attr_nm) + { + if (isset($this->_attr_arr[$attr_nm])) { + return($this->_attr_arr[$attr_nm]); + } else { + return(NULL); + } + } + + function getAttrArr() + { + return($this->_attr_arr); + } + + function getParentId() + { + return($this->parent_id); + } + + function getParentNode() + { + return($this->_parent_node); + } + + function getChild($id) + { + if (isset($this->_child_arr[$id])) { + return($this->_child_arr[$id]); + } else { + return(FALSE); + } + } + + function getFirstChild() + { + $id_arr = array_keys($this->_child_arr); + $num_child = count($id_arr); + + if ($num_child > 0) { + return($this->_child_arr[$id_arr[0]]); + } else { + return(FALSE); + } + } + + function getLastChild() + { + $id_arr = array_keys($this->_child_arr); + $num_child = count($id_arr); + + if ($num_child > 0) { + return($this->_child_arr[$id_arr[$num_child - 1]]); + } else { + return(FALSE); + } + } + + function getChildByIdx($idx) + { + $id_arr = array_keys($this->_child_arr); + + if (isset($this->_child_arr[$id_arr[$idx]])) { + return($this->_child_arr[$id_arr[$idx]]); + } else { + return(FALSE); + } + } + + function getNumChild() + { + return(count($this->_child_arr)); + } + + function removeChild($id) + { + unset($this->_child_arr[$id]); + } + + function removeChildByIdx($idx) + { + $key_arr = array_keys($this->_child_arr); + unset($this->_child_arr[$key_arr[$idx]]); + } + + function removeFirstChild() + { + $key_arr = array_keys($this->_child_arr); + unset($this->_child_arr[$key_arr[0]]); + } + + function removeLastChild() + { + $key_arr = array_keys($this->_child_arr); + unset($this->_child_arr[$key_arr[count($key_arr)-1]]); + } + + function dumpXML($indent_str = "\t") + { + $attr_txt = $this->_dumpAttr(); + $name = $this->_dumpName(); + $xmlns = $this->_dumpXmlns(); + $lvl = $this->_getCurrentLevel(); + $indent = str_pad('',$lvl,$indent_str); + + if ($this->_mt_elem_flg) { + $tag = "$indent<$name$xmlns$attr_txt />"; + return($tag); + } else { + $key_arr = array_keys($this->_child_arr); + $num_child = count($key_arr); + + $tag = "$indent<$name$xmlns$attr_txt>$this->_content"; + + for ($i = 0;$i < $num_child;$i++) { + $node = $this->_child_arr[$key_arr[$i]]; + + $child_txt = $node->dumpXML($indent_str); + $tag .= "\n$child_txt"; + } + + $tag .= ($num_child > 0 ? "\n$indent" : ""); + return($tag); + } + } + + function _dumpAttr() + { + $id_arr = array_keys($this->_attr_arr); + $id_arr_cnt = count($id_arr); + $attr_txt = ''; + + for($i = 0;$i < $id_arr_cnt;$i++) { + $key = $id_arr[$i]; + $attr_txt .= " $key=\"{$this->_attr_arr[$key]}\""; + } + + return($attr_txt); + } + + function _dumpName() + { + $alias = $this->getNamespaceAlias(); + if ($alias == '') { + return($this->getName()); + } else { + return("$alias:" . $this->getName()); + } + } + + function _dumpXmlns() + { + $nmspc = $this->getNamespace(); + $alias = $this->getNamespaceAlias(); + + if ($nmspc != '') { + if ($alias == '') { + return(" xmlns=\"" . $nmspc . "\""); + } else { + return(" xmlns:$alias=\"" . $nmspc . "\""); + } + } else { + return(''); + } + } + + function _getCurrentLevel() + { + if ($this->_parent_id === FALSE) { + return(0); + } else { + $node = $this->getParentNode(); + $lvl = $node->_getCurrentLevel(); + $lvl++; + return($lvl); + } + } +} + +class MathMLNode extends XMLNode +{ + function MathMLNode($id = NULL) + { + parent::XMLNode($id); + } + + function removeBrackets() + { + if ($this->_name == 'mrow') { + if ($c_node_0 = $this->getFirstChild()) { + $c_node_0->isLeftBracket() ? $this->removeFirstChild() : 0; + } + + if ($c_node_0 = $this->getLastChild()) { + $c_node_0->isRightBracket() ? $this->removeLastChild() : 0; + } + } + } + + function isLeftBracket() + { + switch ($this->_content) { + case '{': + case '[': + case '(': + return(TRUE); + break; + } + return(FALSE); + } + + function isRightBracket() + { + switch ($this->_content) { + case '}': + case ']': + case ')': + return(TRUE); + break; + } + return(FALSE); + } +} + +class ASCIIMathPHP +{ + var $_expr; + var $_curr_expr; + var $_prev_expr; + var $_symbol_arr; + var $_node_arr; + var $_node_cntr; + + function ASCIIMathPHP($symbol_arr,$expr = NULL) + { + $this->_symbol_arr = $symbol_arr; + if (isset($expr)) { + $this->setExpr($expr); + } + } + + /** + * Returns an empty node (containing a non-breaking space) 26-Apr-2006 + * + * Used when an expression is incomplete + * + * @return object + * + * @access private + */ + function emptyNode() + { + $tmp_node = $this->createNode(); + $tmp_node->setName('mn'); + $tmp_node->setContent('&#' . hexdec('200B') . ';'); + return $tmp_node; + } + + function pushExpr($prefix) // 2005-06-11 wes + { + $this->_curr_expr = $prefix . $this->_curr_expr; + } + + function setExpr($expr) + { + $this->_expr = $expr; + $this->_curr_expr = $expr; + $this->_prev_expr = $expr; + + $this->_node_arr = array(); + $this->_node_cntr = 0; + } + + function genMathML($attr_arr = NULL) + { + // node + $node_0 = $this->createNode(); + $node_0->setName('math'); + $node_0->setNamepace('http://www.w3.org/1998/Math/MathML'); + + // node + if (isset($attr_arr)) { + $node_1 = $this->createNode(); + $node_1->setName('mstyle'); + $node_1->setAttrArr($attr_arr); + + $node_arr = $this->parseExpr(); + + $node_1->addChildArr($node_arr); + $node_0->addChild($node_1); + } else { + $node_arr = $this->parseExpr(); + $node_0->addChildArr($node_arr); + } + + return TRUE; + } + + /* + function mergeNodeArr(&$node_arr_0,&$node_arr_1) + { + $key_arr_0 = array_keys($node_arr_0); + $key_arr_1 = array_keys($node_arr_1); + + $num_key_0 = count($key_arr_0); + $num_key_1 = count($key_arr_1); + + $merge_arr = array(); + + for ($i = 0;$i < $num_key_0;$i++) { + $merge_arr[$key_arr_0[$i]] = $node_arr_0[$key_arr_0[$i]]; + } + + for ($j = 0;$j < $num_key_1;$i++) { + $merge_arr[$key_arr_1[$i]] = $node_arr_1[$key_arr_1[$i]]; + } + + return($merge_arr); + } + */ + + //Broken out of parseExpr Sept 7, 2006 David Lippman for + //ASCIIMathML 1.4.7 compatibility + function parseIntExpr() + { + $sym_0 = $this->getSymbol(); + $node_0 = $this->parseSmplExpr(); + $sym = $this->getSymbol(); + + if (isset($sym['infix']) && $sym['input'] != '/') { + $this->chopExpr($sym['symlen']); + $node_1 = $this->parseSmplExpr(); + + if ($node_1 === FALSE) { //show box in place of missing argument + $node_1 = $this->emptyNode();//?? + } else { + $node_1->removeBrackets(); + } + + // If 'sub' -- subscript + if ($sym['input'] == '_') { + + $sym_1 = $this->getSymbol(); + + // If 'sup' -- superscript + if ($sym_1['input'] == '^') { + $this->chopExpr($sym_1['symlen']); + $node_2 = $this->parseSmplExpr(); + $node_2->removeBrackets(); + + $node_3 = $this->createNode(); + $node_3->setName(isset($sym_0['underover']) ? 'munderover' : 'msubsup'); + $node_3->addChild($node_0); + $node_3->addChild($node_1); + $node_3->addChild($node_2); + + $node_4 = $this->createNode(); + $node_4->setName('mrow'); + $node_4->addChild($node_3); + + return $node_4; + } else { + $node_2 = $this->createNode(); + $node_2->setName(isset($sym_0['underover']) ? 'munder' : 'msub'); + $node_2->addChild($node_0); + $node_2->addChild($node_1); + + return $node_2; + } + } else { + $node_2 = $this->createNode(); + $node_2->setName($sym['tag']); + $node_2->addChild($node_0); + $node_2->addChild($node_1); + + return($node_2); + } + } elseif ($node_0 !== FALSE) { + return($node_0); + } else { + return $this->emptyNode(); + } + + } + + function parseExpr() + { + // Child/Fragment array + $node_arr = array(); + + // Deal whole expressions like 'ax + by + c = 0' etc. + do { + $sym_0 = $this->getSymbol(); + $node_0 = $this->parseIntExpr(); + $sym = $this->getSymbol(); + // var_dump($sym); + + if (isset($sym['infix']) && $sym['input'] == '/') { + $this->chopExpr($sym['symlen']); + $node_1 = $this->parseIntExpr(); + + if ($node_1 === FALSE) { //should show box in place of missing argument + $node_1 = $this->emptyNode(); + continue; + } + + $node_1->removeBrackets(); + + // If 'div' -- divide + $node_0->removeBrackets(); + $node_2 = $this->createNode(); + $node_2->setName($sym['tag']); + $node_2->addChild($node_0); + $node_2->addChild($node_1); + $node_arr[$node_2->getId()] = $node_2; + + } elseif ($node_0 !== FALSE) { + $node_arr[$node_0->getId()] = $node_0; + } + } while (!isset($sym['right_bracket']) && $sym !== FALSE && $sym['output'] != ''); + + //var_dump($sym); + // Possibly to deal with matrices + if (isset($sym['right_bracket'])) { + $node_cnt = count($node_arr); + $key_node_arr = array_keys($node_arr); + + if ($node_cnt > 1) { + $node_5 = $node_arr[$key_node_arr[$node_cnt-1]]; + $node_6 = $node_arr[$key_node_arr[$node_cnt-2]]; + } else { + $node_5 = FALSE; + $node_6 = FALSE; + } + + // Dealing with matrices + if ($node_5 !== FALSE && $node_6 !== FALSE && + $node_cnt > 1 && + $node_5->getName() == 'mrow' && + $node_6->getName() == 'mo' && + $node_6->getContent() == ',') { + + // Checking if Node 5 has a LastChild + if ($node_7 = $node_5->getLastChild()) { + $node_7_cntnt = $node_7->getContent(); + } else { + $node_7_cntnt = FALSE; + } + + // If there is a right bracket + if ($node_7 !== FALSE && ($node_7_cntnt == ']' || $node_7_cntnt == ')')) { + + // Checking if Node 5 has a firstChild + if ($node_8 = $node_5->getFirstChild()) { + $node_8_cntnt = $node_8->getContent(); + } else { + $node_8_cntnt = FALSE; + } + + // If there is a matching left bracket + if ($node_8 !== FALSE && + (($node_8_cntnt == '(' && $node_7_cntnt == ')' && $sym['output'] != '}') || + ($node_8_cntnt == '[' && $node_7_cntnt == ']'))) { + + $is_mtrx_flg = TRUE; + $comma_pos_arr = array(); + + $i = 0; + + while ($i < $node_cnt && $is_mtrx_flg) { + $tmp_node = $node_arr[$key_node_arr[$i]]; + + if($tmp_node_first = $tmp_node->getFirstChild()) { + $tnfc = $tmp_node_first->getContent(); + } else { + $tnfc = FALSE; + } + + if($tmp_node_last = $tmp_node->getLastChild()) { + $tnlc = $tmp_node_last->getContent(); + } else { + $tnlc = FALSE; + } + + if (isset($key_node_arr[$i+1])) { + $next_tmp_node = $node_arr[$key_node_arr[$i+1]]; + $ntnn = $next_tmp_node->getName(); + $ntnc = $next_tmp_node->getContent(); + } else { + $ntnn = FALSE; + $ntnc = FALSE; + } + + // Checking each node in node array for matrix criteria + if ($is_mtrx_flg) { + $is_mtrx_flg = $tmp_node->getName() == 'mrow' && + ($i == $node_cnt-1 || $ntnn == 'mo' && $ntnc == ',') && + $tnfc == $node_8_cntnt && $tnlc == $node_7_cntnt; + } + + if ($is_mtrx_flg) { + for ($j = 0;$j < $tmp_node->getNumChild();$j++) { + $tmp_c_node = $tmp_node->getChildByIdx($j); + + if ($tmp_c_node->getContent() == ',') { + $comma_pos_arr[$i][] = $j; + } + } + } + + if ($is_mtrx_flg && $i > 1) { + + $cnt_cpan = isset($comma_pos_arr[$i]) ? count($comma_pos_arr[$i]) : NULL; + $cnt_cpap = isset($comma_pos_arr[$i-2]) ? count($comma_pos_arr[$i-2]) : NULL; + $is_mtrx_flg = $cnt_cpan == $cnt_cpap; + } + + $i += 2; + } + + // If the node passes the matrix tests + if ($is_mtrx_flg) { + $tab_node_arr = array(); + + for ($i = 0;$i < $node_cnt;$i += 2) { + $tmp_key_node_arr = array_keys($node_arr); + if (!($tmp_node = $node_arr[$tmp_key_node_arr[0]])) { + break; + } + $num_child = $tmp_node->getNumChild(); + $k = 0; + + $tmp_node->removeFirstChild(); + + $row_node_arr = array(); + $row_frag_node_arr = array(); + + for ($j = 1;$j < ($num_child-1);$j++) { + if (isset($comma_pos_arr[$i][$k]) && + $j == $comma_pos_arr[$i][$k]) { + + $tmp_node->removeFirstChild(); + + $tmp_c_node = $this->createNode(); + $tmp_c_node->setName('mtd'); + $tmp_c_node->addChildArr($row_frag_node_arr); + $row_frag_node_arr = array(); + + $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node; + + $k++; + } else { + + if ($tmp_c_node = $tmp_node->getFirstChild()) { + $row_frag_node_arr[$tmp_c_node->getId()] = $tmp_c_node; + $tmp_node->removeFirstChild(); + } + } + } + + $tmp_c_node = $this->createNode(); + $tmp_c_node->setName('mtd'); + $tmp_c_node->addChildArr($row_frag_node_arr); + + $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node; + + if (count($node_arr) > 2) { + $tmp_key_node_arr = array_keys($node_arr); + unset($node_arr[$tmp_key_node_arr[0]]); + unset($node_arr[$tmp_key_node_arr[1]]); + } + + $tmp_c_node = $this->createNode(); + $tmp_c_node->setName('mtr'); + $tmp_c_node->addChildArr($row_node_arr); + + $tab_node_arr[$tmp_c_node->getId()] = $tmp_c_node; + } + + $tmp_c_node = $this->createNode(); + $tmp_c_node->setName('mtable'); + $tmp_c_node->addChildArr($tab_node_arr); + + if (isset($sym['invisible'])) { + $tmp_c_node->setAttr('columnalign','left'); + } + + $key_node_arr = array_keys($node_arr); + $tmp_c_node->setId($key_node_arr[0]); + + $node_arr[$tmp_c_node->getId()] = $tmp_c_node; + } + } + } + } + + $this->chopExpr($sym['symlen']); + if (!isset($sym['invisible'])) { + $node_7 = $this->createNode(); + $node_7->setName('mo'); + $node_7->setContent($sym['output']); + $node_arr[$node_7->getId()] = $node_7; + } + } + + return($node_arr); + } + + function parseSmplExpr() + { + $sym = $this->getSymbol(); + + if (!$sym || isset($sym['right_bracket'])) //return FALSE; + return $this->emptyNode(); + + $this->chopExpr($sym['symlen']); + + // 2005-06-11 wes: add definition type support + if(isset($sym['definition'])) { + $this->pushExpr($sym['output']); + $sym = $this->getSymbol(); + $this->chopExpr($sym['symlen']); + } + + if (isset($sym['left_bracket'])) { + $node_arr = $this->parseExpr(); + + if (isset($sym['invisible'])) { + $node_0 = $this->createNode(); + $node_0->setName('mrow'); + $node_0->addChildArr($node_arr); + + return($node_0); + } else { + $node_0 = $this->createNode(); + $node_0->setName('mo'); + $node_0->setContent($sym['output']); + + $node_1 = $this->createNode(); + $node_1->setName('mrow'); + $node_1->addChild($node_0); + $node_1->addChildArr($node_arr); + + return($node_1); + } + } elseif (isset($sym['unary'])) { + + if ($sym['input'] == 'sqrt') { + $node_0 = $this->parseSmplExpr(); + $node_0->removeBrackets(); + + $node_1 = $this->createNode(); + $node_1->setName($sym['tag']); + $node_1->addChild($node_0); + + return($node_1); + } elseif (isset($sym['func'])) { //added 2006-9-7 David Lippman + $expr = ltrim($this->getCurrExpr()); + $st = $expr{0}; + $node_0 = $this->parseSmplExpr(); + //$node_0->removeBrackets(); + if ($st=='^' || $st == '_' || $st=='/' || $st=='|' || $st==',') { + $node_1 = $this->createNode(); + $node_1->setName($sym['tag']); + $node_1->setContent($sym['output']); + $this->setCurrExpr($expr); + return($node_1); + } else { + $node_1 = $this->createNode(); + $node_1->setName('mrow'); + $node_2 = $this->createNode(); + $node_2->setName($sym['tag']); + $node_2->setContent($sym['output']); + $node_1->addChild($node_2); + $node_1->addChild($node_0); + return($node_1); + } + } elseif ($sym['input'] == 'text' || $sym['input'] == 'mbox' || $sym['input'] == '"') { + $expr = ltrim($this->getCurrExpr()); + if ($sym['input']=='"') { + $end_brckt = '"'; + $txt = substr($expr,0,strpos($expr,$end_brckt)); + } else { + switch($expr{0}) { + case '(': + $end_brckt = ')'; + break; + case '[': + $end_brckt = ']'; + break; + case '{': + $end_brckt = '}'; + break; + default: + $end_brckt = chr(11); // A character that will never be matched. + break; + } + $txt = substr($expr,1,strpos($expr,$end_brckt)-1); + } + + //$txt = substr($expr,1,strpos($expr,$end_brckt)-1); + $len = strlen($txt); + + $node_0 = $this->createNode(); + $node_0->setName('mrow'); + + if ($len > 0) { + if ($txt{0} == " ") { + $node_1 = $this->createNode(); + $node_1->setName('mspace'); + $node_1->setAttr('width','1ex'); + + $node_0->addChild($node_1); + } + + $node_3 = $this->createNode(); + $node_3->setName($sym['tag']); + $node_3->setContent(trim($txt)); + + $node_0->addChild($node_3); + + if ($len > 1 && $txt{$len-1} == " ") { + $node_2 = $this->createNode(); + $node_2->setName('mspace'); + $node_2->setAttr('width','1ex'); + + $node_0->addChild($node_2); + } + + $this->chopExpr($len+2); + } + return($node_0); + + } elseif (isset($sym['acc'])) { + $node_0 = $this->parseSmplExpr(); + $node_0->removeBrackets(); + + $node_1 = $this->createNode(); + $node_1->setName($sym['tag']); + $node_1->addChild($node_0); + + $node_2 = $this->createNode(); + $node_2->setName('mo'); + $node_2->setContent($sym['output']); + + $node_1->addChild($node_2); + return($node_1); + } else { + // Font change commands -- to complete + } + } elseif (isset($sym['binary'])) { + $node_arr = array(); + + $node_0 = $this->parseSmplExpr(); + $node_0->removeBrackets(); + + $node_1 = $this->parseSmplExpr(); + $node_1->removeBrackets(); + + /* 2005-06-05 wes: added stackrel */ + if ($sym['input'] == 'root' || $sym['input'] == 'stackrel') { + $node_arr[$node_1->getId()] = $node_1; + $node_arr[$node_0->getId()] = $node_0; + } elseif ($sym['input'] == 'frac') { + $node_arr[$node_0->getId()] = $node_0; + $node_arr[$node_1->getId()] = $node_1; + } + + $node_2 = $this->createNode(); + $node_2->setName($sym['tag']); + $node_2->addChildArr($node_arr); + + return($node_2); + } elseif (isset($sym['infix'])) { + $node_0 = $this->createNode(); + $node_0->setName('mo'); + $node_0->setContent($sym['output']); + + return($node_0); + } elseif (isset($sym['space'])) { + $node_0 = $this->createNode(); + $node_0->setName('mrow'); + + $node_1 = $this->createNode(); + $node_1->setName('mspace'); + $node_1->setAttr('width',$sym['space']); + + $node_2 = $this->createNode(); + $node_2->setName($sym['tag']); + $node_2->setContent($sym['output']); + + $node_3 = $this->createNode(); + $node_3->setName('mspace'); + $node_3->setAttr('width',$sym['space']); + + $node_0->addChild($node_1); + $node_0->addChild($node_2); + $node_0->addChild($node_3); + + return($node_0); + } else { + + // A constant + $node_0 = $this->createNode(); + $node_0->setName($sym['tag']); + $node_0->setContent($sym['output']); + return($node_0); + } + + // Return an empty node + return $this->emptyNode(); + } + + function getMathML() + { + $root = $this->_node_arr[0]; + return($root->dumpXML()); + } + + function getCurrExpr() + { + return($this->_curr_expr); + } + + function setCurrExpr($str) + { + $this->_curr_expr = $str; + } + + function getExpr() + { + return($this->_expr); + } + + function getPrevExpr() + { + return($this->_prev_expr); + } + + function createNode() + { + $node = new MathMLNode($this->_node_cntr); + // $node->setNamespaceAlias('m'); + $this->_node_arr[$this->_node_cntr] = $node; + $this->_node_cntr++; + return($node); + } + + /** + * Gets the largest symbol in the expression (greedy). Changed from non-greedy 26-Apr-2006 + * + * @parameter boolean[optional] Chop original string? + * + * @return mixed + * + * @access private + */ + function getSymbol($chop_flg = FALSE) + { + // Implemented a reverse symbol matcher. + // Instead of going front to back, it goes back to front. Steven 26-Apr-2006 + $chr_cnt = strlen($this->_curr_expr); + + if ($chr_cnt == 0) return FALSE; + + for ($i = $chr_cnt; $i > 0; $i--) { + $sym_0 = substr($this->_curr_expr,0,$i); + + // Reading string for numeric values + if (is_numeric($sym_0)) { + + if ($chop_flg) $this->chopExpr($i); + return array('input'=>$sym_0, 'tag'=>'mn', 'output'=>$sym_0, 'symlen'=>$i); + + } elseif (isset($this->_symbol_arr[$sym_0])) { + + if ($chop_flg) $this->chopExpr($i); + $sym_arr = $this->_symbol_arr[$sym_0]; + $sym_arr['symlen'] = $i; + return $sym_arr; + } + } + + // Reading string for alphabetic constants and the minus sign + $char = $this->_curr_expr{0}; + $len_left = $chop_flg ? $this->chopExpr(1) : strlen($this->_curr_expr)-1; + + // Deals with expressions of length 1 + if ($len_left == 0 && isset($this->_symbol_arr[$char])) { + $sym_arr = $this->_symbol_arr[$char]; + $sym_arr['symlen'] = 1; + return $sym_arr; + } else { + $tag = preg_match('/[a-z]/i',$char) ? 'mi' : 'mo'; + return array('input'=>$char, 'tag'=>$tag, 'output'=>$char, 'symlen'=>1); + } + } + + function chopExpr($strlen) + { + $this->_prev_expr = $this->_curr_expr; + + if ($strlen == strlen($this->_curr_expr)) { + $this->_curr_expr = ''; + return(0); + } else { + $this->_curr_expr = ltrim(substr($this->_curr_expr,$strlen)); + return(strlen($this->_curr_expr)); + } + } +} +?> \ No newline at end of file diff --git a/examples/includes/ASCIIMathPHP-2.0/htmlMathML.js b/examples/includes/ASCIIMathPHP-2.0/htmlMathML.js new file mode 100644 index 0000000..f81a1d2 --- /dev/null +++ b/examples/includes/ASCIIMathPHP-2.0/htmlMathML.js @@ -0,0 +1,86 @@ +/* March 19, 2004 MathHTML (c) Peter Jipsen http://www.chapman.edu/~jipsen +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. +This program 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 +(at http://www.gnu.org/copyleft/gpl.html) for more details.*/ + +function convertMath(node) {// for Gecko + if (node.nodeType==1) { + var newnode = + document.createElementNS("http://www.w3.org/1998/Math/MathML", + node.nodeName.toLowerCase()); + for(var i=0; i < node.attributes.length; i++) { + if (node.attributes[i].nodeName == 'displaystyle') { + newnode.setAttribute(node.attributes[i].nodeName,node.attributes[i].nodeValue); + } + } + for (var i=0; i + + Release 0.91 + + - Tested on Cygwin. + - Used Unix file type for source files. + - Updated documentation. + - Prohibited call with undefined parameter to HTML::Parser->parse() from + HTML::_tokenTocEndParser->parse() which caused havoc with version 3.25 + of HTML::Parser. + - Specified 'HTML::Parser' as module that needs to be available in order + to use HTML::Toc. + - Added protected method HTML::TocGenerator::_setActiveAnchorName(). + This method replaces the incongruous access of + 'HTML::TocUpdator::_doDeleteTokens' by HTML::TocGenerator. + HTML::TocUpdator now overrides '_setActiveAnchorName()' to allow + the ancestor call to HTML::TocGenerator only when '_doDeleteTokens' + equals false. + +2001-08-09 Freddy Vulto + + Release 0.90 + + - First release. diff --git a/examples/includes/HTML-Toc-0.91/MANIFEST b/examples/includes/HTML-Toc-0.91/MANIFEST new file mode 100644 index 0000000..e90f3a8 --- /dev/null +++ b/examples/includes/HTML-Toc-0.91/MANIFEST @@ -0,0 +1,26 @@ +Changes +Toc.pod +Toc.pm +TocGenerator.pm +TocInsertor.pm +TocUpdator.pm +Makefile.PL +MANIFEST +t/extend.t +t/format.t +t/generate.t +t/insert.t +t/manualTest.t +t/options.t +t/podExamples.t +t/propagate.t +t/siteMap.t +t/update.t +t/ManualTest/manualTest1.htm +t/SiteMap/index.htm +t/SiteMap/SubDir1/index.htm +t/SiteMap/SubDir1/SubSubDir1/index.htm +t/SiteMap/SubDir2/index.htm +t/SiteMap/SubDir2/SubSubDir1/index.htm +t/SiteMap/SubDir2/SubSubDir2/index.htm +t/SiteMap/SubDir3/index.htm diff --git a/examples/includes/HTML-Toc-0.91/Makefile.PL b/examples/includes/HTML-Toc-0.91/Makefile.PL new file mode 100644 index 0000000..434d4fd --- /dev/null +++ b/examples/includes/HTML-Toc-0.91/Makefile.PL @@ -0,0 +1,8 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + 'NAME' => 'HTML::Toc', + 'VERSION_FROM' => 'Toc.pm', + 'PREREQ_PM' => {'HTML::Parser' => 0}, + 'MAN3PODS' => {}, +); diff --git a/examples/includes/HTML-Toc-0.91/Toc.pm b/examples/includes/HTML-Toc-0.91/Toc.pm new file mode 100644 index 0000000..ae2e8d8 --- /dev/null +++ b/examples/includes/HTML-Toc-0.91/Toc.pm @@ -0,0 +1,549 @@ +#=== HTML::Toc ================================================================ +# function: HTML Table of Contents + + +package HTML::Toc; + + +use strict; + + +BEGIN { + use vars qw($VERSION); + + $VERSION = '0.91'; +} + + +use constant FILE_FILTER => '.*'; +use constant GROUP_ID_H => 'h'; +use constant LEVEL_1 => 1; +use constant NUMBERING_STYLE_DECIMAL => 'decimal'; + + # Templates + + # Anchor templates +use constant TEMPLATE_ANCHOR_NAME => '$groupId."-".$node'; +use constant TEMPLATE_ANCHOR_HREF_BEGIN => + '""'; +use constant TEMPLATE_ANCHOR_HREF_BEGIN_FILE => + '""'; +use constant TEMPLATE_ANCHOR_HREF_END => '""'; +use constant TEMPLATE_ANCHOR_NAME_BEGIN => + '""'; +use constant TEMPLATE_ANCHOR_NAME_END => '""'; +use constant TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_BEGIN => + ''; +use constant TOKEN_UPDATE_END_OF_ANCHOR_NAME_BEGIN => + ''; +use constant TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_END => + ''; +use constant TOKEN_UPDATE_END_OF_ANCHOR_NAME_END => + ''; +use constant TOKEN_UPDATE_BEGIN_NUMBER => + ''; +use constant TOKEN_UPDATE_END_NUMBER => + ''; +use constant TOKEN_UPDATE_BEGIN_TOC => + ''; +use constant TOKEN_UPDATE_END_TOC => + ''; + +use constant TEMPLATE_TOKEN_NUMBER => '"$node  "'; + + # Level templates +use constant TEMPLATE_LEVEL => '"
  • $text\n"'; +use constant TEMPLATE_LEVEL_BEGIN => '"
      \n"'; +use constant TEMPLATE_LEVEL_END => '"
    \n"'; + + +END {} + + +#--- HTML::Toc::new() --------------------------------------------------------- +# function: Constructor + +sub new { + # Get arguments + my ($aType) = @_; + # Local variables + my $self; + + $self = bless({}, $aType); + # Default to empty 'options' array + $self->{options} = {}; + # Empty toc + $self->{_toc} = ""; + # Hash reference to array for each groupId, each array element + # referring to the group of the level indicated by the array index. + # For example, with the default 'tokenGroups', '_levelGroups' would + # look like: + # + # {'h'} => [\$group1, \$group2, \$group3, \$group4, \$group5, \$group6]; + # + $self->{_levelGroups} = undef; + # Set default options + $self->_setDefaults(); + return $self; +} # new() + + +#--- HTML::Toc::_compareLevels() ---------------------------------------------- +# function: Compare levels. +# args: - $aLevel: pointer to level +# - $aGroupLevel +# - $aPreviousLevel +# - $aPreviousGroupLevel +# returns: 0 if new level equals previous level, 1 if new level exceeds +# previous level, -1 if new level is smaller then previous level. + +sub _compareLevels { + # Get arguments + my ( + $self, $aLevel, $aPreviousLevel, $aGroupLevel, $aPreviousGroupLevel + ) = @_; + # Local variables + my ($result); + # Levels equals? + if ( + ($aLevel == $aPreviousLevel) && + ($aGroupLevel == $aPreviousGroupLevel) + ) { + # Yes, levels are equals; + # Indicate so + $result = 0; + } + else { + # No, levels differ; + # Bias to new level being smaller than previous level; + $result = -1; + # Must groups not be nested and do group levels differ? + if ( + ($self->{options}{'doNestGroup'} == 0) && + ($aGroupLevel != $aPreviousGroupLevel) + ) { + # Yes, groups must be kept apart and the group levels differ; + # Level is greater than previous level? + if ( + ($aLevel > $aPreviousLevel) + ) { + # Yes, level is greater than previous level; + # Indicate so + $result = 1; + } + } + else { + # No, group must be nested; + # Level is greater than previous level? + if ( + ($aLevel > $aPreviousLevel) || + ($aGroupLevel > $aPreviousGroupLevel) + ) { + # Yes, level is greater than previous level; + # Indicate so + $result = 1; + } + } + } + # Return value + return $result; +} # _compareLevels() + + +#--- HTML::TocGenerator::_formatLevelIndent() --------------------------------- +# function: Format indent. +# args: - $aText: text to indent +# - $aLevel: Level. +# - $aGroupLevel: Group level. +# - $aAdd +# - $aGlobalLevel + +sub _formatLevelIndent { + # Get arguments + my ($self, $aText, $aAdd, $aGlobalLevel) = @_; + # Local variables + my ($levelIndent, $indent, $nrOfIndents); + # Alias indentation option + $levelIndent = $self->{options}{'levelIndent'}; #=~ s/[0-9]+/&/; + # Calculate number of indents + $nrOfIndents = ($aGlobalLevel + $aAdd) * $levelIndent; + # Assemble indents + $indent = pack("A$nrOfIndents"); + # Return value + return $indent . $aText; +} # _formatLevelIndent() + + +#--- HTML::Toc::_formatToc() -------------------------------------------------- +# function: Format ToC. +# args: - aPreviousLevel +# - aPreviousGroupLevel +# - aToc: ToC to format. +# - aHeaderLines +# note: Recursive function this is. + +sub _formatToc { + # Get arguments + my ( + $self, $aPreviousLevel, $aPreviousGroupLevel, $aToc, $aHeaderLines, + $aGlobalLevel + ) = @_; + # Local variables + my ($level, $groupLevel, $line, $groupId, $text, $compareStatus); + my ($anchorName, $globalLevel, $node, $sequenceNr); + + LOOP: { + # Lines need processing? + while (scalar(@$aHeaderLines) > 0) { + # Yes, lines need processing; + # Get line + $line = shift @$aHeaderLines; + + # Determine levels + ($level, $groupLevel, $groupId, $node, $sequenceNr, + $anchorName, $text) = split( + / /, $line, 7 + ); + # Must level and group be processed? + if ( + ($level =~ m/$self->{options}{'levelToToc'}/) && + ($groupId =~ m/$self->{options}{'groupToToc'}/) + ) { + # Yes, level must be processed; + # Compare levels + $compareStatus = $self->_compareLevels( + $level, $aPreviousLevel, $groupLevel, $aPreviousGroupLevel + ); + + COMPARE_LEVELS: { + + # Equals? + if ($compareStatus == 0) { + # Yes, levels are equal; + # Format level + $$aToc .= $self->_formatLevelIndent( + ref($self->{_templateLevel}) eq "CODE" ? + &{$self->{_templateLevel}}( + $level, $groupId, $node, $sequenceNr, $text + ) : + eval($self->{_templateLevel}), + 0, $aGlobalLevel + ); + } + + # Greater? + if ($compareStatus > 0) { + # Yes, new level is greater than previous level; + # Must level be single-stepped? + if ( + $self->{options}{'doSingleStepLevel'} && + ($aPreviousLevel) && + ($level > $aPreviousLevel) + ) { + # Yes, level must be single-stepped; + # Make sure, new level is increased one step only + $level = $aPreviousLevel + 1; + } + # Increase global level + $aGlobalLevel++; + # Format begin of level + $$aToc .= $self->_formatLevelIndent( + eval($self->{_templateLevelBegin}), -1, $aGlobalLevel + ); + # Process line again + unshift @$aHeaderLines, $line; + # Assemble TOC (recursive) for next level + $self->_formatToc( + $level, $groupLevel, $aToc, $aHeaderLines, $aGlobalLevel + ); + # Format end of level + $$aToc .= $self->_formatLevelIndent( + eval($self->{_templateLevelEnd}), -1, $aGlobalLevel + ); + # Decrease global level + $aGlobalLevel--; + # Exit loop + last COMPARE_LEVELS; + } + + # Smaller? + if ($compareStatus < 0) { + # Yes, new level is smaller than previous level; + # Process line again + unshift @$aHeaderLines, $line; + # End loop + last LOOP; + } + } + } + } + } +} # _formatToc() + + +#--- HTML::Toc::_parseTokenGroups() ------------------------------------------- +# function: Parse token groups + +sub _parseTokenGroups { + # Get arguments + my ($self) = @_; + # Local variables + my ($group, $levelGroups, $numberingStyle); + + # Clear any previous 'levelGroups' + $self->{_levelGroups} = undef; + # Determine default 'numberingStyle' + $numberingStyle = defined($self->{options}{'numberingStyle'}) ? + $self->{options}{'numberingStyle'} : NUMBERING_STYLE_DECIMAL; + + # Loop through groups + foreach $group (@{$self->{options}{'tokenToToc'}}) { + # 'groupId' is specified? + if (! defined($group->{'groupId'})) { + # No, 'groupId' isn't specified; + # Set default groupId + $group->{'groupId'} = GROUP_ID_H; + } + # 'level' is specified? + if (! defined($group->{'level'})) { + # No, 'level' isn't specified; + # Set default level + $group->{'level'} = LEVEL_1; + } + # 'numberingStyle' is specified? + if (! defined($group->{'numberingStyle'})) { + # No, 'numberingStyle' isn't specified; + # Set default numberingStyle + $group->{'numberingStyle'} = $numberingStyle; + } + # Add group to '_levelGroups' variabele + $self->{_levelGroups}{$group->{'groupId'}}[$group->{'level'} - 1] = + $group; + } +} # _parseTokenGroups() + + +#--- HTML::Toc::_setDefaults() ------------------------------------------------ +# function: Set default options. + +sub _setDefaults { + # Get arguments + my ($self) = @_; + # Set default options + $self->setOptions( + { + 'attributeToExcludeToken' => '-', + 'attributeToTocToken' => '@', + 'insertionPoint' => 'after ', + 'levelToToc' => '.*', + 'groupToToc' => '.*', + 'doNumberToken' => 0, + 'doLinkToFile' => 0, + 'doLinkToToken' => 1, + 'doLinkToId' => 0, + 'doSingleStepLevel' => 1, + 'linkUri' => '', + 'levelIndent' => 3, + 'doNestGroup' => 0, + 'doUseExistingAnchors' => 1, + 'doUseExistingIds' => 1, + 'tokenToToc' => [ + { + 'level' => 1, + 'tokenBegin' => '

    ' + }, { + 'level' => 2, + 'tokenBegin' => '

    ' + }, { + 'level' => 3, + 'tokenBegin' => '

    ' + }, { + 'level' => 4, + 'tokenBegin' => '

    ' + }, { + 'level' => 5, + 'tokenBegin' => '

    ' + }, { + 'level' => 6, + 'tokenBegin' => '
    ' + } + ], + 'header' => + "\n\n", + 'footer' => + "\n\n", + } + ); +} # _setDefaults() + + +#--- HTML::Toc::clear() ------------------------------------------------------- +# function: Clear ToC. + +sub clear { + # Get arguments + my ($self) = @_; + # Clear ToC + $self->{_toc} = ""; + $self->{toc} = ""; + $self->{groupIdLevels} = undef; + $self->{levels} = undef; +} # clear() + + +#--- HTML::Toc::format() ------------------------------------------------------ +# function: Format ToC. +# returns: Formatted ToC. + +sub format { + # Get arguments + my ($self) = @_; + # Local variables; + my $toc = ""; + my @tocLines = split(/\r\n|\n/, $self->{_toc}); + # Format table of contents + $self->_formatToc("0", "0", \$toc, \@tocLines, 0); + # Remove last newline + $toc =~ s/\n$//m; + # Add header & footer + $toc = $self->{options}{'header'} . $toc . $self->{options}{'footer'}; + # Return value + return $toc; +} # format() + + +#--- HTML::Toc::parseOptions() ------------------------------------------------ +# function: Parse options. + +sub parseOptions { + # Get arguments + my ($self) = @_; + # Alias options + my $options = $self->{options}; + + # Parse token groups + $self->_parseTokenGroups(); + + # Link ToC to tokens? + if ($self->{options}{'doLinkToToken'}) { + # Yes, link ToC to tokens; + # Determine anchor href template begin + $self->{_templateAnchorHrefBegin} = + defined($options->{'templateAnchorHrefBegin'}) ? + $options->{'templateAnchorHrefBegin'} : + $options->{'doLinkToFile'} ? + TEMPLATE_ANCHOR_HREF_BEGIN_FILE : TEMPLATE_ANCHOR_HREF_BEGIN; + + # Determine anchor href template end + $self->{_templateAnchorHrefEnd} = + defined($options->{'templateAnchorHrefEnd'}) ? + $options->{'templateAnchorHrefEnd'} : + TEMPLATE_ANCHOR_HREF_END; + + # Determine anchor name template + $self->{_templateAnchorName} = + defined($options->{'templateAnchorName'}) ? + $options->{'templateAnchorName'} : + TEMPLATE_ANCHOR_NAME; + + # Determine anchor name template begin + $self->{_templateAnchorNameBegin} = + defined($options->{'templateAnchorNameBegin'}) ? + $options->{'templateAnchorNameBegin'} : + TEMPLATE_ANCHOR_NAME_BEGIN; + + # Determine anchor name template end + $self->{_templateAnchorNameEnd} = + defined($options->{'templateAnchorNameEnd'}) ? + $options->{'templateAnchorNameEnd'} : + TEMPLATE_ANCHOR_NAME_END; + } + + # Determine token number template + $self->{_templateTokenNumber} = + defined($options->{'templateTokenNumber'}) ? + $options->{'templateTokenNumber'} : + TEMPLATE_TOKEN_NUMBER; + + # Determine level template + $self->{_templateLevel} = + defined($options->{'templateLevel'}) ? + $options->{'templateLevel'} : + TEMPLATE_LEVEL; + + # Determine level begin template + $self->{_templateLevelBegin} = + defined($options->{'templateLevelBegin'}) ? + $options->{'templateLevelBegin'} : + TEMPLATE_LEVEL_BEGIN; + + # Determine level end template + $self->{_templateLevelEnd} = + defined($options->{'templateLevelEnd'}) ? + $options->{'templateLevelEnd'} : + TEMPLATE_LEVEL_END; + + # Determine 'anchor name begin' begin update token + $self->{_tokenUpdateBeginOfAnchorNameBegin} = + defined($options->{'tokenUpdateBeginOfAnchorNameBegin'}) ? + $options->{'tokenUpdateBeginOfAnchorNameBegin'} : + TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_BEGIN; + + # Determine 'anchor name begin' end update token + $self->{_tokenUpdateEndOfAnchorNameBegin} = + defined($options->{'tokenUpdateEndOfAnchorNameBegin'}) ? + $options->{'tokenUpdateEndOfAnchorNameBegin'} : + TOKEN_UPDATE_END_OF_ANCHOR_NAME_BEGIN; + + # Determine 'anchor name end' begin update token + $self->{_tokenUpdateBeginOfAnchorNameEnd} = + defined($options->{'tokenUpdateBeginOfAnchorNameEnd'}) ? + $options->{'tokenUpdateBeginOfAnchorNameEnd'} : + TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_END; + + # Determine 'anchor name end' end update token + $self->{_tokenUpdateEndOfAnchorNameEnd} = + defined($options->{'tokenUpdateEndOfAnchorNameEnd'}) ? + $options->{'tokenUpdateEndOfAnchorNameEnd'} : + TOKEN_UPDATE_END_OF_ANCHOR_NAME_END; + + # Determine number begin update token + $self->{_tokenUpdateBeginNumber} = + defined($options->{'tokenUpdateBeginNumber'}) ? + $options->{'tokenUpdateBeginNumber'} : + TOKEN_UPDATE_BEGIN_NUMBER; + + # Determine number end update token + $self->{_tokenUpdateEndNumber} = + defined($options->{'tokenUpdateEndNumber'}) ? + $options->{'tokenUpdateEndNumber'} : + TOKEN_UPDATE_END_NUMBER; + + # Determine toc begin update token + $self->{_tokenUpdateBeginToc} = + defined($options->{'tokenUpdateBeginToc'}) ? + $options->{'tokenUpdateBeginToc'} : + TOKEN_UPDATE_BEGIN_TOC; + + # Determine toc end update token + $self->{_tokenUpdateEndToc} = + defined($options->{'tokenUpdateEndToc'}) ? + $options->{'tokenUpdateEndToc'} : + TOKEN_UPDATE_END_TOC; + +} # parseOptions() + + +#--- HTML::Toc::setOptions() -------------------------------------------------- +# function: Set options. +# args: - aOptions: Reference to hash containing options. + +sub setOptions { + # Get arguments + my ($self, $aOptions) = @_; + # Add options + %{$self->{options}} = (%{$self->{options}}, %$aOptions); +} # setOptions() + + +1; diff --git a/examples/includes/HTML-Toc-0.91/Toc.pod b/examples/includes/HTML-Toc-0.91/Toc.pod new file mode 100644 index 0000000..6348503 --- /dev/null +++ b/examples/includes/HTML-Toc-0.91/Toc.pod @@ -0,0 +1,1710 @@ +=head1 NAME + +HTML::Toc - Generate, insert and update HTML Table of Contents. + +=head1 DESCRIPTION + +Generate, insert and update HTML Table of Contents. + +=head1 Introduction + +The HTML::Toc consists out of the following packages: + + HTML::Toc + HTML::TocGenerator + HTML::TocInsertor + HTML::TocUpdator + +HTML::Toc is the object which will eventually hold the Table of Contents. HTML::TocGenerator does the actual generation of the ToC. HTML::TocInsertor handles the insertion of the ToC in the source. HTML::TocUpdator takes care of updating previously inserted ToCs. + +HTML::Parser is the base object of HTML::TocGenerator, HTML::TocInsertor and HTML::TocUpdator. Each of these objects uses its predecessor as its ancestor, as shown in the UML diagram underneath: + + +---------------------+ + | HTML::Parser | + +---------------------+ + +---------------------+ + | +parse() | + | +parse_file() | + +----------+----------+ + /_\ + | + +----------+----------+ <> +-----------+ + | HTML::TocGenerator + - - - - - -+ HTML::Toc | + +---------------------+ +-----------+ + +---------------------+ +-----------+ + | +extend() | | +clear() | + | +extendFromFile() | | +format() | + | +generate() | +-----+-----+ + | +generateFromFile() | : + +----------+----------+ : + /_\ : + | : + +----------+----------+ <> : + | HTML::TocInsertor + - - - - - - - - -+ + +---------------------+ : + +---------------------+ : + | +insert() | : + | +insertIntoFile() | : + +----------+----------+ : + /_\ : + | : + +----------+----------+ <> : + | HTML::TocUpdator + - - - - - - - - -+ + +---------------------+ + +---------------------+ + | +insert() | + | +insertIntoFile() | + | +update() | + | +updateFile() | + +---------------------+ + +When generating a ToC you'll have to decide which object you want to use: + + TocGenerator: + for generating a ToC without inserting the ToC into the source + TocInsertor: + for generating a ToC and inserting the ToC into the source + TocUpdator: + for generating and inserting a ToC, removing any previously + inserted ToC elements + +Thus in tabular view, each object is capable of: + + generating inserting updating + --------------------------------- + TocGenerator X + TocInsertor X X + TocUpdator X X X + +=head2 Generating + +The code underneath will generate a ToC of the HTML headings C<

    >..C<

    > from a file C: + + use HTML::Toc; + use HTML::TocGenerator; + + my $toc = HTML::Toc->new(); + my $tocGenerator = HTML::TocGenerator->new(); + + $tocGenerator->generateFromFile($toc, 'index.htm'); + print $toc->format(); + +For example, with C containing: + + + +

    Chapter

    + + + +the output will be: + + + + + + +=head2 Inserting + +This code will generate a ToC of HTML headings C<

    >..C<

    > of file C, and insert the ToC after the C<> tag at the same time: + + use HTML::Toc; + use HTML::TocInsertor; + + my $toc = HTML::Toc->new(); + my $tocInsertor = HTML::TocInsertor->new(); + + $tocInsertor->insertIntoFile($toc, 'index.htm'); + +For example, with C containing: + + + +

    Chapter

    + + + +the output will be: + + + + + + + +

    Chapter

    + + + +If you're planning to update the inserted ToC, you'd better use C to insert the ToC. C marks the inserted ToC elements with update tokens. These update tokens allow C to identify and remove the ToC elements during a future update session. This code uses C instead of C: + + use HTML::Toc; + use HTML::TocUpdator; + + my $toc = HTML::Toc->new(); + my $tocUpdator = HTML::TocUpdator->new(); + + $tocUpdator->insertIntoFile($toc, 'index.htm'); + +When applying the code above on 'index.htm': + + + +

    + Chapter +

    + + + +the output will contain additional update tokens: + + + + + + + + +around the inserted ToC elements: + + + + + + + +

    + Chapter +

    + + + +Instead of C you can also use C. C will also insert the ToC, whether there is a ToC already inserted or not. + +=head2 Updating + +This code will generate a ToC of HTML headings C<

    >..C<

    > of file C, and insert or update the ToC after the C<> tag at the same time: + + use HTML::Toc; + use HTML::TocUpdator; + + my $toc = HTML::Toc->new(); + my $tocUpdator = HTML::TocUpdator->new(); + + $tocUpdator->updateFile($toc, 'indexToc.htm'); + +For example, with C containing: + + + + foo + + bar

    + Chapter +

    foo + h + + +the output will be: + + + + + + + +

    + Chapter +

    + + + +All text between the update tokens will be replaced. So be warned: all manual changes made to text between update tokens will be removed unrecoverable after calling C or C. + +=head2 Formatting + +The ToC isn't generated all at once. There are two stages involved: generating and formatting. Generating the ToC actually means storing a preliminary ToC in C{_toc}>. This preliminary, tokenized ToC has to be turned into something useful by calling Cformat()>. For an example, see paragraph 'L'. + +=head1 Advanced + +The ToC generation can be modified in a variety of ways. The following paragraphs each explain a single modification. An example of most of the modifications can be found in the C test file. Within this test, a manual containing: + + preface + introduction + table of contents + table of figures + table of tables + parts + chapters + appendixes + bibliography + +is formatted. + +=head2 Using attribute value as ToC text + +Normally, the ToC will be made of text between specified ToC tokens. It's also possible to use the attribute value of a token as a ToC text. This can be done by specifying the attribute marked with an L within the L token. For example, suppose you want to generate a ToC of the C attributes of the following image tokens: + + + First picture + Second picture + + +This would be the code: + + use HTML::Toc; + use HTML::TocInsertor; + + my $toc = HTML::Toc->new(); + my $tocInsertor = HTML::TocInsertor->new(); + + $toc->setOptions({ + 'tokenToToc' => [{ + 'groupId' => 'image', + 'tokenBegin' => '@' + }], + }); + $tocInsertor->insertIntoFile($toc, $filename); + +and the output will be: + + + + + + + First picture + Second picture + + +=head2 Generate single ToC of multiple files + +Besides generating a ToC of a single file, it's also possible to generate a single ToC of multiple files. This can be done by specifying either an array of files as the file argument and/or by extending an existing ToC. + +=head3 Specify an array of files + +For example, suppose you want to generate a ToC of both C: + + +

    Chapter of document 1

    + + +and C: + + +

    Chapter of document 2

    + + +Here's the code to do so by specifying an array of files: + + use HTML::Toc; + use HTML::TocGenerator; + + my $toc = HTML::Toc->new(); + my $tocGenerator = HTML::TocGenerator->new(); + + $toc->setOptions({'doLinkToFile' => 1}); + $tocGenerator->generateFromFile($toc, ['doc1.htm', 'doc2.htm']); + print $toc->format(); + +And the output will be: + + + + + + +=head3 Extend an existing ToC + +It's also possible to extend an existing ToC. For example, suppose we want the generate a ToC of file C: + + +

    Chapter of document 1

    + + +and extend this ToC with text from C: + + +

    Chapter of document 2

    + + +Here's the code to do so: + + use HTML::Toc; + use HTML::TocGenerator; + + my $toc = HTML::Toc->new(); + my $tocGenerator = HTML::TocGenerator->new(); + + $toc->setOptions({'doLinkToFile' => 1}); + $tocGenerator->generateFromFile($toc, 'doc1.htm'); + $tocGenerator->extendFromFile($toc, 'doc2.htm'); + print $toc->format(); + +And the output will be: + + + + + + +=head2 Generate multiple ToCs + +It's possible to generate multiple ToCs at once by specifying a C object array as the ToC argument. For example, suppose you want to generate a default ToC of HTML headings

    ..

    as well as a ToC of the C image attributes of the following text: + + +

    Header One

    + First picture +

    Paragraph One

    + Second picture + + +Here's how you would do so: + + use HTML::Toc; + use HTML::TocInsertor; + + my $toc1 = HTML::Toc->new(); + my $toc2 = HTML::Toc->new(); + my $tocInsertor = HTML::TocInsertor->new(); + + $toc2->setOptions({ + 'tokenToToc' => [{ + 'groupId' => 'image', + 'tokenBegin' => '@' + }], + }); + $tocInsertor->insertIntoFile([$toc1, $toc2], $filename); + +And the output will be: + + + + + + + + + + +

    Header One

    + First picture +

    Paragraph One

    + Second picture + + +=head2 Generate multiple groups in one ToC + +You may want to generate a ToC consisting of multiple ToC groups. + +=head3 Specify an additional 'Appendix' group + +Suppose you want to generate a ToC with one group for the normal headings, and one group for the appendix headings, using this source file: + + +

    Chapter

    +

    Paragraph

    +

    Subparagraph

    +

    Chapter

    +

    Appendix Chapter

    +

    Appendix Paragraph

    + + +With the code underneath: + + use HTML::Toc; + use HTML::TocInsertor; + + my $toc = HTML::Toc->new(); + my $tocInsertor = HTML::TocInsertor->new(); + + $toc->setOptions({ + 'tokenToToc' => [{ + 'tokenBegin' => '

    ' + }, { + 'tokenBegin' => '

    ', + 'level' => 2 + }, { + 'groupId' => 'appendix', + 'tokenBegin' => '

    ', + }, { + 'groupId' => 'appendix', + 'tokenBegin' => '

    ', + 'level' => 2 + }] + }); + $tocInsertor->insertIntoFile($toc, $filename); + +the output will be: + + + + + + + +

    Chapter

    +

    Paragraph

    +

    Subparagraph

    +

    Chapter

    +

    Appendix Chapter

    +

    Appendix Paragraph

    + + +=head3 Specify an additional 'Part' group + +Suppose you want to generate a ToC of a document which is divided in multiple parts like this file underneath: + + +

    First Part

    +

    Chapter

    +

    Paragraph

    +

    Second Part

    +

    Chapter

    +

    Paragraph

    + + +With the code underneath: + + use HTML::Toc; + use HTML::TocInsertor; + + my $toc = HTML::Toc->new(); + my $tocInsertor = HTML::TocInsertor->new(); + + $toc->setOptions({ + 'doNumberToken' => 1, + 'tokenToToc' => [{ + 'tokenBegin' => '

    ' + }, { + 'tokenBegin' => '

    ', + 'level' => 2, + }, { + 'groupId' => 'part', + 'tokenBegin' => '

    ', + 'level' => 1, + 'numberingStyle' => 'upper-alpha' + }] + }); + $tocInsertor->insertIntoFile($toc, $filename); + +the output will be: + + + + + + + + + +

    A  First Part

    +

    1  Chapter

    +

    1.1  Paragraph

    +

    B  Second Part

    +

    2  Chapter

    +

    2.1  Paragraph

    + + +=head2 Number ToC entries + +By default, the generated ToC will list its entries unnumbered. If you want to number the ToC entries, two options are available. Either you can specify a numbered list by modifying L and L. Or when the ToC isn't a simple numbered list, you can use the numbers generated by HTML::TocGenerator. + +=head3 Specify numbered list + +By modifying L and L you can specify a numbered ToC: + + use HTML::Toc; + use HTML::TocGenerator; + + my $toc = HTML::Toc->new(); + my $tocGenerator = HTML::TocGenerator->new(); + + $toc->setOptions({ + 'templateLevelBegin' => '"
      \n"', + 'templateLevelEnd' => '"
    \n"', + }); + $tocGenerator->generateFromFile($toc, 'index.htm'); + print $toc->format(); + +For instance with the original file containing: + + +

    Chapter

    +

    Paragraph

    + + +The formatted ToC now will contain C
      instead of C
    \n"; + $text .= ""; + } + return $text; + } + function _appendFootnotes_callback($matches) { + $node_id = $this->fn_id_prefix . $matches[1]; + + # Create footnote marker only if it has a corresponding footnote *and* + # the footnote hasn't been used by another marker. + if (isset($this->footnotes[$node_id])) { + # Transfert footnote content to the ordered list. + $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id]; + unset($this->footnotes[$node_id]); + + $num = $this->footnote_counter++; + $attr = " rel=\"footnote\""; + if ($this->fn_link_class != "") { + $class = $this->fn_link_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_link_title != "") { + $title = $this->fn_link_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + } + + $attr = str_replace("%%", $num, $attr); + $node_id = $this->encodeAttribute($node_id); + + return + "". + "$num". + ""; + } + + return "[^".$matches[1]."]"; + } + + + ### Abbreviations ### + + function stripAbbreviations($text) { + # + # Strips abbreviations from text, stores titles in hash references. + # + $less_than_tab = $this->tab_width - 1; + + # Link defs are in the form: [id]*: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1 + (.*) # text = $2 (no blank lines allowed) + }xm', + array(&$this, '_stripAbbreviations_callback'), + $text); + return $text; + } + function _stripAbbreviations_callback($matches) { + $abbr_word = $matches[1]; + $abbr_desc = $matches[2]; + if ($this->abbr_word_re) + $this->abbr_word_re .= '|'; + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + return ''; # String that will replace the block + } + + + function doAbbreviations($text) { + # + # Find defined abbreviations in text and wrap them in elements. + # + if ($this->abbr_word_re) { + // cannot use the /x modifier because abbr_word_re may + // contain significant spaces: + $text = preg_replace_callback('{'. + '(?abbr_word_re.')'. + '(?![\w\x1A])'. + '}', + array(&$this, '_doAbbreviations_callback'), $text); + } + return $text; + } + function _doAbbreviations_callback($matches) { + $abbr = $matches[0]; + if (isset($this->abbr_desciptions[$abbr])) { + $desc = $this->abbr_desciptions[$abbr]; + if (empty($desc)) { + return $this->hashPart("$abbr"); + } else { + $desc = $this->encodeAttribute($desc); + return $this->hashPart("$abbr"); + } + } else { + return $matches[0]; + } + } + +} + + +/* + +PHP Markdown Extra +================== + +Description +----------- + +This is a PHP port of the original Markdown formatter written in Perl +by John Gruber. This special "Extra" version of PHP Markdown features +further enhancements to the syntax for making additional constructs +such as tables and definition list. + +Markdown is a text-to-HTML filter; it translates an easy-to-read / +easy-to-write structured text format into HTML. Markdown's text format +is most similar to that of plain text email, and supports features such +as headers, *emphasis*, code blocks, blockquotes, and links. + +Markdown's syntax is designed not as a generic markup language, but +specifically to serve as a front-end to (X)HTML. You can use span-level +HTML tags anywhere in a Markdown document, and you can use block level +HTML tags (like
    and as well). + +For more information about Markdown's syntax, see: + + + + +Bugs +---- + +To file bug reports please send email to: + + + +Please include with your report: (1) the example input; (2) the output you +expected; (3) the output Markdown actually produced. + + +Version History +--------------- + +See the readme file for detailed release notes for this version. + + +Copyright and License +--------------------- + +PHP Markdown & Extra +Copyright (c) 2004-2008 Michel Fortin + +All rights reserved. + +Based on Markdown +Copyright (c) 2003-2006 John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + +*/ +?> \ No newline at end of file diff --git a/examples/includes/PHP-SmartyPants-1.5.1e/PHP SmartyPants Readme.txt b/examples/includes/PHP-SmartyPants-1.5.1e/PHP SmartyPants Readme.txt new file mode 100644 index 0000000..39d36dd --- /dev/null +++ b/examples/includes/PHP-SmartyPants-1.5.1e/PHP SmartyPants Readme.txt @@ -0,0 +1,394 @@ +PHP SmartyPants +=============== + +Version 1.5.1e - Fri 9 Dec 2005 + +by Michel Fortin + + +based on work by John Gruber + + + +Introduction +------------ + +PHP SmartyPants is a port to PHP of the original SmartyPants written +in Perl by John Gruber. + +PHP SmartyPants is a free web publishing plug-in for WordPress and +Smarty template engine that easily translates plain ASCII punctuation +characters into "smart" typographic punctuation HTML entities. +SmartyPants can also be invoked as a standalone PHP function. + +SmartyPants can perform the following transformations: + +* Straight quotes (`"` and `'`) into "curly" quote HTML entities +* Backtick-style quotes (` ``like this'' `) into "curly" quote HTML + entities +* Dashes (`--` and `---`) into en- and em-dash entities +* Three consecutive dots (`...`) into an ellipsis entity + +This means you can write, edit, and save using plain old ASCII straight +quotes, plain dashes, and plain dots, but your published posts (and +final HTML output) will appear with smart quotes, em-dashes, and proper +ellipses. + +SmartyPants does not modify characters within `
    `, ``,
    +``, or `
    +
    +
    +

    ' . $title . '

    +'; +} + +function make_footer () +{ + echo ' +'; +} + + +function get_var ( $var_name ) +{ + if ( isset($_GET[$var_name]) ) + { + return str_replace("\'", "'", $_GET[$var_name]); + } + elseif ( isset($_POST[$var_name]) ) + { + return str_replace("\'", "'", $_POST[$var_name]); + } + return null; +} + + + +// +// Unset everything +// +foreach ( $_REQUEST as $var ) +{ + unset($$var); +} +foreach ( array( + '_POST' => 'HTTP_POST_VARS', + '_GET' => 'HTTP_GET_VARS', + '_COOKIE' => 'HTTP_COOKIE_VARS', + '_SERVER' => 'HTTP_SERVER_VARS', + '_ENV' => 'HTTP_ENV_VARS', + '_FILES' => 'HTTP_POST_FILES') as $array => $other ) +{ + if ( !isset($$array) ) + { + $$array = $$other; + } + unset($$other); +} + + +// Get what step we're up to +$step = get_var('step'); + +if ( !$step || $step == 1 ) +{ + $errors = 0; + make_header('Step 1'); + echo "Welcome to the GeSHi CSS generator.
    Searching for GeSHi...          ";
    +
    +    // Find GeSHi
    +    $geshi_path = get_var('geshi-path');
    +    $geshi_lang_path = get_var('geshi-lang-path');
    +
    +    if ( !$geshi_path )
    +    {
    +        $geshi_path = '../geshi.php';
    +    }
    +    if ( !$geshi_lang_path )
    +    {
    +        $geshi_lang_path = '../geshi/';
    +    }
    +
    +
    +    if ( is_file($geshi_path) && is_readable($geshi_path) )
    +    {
    +        // Get file contents and see if GeSHi is in here
    +        $file = @file($geshi_path);
    +        $contents = '';
    +        foreach ( $file as $line )
    +        {
    +            $contents .= $line;
    +        }
    +        if ( strpos($contents, 'Found at ' . realpath($geshi_path) . '';
    +        }
    +        else
    +        {
    +            ++$errors;
    +            $no_geshi_dot_php_error = true;
    +            echo 'Not found';
    +        }
    +    }
    +    else
    +    {
    +        ++$errors;
    +        $no_geshi_dot_php_error = true;
    +        echo 'Not found';
    +    }
    +
    +    // Find language files
    +    echo "\nSearching for language files... ";
    +    if ( is_readable($geshi_lang_path . 'css-gen.cfg') )
    +    {
    +
    +        echo 'Found at ' . realpath($geshi_lang_path) . '';
    +    }
    +    else
    +    {
    +        ++$errors;
    +        $no_lang_dir_error = true;
    +        echo 'Not found';
    +    }
    +    echo "
    \n"; + + if ( $errors > 0 ) + { + // We're gonna have to ask for the paths... + echo 'Unfortunately CSSGen could not detect the following paths. Please input them and press "submit" to try again.'; + echo " +
    "; + if ( $no_geshi_dot_php_error ) + { + echo " +
    geshi.php: "; + } + else + { + echo ''; + } + if ( $no_lang_dir_error ) + { + echo " +
    language files directory: (should have a trailing slash)"; + } + else + { + echo ''; + } + + echo " +
    "; + } + else + { + // no errors - echo continue form + echo 'Everything seems to be detected successfully. Use the button to continue. +

    + +'; + } + + make_footer(); +} +// Step 2 +elseif ( $step == 2 ) +{ + make_header('Step 2'); + + $geshi_path = get_var('geshi-path'); + $geshi_lang_path = get_var('geshi-lang-path'); + + $dh = opendir($geshi_lang_path); + $lang_files = array(); + $file = readdir($dh); + while ( $file !== false ) + { + if ( $file == '.' || $file == '..' || $file == 'CVS' || $file == 'css-gen.cfg' ) + { + $file = readdir($dh); + continue; + } + $lang_files[] = $file; + $file = readdir($dh); + } + closedir($dh); + sort($lang_files); + + // Now installed languages are in $lang_files + + echo ' +What languages are you wanting to make this stylesheet for?

    +Detected languages:
    '; + + foreach ( $lang_files as $lang ) + { + $lang = substr($lang, 0, strpos($lang, '.')); + if ($lang) { + echo " $lang
    \n"; + } + } + + echo "Select: All, None, Invert
    \n"; + + echo 'If you\'d like any other languages not detected here to be supported, please enter +them here, one per line:

    +'; + + echo '
    Styles: +
    + + + + + + + + + + + + + +
    Style for the overall code block:
    Default Styles
    Keywords I (if, do, while etc)
    Keywords II (null, true, false etc)
    Inbuilt Functions (echo, print etc)
    Data Types (int, boolean etc)
    Comments (//, etc)
    Escaped Characters (\n, \t etc)
    Brackets ( ([{}]) etc)
    Strings ("foo" etc)
    Numbers (1, -54, 2.5 etc)
    Methods (Foo.bar() etc)
    '; + + echo ' +'; + + make_footer(); +} +// Step 3 +elseif ( $step == 3 ) +{ + make_header('Step 3'); + echo '

    Here is your completed stylesheet. Note that it may not be perfect - no regular expression styles are included for one thing, +you\'ll have to add those yourself (php and xml are just two languages that use them), and line numbers are not included, however +it includes most of the basic information.

    '; + + // Make the stylesheet + $part_selector_1 = ''; + $part_selector_2 = ''; + $part_selector_3 = ''; + + $langs = get_var('langs'); + $extra_langs = trim(get_var('extra-langs')); + if ( $extra_langs != '' ) + { + $l = explode("\r\n", $extra_langs); + foreach ( $l as $lng ) + { + $langs[$lng] = true; + } + } + + + foreach ( $langs as $lang => $dummy ) + { + $part_selector_1 .= ".$lang {PART}, "; + $part_selector_2 .= ".$lang {PART1}, .$lang {PART2}, "; + $part_selector_3 .= ".$lang {PART1}, .$lang {PART2}, .$lang {PART3}, "; + } + $part_selector_1 = substr($part_selector_1, 0, -2); + $part_selector_2 = substr($part_selector_2, 0, -2); + $part_selector_3 = substr($part_selector_3, 0, -2); + + + $default_styles = get_var('default-styles'); + $ol_selector = str_replace('{PART}', 'ol', $part_selector_1); + $overall_styles = get_var('overall'); + $overall_selector = str_replace('{PART}', '', $part_selector_1); + + $stylesheet = "/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */"; + + if ( $overall != '' ) + { + $stylesheet .= "\n$overall_selector {{$overall_styles}}"; + } + if ( $default_styles != '' ) + { + $default_selector = str_replace(array('{PART1}', '{PART2}'), array('.de1', '.de2'), $part_selector_2); + $stylesheet .= "\n$default_selector {{$default_styles}}"; + } + + // Do keywords + $keywords_1 = get_var('keywords-1'); + $keyword_selector_1 = str_replace('{PART}', '.kw1', $part_selector_1); + if ( $keywords_1 != '' ) + { + $stylesheet .= "\n$keyword_selector_1 {{$keywords_1}}"; + } + + $keywords_2 = get_var('keywords-2'); + $keyword_selector_2 = str_replace('{PART}', '.kw2', $part_selector_1); + if ( $keywords_2 != '' ) + { + $stylesheet .= "\n$keyword_selector_2 {{$keywords_2}}"; + } + + $keywords_3 = get_var('keywords-3'); + $keyword_selector_3 = str_replace('{PART}', '.kw3', $part_selector_1); + if ( $keywords_3 != '' ) + { + $stylesheet .= "\n$keyword_selector_3 {{$keywords_3}}"; + } + + $keywords_4 = get_var('keywords-4'); + $keyword_selector_4 = str_replace('{PART}', '.kw4', $part_selector_1); + if ( $keywords_4 != '' ) + { + $stylesheet .= "\n$keyword_selector_4 {{$keywords_4}}"; + } + + // Do other lexics + $comments = get_var('comments'); + $comment_selector = str_replace(array('{PART1}', '{PART2}', '{PART3}'), array('.co1', '.co2', '.coMULTI'), $part_selector_3); + if ( $comments != '' ) + { + $stylesheet .= "\n$comment_selector {{$comments}}"; + } + + $esc = get_var('escaped-chars'); + $esc_selector = str_replace('{PART}', '.es0', $part_selector_1); + if ( $esc != '' ) + { + $stylesheet .= "\n$esc_selector {{$esc}}"; + } + + $brackets = get_var('brackets'); + $brk_selector = str_replace('{PART}', '.br0', $part_selector_1); + if ( $brackets != '' ) + { + $stylesheet .= "\n$brk_selector {{$brackets}}"; + } + + $strings = get_var('strings'); + $string_selector = str_replace('{PART}', '.st0', $part_selector_1); + if ( $strings != '' ) + { + $stylesheet .= "\n$string_selector {{$strings}}"; + } + + $numbers = get_var('numbers'); + $num_selector = str_replace('{PART}', '.nu0', $part_selector_1); + if ( $numbers != '' ) + { + $stylesheet .= "\n$num_selector {{$numbers}}"; + } + + $methods = get_var('methods'); + $method_selector = str_replace('{PART}', '.me0', $part_selector_1); + if ( $methods != '' ) + { + $stylesheet .= "\n$method_selector {{$methods}}"; + } + + echo "
    $stylesheet
    "; + + make_footer(); +} + +?> diff --git a/examples/includes/geshi/contrib/cssgen2.php b/examples/includes/geshi/contrib/cssgen2.php new file mode 100644 index 0000000..cc3c39c --- /dev/null +++ b/examples/includes/geshi/contrib/cssgen2.php @@ -0,0 +1,59 @@ + geshi.css`. + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @package geshi + * @subpackage contrib + * @author revulo + * @copyright 2008 revulo + * @license http://gnu.org/copyleft/gpl.html GNU GPL + * + */ + +require dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'geshi.php'; +$geshi = new GeSHi; + +$languages = array(); +if ($handle = opendir($geshi->language_path)) { + while (($file = readdir($handle)) !== false) { + $pos = strpos($file, '.'); + if ($pos > 0 && substr($file, $pos) == '.php') { + $languages[] = substr($file, 0, $pos); + } + } + closedir($handle); +} +sort($languages); + +header('Content-Type: application/octet-stream'); +header('Content-Disposition: attachment; filename="geshi.css"'); + +echo "/**\n". + " * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann\n" . + " * (http://qbnz.com/highlighter/ and http://geshi.org/)\n". + " */\n"; + +foreach ($languages as $language) { + $geshi->set_language($language); + // note: the false argument is required for stylesheet generators, see API documentation + $css = $geshi->get_stylesheet(false); + echo preg_replace('/^\/\*\*.*?\*\//s', '', $css); +} diff --git a/examples/includes/geshi/contrib/example.php b/examples/includes/geshi/contrib/example.php new file mode 100644 index 0000000..32e6f0c --- /dev/null +++ b/examples/includes/geshi/contrib/example.php @@ -0,0 +1,217 @@ + tag inside the list items (
  • ) thus producing valid HTML markup. + // HEADER_PRE puts the
     tag around the list (
      ) which is invalid in HTML 4 and XHTML 1 + // HEADER_DIV puts a
      tag arount the list (valid!) but needs to replace whitespaces with   + // thus producing much larger overhead. You can set the tab width though. + $geshi->set_header_type(GESHI_HEADER_PRE_VALID); + + // Enable CSS classes. You can use get_stylesheet() to output a stylesheet for your code. Using + // CSS classes results in much less output source. + $geshi->enable_classes(); + + // Enable line numbers. We want fancy line numbers, and we want every 5th line number to be fancy + $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 5); + + // Set the style for the PRE around the code. The line numbers are contained within this box (not + // XHTML compliant btw, but if you are liberally minded about these things then you'll appreciate + // the reduced source output). + $geshi->set_overall_style('font: normal normal 90% monospace; color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;', false); + + // Set the style for line numbers. In order to get style for line numbers working, the
    1. element + // is being styled. This means that the code on the line will also be styled, and most of the time + // you don't want this. So the set_code_style reverts styles for the line (by using a
      on the line). + // So the source output looks like this: + // + //
        + //
      1. + + + GeSHi examples + + + +

        GeSHi Example Script

        +

        To use this script, make sure that geshi.php is in the parent directory or in your +include_path, and that the language files are in a subdirectory of GeSHi's directory called geshi/.

        +

        Enter your source and a language to highlight the source in and submit, or just choose a language to +have that language file highlighted in PHP.

        +parse_code(); + echo '
        '; +} +?> +
        +

        Source to highlight

        +

        + +

        +

        Choose a language

        +

        + +

        +

        + + +

        +
        + + + diff --git a/examples/includes/geshi/contrib/langcheck.php b/examples/includes/geshi/contrib/langcheck.php new file mode 100644 index 0000000..0a2ca32 --- /dev/null +++ b/examples/includes/geshi/contrib/langcheck.php @@ -0,0 +1,666 @@ +Failed
        "; + echo "
          \n"; + foreach($error_cache as $error_msg) { + echo "
        1. "; + switch($error_msg['t']) { + case TYPE_NOTICE: + echo "NOTICE:"; + break; + case TYPE_WARNING: + echo "WARNING:"; + break; + case TYPE_ERROR: + echo "ERROR:"; + break; + } + echo " " . $error_msg['m'] . "
        2. "; + } + echo "
        \n"; + } else { + echo "OK
        "; + } + echo "\n"; + + $error_cache = array(); +} + +function report_error($type, $message) { + global $error_cache, $error_abort; + + $error_cache[] = array('t' => $type, 'm' => $message); + if(TYPE_ERROR == $type) { + $error_abort = true; + } +} + +?> + + + + GeSHi Language File Validation Script + + + +

        GeSHi Language File Validation Script

        +

        To use this script, make sure that geshi.php is in the +parent directory or in your include_path, and that the language files are in a +subdirectory of GeSHi's directory called geshi/.

        +

        Everything else will be done by this script automatically. After the script +finished you should see messages of what could cause trouble with GeSHi or where +your language files can be improved. Please be patient, as this might take some time.

        + +
          +
        1. Checking where to find GeSHi installation ... \n
        2. Listing available language files ... "; + + if (!($dir = @opendir(GESHI_LANG_ROOT))) { + report_error(TYPE_ERROR, 'Error requesting listing for available language files!'); + } + + $languages = array(); + + if(!$error_abort) { + while ($file = readdir($dir)) { + if (!$file || $file[0] == '.' || strpos($file, '.') === false) { + continue; + } + $lang = substr($file, 0, strpos($file, '.')); + $languages[] = $lang; + } + closedir($dir); + } + + $languages = array_unique($languages); + sort($languages); + + if(!count($languages)) { + report_error(TYPE_WARNING, 'Unable to locate any usable language files in "'.GESHI_LANG_ROOT.'"!'); + } + + output_error_cache(); +} + +if (isset($_REQUEST['show']) && in_array($_REQUEST['show'], $languages)) { + $languages = array($_REQUEST['show']); +} + +if(!$error_abort) { + foreach ($languages as $lang) { + echo "
        3. \n
        4. Validating language file for '$lang' ... "; + + $langfile = GESHI_LANG_ROOT . $lang . '.php'; + + unset($language_data); + + if(!is_file($langfile)) { + report_error(TYPE_ERROR, 'The path "' .$langfile. '" does not ressemble a regular file!'); + } else if(!is_readable($langfile)) { + report_error(TYPE_ERROR, 'Cannot read file "' .$langfile. '"!'); + } else { + $langfile_content = file_get_contents($langfile); + if(preg_match("/\?>(?:\r?\n|\r(?!\n)){2,}\Z/", $langfile_content)) { + report_error(TYPE_ERROR, 'Language file contains trailing empty lines at EOF!'); + } + if(!preg_match("/\?>(?:\r?\n|\r(?!\n))?\Z/", $langfile_content)) { + report_error(TYPE_ERROR, 'Language file contains no PHP end marker at EOF!'); + } + if(preg_match("/\t/", $langfile_content)) { + report_error(TYPE_NOTICE, 'Language file contains unescaped tabulator chars (probably for indentation)!'); + } + if(preg_match('/^(?: )*(?! )(?! \*) /m', $langfile_content)) { + report_error(TYPE_NOTICE, 'Language file contains irregular indentation (other than 4 spaces per indentation level)!'); + } + + if(!preg_match("/\/\*\*((?!\*\/).)*?Author:((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not contain a specification of an author!'); + } + if(!preg_match("/\/\*\*((?!\*\/).)*?Copyright:((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not contain a specification of the copyright!'); + } + if(!preg_match("/\/\*\*((?!\*\/).)*?Release Version:((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not contain a specification of the release version!'); + } + if(!preg_match("/\/\*\*((?!\*\/).)*?Date Started:((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not contain a specification of the date it was started!'); + } + if(!preg_match("/\/\*\*((?!\*\/).)*?This file is part of GeSHi\.((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not state that it belongs to GeSHi!'); + } + if(!preg_match("/\/\*\*((?!\*\/).)*?language file for GeSHi\.((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not state that it is a language file for GeSHi!'); + } + if(!preg_match("/\/\*\*((?!\*\/).)*?GNU General Public License((?!\*\/).)*?\*\//s", $langfile_content)) { + report_error(TYPE_WARNING, 'Language file does not state that it is provided under the terms of the GNU GPL!'); + } + + unset($langfile_content); + + include $langfile; + + if(!isset($language_data)) { + report_error(TYPE_ERROR, 'Language file does not contain a $language_data structure to check!'); + } else if (!is_array($language_data)) { + report_error(TYPE_ERROR, 'Language file contains a $language_data structure which is not an array!'); + } + } + + if(!$error_abort) { + if(!isset($language_data['LANG_NAME'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'LANG_NAME\'] specification!'); + } else if (!is_string($language_data['LANG_NAME'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'LANG_NAME\'] specification which is not a string!'); + } + + if(!isset($language_data['COMMENT_SINGLE'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'COMMENT_SIGNLE\'] structure to check!'); + } else if (!is_array($language_data['COMMENT_SINGLE'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'COMMENT_SINGLE\'] structure which is not an array!'); + } + + if(!isset($language_data['COMMENT_MULTI'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'COMMENT_MULTI\'] structure to check!'); + } else if (!is_array($language_data['COMMENT_MULTI'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'COMMENT_MULTI\'] structure which is not an array!'); + } + + if(isset($language_data['COMMENT_REGEXP'])) { + if (!is_array($language_data['COMMENT_REGEXP'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'COMMENT_REGEXP\'] structure which is not an array!'); + } + } + + if(!isset($language_data['QUOTEMARKS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'QUOTEMARKS\'] structure to check!'); + } else if (!is_array($language_data['QUOTEMARKS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'QUOTEMARKS\'] structure which is not an array!'); + } + + if(isset($language_data['HARDQUOTE'])) { + if (!is_array($language_data['HARDQUOTE'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'HARDQUOTE\'] structure which is not an array!'); + } + } + + if(!isset($language_data['ESCAPE_CHAR'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'ESCAPE_CHAR\'] specification to check!'); + } else if (!is_string($language_data['ESCAPE_CHAR'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'ESCAPE_CHAR\'] specification which is not a string!'); + } else if (1 < strlen($language_data['ESCAPE_CHAR'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'ESCAPE_CHAR\'] specification is not empty or exactly one char!'); + } + + if(!isset($language_data['CASE_KEYWORDS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'CASE_KEYWORDS\'] specification!'); + } else if (!is_int($language_data['CASE_KEYWORDS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'CASE_KEYWORDS\'] specification which is not an integer!'); + } else if (GESHI_CAPS_NO_CHANGE != $language_data['CASE_KEYWORDS'] && + GESHI_CAPS_LOWER != $language_data['CASE_KEYWORDS'] && + GESHI_CAPS_UPPER != $language_data['CASE_KEYWORDS']) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'CASE_KEYWORDS\'] specification which is neither of GESHI_CAPS_NO_CHANGE, GESHI_CAPS_LOWER nor GESHI_CAPS_UPPER!'); + } + + if(!isset($language_data['KEYWORDS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'KEYWORDS\'] structure to check!'); + } else if (!is_array($language_data['KEYWORDS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'KEYWORDS\'] structure which is not an array!'); + } else { + foreach($language_data['KEYWORDS'] as $kw_key => $kw_value) { + if(!is_integer($kw_key)) { + report_error(TYPE_WARNING, "Language file contains an key '$kw_key' in \$language_data['KEYWORDS'] that is not integer!"); + } else if (!is_array($kw_value)) { + report_error(TYPE_ERROR, "Language file contains a \$language_data['CASE_SENSITIVE']['$kw_value'] structure which is not an array!"); + } + } + } + + if(!isset($language_data['SYMBOLS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'SYMBOLS\'] structure to check!'); + } else if (!is_array($language_data['SYMBOLS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'SYMBOLS\'] structure which is not an array!'); + } + + if(!isset($language_data['CASE_SENSITIVE'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'CASE_SENSITIVE\'] structure to check!'); + } else if (!is_array($language_data['CASE_SENSITIVE'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'CASE_SENSITIVE\'] structure which is not an array!'); + } else { + foreach($language_data['CASE_SENSITIVE'] as $cs_key => $cs_value) { + if(!is_integer($cs_key)) { + report_error(TYPE_WARNING, "Language file contains an key '$cs_key' in \$language_data['CASE_SENSITIVE'] that is not integer!"); + } else if (!is_bool($cs_value)) { + report_error(TYPE_ERROR, "Language file contains a Case Sensitivity specification for \$language_data['CASE_SENSITIVE']['$cs_value'] which is not a boolean!"); + } + } + } + + if(!isset($language_data['URLS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'URLS\'] structure to check!'); + } else if (!is_array($language_data['URLS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'URLS\'] structure which is not an array!'); + } else { + foreach($language_data['URLS'] as $url_key => $url_value) { + if(!is_integer($url_key)) { + report_error(TYPE_WARNING, "Language file contains an key '$url_key' in \$language_data['URLS'] that is not integer!"); + } else if (!is_string($url_value)) { + report_error(TYPE_ERROR, "Language file contains a Documentation URL specification for \$language_data['URLS']['$url_value'] which is not a string!"); + } else if (preg_match('#&([^;]*(=|$))#U', $url_value)) { + report_error(TYPE_ERROR, "Language file contains unescaped ampersands (&) in \$language_data['URLS']!"); + } + } + } + + if(!isset($language_data['OOLANG'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'OOLANG\'] specification!'); + } else if (!is_int($language_data['OOLANG']) && !is_bool($language_data['OOLANG'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'OOLANG\'] specification which is neither boolean nor integer!'); + } else if (false !== $language_data['OOLANG'] && + true !== $language_data['OOLANG'] && + 2 !== $language_data['OOLANG']) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'OOLANG\'] specification which is neither of false, true or 2!'); + } + + if(!isset($language_data['OBJECT_SPLITTERS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'OBJECT_SPLITTERS\'] structure to check!'); + } else if (!is_array($language_data['OBJECT_SPLITTERS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'OBJECT_SPLITTERS\'] structure which is not an array!'); + } + + if(!isset($language_data['REGEXPS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'REGEXPS\'] structure to check!'); + } else if (!is_array($language_data['REGEXPS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'REGEXPS\'] structure which is not an array!'); + } + + if(!isset($language_data['STRICT_MODE_APPLIES'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'STRICT_MODE_APPLIES\'] specification!'); + } else if (!is_int($language_data['STRICT_MODE_APPLIES'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'STRICT_MODE_APPLIES\'] specification which is not an integer!'); + } else if (GESHI_MAYBE != $language_data['STRICT_MODE_APPLIES'] && + GESHI_ALWAYS != $language_data['STRICT_MODE_APPLIES'] && + GESHI_NEVER != $language_data['STRICT_MODE_APPLIES']) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'STRICT_MODE_APPLIES\'] specification which is neither of GESHI_MAYBE, GESHI_ALWAYS nor GESHI_NEVER!'); + } + + if(!isset($language_data['SCRIPT_DELIMITERS'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'SCRIPT_DELIMITERS\'] structure to check!'); + } else if (!is_array($language_data['SCRIPT_DELIMITERS'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'SCRIPT_DELIMITERS\'] structure which is not an array!'); + } + + if(!isset($language_data['HIGHLIGHT_STRICT_BLOCK'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'HIGHLIGHT_STRICT_BLOCK\'] structure to check!'); + } else if (!is_array($language_data['HIGHLIGHT_STRICT_BLOCK'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'HIGHLIGHT_STRICT_BLOCK\'] structure which is not an array!'); + } + + if(isset($language_data['TAB_WIDTH'])) { + if (!is_int($language_data['TAB_WIDTH'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'TAB_WIDTH\'] specification which is not an integer!'); + } else if (1 > $language_data['TAB_WIDTH']) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'TAB_WIDTH\'] specification which is less than 1!'); + } + } + + if(isset($language_data['PARSER_CONTROL'])) { + if (!is_array($language_data['PARSER_CONTROL'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'PARSER_CONTROL\'] structure which is not an array!'); + } + } + + if(!isset($language_data['STYLES'])) { + report_error(TYPE_ERROR, 'Language file contains no $language_data[\'STYLES\'] structure to check!'); + } else if (!is_array($language_data['STYLES'])) { + report_error(TYPE_ERROR, 'Language file contains a $language_data[\'STYLES\'] structure which is not an array!'); + } else { + $style_arrays = array('KEYWORDS', 'COMMENTS', 'ESCAPE_CHAR', + 'BRACKETS', 'STRINGS', 'NUMBERS', 'METHODS', 'SYMBOLS', + 'REGEXPS', 'SCRIPT'); + foreach($style_arrays as $style_kind) { + if(!isset($language_data['STYLES'][$style_kind])) { + report_error(TYPE_ERROR, "Language file contains no \$language_data['STYLES']['$style_kind'] structure to check!"); + } else if (!is_array($language_data['STYLES'][$style_kind])) { + report_error(TYPE_ERROR, "Language file contains a \$language_data['STYLES\']['$style_kind'] structure which is not an array!"); + } else { + foreach($language_data['STYLES'][$style_kind] as $sk_key => $sk_value) { + if(!is_int($sk_key) && ('COMMENTS' != $style_kind && 'MULTI' != $sk_key) + && !(('STRINGS' == $style_kind || 'ESCAPE_CHAR' == $style_kind) && 'HARD' == $sk_key)) { + report_error(TYPE_WARNING, "Language file contains an key '$sk_key' in \$language_data['STYLES']['$style_kind'] that is not integer!"); + } else if (!is_string($sk_value)) { + report_error(TYPE_WARNING, "Language file contains a CSS specification for \$language_data['STYLES']['$style_kind'][$key] which is not a string!"); + } + } + } + } + + unset($style_arrays); + } + } + + if(!$error_abort) { + //Initial sanity checks survived? --> Let's dig deeper! + foreach($language_data['KEYWORDS'] as $key => $keywords) { + if(!isset($language_data['CASE_SENSITIVE'][$key])) { + report_error(TYPE_ERROR, "Language file contains no \$language_data['CASE_SENSITIVE'] specification for keyword group $key!"); + } + if(!isset($language_data['URLS'][$key])) { + report_error(TYPE_ERROR, "Language file contains no \$language_data['URLS'] specification for keyword group $key!"); + } + if(empty($keywords)) { + report_error(TYPE_WARNING, "Language file contains an empty keyword list in \$language_data['KEYWORDS'] for group $key!"); + } + foreach($keywords as $id => $kw) { + if(!is_string($kw)) { + report_error(TYPE_WARNING, "Language file contains an non-string entry at \$language_data['KEYWORDS'][$key][$id]!"); + } else if (!strlen($kw)) { + report_error(TYPE_ERROR, "Language file contains an empty string entry at \$language_data['KEYWORDS'][$key][$id]!"); + } else if (preg_match('/^([\(\)\{\}\[\]\^=.,:;\-+\*\/%\$\"\'\?]|&[\w#]\w*;)+$/i', $kw)) { + report_error(TYPE_NOTICE, "Language file contains an keyword ('$kw') at \$language_data['KEYWORDS'][$key][$id] which seems to be better suited for the symbols section!"); + } + } + if(count($keywords) != count(array_unique($keywords))) { + $kw_diffs = array_count_values($keywords); + foreach($kw_diffs as $kw => $kw_count) { + if($kw_count > 1) { + report_error(TYPE_WARNING, "Language file contains per-group duplicate keyword '$kw' in \$language_data['KEYWORDS'][$key]!"); + } + } + } + } + + $disallowed_before = "(?|^&"; + $disallowed_after = "(?![a-zA-Z0-9_\|%\\-&;"; + + foreach($language_data['KEYWORDS'] as $key => $keywords) { + foreach($language_data['KEYWORDS'] as $key2 => $keywords2) { + if($key2 <= $key) { + continue; + } + $kw_diffs = array_intersect($keywords, $keywords2); + foreach($kw_diffs as $kw) { + if(isset($language_data['PARSER_CONTROL']['KEYWORDS'])) { + //Check the precondition\post-cindition for the involved keyword groups + $g1_pre = $disallowed_before; + $g2_pre = $disallowed_before; + $g1_post = $disallowed_after; + $g2_post = $disallowed_after; + if(isset($language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'])) { + $g1_pre = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE']; + $g2_pre = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE']; + } + if(isset($language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'])) { + $g1_post = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER']; + $g2_post = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER']; + } + + if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_BEFORE'])) { + $g1_pre = $language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_BEFORE']; + } + if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_AFTER'])) { + $g1_post = $language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_AFTER']; + } + + if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_BEFORE'])) { + $g2_pre = $language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_BEFORE']; + } + if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_AFTER'])) { + $g2_post = $language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_AFTER']; + } + + if($g1_pre != $g2_pre || $g1_post != $g2_post) { + continue; + } + } + report_error(TYPE_WARNING, "Language file contains cross-group duplicate keyword '$kw' in \$language_data['KEYWORDS'][$key] and \$language_data['KEYWORDS'][$key2]!"); + } + } + } + foreach($language_data['CASE_SENSITIVE'] as $key => $keywords) { + if(!isset($language_data['KEYWORDS'][$key]) && $key != GESHI_COMMENTS) { + report_error(TYPE_WARNING, "Language file contains an superfluous \$language_data['CASE_SENSITIVE'] specification for non-existing keyword group $key!"); + } + } + foreach($language_data['URLS'] as $key => $keywords) { + if(!isset($language_data['KEYWORDS'][$key])) { + report_error(TYPE_WARNING, "Language file contains an superfluous \$language_data['URLS'] specification for non-existing keyword group $key!"); + } + } + foreach($language_data['STYLES']['KEYWORDS'] as $key => $keywords) { + if(!isset($language_data['KEYWORDS'][$key])) { + report_error(TYPE_WARNING, "Language file contains an superfluous \$language_data['STYLES']['KEYWORDS'] specification for non-existing keyword group $key!"); + } + } + + foreach($language_data['COMMENT_SINGLE'] as $ck => $cv) { + if(!is_int($ck)) { + report_error(TYPE_WARNING, "Language file contains an key '$ck' in \$language_data['COMMENT_SINGLE'] that is not integer!"); + } + if(!is_string($cv)) { + report_error(TYPE_WARNING, "Language file contains an non-string entry at \$language_data['COMMENT_SINGLE'][$ck]!"); + } + if(!isset($language_data['STYLES']['COMMENTS'][$ck])) { + report_error(TYPE_WARNING, "Language file contains no \$language_data['STYLES']['COMMENTS'] specification for comment group $ck!"); + } + } + if(isset($language_data['COMMENT_REGEXP'])) { + foreach($language_data['COMMENT_REGEXP'] as $ck => $cv) { + if(!is_int($ck)) { + report_error(TYPE_WARNING, "Language file contains an key '$ck' in \$language_data['COMMENT_REGEXP'] that is not integer!"); + } + if(!is_string($cv)) { + report_error(TYPE_WARNING, "Language file contains an non-string entry at \$language_data['COMMENT_REGEXP'][$ck]!"); + } + if(!isset($language_data['STYLES']['COMMENTS'][$ck])) { + report_error(TYPE_WARNING, "Language file contains no \$language_data['STYLES']['COMMENTS'] specification for comment group $ck!"); + } + } + } + foreach($language_data['STYLES']['COMMENTS'] as $ck => $cv) { + if($ck != 'MULTI' && !isset($language_data['COMMENT_SINGLE'][$ck]) && + !isset($language_data['COMMENT_REGEXP'][$ck])) { + report_error(TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['COMMENTS'] specification for Single Line or Regular-Expression Comment key $ck!"); + } + } + if (isset($language_data['STYLES']['STRINGS']['HARD'])) { + if (empty($language_data['HARDQUOTE'])) { + report_error(TYPE_NOTICE, "Language file contains superfluous \$language_data['STYLES']['STRINGS'] specification for key 'HARD', but no 'HARDQUOTE's are defined!"); + } + unset($language_data['STYLES']['STRINGS']['HARD']); + } + foreach($language_data['STYLES']['STRINGS'] as $sk => $sv) { + if($sk && !isset($language_data['QUOTEMARKS'][$sk])) { + report_error(TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['STRINGS'] specification for non-existing quotemark key $sk!"); + } + } + + foreach($language_data['REGEXPS'] as $rk => $rv) { + if(!is_int($rk)) { + report_error(TYPE_WARNING, "Language file contains an key '$rk' in \$language_data['REGEXPS'] that is not integer!"); + } + if(is_string($rv)) { + //Check for unmasked / in regular expressions ... + if(empty($rv)) { + report_error(TYPE_WARNING, "Language file contains an empty regular expression at \$language_data['REGEXPS'][$rk]!"); + } else { + if(preg_match("/(?)/s", $rv)) { + report_error(TYPE_WARNING, "Language file contains a regular expression with an unescaped match for a pipe character '|' which needs escaping as '<PIPE>' instead at \$language_data['REGEXPS'][$rk]!"); + } + } + } elseif(is_array($rv)) { + if(!isset($rv[GESHI_SEARCH])) { + report_error(TYPE_ERROR, "Language file contains no GESHI_SEARCH entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); + } elseif(!is_string($rv[GESHI_SEARCH])) { + report_error(TYPE_ERROR, "Language file contains a GESHI_SEARCH entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); + } else { + if(preg_match("/(?)/s", $rv[GESHI_SEARCH])) { + report_error(TYPE_WARNING, "Language file contains a regular expression with an unescaped match for a pipe character '|' which needs escaping as '<PIPE>' instead at \$language_data['REGEXPS'][$rk]!"); + } + } + if(!isset($rv[GESHI_REPLACE])) { + report_error(TYPE_WARNING, "Language file contains no GESHI_REPLACE entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); + } elseif(!is_string($rv[GESHI_REPLACE])) { + report_error(TYPE_ERROR, "Language file contains a GESHI_REPLACE entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); + } + if(!isset($rv[GESHI_MODIFIERS])) { + report_error(TYPE_WARNING, "Language file contains no GESHI_MODIFIERS entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); + } elseif(!is_string($rv[GESHI_MODIFIERS])) { + report_error(TYPE_ERROR, "Language file contains a GESHI_MODIFIERS entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); + } + if(!isset($rv[GESHI_BEFORE])) { + report_error(TYPE_WARNING, "Language file contains no GESHI_BEFORE entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); + } elseif(!is_string($rv[GESHI_BEFORE])) { + report_error(TYPE_ERROR, "Language file contains a GESHI_BEFORE entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); + } + if(!isset($rv[GESHI_AFTER])) { + report_error(TYPE_WARNING, "Language file contains no GESHI_AFTER entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); + } elseif(!is_string($rv[GESHI_AFTER])) { + report_error(TYPE_ERROR, "Language file contains a GESHI_AFTER entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); + } + } else { + report_error(TYPE_WARNING, "Language file contains an non-string and non-array entry at \$language_data['REGEXPS'][$rk]!"); + } + if(!isset($language_data['STYLES']['REGEXPS'][$rk])) { + report_error(TYPE_WARNING, "Language file contains no \$language_data['STYLES']['REGEXPS'] specification for regexp group $rk!"); + } + } + foreach($language_data['STYLES']['REGEXPS'] as $rk => $rv) { + if(!isset($language_data['REGEXPS'][$rk])) { + report_error(TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['REGEXPS'] specification for regexp key $rk!"); + } + } + + + } + + output_error_cache(); + + flush(); + + if($error_abort) { + break; + } + } +} +?>
        5. +
        + +

        Validation process completed in seconds.

        + + + + diff --git a/examples/includes/geshi/docs/BUGS b/examples/includes/geshi/docs/BUGS new file mode 100644 index 0000000..8a5cf04 --- /dev/null +++ b/examples/includes/geshi/docs/BUGS @@ -0,0 +1,29 @@ + + BUGS - list of known bugs in GeSHi + Version 1.0.8 + +- Number highlighting is quite poor [possibly better now] +- I'm not happy with URLS - there still could be extra bugs, and it's rather unflexible + (see TODO for a possible fix) +- "Important" sections for some reason seem to have their spans added after every + newline up until the next lexic, instead of stopping at the part. In fact, + context sensitiveness is quite poor... +- Using the extra line number highlighting feature without actually using line numbers + will result in malformed XHTML (not sure about this one though...) +- Slow!!! Especially for source with lots of strings in it. GeSHi will work acceptably + for sourcecode under 5K (for simple language files like SQL, a 100K file can be + highlighted in just 6 seconds), but above about 25K things get a little slow... If + you're using this as part of some larger software, you may want to think about + making some sort of "cache" effect to speed things up and reduce server load. +- The result is built by string replacement instead of by building another string based + on the source, that would be much safer. The focus of releases beyond 1.0.7 will be on + changing this behaviour, which may well fix some of the other bugs mentioned above. +- As of 1.0.7.1, dots (.) are allowed before keywords. This may change highlighting of some + things slightly, if you notice anything odd about the highlighting then please report + it to me. +- Perl/Javascript /.../ regex syntax is only supported basically and there's no + guarantee it is working all the time. +- The
         header output is not XHTML compliant. Please use the 
        header instead. + +Send any bug reports to BenBE@omorphia.de, or submit them via the bug tracker at +sourceforge (http://sourceforge.net/tracker/?group_id=114997&atid=670231) diff --git a/examples/includes/geshi/docs/CHANGES b/examples/includes/geshi/docs/CHANGES new file mode 100644 index 0000000..d64c4e5 --- /dev/null +++ b/examples/includes/geshi/docs/CHANGES @@ -0,0 +1,682 @@ + + CHANGES - Changelog for GeSHi (geshi.php only) + +Changes to the code are listed under the version they occured in, with who suggested +it by each one (if there's nobody listed as suggesting it I dreamed it up :)). Users +who suggested an idea often also provided the code that was used as a basis for the +changes - thanks to all who suggested these ideas and gave me the code to show me how! + +Language files listed under each version were made by the author beside them, and then +modified by me for consistency/bug fixing. + +Please send any bug reports to BenBE@omorphia.de, or use the bug report tracker +at sourceforge (http://sourceforge.net/tracker/?group_id=114997&atid=670231) + +Version 1.0.8.3 + - Added language files + * DCS (Stelio Passaris) + * Locomotive Basic (Nacho Cabanes) + * LSL2 (Linden Scripting Language) (William Fry) + * Modula-3 (Martin Bishop) + * Oberon-2 (Mike Mol) + * Rebol (Lecanu Guillaume) + - Fixed a problem where HardEscapes weren't working when no escape char was given (BenBE) + - Added a PARSER_CONTROL setting to treat whitespace inside of keywords in + the language file as "any whitespace" in the source (i.e. "CREATE TABLE" + in SQL will match "CREATE\s+TABLE" instead of literally matching) (BenBE) + - Added a possibility to allow setting the style for escape characters (BenBE) + - Improvements to language files (BenBE) + * Added some missing Perl keywords and obscure default variables (BenBE) + * Allow for escaped colons to appear in CSS names (BenBE, simon) + * Added multiline continuation suppoert of preprocessor defines for + C, C for Mac, C++ and CC++ with Qt support (BenBE) + * keywords for C-based languages are case-sensitive (BenBE) + * Broken AutoIt highlighting (BenBE) + * Problem with escaped backslash in PHP and D (BenBE) + * Added some more functions for PHP (BenBE) + * Some changes for AppleScript (Stefan Klieme) + * Forbid highlighting keywords followed by / in bash (BenBE) + * Updated the LaTeX file to link some keywords (BenBE) + * Additional text rendered when matching special variables for PowerShell (BenBE) + * Added some more keywords for ABAP (BenBE, Sandra Rossi, Jacob Laursen) +Version 1.0.8.2 + - Added language files + * Brainfuck \ Brainfork (Benny Baumann) + * HQ9+ (Benny Baumann) + * INTERCAL (Benny Baumann) + * LOLcode (Benny Baumann) + * LScript (Beau McGuigan) + * Pixel Bender (Richard Olsson) + * ProvideX (Jeff Wilder) + * VIM Script (Swaroop C H) + * Visual Prolog (Thomas Linder Puls) + * Whitespace (Benny Baumann) + - Changed priority for COMMENT_REGEXP compared to String highlighting (BenBE) + - Fixed correct escaping of spaces inside of URLs (BenBE) + - Updated the list of common file extensions (BenBE) + - Updated the language file check script in contrib/ (BenBE) + - Fixed a problem with link targets resulting in unclickable links (SF#2379120, BenBE) + - Fixed an undefined variable issue in langcheck.php (BenBE) + - Improvements to language files (BenBE) + * eMail Header highlighting now uses the correct delimiters for keywords (BenBE) + * eMail (RFC822\mbox) highlighting now highlights IPs, MIME types and + subfield assignments correctly (BenBE) + * Minor style changes in COBOL to improve loading performance (BenBE) + * Added some missing keywords for D (BenBE) + * Removed duplicate keywords from Progres, SAS and TSQL (BenBE) + * Fixed Heredoc Syntax for Bash (SF#2185319, BenBE) + * Moved symbol-lookalike sequences from keyword groups to separate symbol group + for languages asp, klonec, klonecpp, php, php-brief (BenBE) + * Fixed a lot of duplicate keyword warnings (BenBE) + * Added missing keywords to the Python language file, + introducing support for Python 3.0. (SF#2441839, milian) + * Updated documentation links for TypoScript (SF#2014276, BenBE) + * Fixed a problem with tag and attribute names in XML highlighting (SF#2276119, BenBE) + * Improved MySQL language file (BenBE, JavaWoman) + * Some commentss accidentially mistaken for DocComments (SF#2454897, BenBE) + * Added improved Escape Char handling for c, c_mac, cpp and cpp_qt (SF#2458743, BenBE) +Version 1.0.8.1 + - Added language files + * AviSynth (Ryan Jones) + * eMail \ mbox (Benny Baumann) + * GNU Make (Neil Bird) + * Oracle 11i support (Simon Redhead) + * Prolog (Benny Baumann) + * SciLab (Christophe David) + * TeraTerm macro language (Boris Maisuradze) + - Added support for Escape Regular Expressions (BenBE) + * Implemented C-style Escapes in PHP (BenBE) + * Introduced support for \xAB and \007 style Char Escapes in PHP (BenBE) + * Implemented Variable Highlighting in PHP (BenBE) + * Implemented Variable Highlighting in Bash (milian) + - Fixed a problem with PCRE patterns for Keyword matching sometimes producing + very large strings, that could not be handled by some versions of PCRE lib, + causing broken highlighting an Regexp Compile errors (BenBE, milian) + - Fixed broken highlighting of bash commands like `dbus-send --dest=org.....`, + i.e. the dest was highlighted as variable declaration (milian) + - Fixed broken highlighting of some symbols in their escaped form (BenBE) + ( and were accidentially filtered even though they are valid) + - Fixed a "memory leak" in the *_regexp_caches (milian) + - Fixed broken Escape chars if classes were disabled + - start_line_numbers_at() was ignored when GESHI_HEADER_PRE_TABLE was set (revulo) + - Fixed a problem allowing Remote Code Inclusion under certain circumstances (BenBE) + - Changes to default CSS in order to make the GESHI_HEADER_PRE_TABLE align properly, + even on Windows / Mac systems with strange fonts (milian, revulo, ^RT) + - Minor style changes to the following languages: + * cpp-qt (milian) + * MySQL (BenBE) + * PHP (BenBE) + - Improvements to language files (BenBE, milian) + * Added MinSpareThread\MaxSpareThreads to Apache highlighter (BenBE) + * Added new Keyword group for APT sources.list highlighter (BenBE) + * Fixed highlighting in LaTeX for \begin{} and \end{}, i.e. the stuff inside + the curly braces. (milian, thanks for the report go to Matthias Pospiech) + * Improved String support for D (BenBE) + * MySQL was seriously broken (BenBE) + * Reworked Keyword groups for MySQL to allow for more configuration (BenBE) + * Improved Mirc script language file (milian) + * Improved C++ Qt language file (milian) + * Minor bug with Transpose Operator in Matlab (BenBE, Daniele de Rigo) + * Highlighting of Batch Files for Windows (BenBE) + * Updated AutoIt to include latest changes for AutoIt v3.2.12.1 (BenBE, Thierry) + * Fixed duplicate keyword warnings for Perl, Tcl and Typoscript (BenBE) + * Fixed Doc-URL getting reparsed by highlighted keywords of other groups (BenBE, Jordi Boggiano) +Version 1.0.8 + - Added language files + * APT sources.list (milian) + * Boo (Marcus Griep) + * CIL (Common Intermediate Language, .NET Assembly) (Marcus Griep) + * COBOL (Benny Baumann) + * Gnuplot (milian) + * KLoneC (Mickael Auger) + * KLoneC++ (Mickael Auger) + * PIC16xxx assembler (Phil Mattison) + * POV-Ray (Carl Fürstenberg) + * PowerShell (Frode Aarebrot) + * Progress (Marco Aurelio de Pasqual) + * TypoScript (Jan-Philipp Halle) + * Xorg configuration (milian) + - Make GeSHi's constructor arguments optional, so something like `$foo = new GeSHi;` is possible. (milian) + - Added an optimizer for lists to regular expressions. Using these cached lists results in a speedup of approx. 50%. + The slightly increased memory consumption (~150KB for PHP language file) is more than worth it! (milian) + - Some more memory & speed optimizations all over GeSHi (milian) + * Reduced memory overhead when highlighting keywords (BenBE) + * Keyword Linking now uses considerably less strtolower calls (milian) + * Cache Symbol Search Regexp and make Symbol Highlighting faster (milian) + * Use more native functions like substr_replace and strcasecmp to speed things up (milian) + * Use considerably less strlen() calls on various points by caching the results (milian) + * Properly set comments to be case insensitive where appropriate to increase performance (milian) + * Improve the performance of the strict mode tokenizer, making highlighting of languages like + HTML, ColdFusion or XML faster (milian) + * Setup caches for parsing on demand to make stylesheet generators fast (milian) + - Various improvements to Strict Block Handling (BenBE, milian) + * Added support for RegExp-based Strict Blocks (BenBE) + * Fixed highlighting incorrectly stopping at ?> in PHP (SF#1330968, BenBE) + * Languages with STRICT_MODE_APPLIES = GESHI_MAYBE default to strict mode now. When no highlightable + code is found in this mode, we fallback to the same setting as if GESHI_NEVER was set. That way it + should not be needed to call enable_strictmode() manually. (milian) + - Added new GESHI_HEADER_PRE_VALID type which uses the following markup: (milian) + * With line numbers:
        header
        1. ...
        2. ...
        + * Without line numbers:
        header...CODE...
        + => valid HTML and no need for   indentation + - Added new GESHI_HEADER_PRE_TABLE type which can be used to prevent linenumber-selection in Firefox + on copy'n'paste. (milian) + - set_language will not reset any language settings by default anymore. + * Added $force_reset param for to force full reload of a language. (milian) + * Make sure strict_mode is set properly when doing repeated set_language calls (milian) + - Fixed some problems with old PHP versions (SF#1975625, milian, BenBE) + - Fixed broken use with Suhosin Patch when /e modifier was disabled (SF#2021800, BenBE) + - Added support for external style information files to override language defaults without modifying language files (BenBE) + - The overall_class is now up to the user, and the language-code is _always_ added as a class (milian) + - Fixed Economy Mode for GeSHi::get_stylesheet() - now it just makes so much more sense! (milian) + - Fixed Economy Mode when COMMENT_REGEXP are used (BenBE) + - Changed the default encoding to use UTF-8, due to SF#2037598, BenBE) + - Improved overall string support: + * Added support for multichar string delimiters (SF#1932083, BenBE) + * Fixed problems of unfinished strings and comments producing invalid XHTML (SF#1996353, BenBE) + * Multichar Quotemarks sometimes had inconsistent behaviour (BenBE) + * Support for multiple styles of strings depending on the starter (BenBE) + * Properly handle escapes in strings, i.e. '\\' was not working properly before (milian) + * Fixed escape char support when an escape char is followed by multi-byte chars (SF#2037598, BenBE) + - Improved flexibility in language files (BenBE, milian) + * Added PARSER_CONTROL for OOLANG method highlighting (SF#1923060, BenBE) + * Added possibility to define strict blocks using an Regexp (BenBE) + * Removed explicit escaping of / in Regular Expressions (BenBE) + * Ignoring empty keyword groups when highlighting (milian) + * Make language_permissions configurable in language files via ['PARSER_CONTROL']['ENABLE_FLAGS'] + this makes is_a calls unneeded and thus prevents PHP notices in PHP 5.x (milian) + * Extended support for number formats now covering the most common formats (SF#1923058, BenBE) + * Lifted a limitation that keywords had to have at least 2 subsequent letters (BenBE) + * Changed behaviour of PARSER_CONTROL now allowing to provide the full Lookahead and Lookbehind + expressions used as delimiters inside keywords instead of a simple char group (BenBE) + * Fixed improper handling of newlines in REGEXPS so this does not produce invalid html anylonger (milian) + - Some typos and mistakes in the documentation (BenBE) + - Added a script to contrib/ to verify language files are correct (BenBE) + - Fixed loads of compliancy warnings detected with that automated compliance testing script (BenBE) + - Many other improvements to various language files (BenBE, milian) + * Reduce strict errors & notices for language files (milian) + * Fixed symbol highlighting with C++ sometimes missing keywords after ; and comments (BenBE) + * Improved comment handling with TCL (Lars Hellström, BenBE) + * Fixed broken handling with XML comments (BenBE, SF#1849233) + * Fixed HTML comments spawning multiple lines producing invalid XHTML output (SF#1738173, BenBE) + * Added support for parameters beginning with dash in BASH language (BenBE) + * Support Apache's configuration sections, see http://httpd.apache.org/docs/2.2/sections.html (milian) + * Minor issue with PHP Heredoc and Nowdoc syntax sometimes not getting highlighted (BenBE) + * Updated Objective-C language file (SF#2013961, Quinn Taylor, BenBE) + * Added some keywords for VHDL (beshig, BenBE) + * Fixed severly broken ColdFusion language file (milian) + * Fixed some incorrectly highlighted things with the CSS language file (milian, BenBE) + * Improved Smarty language file (milian) + * Improved CSS language file (milian) + * Improved Pascal language file (milian) + * Improved LaTeX language file (Андрей Парамонов, BenBE) + * Fixed a regular expression in mIRC language file that caused a warning message to be issued (BenBE) + * Removed <, > and / from HTML names, now only containing the real tag names (BenBE) + * Use spaces instead of tabs for indendation in language files to have a consistent + coding standard accross geshi files (milian) + * Added some comment styles, keywords and added index highlighting (Chusslove Illich, Часлав Илић) + - Removed some private methods which were only called at exactly one place (milian) + * format_header_content + * format_footer_content + * get_attributes + - Second part of default style changes. Affected in this release: + * C++ + * C++ (QT) + * CSS + * VHDL +Version 1.0.7.22 + - Added language files + * glSlang (BenBE) + * KiXtart (Riley McArdle) + * Lotus Notes @Formulas (Richard Civil) + * LotusScript (Richard Civil) + * MXML (David Spurr) + * Scala (Franco Lombardo) + * ActionScript 3 (Jordi Boggiano) + * GNU Gettext .po/.pot (Milian Wolff) + * Verilog (Günter Dannoritzer) + - Fixed a problem not yet addressed in 1.0.7.21 regarding highlighting of + symbols that caused some extra characters to be added in the output or + broke highlighting and standard compliance due to missing escaping of + internally used characters (SF#192320 and SF#1926259, BenBE) + - Fixed missing style information for ocaml language file (The_PHP_Jedi) + - Fixed a bug causing masses of warnings in rendered output if language file + miss style information (The_PHP_Jedi, BenBE) + - Missing tab width information could lead to warnings (BenBE) + - Missing symbol information for ASP (SF#1952038, nfsupport, BenBE) + - Empty delimiter message with OOoBasic (BenBE, Ccornell) + - Escaping of comments in LaTeX ignored (SF#1749806, BenBE) + - Modified Math environment $$ in LaTeX to be non-greedy (BenBE) + - Added possibility to match a regexp as comment (SF#1914640, SF#1945301, SF#1934832, BenBE) + - Introduced C-Style multiline continuation comments (SF#1914640, SF#1945301, BenBE) + - Introduced Fortran Comments (SF#1914640, SF#1934832, BenBE) + - Implemented Heredoc and Nowdoc Syntax for PHP and Perl (SF#1914640, BenBE) + - Implemented Compiler Directives for Delphi (SF#1914640, BenBE) + - Implemented minimalistic support for JavaScript \ Perl Regular Expressions (SF#1786665, SF#1754333, SF#1956631, BenBE) + - Fixed Strings in Matlab to be handled as comments instead of regexps, to prevent keywords being linked (BenBE) + - Applied PARSER_CONTROL fix of CPP for CPP-QT-Derivative (BenBE) + - Fixed incorrect treatment of unequally long multiline comment separators (related to SF #1891630, BenBE) + - Added PARSER_CONTROL settings for keywords in ASM language file (SF#1835148, BenBE) + - Fixed missing CASSE_SENSITIVE entry for DOS language file (SF#1956314, BenBE) + - Fixed accidential highlighting of keywords in argument names (SF#1956456, Milian Wolff, BenBE) + - Fixed yet again some #-related bash problem (SF#1956459, Milian Wolff, BenBE) + - Added backticks as symbols (Milian Wolff) + - Example script remembers selections and source submitted (Milian Wolff) + - Example script allows remembered source and preselected language to be cleared (Milian Wolff) + - Example script now properly includes geshi and doesn't suppress error messages anylonger. (Milian Wolff) + - Code cleanup by using direct string indexing instead of substr with length 1 (Milian Wolff) + - Optimized generation of code parts in strict mode (Milian Wolff) + - Optimized COMMENT_REGEXP by using an incremental regexp cache (Milian Wolff, BenBE) + - Fixed a problem that rarely skipped highlighting of escaped chars which usually should have gotten highlighted (BenBE) + - Optimized generation of highlighted strings to use fast skip forward while highlighting them (Milian Wolff, BenBE) + - Optimization using basic rework of indent function improving tab expansion performance (BenBE) + - Lots of other minor optimizations based on coding style improvements (Milian Wolff) + - Implemented setting to force spans to be closed before newlines, see SF#1727398 (Milian Wolff) + - Added missing credits for D language file to THANKS file (SF#1720899, BenBE) + - Optimization to prevent loading the current language file twice (Milian Wolff) + - Optimization: Use file_get_contents() to load sourcecode from files. + Even if GeSHi worked with PHP 4.1 before, it doesn't now. (Milian Wolff) + - Added description of extra language features (SF#1970248, BenBE) + - Added support for highlighting the C# using and namespace directives (SF #1395677, BenBE) + - Added support for highlighting the Java import and package directives (SF #1395677, BenBE) + - Fixed minor problem in Haskell cuasing accidential start of comment (SF#1987221, BenBE) + - Fixed minor issue causing loads of warnings if a language files defines no symbols (BenBE) + - Updated some aspects of the documentation and included further hints (BenBE) + - First of series of color scheme changes. Affected languages (sofar): + * Assembler (x86) + * Bash + * C + * C# + * Delphi + * Fortran77 + * glSlang + * Java & Java 5 + * JavaScript + * OCaml + * OpenOffice.org Basic + * Pascal + * Perl + * PHP and PHP-Brief +Version 1.0.7.21 + - Added language files + * Basic4GL (Matthew Webb) + - Fixed problem with mIRC language highlighting spaces only (BenBE) + - Language files can now specify a function to be called to decide the + colour of a regular expression match + - Added single quote to Lua (Darrin Roenfanz) + - Compare comments case insensitively (fixes AutoIT comments somewhat) + (Daniel Gordon) + - Fixed symbols not being highlighted at all (SF #1767953, BenBE) + - Fixed brackets not correctly managed (SF #1767954, BenBE) + - Changed default languages for some extensions + - Included color and character information for symbol highlighting in some languages (BenBE) + - Fixed a problem with extension detection if default was used (BenBE) + - Fixed a highlighting problem with the LaTeX language (SF #1776182, BenBE) + - Added a new parameter for enable_highlighting to reduce source duplication (SF #1786104, BenBE) + - Updated doxygen documentation to include since tags and some missing parameters + - Disabled symbol highlighting by default (doesn't affect brackets, cf. documentation) (BenBE) + - Added a check for set_case_keywords for the given param to be supported (BenBE) + - Minor rework of the HTML documentation layout \ W3C compliance (BenBE) + - Fixed highlighting error in bash language avoiding keywords in comments (SF #1786314, SF #1564839, BenBE) + - Fixed template params for C++ and C# not being highlighted (SF #1772919, BenBE) + - Fixed more reported problems about mirc highlighting + - Added some missing keywords for VB.NET + - Fixed some warnings in DOS language file (Florian Angehrn) + - Add possibility to handle more than one extra line style (SF #1698255, German Rumm, BenBE) + - Fixed handling of URLs when output case differs from URL case (SF #1815504, Tom Samstag, BenBE) + - Fixed POD (Plain Old Documentation) format problems breaking highlighting of Perl (SF #1891630, Shannon Wynter, BenBE) + - Fixed a problem with mIRC when & was used for identifiers (SF #1875552, BenBE) +Version 1.0.7.20 + - Added language files + * Genero (logic) and Per (forms) (FOURJ's Genero 4GL) (Lars Gersmann) + * Haskell (Dagit) + * ABAP (Andres Picazo) + * Motorola 68k Assembler (for MC68HC908GP32 Microcontroller) (BenBE) + * Dot (Adrien Friggeri) + - Fixed java documentation search for keywords to actually go to the + documentation (spaze) + - Applied fix for bug 1688864 (bad regexes) (Tim Starling) + - Fixed comment CSS rule in visualfoxpro + - ThinBASIC language update (Eros Olmi) + - mIRC language update (BenBE) + - Fixed outdated documentation URL of Perl language file (RuralMoon by BenBE) + - Fixed tab replacement code not generating the correct number of spaces in + some cases (Guillermo Calvo) + - Fixed two typos in Z80 language file + - Applied fix for bug 1730168 (Daniel Naber) + - Applied fix for bug 1705482 (Jason Frame) + * Configurable line endings (Replace \n by custom string) + * per-language tab-widths (Adjustable for width>=1) + * Included defaults for ASM (x86, m68k, z80), C, C (Mac), C++, C++ (QT), C#, + Delphi, CSS,, HTML, PHP, PHP (Brief), QBasic, Ruby, XML + - Added a possibility to force generation of a surrounding tag around + the highlighted source + - Applied fix for additional keywords for the bash language + (cf. http://bash.thefreebizhost.com/bash_geshi.php, BenBE / Jan G) + - Fix bad colour definition in GML language (Andreas Gohr) + - Fixed phpdoc comments not being indented one space if they should be (Andy + Hassall) +Version 1.0.7.19 + - Added language files + * X++ (Simon Butcher) + * Rails (Moises Deniz) + - Fixed invalid HTML being generated and doctypes not being highlighted over + multiple lines properly when line numbers are on (Validome) + - Improved the ruby syntax highlighting by basing it off the Rails file + - Changed some regular expressions to possibly help with badly performing + regex support in PHP (Tim Starling) + - Allow {TIME}, {LANGUAGE} and {VERSION} to be used in the header as well as + the normal
        + \ No newline at end of file diff --git a/examples/includes/geshi/docs/api/index.html b/examples/includes/geshi/docs/api/index.html new file mode 100644 index 0000000..f499a8f --- /dev/null +++ b/examples/includes/geshi/docs/api/index.html @@ -0,0 +1,24 @@ + + + + + + GeSHi 1.0.8 + + + + + + + + + + + <H2>Frame Alert</H2> + <P>This document is designed to be viewed using the frames feature. + If you see this message, you are using a non-frame-capable web client.</P> + + + \ No newline at end of file diff --git a/examples/includes/geshi/docs/api/li_geshi.html b/examples/includes/geshi/docs/api/li_geshi.html new file mode 100644 index 0000000..f074e37 --- /dev/null +++ b/examples/includes/geshi/docs/api/li_geshi.html @@ -0,0 +1,46 @@ + + + + + + + + + + +
        geshi
        +
        + +
        + +
        Description
        +
        + Class trees
        + Index of elements
        + Todo List
        +
        + + + + + + + +
        Sub-packagecore
        +
        +
        +
         Classes
        +
        ClassGeSHi
        +
         Functions
        +
        Functiongeshi_highlight
        +
         Files
        +
        Filegeshi.php
        +
        +
        + + +
        +
        +

        phpDocumentor v 1.4.2

        + + \ No newline at end of file diff --git a/examples/includes/geshi/docs/api/media/banner.css b/examples/includes/geshi/docs/api/media/banner.css new file mode 100644 index 0000000..032b037 --- /dev/null +++ b/examples/includes/geshi/docs/api/media/banner.css @@ -0,0 +1,33 @@ +body +{ + background-color: #EEEEEE; + margin: 0px; + padding: 0px; +} + +/* Banner (top bar) classes */ + +.banner { } + +.banner-menu +{ + text-align: right; + clear: both; + padding: .5em; + border-top: 2px solid #AAAAAA; +} + +.banner-title +{ + text-align: right; + font-size: 20pt; + font-weight: bold; + margin: .2em; +} + +.package-selector +{ + background-color: #DDDDDD; + border: 1px solid #AAAAAA; + color: #000090; +} diff --git a/examples/includes/geshi/docs/api/media/images/AbstractClass.png b/examples/includes/geshi/docs/api/media/images/AbstractClass.png new file mode 100644 index 0000000000000000000000000000000000000000..afa9d1d9261500c57ec37cff1de8cf43b31dbf25 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfZSaHJ|V9E z|NjRvPcK>oB;jC!uy7wgKahK+w)SFm^_jG^eUXv70s?k;dvAAg+Gb<3&cI-?g2GG& zh8_lnGzNx)iHU~;0{$Bt?{jhjD)_IizRSYmznt6_Lqnj-|B{khH8nS=tN#}e_{zt( zR#EXk2ggfJ&eakUK)aWTi~nF?_`tyMoPps!1H*L&hBwx{7GaqsHK2b=zCZk2F6c8jl1JVN5*@+%rr7PI}^11C*oaK4^xC05VCJK_3< zud|-<{@_}WT(>@P3->I)OHK!WY*;^8{ZU{D!{pbT`vks!nK+ee*>;`t+%u+Jea(8o vR5x-}=mldp!DT+b`?hi(nsMPiM;)`hf`a|hX9_^KGcb6%`njxgN@xNA_;dCz literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/AbstractClass_logo.png b/examples/includes/geshi/docs/api/media/images/AbstractClass_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8f65c390e37b548578390c0bdbe4a4bc469c4d19 GIT binary patch literal 1232 zcmb`F`%jZ+6vq#W@U{$S1TZXV4viCPx3q`=k`4L zo1#BJx0H}AAicqQU>vV%^^<9m|tWsIx<8LP>5;)!-8{5Ba8xawKa^8)JAwolYrP3xG ze;gi;N)W-psLCUuuq7;v;PILTf-XM)dx3ypvzvl~UU4|4;9xV4hpH34zB3F)V?aO$ zn|+nbCFt}9e}9{g&n%sOWyOknOy(?=N>C`M!zl`-mcbw}tb)O4@%Ek}kw)FzM%>+P z&dw7gQYD>^Hi$-;0kAkbTLCIOJjMZr0D1sUQ>kWvt0dArfEIuTfD>f$DGaLt_zu7T zPzaEN77pxLob%;x2CG}`xIIwL@5%qsVT}twSp0*)++a!sc%Q?K z`N@jCeTp+nwyR|s`Xqf{xt8ToY?#m#I3M+++}?TZyynf|!6(h%ZXB5YwRD&DpE->+ zQa?!d&ipfd^zwzIKtBJ~qLA$Mj4wHSb~mtdtP52mbBN=vTM#>mfmycxM}yu)6Bg^4@lw*?MFu3*Llv~ zTq;{9ldCeY*UL|oCB+&|W}C3XvTUffR~(q#WAaNg-nYFVl1oFwjfcGkWO1Lan7mWj zTHAk$B{{PsrhD+|_&Dv{Dq|lMERc7*{?yjm*&4fucG~As73P}JZF+xm+H<2#y7rxG zW9=q?%ZBwC`JJPAZS{(h+4A?WNris0W9rS3rW|*EzKH2={VP|ERZ$+~<|y91p2^}Q nm5>e}t(H)$%7m@A#{7td(X}C*54y81qwfI{akQvb7@z$w+j=f( literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/AbstractMethod.png b/examples/includes/geshi/docs/api/media/images/AbstractMethod.png new file mode 100644 index 0000000000000000000000000000000000000000..605ccbe58e04d8f1462227f08369ef6d8e5d4fe0 GIT binary patch literal 696 zcmV;p0!RIcP){TiMy!!e(Yf-7_V#G2iUr zLy?{{R5VTt!-qRXx-)@b&OX;WKp!2|aT>;Q#=c z001J6D>1||Q0X(T002sRN{?O-R{#J232;bRa{vGf5&!@T5&_cPe*6Fc02XvbSad^j zWnpw_Z*Cw|X>DZyFf=bPGA}SQ*^*j90000WbVXQnQ*UN;cVTj608L?Ia&K*AWNBd_ zMrm?ocW-iQb0AGvyOAm+0002PNklfMHT-Bv8QIEs=+ZPf$A`E>2c0)H#Sj$PWnk1p@>G(zLXgfTkY(YJ2o$Mf2{EX7&_@CL4Lsu zf=WupE-s;IY31eR9Y|p2?lbS+y#t0XRlwut?cae`au#?*7Bet#3xP1>rMq>1fPxAo zt`Q}{`DrEPiAAXlzKO|2`MIennTZN+nMJAP`9;~q3ceA$Cu*qx)rx`CIv1rTmSpDV zDTHL^rZO0q=o=X68yMf56y*d|@zK-8F{EOS?)lqMO%4*R4`(`@EDFELx7ssVZORd| zq%5HzwQYvlS2%cGPXFHD@~{05-~Gi~FPw_9ndsyAvUly>(4LD`8%wTUDBXMa-M%{6 zPZCGZ>%ZQD?T}l&!`s7tUKsOr`-?Wu<;}Q-LQ_10v>q37%ry4uIK**v&qDxa`a*R3vrciLZ8L}yD) oC>0QH(U@~sMxOVvCC6j?c~N@r8XNCh0zJ>*>FVdQ&MBb@0EQ=S+yDRo literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/AbstractPrivateClass_logo.png b/examples/includes/geshi/docs/api/media/images/AbstractPrivateClass_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4e68f570dcb38ee67756ce2231bb5c38e77cce71 GIT binary patch literal 1615 zcmd5)X;Twc6n!ia!lFSW4Jkrc1`LPY$1sj(#lRGf?-K4OF)W1MOFm{ z#7YHOM1d45sY*y?RaT*Ff-H@QqJv;$S_hSqKJ6F#4|-7%db^6N%JBAT-(9*4o%q znVVM{8z&gwu}%jHt3R3eeo)zwv3Rdtk> zHkX%IR8+_c3#BLl`T3*C$>o`ujcI8r9xppPdr&AWJ9+Y=SiH#R_r%1&N)#a> zLp)xoP^jW?x*{TSg~HD8@MMu_J|N&;P>>Mv3@w(yNtt`_4MTNcqLq} z%GI^Y$LAr10vpK)47}svp&}CHWHOh_eLy0K*z8s^S%t^Hv9+Bb5@VQ58Hse=#f8OU z!IlG<%q?^C0ynn}bMx!Y&f#=AmrftS zz{0{8=0u^Owi_rERBYA2Al=^ngo6W*NbJU9H<8F%9BxBfdvV7O=!jBFYZ-~mv9x@x zsR@ORv9^X@%xG!71fbr~a2|np3MB<#5&&q>5CDxxWG?{FDLDW|y1G&TngOW$U}y!L z4IC~XfGhw62!t2_EEWrG`q&@}0J;|r4?^#yB9<>37+4Ughj_fi#GHz2*JLti8^rv7 zu=W9PsQxe5o@p5i8$iZ+2Ey)icfJp`vH6pmki>~-0U~xRPm~y%5D9!j!xLhUM@H~N zaUT4H$i&!$Xd%ugKz7d73jRgE|LdL*87kt(3UD0$@kl^$b|5%85QsCyT&R@#EjpFV zNxB$0{_dMGCPphR1jGN@&Te?$F)~u1_bJ2p$i%={-+*sD-;Or!G|aRk{(Pj}Kd}0H zUF|6ogUq)Y;t|lhxz(~t`eQ_RUoq1-eLFT?AP8E>XkA)fHggqi^htaeb*$=!t4&v9 zqXdHJ6|UE%Zb#CMmiE)kj0RV6b=%tA)%tp^#^=wTC2c+JUMy1oOuKh7@94hZJCoCG zXxaS2yJN@J#J33U`c+%lKU?M&7D~KdDwWEKxzE31HT2^+xj+0k>P|X8pxN^#{*0l; zJtxPg-}2sdI`*|*oC&-#etYRjR+M_H)cIG6TS0l{{gE&BmCtq~sCpA%t$SPejT1KZ zhgY7Xi)In=GWoXzL>tiaEgkbHwlbdGz1?uS;}g9r9hTrqerW-%FO1@shEpP|okxi= zPM5cWANffS>kbM9sa+||;ebojEN0yA9yek&f^IImjYjiE#g2W+w}g5r{lcI0tMbXg zn)g@NIfMqbGFiEQJ-TD7%ey9VJ;gYDC9Ao8C1ZwKf{tkXg^MxlZFwOFr^!}`w~YQU zd1uJz%3r<80}oBt)q-)m&*Rf}D)wh9&K|(^9IVw$da;MNxX>Y)R&c|pBRwc!j(BVG z1gV@=8A+_ZCz$E2gI1@w{L*m@r+H)9vC7|V^Qd`Hj&)~W1WkS8@5e~OE~BI%6gwn= zr*W1_Ms>6Hs`1daQJXsTMk+A3=fdt{i_4foPsd6$>Q%`uT3s3z34l|D0EF>7@e!`_b&3NDRW2J ly0$Y=SuS5{3YHYFR9bNnjKnZ6dJUX%K&SaqC6tg;{{UJF@sa=l literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/AbstractPrivateMethod.png b/examples/includes/geshi/docs/api/media/images/AbstractPrivateMethod.png new file mode 100644 index 0000000000000000000000000000000000000000..41cc9f021734b6f99a723a687827190f2ae645e2 GIT binary patch literal 874 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vk7#J8+1AIbU z|Ns9Flwsj#1(FdZp_~dll^g2aJA$}1LE7U51%YJBiZnqBFdculhYlSI zePQDH(Aed!@#@v9{V!U0T+*|>Vq|mPaK+-qHfL>(<z;@U}mwJ#*$v?ZZY|dku|t z>TYOnx7uW^y4kR+tIJ@Wf$1uBpzT)k?NpbUwl>yHs;P72AM0gsJN85x|f1nsNASyQ)C^V z5(o6cX?uI1gPQ_$zUt}*MFj!9qne@NAL##8Sy?4sMa%1B#506*U(#MpQkI2X< zc`N_t;!<)|IwT?j3`C$$JEf(8o_)r^aG!xeU0r=914Ae{#Jqy9S^>kcyd=mkm_blU z$=KK>G&D3VtsLmpnX6WvIdc~R-hlxyN~jN}hd;CiI)SsmBeIx*fm;ZK886+f`vVjd zD{+k|aV|AI6tkVJh3R1!8b9vC_gtf zB{NaMEwd=KJijQrSiv`9_e3ofpxV=(E{-7;bCLzbgr`rKFk#BGq?87R>nEOk>FJpx zR5!!H#V1TpU<$_pmPbOx#d~EhvfQbWT_nhq+3L!8?pK_VPC(<7l;G z*2$BHZrL7j2|sUR5%A_P)N-TQ+}Y|GrRdK zV81Pn)+>0zGnMUCiP|Spqc&^AG^y;y-0mPhgGJ5$HDs$bXTdY0@m-PJEq%`?TdG9A z`7w;w(EZ*psMAWc}ikt!qr000(rMObu0a%Ew3 zX>V>IRB3Hx05CK!FfuPNGue__LI3~&s7XXYRCt_C%4rvYKmdi|(V{3Sky0s2sVw0{ z3ns_0{QqBM)L8Df_c<4+W|ZRbuE?ptT;0z>z23f%IS}<{hVT1%ezB)pU1LBR7z?!4 zdf1$>0)?RM<32r|FI3$jzfkuMegO9fmRSW?+;gd{A6?vpl~i!EaT78927Y{aY)A+t zD;|Uj0{6%|rRRA`LWdbZAQrk%Pf@@U0ViwJZw&^h9P>Z*1$ZnRgm9bKlmGw#07*qo IM6N<$g0d3*MgRZ+ literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Class_logo.png b/examples/includes/geshi/docs/api/media/images/Class_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f223c479a6c6fefab504deb84ab824d2e744713 GIT binary patch literal 1600 zcmd5*`!|$%9DdQB9VXJcrO7tT6s8%5m)$T$<9->p85y@dE{&RXZA?TG%_2nB{k}w+ z>>y&K8JEf>)@4JEu#A%^x8$DGyKmbsyZ^yH=X@^b^L>8!JkR-jlN{|WrKJu_0RSLv zZDr;RS2P?)5fX5&yJ6f47l|;kH4TA4Ow2fl06^Tq(T-*gK@j``L!Zj}+HeO}zBX0; zizS_}vsy(-{E4`_@#vbdi+5fGm5%u5_tDdPtzuhX8qOmN&M4C`MSV{xS#?0cPBr16I(qS$$iDTJrh_s?O!p#8Hcm?#qi{w{Bl~rNTh%>k zux{n)ub}uDC~68~PeK9XP|o0n-x!qAyY4;;IgdbbU2Fb*kj)U}I`FAP@Yeb{ME(1wR2$S zCnkTzwDp5^%MQJH%Za}Qw(J@Sb}rN|#d2rO_**uOn}$u>PW5Z&eqR6^w@vF-EowJR z?ytf7pRC>Vy0c(Xy#ZElT5*>`i$x}PS71@3%2n|0Ix}zDrR23?#T;0%YIu7FmT6El z2Nu24DVZbXi)=HebP7bUa4>sWJ4d9GHAl=E1#c}<6Gn-tBHfgEozyY>%|Y;&c|yW4 zku#~q8L_(3kLUF3#=OE^@6x?8LyQ_DL=9+0x1A2}#zl7MT$&`ZUJ%&*xUeUhY#|}I zSN$R%Hj~6`#Raq+3+8G3+=%z@#4@=!KOxb#LH%4E&aW2hTXDiu02{99&efzpfNj@w zsn?)ZV`*i_sYO_)-;O(09;Z}d95XSL46I%8F`F_qo10kk0*qOr$PC`va_ndpbYvy|{2GJehB@IiF4o$aZ>K{XIGb8+#H_!n;6$gipr{DZ!g z{{X(k{~?NKvs$nq$xth|FaSV)_a(%J{)*XyhiJArolOn#XGi$37y!k`j};QcILGus zTQFISh!9pl7@9&C{EEZET*WV3Qx?OA%?t@f)0jaFfT*WU)YT?}FEiZ9@ONZdo1LLu zF7opRBrE~}wa)fRZUyglRb^$GxSn2Pg91AFWDunfuj18GhDIRNFt3KCaO!XG6XR&1 z28*aehm}!<>IiA_!AaB^KQ(Cz%0e>k6#30Eu? zFVRRBHaEw|$2T?#1h?9*(e0eWnYQm1Hr1B!cKi1WHPMl!yyD`-M9a|7P&O+nm`UBf zx#`hy(nM;f-efI&Ys=m~Cg$M5y1IM!ni-dtGv`C5w7MQkIj2kLO^;6v4}(M!NmW%J zqg~58a-sbR!Ac6xD=uAAR*p0`XIvs=o+nJC@!AI@u?L*fb6sg?her$|Pd^gJMy6kX zyY5=9aetfR0c3@|$s=BsOcoC~V2u4xFqbA7rlWwKMHLuT_IuR@E0N<;1(y5jqdklr zA18PT(&hJAnw&ypeXE(*jBty~<~W1~;xeKKN4`lJ4URwYtcit4vd9TpEPUi`Ko+~! znxf<=Hu;%f(yED6tR88cY6$)$k_sYx5+paB)@w47v$fpK_KbB9<-0uWWx$V$Y(nJvu4LwpP~GnArV?p7r+FCdX3sF>*+w zM8ps6Vm(S|1s-pS4xBiFG!w(f$;lxV0eSz9%%(EsBY==fcwRHDvGW Fe*-2SG_e2x literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Constant.png b/examples/includes/geshi/docs/api/media/images/Constant.png new file mode 100644 index 0000000000000000000000000000000000000000..a9c6f28b3591824c0732239096324984401092e5 GIT binary patch literal 752 zcmVOeFFcbb@qHow`d0Y;LfV5s^(xaR!&Cux=r_h zK>yEkwuWTri~;WM?zB!GySux2ODz7(wV9cj|EC>kUsw2=N7!5`|NsB+nG)o;ng6pi z?6#AtQ5D^iW&g!kh=_>Y-QAyDGK@(hpKnk5)xQ6t5&Et%|AnnE%s?=+VL4bRGY=KmW3S?UXD3%7ojB4yZ&Sl06&8RVDFrLHC>x|F0|m!)5=D zWMNxY|E`aEUP|_}Os8!{fqZ!Ru{!;~Pu+z8ja4uIq=V{$Q2oE5_n8Xrj{yJCdF-7Z z_OC#eKOFz28iqL-|EnYarde7~M!IDR)?gv_vy8A<63$a7|GS6&yh+s0%m2(~=8gyd zoe2K4Iq#eo+=dGO)q%E8AK!Z)?wTmWSRMbM5&y4||I~k!LLndTsj>h7010qNS#tmY z3h)2`3h)6!tTdPa001C#MObuGZ)S9NVRB^vO<`klZ*65{X<;BnX>w(EZ*psMAWc}i zkt!qr000(rMObu0a%Ew3X>V>IRB3Hx05CK!FfuPNGue__LI3~&=1D|BRCt_YkcI#b zK`4U(M2Pz6Icht~3ql2S@>nhM`5YqHd=mvh0y@s|8GK1fN}j>Ix{QKA0Y9^hBqh%T z(^Rc&DK|!G1|1(GJ`i8dK0M7tpHq-QLoYCi2h10jNsn_^VK8(|g2;!4`U}LlFfznw zDp-HqkjkAq?C=KG<_Aoa(CHB9TlWKE$_z ijGSU(oWd#~?*ag}r7qqQ?+~c~0000;SsO~ttNgt@c?ITUy+H?~F1$qJv5 zrj%inz4BS|lBY2XpN7wU95Cg+N6)R&S-Wy3tx4&gXH|B=yx^o^#sQu9?QQ>K8~%sZ z{0}Jm@7e#puI6oK)~nE@m)?oj|A$=pANt%j?acp}v%f-5{aU(vY0a7Rz}r@CC;s>y z_~w2^f9i&*uDiZCoO5v6`rY`9vHRwCT`RgWmp`jpSqZe)c-0rXl`kw;yt7~a!fK~g z=)5OIi*oZ8r2!qIu*ouQW?EwBb;IdTOs3w|UZw3aUl-^?yPlho&DXT%Y3a3H_piCa zH_y(z`J!&~1--@#`u#SZWfuag168_I91G66);c&DuZkdK$q?W#UzIB6L*!=K%vvBTz%$TUpUjQPxsc+FV-7 zR7zY|e1`Pi6Tt84q|K9b~#>w5dpFQc%z_t$REF)G#$AI3{PO zi`#}?{&3@lPKQ}}C9A8dZ}IjAKfWk!a7giqTGl_Y+%GXPku##9bLwQK<5PFJZ+-_fA85GosxS7-Us$eq7dr0=(3bNhOU@OqP3*jGIQ@yq)Vq6&7M{#q z477Sr{(QThn~}}e&ZN!sueoC0eDO%k^aC-opNFK(Oq=OhcEPdW>{HKZz2YNN!Y4j; z3AV^N{LRk&iIdY~8yo$^9eXUQx0}^%F{pl^sd+`+YMoB)e`)Cta&kM>a@MPsK9Ml& z)7M|AkoTXLcaDa}VO>_ z%)r1c1j3A$?$-SQ3W}AuMwB=gr6!hS=I1GdWag$a7?|iA80i}r-<%ZX1XQ5_QW2b= zR#Ki=l*-_nm|T>fo0^iDsNj}alvYxA!qX>A zNlIy8vJMV5*3M3^SKHChH*MR#g{~aNJ_mfmqwk-%q}ar&_F&=i{FJ=+5=XdFicd7L z@bKuq?cMu$iKN7hJ&QyoB>wp5$i&=np1gX8$i&uZ%B&^(gI6I0} zGUVzNQK6O$8{S zC}qw=9fKWQ#zRcqIUjNk==S15ts}q2y)L~lP}(>_ogbmaoJrJ0AgwbXi6JhpDPFKT z9$x~a$ENK7000SaNLh0L01EH`01EH{Laa2H0000WbVXQnQ*UN;cVTj608L?Ia&K*A zWNBd_Mrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEBDMFf-Yb zT0#H-0HH}lK~#90W8iRC=0FAv99%)3!YBe-))JP&C<2Chw%iuNNCHkg-d5alQo;xU z8CL}X4_hHdm;k$sti6G8pr((nFjT%dS9ocX$5n$N$)Tp@>xCyk+k0?wOgH`Q@&JYcT)s zdE3HL%*@Q>)vf*e_W$H#w30>t^on|8F81N2s;a8ZvP6i8i1*uE-QC^)@Pqg0b?wn( z|JsUdXkPpC*^GEfs*66hqd1H2uT%f=o&W#;+=l<-g2$mxWdJZVFEBDMFf-YbT0#H- z0Od(UK~#90V{n52MNTM#0YtFI1j@(B2XI0KbfYa?T|L!(nVh{iK>~u&X4;-2GBUh+ zO#b|wKmqRrZ4q7|2-S~r3FdcW5R3`;1aU+4g;eeQ#5oya13hJAO+rKM?S)kNjI5;@ zxP3%G@<6_jL6VUZKZ6*X3`AZi%uqr{fsw(ANe{{o(+mk>VPxPm*V5M)0)jA)NMTb+ zeg-!Ib2&Lxsjy^C=6G9UE@=igP7RJkK126N2W6fJNk&ef)1_7Xj9k=&ZABS?e6Z)F u#ckM?93xmje28y3`Ng@o#2KYQ-UR?_sW14`Hh}s70000AMyVi9{#UaQ0r%7Fss&l*vy)E6e!K$>FVdQ&MBb@0CA5htN;K2 literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Index.png b/examples/includes/geshi/docs/api/media/images/Index.png new file mode 100644 index 0000000000000000000000000000000000000000..6558ec393a6e0b35fb7776a52b4ca9c10da0d5c3 GIT binary patch literal 584 zcmV-O0=NB%P)sGc1s$KlTB|5tUFl&jIZ$KRg6;GCqm5-wl6(B`4Q;1)J+i=@-=`2U5V zz0~Rd#@X$9lDq;jjf$eZgrL)or^gjMgq*e3yWRhls?|-6=3oE-010qNS#tmY3h)2` z3h)6!tTdPa001C#MObuGZ)S9NVRB^vO<`klZ*65{X<;BnX>w(EZ*psMAWc}ikt!qr z000(rMObu0a%Ew3X>V>IRB3Hx05CK!FfuPNGue__LI3~&s!2paRCt^{$?Fn1@%ouFXELYW(Fj^6Z(U`)_51(-|7XseY25!>(WA}p^8eefzIoSOHBLL@ zu5c=u23 zg#EgG*R(4R8Bcv1+IdSoXt7!L5tEf~j@@~uVBhR|_Md6WYSZ+C#*073PQ0UAdtN0gNKbwkHzugYdUHQk=cz1X!nX~(+V z_vf=O_Fb>Npdzh8PLU=1Pe4dSL)YuZgf>gNH%uxGi_eHC{A4Kd*st(Y%3;N2oyz=} znqKw`%X@Y1uQTv0S!*U^fJH$hN@BTe&;g&?!xjVTG>^jPxS@?+*er933 sa(UjQ<*PC{8=_;sg?l=%aQ~mEp5P)i@yk~|9Z;Bfy85}Sb4q9e05`Dm_y7O^ literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Interface_logo.png b/examples/includes/geshi/docs/api/media/images/Interface_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f223c479a6c6fefab504deb84ab824d2e744713 GIT binary patch literal 1600 zcmd5*`!|$%9DdQB9VXJcrO7tT6s8%5m)$T$<9->p85y@dE{&RXZA?TG%_2nB{k}w+ z>>y&K8JEf>)@4JEu#A%^x8$DGyKmbsyZ^yH=X@^b^L>8!JkR-jlN{|WrKJu_0RSLv zZDr;RS2P?)5fX5&yJ6f47l|;kH4TA4Ow2fl06^Tq(T-*gK@j``L!Zj}+HeO}zBX0; zizS_}vsy(-{E4`_@#vbdi+5fGm5%u5_tDdPtzuhX8qOmN&M4C`MSV{xS#?0cPBr16I(qS$$iDTJrh_s?O!p#8Hcm?#qi{w{Bl~rNTh%>k zux{n)ub}uDC~68~PeK9XP|o0n-x!qAyY4;;IgdbbU2Fb*kj)U}I`FAP@Yeb{ME(1wR2$S zCnkTzwDp5^%MQJH%Za}Qw(J@Sb}rN|#d2rO_**uOn}$u>PW5Z&eqR6^w@vF-EowJR z?ytf7pRC>Vy0c(Xy#ZElT5*>`i$x}PS71@3%2n|0Ix}zDrR23?#T;0%YIu7FmT6El z2Nu24DVZbXi)=HebP7bUa4>sWJ4d9GHAl=E1#c}<6Gn-tBHfgEozyY>%|Y;&c|yW4 zku#~q8L_(3kLUF3#=OE^@6x?8LyQ_DL=9+0x1A2}#zl7MT$&`ZUJ%&*xUeUhY#|}I zSN$R%Hj~6`#Raq+3+8G3+=%z@#4@=!KOxb#LH%4E&aW2hTXDiu02{99&efzpfNj@w zsn?)ZV`*i_sYO_)-;O(09;Z}d95XSL46I%8F`F_qo10kk0*qOr$PC`va_ndpbYvy|{2GJehB@IiF4o$aZ>K{XIGb8+#H_!n;6$gipr{DZ!g z{{X(k{~?NKvs$nq$xth|FaSV)_a(%J{)*XyhiJArolOn#XGi$37y!k`j};QcILGus zTQFISh!9pl7@9&C{EEZET*WV3Qx?OA%?t@f)0jaFfT*WU)YT?}FEiZ9@ONZdo1LLu zF7opRBrE~}wa)fRZUyglRb^$GxSn2Pg91AFWDunfuj18GhDIRNFt3KCaO!XG6XR&1 z28*aehm}!<>IiA_!AaB^KQ(Cz%0e>k6#30Eu? zFVRRBHaEw|$2T?#1h?9*(e0eWnYQm1Hr1B!cKi1WHPMl!yyD`-M9a|7P&O+nm`UBf zx#`hy(nM;f-efI&Ys=m~Cg$M5y1IM!ni-dtGv`C5w7MQkIj2kLO^;6v4}(M!NmW%J zqg~58a-sbR!Ac6xD=uAAR*p0`XIvs=o+nJC@!AI@u?L*fb6sg?her$|Pd^gJMy6kX zyY5=9aetfR0c3@|$s=BsOcoC~V2u4xFqbA7rlWwKMHLuT_IuR@E0N<;1(y5jqdklr zA18PT(&hJAnw&ypeXE(*jBty~<~W1~;xeKKN4`lJ4URwYtcit4vd9TpEPUi`Ko+~! znxf<=Hu;%f(yED6tR88cY6$)$k_sYx5+paB)@w47v$fpK_KbB9<-0uWWx$V$Y(nJvu4LwpP~GnArV?p7r+FCdX3sF>*+w zM8ps6Vm(S|1s-pS4xBiFG!w(f$;lxV0eSz9%%(EsBY==fcwRHDvGW Fe*-2SG_e2x literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/L.png b/examples/includes/geshi/docs/api/media/images/L.png new file mode 100644 index 0000000000000000000000000000000000000000..eb334edaeac52e2f473ffd92a49b025fb6148ec3 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*$P6UUaa~gcQtTz3zOL*Scz79Am98pQqyvRG z3p^r=85p=efH0%e8j~47LAC&&5ZCE_)&Kwh7Y~}?0Tf{>3Gxg6&+v4+fftY`;pyTS tQgJK!NBsYWhyUvpj=8p5Ib^(%U@*zon(m*SoDEdN;OXk;vd$@?2>{+EE2IDb literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Lminus.png b/examples/includes/geshi/docs/api/media/images/Lminus.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c43c0aa3bebb499e86eb744b1e47b9a9445ba7 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!VDzYUPT51DfSXiUsv`EJiLsmQh${X`~(Vd z7I;J!Gca&{0AWU_H6}BFf(8LTA+A9B|NsBf`>KHqVn8Lk#c`lIrjj7P;QtIyw;Ol? zc?O;?jv*Ddk_A|pTm=*lC~zFVdQ&MBb@0OtiQr2qf` literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Lplus.png b/examples/includes/geshi/docs/api/media/images/Lplus.png new file mode 100644 index 0000000000000000000000000000000000000000..848ec2fc3bbaab6345864c303684ff8a86559cfb GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!VDzYUPT51DfSXiUsv`EJiLtR`ZJfMMF533 z3p^r=85p=efH0%e8j~47L4yFF5LY1m|NsB#ebqn)F`$y&;y6$pQ%R6t@PCG<+YP*c zJX22>$B>F!$pS1)t^$e&6gZd#)XV}^6#`leL>0XheB5$;*x1}$U0qr4a0#d>%paztiFSddoE z=FO+Zs9v~B@b&OYf=WY?JVJfcJk32QO)AOb$urFVKXE`Ry)jqsH71)XJB8YEt>{GE zGvwvuGqv|cy!A6?%sp|-T8&j?o?bnP-A{*1r^4t+dqpBkBPV|V>IRB3Hx05CK!FfuPNGue__LI3~& zAaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6&Wp{6KYjYq?Si6xbBme*ayGcYrRCt_Y z&;kMn2M1Xdeh6R)4Ab%Sw6|x9hYPq^SqVCeF?quTBwVb*o#mC81mFUy;m%?#?D`xC z0cWuYe|IAv4`YZxESp$_l#sZsh-s)UL?ALUMqSb?I@nP<)JGU7U}h%a#vI_K=%}q7 zq~RmZ$N<)8;N{4}qYx4zCu$87;NdY>VCC|)P=g6*o7-s0FmMCSfC?zsMKS0(@xufx vP5c-vI3ex;lft~dN-&p#Ny9iND4!ny)Wjn48}#yJ00000NkvXXu0mjf>`)kw literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Page.png b/examples/includes/geshi/docs/api/media/images/Page.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe7986ee2e78f7079d6de1a13ef29bff125f7a8 GIT binary patch literal 592 zcmV-W0wTQkb(FJYg{r&I=J@>oPidBsr@_|i|DM0#0xyTVySs>p zi0u&l@7S9O=i(&oFz-*}d|5-wk#ve_0k zZi}ST)an1e-~WcE$O18qgrL(EJcN#?$DzRBm8#XK#^imQz1B}9Gynhq32;bRa{vGe z@Bjb`@Bu=sG?)MY03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22; zDkJ~^02XvbSad^jWnpw_Z*Cw|X>DZyFf=bPGA}SQ*^*j900025Nkl8X^a6$`;}MU&lC(fZYGN)*U*T&WTYe`t|6?P&^gvL>{}6e8nl zLI{`JKlCFG|LqoMkSE{iD56H;IN0Sraje`6bqbr=>+Ac4L(v&iSUtNMDLgY2KvhT^ eCV+sH1<((?kR=WgbuC-~0000)GO-L0AERF6v)dP%qbhFs5=j^@`6F?l_(@;?;SYFPR0 zI9jbQwZey3=y8ba9+c^JAk$@k`bNJ*XM8mL<6q0r!V+YD551g+rvHRYW=KB^jl71Q zyjUEXf%<=gv{N57&;Ray_CaNWG~<7$j7xBl@^MHtX718|yz^v1Gcq;sXrgWOL-%8| zeAujcX!zyfo16VFq#9G>J(EnWtL=RyR-0NB6V)oy zRmEie9Z=A1gd35_HMMe(FE?E78WVI3@nv91+wgViUAV!rpFqJ)Wl_to!seceCS_?; zZ;4o$E4k0B*A>>Q@@^>L31o}zmDNbO)e5c<%)AP+E5P*1yXjXRr0_e>m1)_fP3L*4 zq>@`n#eK};ri8-Yv`eDs;=aU7t-G*r(;{fc=?O5OKSe$`R3j_d*nP9?x%J(%fQEH%67mU3Hek2mE8BI_V-TD<8{d?o6-ef!PG`p%c&+4{j^aUgcH zPg_HSd3If0jjtfvXN7{Bm9@0` z{!FFF(*y6@p7PEXiOALIn)UNaUZG?FMfe@usLHF4iAJOOeEx9SoR_ols++f6a=J|s z5ggQNwU#-2UgKh&U;x$U?l6kKlg`fF$Kh~T&%}(*P&e;MzM$e1iDYH5)s7SzdNQ)O zW|LFc9?jNAIaVEr_>4^{Y;|6Zw5lrHumeb(iS9?J(ExtAVJMHD8w=kA5FA7#v<61y F{sZ~k(bNC{ literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/PrivateClass.png b/examples/includes/geshi/docs/api/media/images/PrivateClass.png new file mode 100644 index 0000000000000000000000000000000000000000..470e6d5684f29e52abb36ee6036a4d0b717f92e4 GIT binary patch literal 790 zcmV+x1L^#UP)WmEhNm^6>N2zOCt|Fuvb2MPgIr%?-{0R%gxJKy#3oLoEQio1TB$RW z>}rOS@9*z3X3RRU*Z=?jNYVd(pWkzHbE2lGGqCn7nbbf>Stx6=M8@%WtGpvWd{9$d zW@ctxl-^f`)gwrPNl|4eO^Yjd!Y3yuC{eAu(Bd|2#VxYmFkYoDiPgf`>UMyN)z#HS z%>A{^=P{-CPSgKgi`geqs99WJM7{YbYtFRD+-aQPBu9}dn9Ep?+$&_jF0SJ+!SP*W zX)~JcM@?QQa<)}jTP=IfF8)Ib00009a7bBm000XT000XT0n*)m`~Uy|Aaq4obW?9; zba!ELWdKcKV{&h8Wn^h#AVz6&Wp{6KYjYq?Si6xbBme*a7IZ~ebVG7wVRUJ4ZXi@? zZDjy3G%qkRFEBINl3GFl008buL_t(|oMUj)Q(}VxtyFm#HwHbAypTdL(6@<=mvd%N zQkP73cXv}CPB4cExH8Hr zR9dNMl-WZB*f~Ua3V1C`?H#MY0*R^toKm_>URD+2h7KTs7*P=&Pi7Gj&r(CfOje+P zFt?7JoTp{7PL{MZM8L#S&O(+`PDicC$POfs3ly+qPy-6^M{5QG1%xD+<>aCiZ7tPU z^H~Lf0(?n|mdsYno>sEH;pIUBhYhhT*-1^kj&-m>@4F3035e9 Ui&^Ep{Qv*}07*qoM6N<$f)e~=1ONa4 literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/PrivateClass_logo.png b/examples/includes/geshi/docs/api/media/images/PrivateClass_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..590e00640baeca2f541347cc1c5067c255030bba GIT binary patch literal 1836 zcmdT^`&Sa!7N)T^!|2#(lU~J2d<$xV*reb%if{uGAB2xcCr~6EBoS~N3`R%8oA1Z9 zjI?x2^HGvbVw2{xv>MSY!8DVxe2kTOO|w!{=Jd;~yVm^+?p|x3z1KPWoOQnaedlBa z1?)G}hv`Eg5JNJFKm!r}(V==^BvfbjfuJYElj%?>bo^=HBn0wFeULw$sMG1d%HLKu zxBzkwfr3JzfTUsI<@w&3l8(u&mT`$j!bTAk>Lj{8{G)6;Xhe<^xY#~9JI zx3?b|Ud!owO;hVQDqYy%2IZmdeCu=a(B{wGi%O+3M75INIh1s3f~0znAN+9Y`W*B2 zYFSHH*zMJT-gTef-zyY~$j*1CuC)_;*9A8gz*V^|uYx-Nq_)2&cB}^f_O_;`#Wz=Dmm0WGd_5vmZPn;Z@Y$?s-xl010-LVn-j7_WpUmV?gQ z#@BnsDCw;D-Mk{e0y63*g(>ik5-}JIM`rWR*c|KVbAjP(z>W_i1`*!8_i(%|;{uGC z=1*tRXf#K<;z00WJ9@QwgxE5?z#+KKmR3oohFArc09Du>_{D}=45RaiWSTAcoE0S( z@N0$7w#FA*`D6m3Ej=?Wu_-VQ{;qw(T^K2l4WQn_MPTm22Kq5Uga8S_V6a;oN&P@u zQzBZxL5Q(6h7b}0@Ff42os>5;w6y`Ds8kaR|6@St|4;V1Z*vQP`#GOQZH!5*#rSH(*E!w%R>-W{9c69(j2#gn5S*Pqeeq^v zzkL7CbksY8FY>ZH_y6!U8jYr2bRG(APR1>F*_YGqtw{Yg0`Hk*&pV0b&!3yS)ld!| zn-f5urNP6I+p~<`D6nDn7fewiT>32o*H`kl6t(#{?$F=*N%E5432(0YCHDnRmtM{%F+ZC$WQDv++M6`c7mUI8vfQsyf=ACU$>$DI+n##uKp{O$Xh-}+|U_|mnTX|Q;*F+<{u+T@*V3jZ|K z&~S*U?dR?=dYp2%b8#zklwvgU3(HA5ZJ*GQU#Pd#ydxV9O*j5)xBk^zxanB&!TRJbl+-sIOMSY7+S!-!q6vOvO6U|hJ<$tucw(e2>IopzU zf2Q#2*c**a=_FsApXeEHs+lu9>UQWW!OhK72-@dJnVPY@2A%?hObj3>@XYkT0K34m Aj{pDw literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/PrivateMethod.png b/examples/includes/geshi/docs/api/media/images/PrivateMethod.png new file mode 100644 index 0000000000000000000000000000000000000000..d01f2b314b973da7318cdb98a71a326f383e5864 GIT binary patch literal 918 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vk7#J8E0(?ST z|NsBrx}lMUpA{(2slZdYq28zK9FXna5yY)2U{iVAD08bu#A0RNsVOVc1TDmPHTipb zdQ55!GnYS0Uh*_%;nVQBj{~OMck8;@+}kAODC6$#?$PP#(BP7mmKGHirRd(Fy|8-qYX6HC z9+&iNuNW;|w!-GTq4$nAHfL?^c7FHT`aNmOeB(356Bn%kIv{R`xBWrwnKNf)W>PYjD}zLwkAT3uZo(G~1G(Z;{#vR6}oNlA%PpSD}U zF^_6j=PGB;3=*#Y$WwN}P*Q6H7Al^Atid zb5j`%O!N(m^bL$}PKt5@s!#x_2+mI{DNig)W$;Z*F3QhMP037DaLX)8Ezd8?E>`f3 z*ga881*rD2r;B4q#hhdTK`}8wQQ_$c$qh{j*4F9e`#W^>b~G%TwQJr~Z#{D#1vl?l z|LazJX0WSGSg|%ebAsU9Bi!N!<-8wzw);;`Y~fl`b(`(zvrGw95l%-IFCTC1&!2ls zzwGV0^wWWiW15+nU*5!-t};9e3k&TQp8P2% zX10&@>Zv(AJSVl5iLPpE{gyxy^(5I^ sFWFixmIS`k36rN!*Izp!t?eTtSH52M{Yh~%f!<^AboFyt=akR{02;ETy8r+H literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/PrivateVariable.png b/examples/includes/geshi/docs/api/media/images/PrivateVariable.png new file mode 100644 index 0000000000000000000000000000000000000000..d76b21d4e9e8656a68989f007945ab14507ae23c GIT binary patch literal 772 zcmV+f1N;1mP)%f|KD9dx9b1xbjG4eNtEH2jam85a{u&(X=GITZxLbNk_B|L=MK=xa7(sn)kg@8o`zfK1-9S*@a5ux7 zfmfd7&Z|n=(z?t5000SaNLh0L01EH`01EH{Laa2H0000WbVXQnQ*UN;cVTj608L?I za&K*AWNBd_Mrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEBDM zFf-YbT0#H-0Od(UK~#90W8e{Sh>wpK_v7H<0s#g#e~U6rcWa$YHYh)|I4&;C+*d}O z2f|lomMalTR8dirW#a+!op`m(q>74+J*{+kKztWlvm~$d^mHFbLpC7aKvFO=TL8$- z(9YH4VPIntQ#1*-Nlnd2bB@(uW8hJbF68FUi^)(>aJDaCV_;(~R6mrqkrNJ-9N zW6+HbC{^VT@L*JM&I(uJVNf@UHVOzZ($7!fbQ1-dZx^5&WvUzCEm6)Q&B_DjGcf1| zBm@>j=z`qG8lcY2t!~7v&IWNmtEDgym~unB%LM?}VJts-{;Z7v0000paztiFSddoE z=FO+Zs9v~B@b&OYf=WY?JVJfcJk32QO)AOb$urFVKXE`Ry)jqsH71)XJB8YEt>{GE zGvwvuGqv|cy!A6?%sp|-T8&j?o?bnP-A{*1r^4t+dqpBkBPV|V>IRB3Hx05CK!FfuPNGue__LI3~& zAaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6&Wp{6KYjYq?Si6xbBme*ayGcYrRCt_Y z&;kMn2M1Xdeh6R)4Ab%Sw6|x9hYPq^SqVCeF?quTBwVb*o#mC81mFUy;m%?#?D`xC z0cWuYe|IAv4`YZxESp$_l#sZsh-s)UL?ALUMqSb?I@nP<)JGU7U}h%a#vI_K=%}q7 zq~RmZ$N<)8;N{4}qYx4zCu$87;NdY>VCC|)P=g6*o7-s0FmMCSfC?zsMKS0(@xufx vP5c-vI3ex;lft~dN-&p#Ny9iND4!ny)Wjn48}#yJ00000NkvXXu0mjf>`)kw literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/StaticVariable.png b/examples/includes/geshi/docs/api/media/images/StaticVariable.png new file mode 100644 index 0000000000000000000000000000000000000000..8e820193cf930c4147eba542a1b50626933d1f42 GIT binary patch literal 688 zcmV;h0#E&kP)ugtEVnh;=iW%reFK|K(=fyleQ_jJUz6HFV9ct*geON>7>N>(GgmfJ|kL+1=gU z^~Y`c%U_K>y!eySuyp^oG^8 zOJ%3#Pt*VAzglvk(fQzS|Kx&gliM$y+%{plJI?=wq~ZVfjLxV|_|0oEwD7g7kJ`IY z``=&x-kSgDYyawSp@vA;vQq!uhw#*m-@tNLp5*`PleCyn|MHYq)&I_`O8L%mFH&Tq z00009a7bBm000W`000W`0Ya=am;e9(Aaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6& zWp{6KYjYq?Si6xbBme*a7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkRFEBINl3GFl007WQ zL_t(|oMT{NQ!(J+;Bd9(Wn%#W1{OIVrx+F&;*6wS&87O>I`iFMG>&~Wn?kpl^s3aTqPC~9aZgzBhqu>l3V zEJEUe@?l}Z!7lo83@mJN_9niTy1Jpl!gdkiKmisO)({&oUzpiX1}q>a${hye3fnpI z39x|#*m&f1fLvyFNkfn=ASHU{Ea4lA_OTmCm4hW!rK?49w W#UB-s5zQI^0000H> zJR*x37`Q%wFr(8NlNmrkwg8_H*Xe!L|Ns9N51QZs6k#d}@(cdY@N~O@7mz3J>Eakt raVz;p{QriB|LYZwxwcz9n9R-~pRXx?mgVYJpb`d8S3j3^P6#nkpi;(?AirP+hi5m^fE-m% z7srr_TgeFwOpI(f46|1#2yiGY`Di?KiU>FVdQ I&MBb@06e2A@c;k- literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Tplus.png b/examples/includes/geshi/docs/api/media/images/Tplus.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8d8f4fd38259b2ef70fc63fad505fb0a0f55a4 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!VDzYUPT51DfSXiUsv`EJiLtRLI=-jc>;wv z3p^r=85p=efH0%e8j~47L4yFF5LY1m|NsB#ebqn)F`$y&;y6$pQ%R6t@PCG<+YP*c zJY!E6$B>F!$pS1)t^$e&6gZd#)XV}^6#`leL>0XheB5$;*x1}$U0qr4a0#d>%86hy4NT6+w`tp00i_>zopr0L}p{>Hq)$ literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/Variable.png b/examples/includes/geshi/docs/api/media/images/Variable.png new file mode 100644 index 0000000000000000000000000000000000000000..8e820193cf930c4147eba542a1b50626933d1f42 GIT binary patch literal 688 zcmV;h0#E&kP)ugtEVnh;=iW%reFK|K(=fyleQ_jJUz6HFV9ct*geON>7>N>(GgmfJ|kL+1=gU z^~Y`c%U_K>y!eySuyp^oG^8 zOJ%3#Pt*VAzglvk(fQzS|Kx&gliM$y+%{plJI?=wq~ZVfjLxV|_|0oEwD7g7kJ`IY z``=&x-kSgDYyawSp@vA;vQq!uhw#*m-@tNLp5*`PleCyn|MHYq)&I_`O8L%mFH&Tq z00009a7bBm000W`000W`0Ya=am;e9(Aaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6& zWp{6KYjYq?Si6xbBme*a7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkRFEBINl3GFl007WQ zL_t(|oMT{NQ!(J+;Bd9(Wn%#W1{OIVrx+F&;*6wS&87O>I`iFMG>&~Wn?kpl^s3aTqPC~9aZgzBhqu>l3V zEJEUe@?l}Z!7lo83@mJN_9niTy1Jpl!gdkiKmisO)({&oUzpiX1}q>a${hye3fnpI z39x|#*m&f1fLvyFNkfn=ASHU{Ea4lA_OTmCm4hW!rK?49w W#UB-s5zQI^0000(x0NIF%{nuT>i_6Z|J+03z&LVrQvdj0nPvbd zPMvIEmeZ?!4s&x# z#i%Uo#W*vP>T-Bh-n}vA&qc6+7`mT2TL1t632;bRa{vGe@Bjb`@Bu=sG?)MY03dWl zSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^jWnpw_ zZ*Cw|X>DZyFf=bPGA}SQ*^*j90002ANklU5Ub z)J&2>v72qTTu7E`nx@t2xdQKkZtdZYg4lY+yP)e911YGU#WzGE3Im~vZA6xzk`9>4 zNL8_RMr5ZhnC39*aq{=8RR=h(7tdcVhw%9H0)imQWkC?GbCM*z2n^6y_rKc*n=K%t TSg55|Cs*qzIWRJ6ld^s^>bP0l+XkKHvAUX literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/file.png b/examples/includes/geshi/docs/api/media/images/file.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb2427f8afe94b50835b0a6fb2f7fc4b6624bb9 GIT binary patch literal 462 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+o!2~3GGZMc6DV-A6h!W?b)Wnj^{5*w_%-mFl zkkV8IBTEIZ#5@Hf0|O%FdgViBVQqh^b}u-UUD* z&H|6fVg?4j!ywFfJby(BP>?0v(btiIVPik{pF~y$21Zp+7srr_TgiX^|F>tp*udH$ zEiL_V#ftUo-3uDh%uP)G{Qt|SZB_7q!9$E~2FI`q8Re^|Ns4w54;**JyG{r3reJX3bz{Zf3vmrZqg`n}6P+S5*tz>i^H* z#2~u%W)Z8#mr%xxhMwd+SvmjaL%%Odb!ew<(5(2Ban^6jjOpAT8-5&KS>(Rw-29d% zNdZfFap?uEMT+k<(v+DOT$Z%I^ZS1lw?N{?lj=*DIus0-A5UO#>EQ|b(2vWFmuh=~9H|IVo^qIey?Dz1hsy_{P4Pvu|$000SaNLh0L01EH`01EH{Laa2H0000W zbVXQnQ*UN;cVTj608L?Ia&K*AWNBd_Mrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$d zbZKvHAXI5>WdJZVFEBDMFf-YbT0#H-0F6mRK~#90WyotAfiM_=;n!)RO))lyYKg9G zDu)jI|9{59Wq7{b4-9^S|1r5?yt?|k_gEL_vSjsQJ~o|}aLiJr)OMPgdUXK!BBdrI ziX117J(mLBNUinDT$y2+3p0|WwfAs4W|lcJ!*ci>ABPQvf>`e66oz{@WlRWx5Nh&6 i1*3pkRRDgc|J5D1CKP}NM>^*K0000|Jy16 literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/function_folder.png b/examples/includes/geshi/docs/api/media/images/function_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..8b3d6e3b12902fd6de044496082464dbc7639d42 GIT binary patch literal 605 zcmV-j0;2tiP)|{;@VQH zutK?#8|2oVPNX5otuVc-H2>T~`qMo_z!(4RRPW0<*~LTu^jkBj5P!Tt|K&_$wm39v z5ILL=BqI z!r&0NoVJJLDxgp-+TMLq>XzlVuBikpI}FsMP+>!akcx{yaKxWv;lIWQI-(jqRCU$Q00000NkvXXu0mjfHW&%O literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/next_button.png b/examples/includes/geshi/docs/api/media/images/next_button.png new file mode 100644 index 0000000000000000000000000000000000000000..cdbc615d994890b8d3b5ebe89d442ea1d0bdcf33 GIT binary patch literal 657 zcmV;C0&e|@P)>%!0InVFe0X3Tk++2-cv|NsBJy}eg}(|db+t*x!g)adv3 z_j7Y|rn=z0$>ZMM-tX`4KW@&Ajg7^{#b#z^wY9a6sobTdrOeFC+TiVjgM-%A*0aLm zTwGj+qT6qh*h+WM*WK!7W@ee0nXJF&WQx{%o7>so?BwU}l&#?3;^@xa?}MP(t-ap6 zEIdd6000SaNLh0L01m?d01m?e$8V@)0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEKJN zFf-)xbMgQH03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^ z0ZK_kK~#90g_GNIgCGzd~1b@PXAis>##hF-Lcwks_T5{Gt1=G+~a%dFwQCnQZU3J+k?=iHfkBIVqw%X0=b%mMM4MWsfC|3Za zJLI<3MRLMm2C;EFN?uzwL|DX3a6V)!kcPBr r4(}qx0<9ZuvwaL3$t_-E{1p8KSMoIIFM}#&00000NkvXXu0mjfmFG8p literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/next_button_disabled.png b/examples/includes/geshi/docs/api/media/images/next_button_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..4a11780fc0ec50dd27cdb6a52f863c511e32b61a GIT binary patch literal 543 zcmV+)0^t3LP)D z03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^j zWnpw_Z*Cw|X>DZyFf=bQGA}SQTlLsPeLfOt#LNVQ}_yWVA&J!XM&=yzgAag0bSrwNq7QKuW}AeCmE|^Nojv;1W49t( zJ^R_7npd}q|9AEYBEEOSPL(b=(wtUnF~5x!^#c9rjMvp>dVHd>fI6h^x!+-x^4?w{ zA}`WpEJtxdM>gE74H3rQb1zDxCZhMp#IYTl92jdPHrzr4kKJTmn+Eji>=$zWWK{du hHd63A_=WQ``UAH88gT1vi|haZ002ovPDHLkV1oT`@4^58 literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/package.png b/examples/includes/geshi/docs/api/media/images/package.png new file mode 100644 index 0000000000000000000000000000000000000000..b04cf566d4ac41fa95f87664cf65325cc51e8a64 GIT binary patch literal 668 zcmV;N0%QG&P)t@djQ|x-^8(p z?4%BxbRnvSIo8(J;;cKFW&rs3_^P0a=H}+Wz`&@4HsP26zocrIZ4l3l0QR&iRXPBo zdnn+jGIdY@nPvdLr+C=OsEk?wl583Es}SUx0Hl8}w3Siws0*g0p<_e<_q#u(c^k{N zhsBHlt8)OYia^7{zq@__-VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^jWnpw_ zZ*Cw|X>DZyFf=bPGA}SQ*^*j90002jNklc}6)3g8( z2ru$H580mZyrWAbSccU12f~7K5mUsGBX6FN7o9)y4In#v$>W9q0000@uL8oa~j{sfyu2e|KUjW+DCy{0JN1+^UXT2cmT$oA=$Mq|M6Jhn+c_M3;+0E zbx;8R*gvs`8movsnPvdrmjLt9Kjg6{xsNKVeGbg7FZ<$8{qAY-)kDUkCzNLg*TZiA z)ja?7TfLMa+qE&-lK}C{I^?=9yq74~zG|$36Zh6a^rZm*+(ZBWW~z4x;hqqmcOiRJ z0IiEc|K?4LUIG8;Po#Y-wvr&V>IRB3Hx05CK!FfuPNGue__LI3~&Aaq4obW?9;ba!ELWdKcKV{&h8 zWn^h#AVz6&Wp{6KYjYq?Si6xbBme*aqDe$SRCt_K&07n zYC8yeE(c9}CP^I;-Xj?!ixGY5~lHzpft}vlT9I`brT10000%q?FnVFe0X3Vv2q^)rKP2vv)}0J@jq_P*4*ihjg4kzX1%?=#l^*vtlzDzt>WeD%*@Qz*49dQ&}@*_ zgM)*ny5P~$Sz@EU>hb z00009a7bBm000id000id0mpBsWB>pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qnSFEBIY z@^kV4001C#MObuGZ)S9NVRB^vO<`klZ*65{X<;BnX>w(EZ*psMAWc}ikt!qr00BTr zL_t(|oOP4!R>L3+K%uvC@aN(<}}S| z_cY8cJz7aQY#zo&M2jq~x36itf~8liMJ`!c@Asvy$I6;i&)Dnru()HiB+edazpMKd zEoJN8-)<(BGm@V>Kss~sJD&cma7A&3Rf z-i?ioW@cust*yny#e;)`TwGjcW@ee0nN!N#@Bjb+32;bRa{vGi!vFvd!vV){sAK>D z03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^j zWnpw_Z*Cw|X>DZyFf=bQGA}SQx z*6k)+-YhrkG_XnH4KgoalbW`Y#C%zLMG(A8#WIe0Sdy)s;aR#>iI`s&ukbi9->Bn; zl^kv0>?j`lHcTk$X~oOxj`mj&)#BNTkGP5zKdfml{jyB_s;gQ~-J%yw(;cg&WqD+e z@4Tv&%scxQ+Swu0bZj8*=8QhlX_YI61C}V0RhrpeSIKn$X;_d%y$~5a%u?9ODEgSKg~J500000NkvXXu0mjffsXN< literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/private_class_logo.png b/examples/includes/geshi/docs/api/media/images/private_class_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..590e00640baeca2f541347cc1c5067c255030bba GIT binary patch literal 1836 zcmdT^`&Sa!7N)T^!|2#(lU~J2d<$xV*reb%if{uGAB2xcCr~6EBoS~N3`R%8oA1Z9 zjI?x2^HGvbVw2{xv>MSY!8DVxe2kTOO|w!{=Jd;~yVm^+?p|x3z1KPWoOQnaedlBa z1?)G}hv`Eg5JNJFKm!r}(V==^BvfbjfuJYElj%?>bo^=HBn0wFeULw$sMG1d%HLKu zxBzkwfr3JzfTUsI<@w&3l8(u&mT`$j!bTAk>Lj{8{G)6;Xhe<^xY#~9JI zx3?b|Ud!owO;hVQDqYy%2IZmdeCu=a(B{wGi%O+3M75INIh1s3f~0znAN+9Y`W*B2 zYFSHH*zMJT-gTef-zyY~$j*1CuC)_;*9A8gz*V^|uYx-Nq_)2&cB}^f_O_;`#Wz=Dmm0WGd_5vmZPn;Z@Y$?s-xl010-LVn-j7_WpUmV?gQ z#@BnsDCw;D-Mk{e0y63*g(>ik5-}JIM`rWR*c|KVbAjP(z>W_i1`*!8_i(%|;{uGC z=1*tRXf#K<;z00WJ9@QwgxE5?z#+KKmR3oohFArc09Du>_{D}=45RaiWSTAcoE0S( z@N0$7w#FA*`D6m3Ej=?Wu_-VQ{;qw(T^K2l4WQn_MPTm22Kq5Uga8S_V6a;oN&P@u zQzBZxL5Q(6h7b}0@Ff42os>5;w6y`Ds8kaR|6@St|4;V1Z*vQP`#GOQZH!5*#rSH(*E!w%R>-W{9c69(j2#gn5S*Pqeeq^v zzkL7CbksY8FY>ZH_y6!U8jYr2bRG(APR1>F*_YGqtw{Yg0`Hk*&pV0b&!3yS)ld!| zn-f5urNP6I+p~<`D6nDn7fewiT>32o*H`kl6t(#{?$F=*N%E5432(0YCHDnRmtM{%F+ZC$WQDv++M6`c7mUI8vfQsyf=ACU$>$DI+n##uKp{O$Xh-}+|U_|mnTX|Q;*F+<{u+T@*V3jZ|K z&~S*U?dR?=dYp2%b8#zklwvgU3(HA5ZJ*GQU#Pd#ydxV9O*j5)xBk^zxanB&!TRJbl+-sIOMSY7+S!-!q6vOvO6U|hJ<$tucw(e2>IopzU zf2Q#2*c**a=_FsApXeEHs+lu9>UQWW!OhK72-@dJnVPY@2A%?hObj3>@XYkT0K34m Aj{pDw literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/tutorial.png b/examples/includes/geshi/docs/api/media/images/tutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..bc19737521daf3fdf8ba84693a6c1db275587a5c GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfZXr^pAgre zprHL{KJDGRx2LCv!T8Mo|NkA*ZeG25wYa$W-Me?omMzQgdGzervomMTq@|^;S+i#5 z%$Y4ME$=`5xp(j0`I}#l9z7Zv8M$@qR-kNkbv01-`}gk!y^mPGos9)r!CBxDS#iRWF{)OWfrBD=NDxcEBHq2o~We) zR4WEj>s*wYSdy8arx22vo62BdqHkafM2UK~>Od6>JzX3_D(1wVzsPr3frB+*)nX0d z)r+?ozWcww_=ZWek(`gs#BPRvqA|;NeJ*kO*ruqfcq}a9c#C3L?KpBF@G1}eAg_> R{R!w;22WQ%mvv4FO#oMzwKo6& literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/tutorial_folder.png b/examples/includes/geshi/docs/api/media/images/tutorial_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..2a468b2a06fa3424ba94773373637d424f91f7e0 GIT binary patch literal 572 zcmV-C0>k}@P)>~W@cuiqoe=KGyn8k-rnBK%*_ATKmXxKdU|^Q=uf|NmyHcL<7#inXPLp`VEqaE{#o000SaNLh0L01FZT01FZU z(%pXi0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEBDMFf-YbT0#H-03dWlSaefwW^{L9 za%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^0HH}lK~#90Rm|HGfj|I&;Z-?S zTE~>lvDmU9)2vA$a-s45?_+lx7yird;s>}vSUUa%B5*H?0lB_-jxz$}S+Eu>Tci^} zf*_zRSBAc7nwO;j`bo#VVd?HJ70@Hv7$8pt&R;?fo08O0cTlDBo5&$ zS2)D&L_ip-Xv-c3iad`)mSr0V%M{(b3i`Z5_cW1MYXWTY*ZT`cP91=4{NC>X0000< KMNUMnLSTaQ$PWMj literal 0 HcmV?d00001 diff --git a/examples/includes/geshi/docs/api/media/images/up_button.png b/examples/includes/geshi/docs/api/media/images/up_button.png new file mode 100644 index 0000000000000000000000000000000000000000..ff36c59356d1d67cf8c4d12cef7b5aff7bf4dbc1 GIT binary patch literal 668 zcmV;N0%QG&P)%Pk4nVFe0X3Tq=+TY{p|NsA1fYZIby?c9mt*x!i*Xj57 z_j7Y|p0wcB-0AP{?>}zNjg5_FW@fduwWXz{lda&z#l@+-;@;%(Zjsl_%*=y>gJX); zOLx%L*4A8HT!y3E-rnA{#N%dWW|^6pp||AZ=k2Gu;O6G$tG?unrQUFp*;j$nOL)=N z-H!7B000SaNLh0L01m?d01m?e$8V@)0000WbVXQnQ*UN;cVTj608L?Ia&K*AWNBd_ zMrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEKJNFf-)xbMgQH z0aZyvK~#90eUl4s!XOZUanyCl+N~BSZdg%F=FV*U|Nm|WGzj(aC4Hp#g}ZVbsUwYZ z&Rzjil!QBIZEnCM*G;mFfhMO*Sgs&ijd4EZ4F>=mqdHh2`yC0Klf6aD**dot!!VqZ z1kM^tYtrbhSZY~S)mve)l_6jX>4Z|XyI6o$PsyzG!CTd_u;_}+68;72Gqbc*E#XaG z{1KHkUhfaBA749OLuPS0vpzyLTx|WwI-s@b{QWyw?8=I(yrMOhmdva(hL@P@CDfl= z3@+A)(FIx?d>#r*+a&qgfBjDR2CScBhYVBOmN=QV;cFbnb7;T&7X-qIrqsl*m$}d$CKcW835(Ow@m?{E zuz;N49J94VK$ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/includes/geshi/docs/api/todolist.html b/examples/includes/geshi/docs/api/todolist.html new file mode 100644 index 0000000..95177c1 --- /dev/null +++ b/examples/includes/geshi/docs/api/todolist.html @@ -0,0 +1,42 @@ + + + + + + Todo List + + + + +

        Todo List

        +

        geshi

        +

        GeSHi::disable_highlighting()

        +
          +
        • Rewrite with array traversal
        • +
        +

        GeSHi::enable_highlighting()

        +
          +
        • Rewrite with array traversal
        • +
        +

        GeSHi::enable_important_blocks()

        +
          +
        • REMOVE THIS SHIZ FROM GESHI!
        • +
        +

        GeSHi::get_language_name_from_extension()

        +
          +
        • Re-think about how this method works (maybe make it private and/or make it a extension->lang lookup?)
        • +
        • static?
        • +
        +

        GeSHi::highlight_lines_extra()

        +
          +
        • Some data replication here that could be cut down on
        • +
        +

        GeSHi::load_from_file()

        +
          +
        • Complete rethink of this and above method
        • +
        +

        + Documentation generated on Thu, 25 Dec 2008 14:34:53 +0100 by phpDocumentor 1.4.2 +

        + + \ No newline at end of file diff --git a/examples/includes/geshi/docs/geshi-doc.html b/examples/includes/geshi/docs/geshi-doc.html new file mode 100644 index 0000000..fff5347 --- /dev/null +++ b/examples/includes/geshi/docs/geshi-doc.html @@ -0,0 +1,4051 @@ + + + + GeSHi Documentation 1.0.8.3 + + + + + + + + +

        GeSHi Documentation

        + +
        + +

        Version 1.0.8.3

        + +

        The GeSHi Logo

        + +
        +
        Authors:
        +
        © 2004 - 2007 Nigel McNie
        + +
        © 2007 - 2009 Benny Baumann
        + +
        © 2008 - 2009 Milian Wolff
        + +
        GeSHi Website:
        +
        http://qbnz.com/highlighter
        +
        + +
        + +

        This is the documentation for GeSHi - Generic Syntax Highlighter.

        + +

        The most modern version of this document is available on the web - +go to http://qbnz.com/highlighter/documentation.php to view it.

        + +

        Any comments, questions, confusing points? Please get in contact with the developers! We +need all the information we can get to make the use of GeSHi and everything related to it (including this documentation) +a breeze.

        + +

        Contents

        + +
        +
        + +

        1 Introduction

        + +

        GeSHi is exactly what the acronym stands for: a Generic Syntax Highlighter. As long +as you have a language file for almost any computer language - whether it be a +scripting language, object orientated, markup or anything in between - GeSHi can +highlight it! GeSHi is extremely customisable - the same source can be highlighted +multiple times in multiple ways - the same source even with a different language. +GeSHi outputs XHTML strict compliant code1, and can +make use of CSS to save on the amount of output. And what is the cost for all of this? You need +PHP. That’s all!

        + +

        1.1 Features

        + +

        Here are some of the standout features of GeSHi:

        + +
        +
        Programmed in PHP:
        +
        GeSHi is coded entirely in PHP. This means that where ever you have PHP, you +can have GeSHi! Almost any free webhost supports PHP, and GeSHi works fine with PHP > 4.3.02.
        + +
        Support for many languages:
        +
        GeSHi comes with more than 100 languages, including PHP, HTML, CSS, Java, C, Lisp, XML, Perl, Python, +ASM and many more!
        + +
        XHTML compliant output:
        +
        GeSHi produces XHTML compliant output, using stylesheets, so you need not worry about +GeSHi ruining your claims to perfection in the standards department ;)
        + +
        Highly customisable:
        +
        GeSHi allows you to change the style of the output on the fly, use CSS classes or not, use an external +stylesheet or not, use line numbering, change the case of output keywords… the list goes on and on!
        + +
        Flexible:
        +
        Unfortunately, GeSHi is quite load/time intensive for large blocks of code. However, you want speed? +Turn off any features you don’t like, pre-make a stylesheet and use CSS classes to reduce the amount of output and more - +it’s easy to strike a balance that suits you.
        +
        + +

        This is just a taste of what you get with GeSHi - the best syntax highlighter for the web in the world!

        + +

        1.2 About GeSHi

        + +

        GeSHi started as a mod for the phpBB forum system, to enable highlighting of more +languages than the available (which can be roughly estimated to exactly 0 ;)). However, it quickly spawned into an +entire project on its own. But now it has been released, work continues on a mod +for phpBB3 - and hopefully for many forum systems, blogs and other web-based systems.

        + +

        Several systems are using GeSHi now, including:

        + +
          +
        • Dokuwiki - An advanced wiki engine
        • +
        • gtk.php.net - Their manual uses GeSHi for syntax highlighting
        • +
        • WordPress - A powerful blogging system4
        • +
        • PHP-Fusion - A constantly evolving CMS
        • +
        • SQL Manager - A Postgres DBAL
        • +
        • Mambo - A popular open source CMS
        • +
        • MediaWiki - A leader in Wikis[^plugin-only]
        • +
        • TikiWiki - A megapowerful Wiki/CMS
        • +
        • TikiPro - Another powerful Wiki based on TikiWiki
        • +
        • WikkaWiki - A flexible and lightweight Wiki engine
        • +
        • RWeb - A site-building tool
        • +
        + +

        GeSHi is the original work of Nigel McNie. The project was later handed over to Benny Baumann. +Others have helped with aspects of GeSHi also, they’re mentioned in the THANKS file.

        + +

        1.3 Credits

        + +

        Many people have helped out with GeSHi, whether by creating language files, submitting bug +reports, suggesting new ideas or simply pointing out a new idea or something I’d missed. All +of these people have helped to build a better GeSHi, you can see them in the THANKS +file.

        + +

        Do you want your name on this list? Why not make a language file, or submit a valid bug? Or perhaps help me with an +added feature I can’t get my head around, or suggest a new feature, or even port +GeSHi to anothe language? There’s lots you can do to help out, and I need it all :)

        + +

        1.4 Feedback

        + +

        I need your feedback! ANYthing you have to say is fine, whether it be a query, +congratulations, a bug report or complaint, I don’t care! I want to make this software +the best it can be, and I need your help! You can contact me in the following ways:

        + + + +

        Remember, any help I am grateful for :)

        + +

        2 The Basics

        + +

        In this section, you’ll learn a bit about GeSHi, how it works and what it uses, how to install it and how to use +it to perform basic highlighting.

        + +

        2.1 Getting GeSHi work

        + +

        If you’re reading this and don’t have GeSHi, that’s a problem ;). So, how do you get your hands on it?

        + +

        2.1.1 Requirements

        + +

        GeSHi requires the following to be installable:

        + +
          +
        • PHP. It’s untested with anything other below 4.4.X. I hope to extend this range soon. I see no reason why +it won’t work with any version of PHP above 4.3.0.
        • +
        • Approximately 2 megabytes of space. The actual script is small - around 150K - but most of the size comes +from the large number of language files (over 100!). If you’re pushed for space, make sure you don’t upload to +your server the docs/ or contrib/ directory, and you may want to leave out any language files that don’t +take your fancy either.
        • +
        + +

        As you can see, the requirements are very small. If GeSHi does NOT work for you in a particular version of PHP, let +me know why and I’ll fix it.

        + +

        2.1.2 Downloading GeSHi

        + +

        There are several ways to get a copy of GeSHi. The first and easiest way of all is +visiting http://qbnz.com/highlighter/downloads.php to obtain the latest version. +This is suitable especially when you plan on using GeSHi on an production website +or otherwise need a stable copy for flawless operation.

        + +

        If you are somewhat more sophisticated or need a feature just recently implemented +you might consider getting GeSHi by downloading via SVN. There are multiple ways +for doing so and each one has its own advantages and disadvantages. Let’s cover +the various locations in the SVN you might download from:

        + +
          +
        • https://geshi.svn.sourceforge.net/svnroot/geshi/tags/:
          +This directory holds all previous releases of GeSHi each as a subdirectory. By downloading from here you can test your code with various old versions +in case something has been broken recently.
        • +
        • https://geshi.svn.sourceforge.net/svnroot/geshi/branches/RELEASE_1_0_X_STABLE/geshi-1.0.X/src/:
          +This directory is the right place for you if you want to have reasonably current versions of GeSHi but need something that is stable. This directory +is updated once in a while between updates whenever there’s something new but which is already reasonably stable. This branch is used to form the +actual release once the work is done.
        • +
        • https://geshi.svn.sourceforge.net/svnroot/geshi/trunk/geshi-1.0.X/src/:
          +This directory is the working directory where every new feature, patch or improvement is committed to. This directory is updated regularly, but is not +guaranteed to be tested and stable at all times. With this version you’ll always get the latest version of GeSHi out there, but beware of bugs! There +will be loads of them here! So this is absolutely not recommended for productive use!
        • +
        + +

        If you have choosen the right SVN directory for you do a quick +svn co $SVNPATH geshi where $SVNPATH is one of the above paths and your desired version of GeSHi will be +downloaded into an subdirectory called “geshi”. If you got a version of GeSHi +you can go on installing as shown below.

        + +

        2.1.3 Extracting GeSHi

        + +

        Packages come in .zip, .tar.gz and .tar.bz2 format, so there’s no complaining about whether it’s available for +you. *nix users probably want .tar.gz or .tar.bz2 and windows users probably want .zip. +And those lucky to download it directly from SVN don’t even need to bother extracting GeSHi.

        + +

        To extract GeSHi in Linux (.tar.gz):

        + +
          +
        1. Open a shell
        2. +
        3. cd to the directory where the archive lies
        4. +
        5. Type tar -xzvf [filename] where [filename] is the name of the archive (typically GeSHi-1.X.X.tar.gz)
        6. +
        7. GeSHi will be extracted to its own directory
        8. +
        + +

        To extract GeSHi in Windows (.zip):

        + +
          +
        1. Open Explorer
        2. +
        3. Navigate to the directory where the archive lies
        4. +
        5. Extract the archive. The method you use will depend on your configuration. Some people can right-click upon +the archive and select “Extract” from there, others may have to drag the archive and drop it upon an extraction program.
        6. +
        + +

        To extract from .zip you’ll need an unzipping program - unzip in Linux, or 7-Zip, WinZip, WinRAR or similar for Windows.

        + +

        2.1.4 Installing GeSHi

        + +

        Installing GeSHi is a snap, even for those most new to PHP. There’s no tricks involved. Honest!

        + +

        GeSHi is nothing more than a PHP class with related language support files. Those of you familiar with PHP can then +guess how easy the installation will be: simply copy it into your include path somewhere. You can put it wherever you +like in this include path. I recommend that you put the language files in a subdirectory of your include path too - +perhaps the same subdirectory that geshi.php is in. Remember this path for later.

        + +

        If you don’t know what an include path is, don’t worry. Simply copy GeSHi to your webserver. So for example, say your +site is at http://mysite.com/myfolder, you can copy GeSHi to your site so the directory structure is like this:

        + +
        http://mysite.com/myfolder/geshi/[language files]
        +http://mysite.com/myfolder/geshi.php
        +
        + +

        Or you can put it in any subdirectory you like:

        + +
        http://mysite.com/myfolder/includes/geshi/[language files]
        +http://mysite.com/myfolder/includes/geshi.php
        +
        + +
        + +
        Caution:
        + +

        When using GeSHi on a live site, the only directory required is the geshi/ subdirectory. Both contrib/ and docs/ are +worthless, and furthermore, as some people discovered, one of the files in contrib had a security hole (fixed as of 1.0.7.3). +I suggest you delete these directories from any live site they are on.

        + +
        + +

        2.2 Basic Usage

        + +

        Use of GeSHi is very easy. Here’s a simple example:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +28
        //
        +// Include the GeSHi library//
        +include_once 'geshi.php'; 
        +//// Define some source to highlight, a language to use
        +// and the path to the language files//
        + $source = '$foo = 45;
        +for ( $i = 1; $i < $foo; $i++ ){
        +  echo "$foo\n";  --$foo;
        +}';$language = 'php';
        + //
        +// Create a GeSHi object//
        + $geshi = new GeSHi($source, $language);
        + //
        +// And echo the result!//
        +echo $geshi->parse_code();
        + +

        As you can see, there’s only three really important lines:

        + +

        include_once('geshi.php')

        + +

        This line includes the GeSHi class for use

        + +

        $geshi = new GeSHi($source, $language);

        + +

        This line creates a new GeSHi object, holding the source and the language you want to use for highlighting.

        + +

        echo $geshi->parse_code();

        + +

        This line spits out the result :)

        + +

        So as you can see, simple usage of GeSHi is really easy. Just create a new GeSHi object and get the code!

        + +

        Since version 1.0.2, there is a function included with GeSHi called geshi_highlight. This behaves exactly as the php +function highlight_string() behaves - all you do is pass it the language you want to use to highlight and the +path to the language files as well as the source. Here are some examples:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +
        // Simply echo the highlighted code
        +geshi_highlight($source, 'php', $path); 
        +// Get the code back, for use later$code = geshi_highlight($source, 'java', $path, true);
        + // Check if there is an error with parsing this code
        + ob_start();
        +$result = geshi_highlight($source, 'perl', $path);$code = ob_get_contents();
        + ob_end_clean();
        +if ( !$result ){
        +    // There was an error with highlighting...}
        +else{
        +    // All OK :)}
        + +

        However, these are really simple examples and doesn’t even begin to cover all the advanced features of GeSHi. +If you want to learn more, continue on to section 3: Advanced Features.

        + +

        3 Advanced Features

        + +

        This section documents the advanced features of GeSHi - strict mode, using CSS classes, changing styles on the fly, +disabling highlighting of some things and more.

        + +

        In this section there are many code snippets. For all of these, you should assume that the GeSHi library has been +included, and a GeSHi object has been created and is referenced by the variable $geshi. Normally, the +source, language and path used are arbitary.

        + +

        3.1 The Code Container

        + +

        The Code Container has a fundamental effect on the layout of your code before you even begin to style. What is the +Code Container? It’s the bit of markup that goes around your code to contain it. By default your code is surrounded +by a <pre>, but you can also specify a <div>.

        + +

        The <pre> header is the default. If you’re familiar with HTML you’ll know that whitespace is rendered +“as is” by a <pre> element. The advantage for you is that if you use <pre> the whitespace +you use will appear pretty much exactly how it is in the source, and what’s more GeSHi won’t have to add a whole +lot of <br />’s and non-breaking spaces (&nbsp;) to your code to indent it. This saves +you source code (and your valuable visitors waiting time and your bandwidth).

        + +

        But if you don’t like <pre> or it looks stupid in your browser no matter what styles you try to +apply to it or something similar, you might want to use a <div> instead. A <div> will +result in more source - GeSHi will have to insert whitespace markup - but in return you can wrap long lines of code +that would otherwise have your browser’s horizontal scrollbar appear. Of course with <div> you can +not wrap lines if you please. The highlighter demo at the GeSHi home page uses the <div> +approach for this reason.

        + +

        At this stage there isn’t an option to wrap the code in <code> tags (unless you use the function +geshi_highlight), partly because of the inconsistent and unexpected ways stuff in <code> tags is +highlighted. Besides, <code> is an inline element. But this may become an option in future versions.

        + +

        As of GeSHi 1.0.7.2 there is a new header type, that specifies that the code should not be wrapped in anything at all.

        + +

        Another requested addition has been made in GeSHi 1.0.7.20 to force GeSHi to create a block around the highlighted +source even if this wasn’t necessary, thus styles that are applied to the output of GeSHi can directly influence +the code only even if headers and footers are present.

        + +

        To change/set the header to use, you call the set_header_type() method. It has one required argument which +defines the container type. Available are:

        + +
        +
        $geshi->set_header_type(GESHI_HEADER_DIV);
        +
        +

        Puts a <div> around both, code and linenumbers. Whitespace is converted to &nbsp; +sequences (i.e. one whitespace and the html entity of a non-breaking whitespace) to keep your indendation level +in tact. Tabs are converted as well and you can manually define the tab-width. Lines are automatically wrapped. +Linenumbers are created using an ordered list.

        +
        + +
        $geshi->set_header_type(GESHI_HEADER_PRE);
        +
        +

        Wraps code and linenumbers in a <pre> container. This way whitespace is kept as-is and thus +this header produces less overhead then the GESHI_HEADER_DIV header type. Since linenumbers are still +created using an ordered list this header type produces invalid HTML.

        +
        + +
        $geshi->set_header_type(GESHI_HEADER_PRE_VALID);
        +
        Available since 1.0.8
        + +
        +

        When linenumbers are disabled, this behaves just like GESHI_HEADER_PRE. In the other case though, a +<div> is used to wrap the code and linenumbers and the <pre> is put inside the list +items (<li>). This means slightly larger HTML output compared to GESHI_HEADER_PRE, but the +output is valid HTML.

        +
        + +
        $geshi->set_header_type(GESHI_HEADER_PRE_TABLE);
        +
        Available since 1.0.8
        + +
        +

        Once again a <div> tag wraps the output. This time though no ordered list is used to create an ordered list, +but instead we use a table with two cells in a single row. The left cell contains a <pre> tag which holds all +linenumbers. The second cell holds the highlighted code, also wrapped in a <pre> tag, just like with +GESHI_HEADER_PRE.

        +
        + +
        +

        This produces valid HTML and works around the nasty selection behaviour of Firefox and other Gecko based +browsers, see SF#1651996 for more information.

        +
        + +
        $geshi->set_header_type(GESHI_HEADER_NONE);
        +
        Available since 1.0.7.2
        + +
        +

        No wrapper is added.

        +
        +
        + +

        Those are the only arguments you should pass to set_header_type. Passing anything else may cause inconsistencies +in what is used as the Code Container (although it should simply use a <pre>). Better not to risk it.

        + +
        + +
        Note:
        + +

        GESHI_HEADER_DIV, GESHI_HEADER_PRE, etc. are constants, so don’t put them in strings!

        + +
        + +
        + +
        Caution:
        + +

        The default styles for the <pre> and <div> will be different, especially if you use + line numbers!

        + +

        I have found that a <pre> results in code that is smaller than for that of a <div>, you + should rectify this difference by using set_overall_style() if you need to. But be aware of this + difference for if you are changing the header type!

        + +
        + +

        3.2 Line Numbers

        + +

        GeSHi has the ability to add line numbers to your code (see the demo available at http://qbnz.com/highlighter/demo.php +to see what can be achieved). Line numbers are a great way to make your code look professional, especially if you use the +fancy line numbers feature.

        + +

        There are multiple methods for highlighting line numbers, but none of them is perfect. Of the various ways to highlight +line numbers GeSHi itself implements 2 different approaches, but allows you +by the way it generates the code to do the line numbers yourself if necessary - but more on this case later.

        + +

        The easiest approach is using the <ol>-tag for generating the line numbers, but +even though this is the easiest one there’s a big drawback with this one when +using Gecko-engine based browsers like Firefox or Konqueror. In these browsers +this approach will select the line numbers along with the code or will include extra markup in the selection.

        + +

        The other approach has been implemented in the 1.0.8 release of GeSHi with the GESHI_HEADER_PRE_TABLE header type. +When using this header type the line numbers are rendered apart from the source +in a table cell while the actual source is formatted as if the GESHI_HEADER_PRE header had been used. +This approach works with Firefox and other Gecko-based browsers so far although extreme care +has to be taken when applying styles to your source as Windows has some fonts +where bold font is of different height than normal or italic text of the same fontface.

        + +

        3.2.1 Enabling Line Numbers

        + +

        To highlight a source with line numbers, you call the enable_line_numbers() method:

        + +

        $geshi->enable_line_numbers($flag); +Where $flag is one of the following:

        + +
          +
        • GESHI_NORMAL_LINE_NUMBERS - Use normal line numbering
        • +
        • GESHI_FANCY_LINE_NUMBERS - Use fancy line numbering
        • +
        • GESHI_NO_LINE_NUMBERS - Disable line numbers (default)
        • +
        + +

        Normal line numbers means you specify a style for them, and that style gets applied to all of them. Fancy line numbers +means that you can specify a different style for each nth line number. You change the value of n (default 5):

        + +

        $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 37);

        + +

        The second parameter is not used in any other mode. Setting it to 0 is the same as simply using normal line numbers. +Setting it to 1 applies the fancy style to every line number.

        + +
        + +
        Note:
        + +

        The values above are CONSTANTS - so don’t put them in strings!

        + +
        + +

        3.2.2 Styling Line Numbers

        + +

        As of GeSHi 1.0.2, line numbers are added by the use of ordered lists. This solves the old issues of line number +styles inheriting from styles meant for the code. Also, this solves an important issue about selecting code. For +example, line numbers look nice, but when you go to select the code in your browser to copy it? You got the line +numbers too! Not such a good thing, but thankfully this issue is now solved. What is the price? Unfortunately the +whole way that styles are inherited/used has changed for those of you who were familiar with 1.0.1, and there is +quite a bit more HTML involved. So think carefully about these things before you enable line numbers.

        + +

        Now, onto how to style line numbers:

        + +

        Styles are set for line numbers using the set_line_style() method:

        + +

        $geshi->set_line_style('background: #fcfcfc;');

        + +

        If you’re using Fancy Line Numbers mode, you pass a second string for the style of the nth line number:

        + +

        $geshi->set_line_style('background: #fcfcfc;', 'background: #f0f0f0;');

        + +

        The second style will have no effect if you’re not using Fancy Line Numbers mode.

        + +

        By default, the styles you pass overwrite the current styles. Add a boolean “true” after the styles you specify to combine them with the current styles:

        + +
        PHP code
        1
        +23
        +4
        $geshi->set_line_style('background: red;', true);
        + // or, for fancy line numbers
        +$geshi->set_line_style('background: red;', 'background: blue;', true);
        + +
        + +
        Note:
        + +

        Due to a bug with Firefox the issue that should have been fixed with 1.0.2 has reappeared in another form as Firefox + includes extra text\markup into plaintext versions of webpage copies. This can sometimes be useful (actually it’s + used to get the plaintext version of this documentation), but more often is quite annoying. Best practice so far is + to either not use line numbers, or offer the visitor of your page a plaintext version of your source. To learn more + have a look at the SF.net BugTracker Issue #1651996. This will hopefully be fixed in GeSHi version 1.2 + or as soon as Firefox provides webdevelopers with adequate ways to control this feature - whichever comes first!

        + +
        + +
        + +
        Caution:
        + +

        When you set line number styles, the code will inherit those styles! This is the main issue to come out of the 1.0.2 + release. If you want your code to be styled in a predictable manner, you’ll have to call the set_code_style() + method to rectify this problem.

        + +

        Note also that you cannot apply background colours to line numbers unless you use set_overall_style(). + Here’s how you’d style:

        + +
          +
        1. Use set_overall_style() to style the overall code block. For example, you can set the border +style/colour, any margins and padding etc. using this method. In addition: set the background colour for +all the line numbers using this method.

        2. +
        3. Use set_line_style() to style the foreground of the line numbers. For example, you can set the colour, +weight, font, padding etc. of the line numbers using this method.

        4. +
        5. Use set_code_style() to explicitly override the styles you set for line numbers using +set_line_style. For example, if you’d set the line numbers to be bold (or even if you’d only set +the fancy line number style to be bold), and you didn’t actually want your code to be bold, you’d make sure +that font-weight: normal; was in the stylesheet rule you passed to set_code_style().

          + +

          This is the one major change from GeSHi 1.0.1 - make sure you become familiar with this, and make sure that you check +any code you have already styled with 1.0.1 when you upgrade to make sure nothing bad happens to it.

        6. +
        + +
        + +

        3.2.3 Choosing a Start Number

        + +

        As of GeSHi 1.0.2, you can now make the line numbers start at any number, rather than just 1. This feature is useful +if you’re highlighting code from a file from around a certain line number in that file, as an additional guide to +those who will view the code. You set the line numbers by calling the start_line_numbers_at() method:

        + +

        $geshi->start_line_numbers_at($number);

        + +

        $number must be a positive integer (or zero). If it is not, GeSHi will convert it anyway.

        + +

        If you have not enabled line numbers, this will have no effect.

        + +
        + +
        Caution:
        + +

        Although I’d like GeSHi to have XHTML strict compliance, this feature will break compliancy (however transitional + compliancy remains). This is because the only widely supported way to change the start value for line numbers is + by using the start=”number” attribute of the <ol> tag. Although CSS does provide a mechanism for + doing this, it is only supported in Opera versions 7.5 and above (not even Firefox supports this).

        + +
        + +

        3.3 Using CSS Classes

        + +

        Using CSS to highlight your code instead of in-lining the styles is a definate bonus. Not only is it more compliant +(the w3c is deprecating the style attribute in XHTML 2.0) but it results in far less outputted code - up to a whopping +90% saving - which makes a *huge* difference to those unlucky of us on modems!

        + +

        3.3.1 Enabling CSS Classes

        + +

        By default, GeSHi doesn’t use the classes, so it’s easy just to whack out some highlighted code if you need without +worrying about stylesheets. However, if you’re a bit more organised about it, you should use the classes ;). To turn +the use of classes on, you call the enable_classes() method:

        + +

        $geshi->enable_classes();

        + +

        If you want to turn classes OFF for some reason later:

        + +

        $geshi->enable_classes(false);

        + +

        If classes are enabled when parse_code() is called, then the resultant source will use CSS classes in the +output, otherwise it will in-line the styles. The advantages of using classes are great - the reduction in source will +be very noticeable, and what’s more you can use one stylesheet for several different highlights on the same page. In +fact, you can even use an external stylesheet and link to that, saving even more time and source (because stylesheets +are cached by browsers).

        + +
        + +
        Note:
        + +

        There have been problems with inline styles and the Symbol Highlighting added in 1.0.7.21. If you can you should + therefore turn CSS classes ON to avoid those issues. Although latest reworks in 1.0.8 should fix most of those issues.

        + +
        + +
        + +
        Caution:
        + +

        This should be the very first method you call after creating a new GeSHi object! That way, various other methods + can act upon your choice to use classes correctly. In theory, you could call this method just before parsing the + code, but this may result in unexpected behaviour.

        + +
        + +

        3.3.2 Setting the CSS class and ID

        + +

        You can set an overall CSS class and id for the code. This is a good feature that allows you to use the same +stylesheet for many different snippets of code. You call set_overall_class() and set_overall_id +to accomplish this:

        + +
        PHP code
        1
        +2
        $geshi->set_overall_class('mycode');
        +$geshi->set_overall_id('dk48ck');
        + +

        The default classname is the name of the language being used. This means you can use just the one stylesheet for all +sources that use the same language, and incidentally means that you probably won’t have to call these methods too often.

        + +

        CSS IDs are supposed to be unique, and you should use them as such. Basically, you can specify an ID for your code +and then use that ID to highlight that code in a unique way. You’d do this for a block of code that you expressly +wanted to be highlighted in a different way (see the section below on gettting the stylesheet for your code for an example).

        + +
        + +
        Note:
        + +

        As of GeSHi 1.0.8 the class name will always include the language name used for highlighting.

        + +
        + +

        3.3.3 Getting the stylesheet for your code

        + +

        The other half of using CSS classes is getting the stylesheet for use with the classes. GeSHi makes it very easy to +get a stylesheet for your code, with one easy method call:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +
        $geshi->enable_classes();
        + // Here we have code that will spit out a header for
        +// a stylesheet. For example: 
        +echo '<html><head><title>Code</title>
        +<style type="text/css"><!--';
        +// Echo out the stylesheet for this code blockecho $geshi->get_stylesheet();
        + // And continue echoing the page
        + echo '-->
        +</style></head><body>';
        + +

        The get_stylesheet() method gets the stylesheet for your code in one easy call. All you need to do +is output it in the correct place. As you can also see, you don’t even have to enable class usage to get the +stylesheet nessecary either - however not enabling classes but using the stylesheet may result in problems later.

        + +

        By default, get_stylesheet() tries to echo the least amount of code possible. Although currently it doesn’t +check to see if a certain lexic is even in the source, you can expect this feature in the future. At least for the +present however, if you explicitly disable the highlighting of a certain lexic, or disable line numbers, the related +CSS will not be outputted. This may be a bad thing for you perhaps you’re going to use the stylesheet for many blocks +of code, some with line numbers, others with some lexic enabled where this source has it disabled. Or perhaps you’re +building an external stylesheet and want all lexics included. So to get around this problem, you do this:

        + +

        $geshi->get_stylesheet(false);

        + +

        This turns economy mode off, and all of the stylesheet will be outputted regardless.

        + +

        Now lets say you have several snippets of code, using the same language. In most of them you don’t mind if they’re +highlighted the same way (in fact, that’s exactly what you want) but in one of them you’d like the source to be +highlighted differently. Here’s how you can do that:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +2829
        +3031
        +3233
        +3435
        +3637
        +3839
        +4041
        +4243
        +4445
        +4647
        +48
        // assume path is the default "geshi/" relative to the current directory
        + $geshi1 = new GeSHi($source1, $lang);
        +$geshi2 = new GeSHi($source2, $lang); 
        +$geshi3 = new GeSHi($source3, $lang); 
        +// Turn classes on for all sources$geshi1->enable_classes();
        + $geshi2->enable_classes();
        +$geshi3->enable_classes(); 
        +// Make $geshi3 unique$geshi3->set_overall_id('different');
        +  
        +//// Methods are called on $geshi3 to change styles...
        +// 
        +echo '<html><head><title>Code</title>
        + <style type="text/css">
        +<!--';
        + // Get the nessecary stylesheets
        +echo $geshi1->get_stylesheet(); 
        +echo $geshi3->get_stylesheet(); 
        +echo '--></style></head>
        +<body>'; 
        + echo 'Code snippet 1:';
        +echo $geshi1->parse_code();echo 'Code snippet 2 (same highlighting as 1):';
        + echo $geshi2->parse_code();
        +echo 'Code snippet 3 (DIFFERENT highlighting):';echo $geshi3->parse_code();
        +  
        +echo '</body></html>';
        + +

        Before version 1.0.2, you needed to set the class of the code you wanted to be unique to the empty string. This +limitation has been removed in version 1.0.2 - if you set the ID of a block of code, all styling will be done based +on that ID alone.

        + +

        3.3.4 Using an External Stylesheet

        + +

        An external stylesheet can reduce even more the amount of code needed to highlight some source. However there are some +drawbacks with this. To use an external stylesheet, it’s up to you to link it in to your document, normally with +the following HTML:

        + +
        HTML code
        1
        +23
        +
        <html>
        +<head><link rel="stylesheet" type="text/css" href="url_to_stylesheet.css" />
        + +

        In your external stylesheet you put CSS declarations for your code. Then just make sure you’re using the correct class (use +set_overall_class() to ensure this) and this should work fine.

        + +

        This method is great if you don’t mind the source always being highlighted the same (in particular, if you’re making a +plugin for a forum/wiki/other system, using an external stylesheet is a good idea!). It saves a small amount of code and +your bandwidth, and it’s relatively easy to just change the stylesheet should you need to. However, using this will render +the methods that change the styles of the code useless, because of course the stylesheet is no longer being dynamically +generated. You can still disable highlighting of certain lexics dynamically, however.

        + +
        + +
        Note:
        + +

        As of version 1.0.2, GeSHi comes with a contrib/ directory, which in it contains a “wizard” script for creating + a stylesheet. Although this script is by no means a complete solution, it will create the necessary rules for the + basic lexics - comments, strings for example. Things not included in the wizard include regular expressions for any + language that uses them (PHP and XML are two languages that use them), and keyword-link styles. However, this script + should take some of the tedium out of the job of making an external stylesheet. Expect a much better version of this + script in version 1.2!

        + +
        + +

        3.4 Changing Styles

        + +

        One of the more powerful features of GeSHi is the ability to change the style of the output dynamically. Why be chained +to the boring styles the language authors make up? You can change almost every single aspect of highlighted code - and +can even say whether something is to be highlighted at all.

        + +

        If you’re confused about “styles”, you probably want to have a quick tutorial in them so you know what you can do with +them. Checkout the homepage of CSS at http://www.w3.org/Style/CSS.

        + +

        3.4.1 The Overall Styles

        + +

        The code outputted by GeSHi is either in a <div> or a <pre> (see the section entitled “The +Code Container”), and this can be styled.

        + +

        $geshi->set_overall_style('... styles ...'); +Where styles is a string containing valid CSS declarations. By default, these styles overwrite the current styles, but you can change this by adding a second parameter:

        + +

        $geshi->set_overall_style('color: blue;', true); +The default styles “shine through” wherever anything isn’t highlighted. Also, you can apply more advanced styles, like position: (fixed|relative) etc, because a <div>/<pre> is a block level element.

        + +
        + +
        Note:
        + +

        Remember that a <div> will by default have a larger font size than a <pre>, as discussed in the section “The Code Container”.

        + +
        + +

        3.4.2 Line Number Styles

        + +

        You may wish to refer to the section [Styling Line Numbers][1] before reading this section.

        + +

        As of version 1.0.2, the way line numbers are generated is different, so therefore the way that they are styled is +different. In particular, now you cannot set the background style of the fancy line numbers to be different from that +of the normal line numbers.

        + +

        Line number styles are set by using the method set_line_style:

        + +

        $geshi->set_line_style($style1, $style2);

        + +

        $style1 is the style of the line numbers by default, and $style2 is the style of the fancy line numbers.

        + +
        + +
        Caution:
        + +

        Things have changed since 1.0.1! This note is very important - please make sure you check this twice before + complaining about line numbers!

        + +

        Because of the way that ordered lists are done in HTML, there really isn’t normally a way to style the actual + numbers in the list. I’ve cheated somewhat with GeSHi - I’ve made it possible to use CSS to style the foreground of + the line numbers. So therefore, you can change the color, font size and type, and padding on them. If you want to + have a pretty background, you must use set_overall_style() to do this, and use set_code_style() + to style the actual code! This is explained in the section above: Styling Line Numbers.

        + +

        In addition, the styles for fancy line numbers is now the difference between the normal styles and the styles you want + to achieve. For example, in GeSHi prior to 1.0.2 you may have done this to style line numbers:

        + +

        $geshi->set_line_style('color: red; font-weight: bold;', 'color: green; font-weight: bold');

        + +

        Now you instead can do this:

        + +

        $geshi->set_line_style('color: red; font-weight: bold;', 'color: green;');

        + +

        The font-weight: bold; will automatically carry through to the fancy styles. This is actually a small + saving in code - but the difference may be confusing for anyone using 1.0.1 at first.

        + +
        + +

        3.4.3 Setting Keyword Styles

        + +

        Perhaps the most regular change you will make will be to the styles of a keyword set. In order to change the styles for +a particular set, you’ll have to know what the set is called first. Sets are numbered from 1 up. Typically, set 1 +contains keywords like if, while, do, for, switch etc, set 2 contains null, false, true etc, set 3 +contains function inbuilt into the language (echo, htmlspecialchars etc. in PHP) and set 4 contains data types and +similar variable modifiers: int, double, real, static etc. However these things are not fixed, and you should +check the language file to see what key you want. Having a familiarity with a language file is definately a plus for +using it.

        + +

        To change the styles for a keyword set, call the set_keyword_group_style() method:

        + +

        $geshi->set_keyword_group_style($group, $styles);

        + +

        Where $group is the group to change the styles for and $styles is a string containing the styles +to apply to that group.

        + +

        By default, the styles you pass overwrite the current styles. Add a boolean true after the styles you specify to +combine them with the current styles:

        + +

        $geshi->set_keyword_group_style(3, 'color: white;', true);

        + +

        3.4.4 Setting Comment Styles

        + +

        To change the styles for a comment group, call the set_comments_style() method:

        + +

        $geshi->set_comments_style($group, $styles);

        + +

        Where $group is either a number corresponding to a single-line comment, or the string 'MULTI' to +specify multiline comments:

        + +
        PHP code
        1
        +2
        $geshi->set_comments_style(1, 'font-style: italic;');
        +$geshi->set_comments_style('MULTI', 'display: hidden;');
        + +

        By default, the styles you pass overwrite the current styles. Add a boolean true after the styles you specify to +combine them with the current styles:

        + +

        $geshi->set_comments_style(1, 'font-weight: 100;', true);

        + +
        + +
        Note:
        + +

        In 1.0.7.22 a new kind of Comments called “COMMENT_REGEXP” has been added. Those are handled by setting single + line comment styles.

        + +
        + +

        3.4.5 Setting Other Styles

        + +

        GeSHi can highlight many other aspects of your source other than just keywords and comments. Strings, Numbers, Methods +and Brackets among other things can all also be highlighted. Here are the related methods:

        + +
        PHP code
        1
        +23
        +45
        +67
        +
        $geshi->set_escape_characters_style($styles[, $preserve_defaults]);
        +$geshi->set_symbols_style($styles[, $preserve_defaults]); 
        +$geshi->set_strings_style($styles[, $preserve_defaults]);$geshi->set_numbers_style($styles[, $preserve_defaults]);
        +$geshi->set_methods_style($key, $styles[, $preserve_defaults]);$geshi->set_regexps_style($key, $styles[, $preserve_defaults]);
        + +

        $styles is a string containing valid stylesheet declarations, while $preserve_defaults should be set +to true if you want your styles to be merged with the previous styles. In the case of set_methods_style(), +you should select a group to set the styles of, check the language files for the number used for each “object splitter”.

        + +

        Like this was possible for set_method_style a new parameter has been introduced for +set_symbols_style too which allows you to select the group of symbols for which you’d like to change your +style. $geshi->set_symbols_style($styles[, $preserve_defaults[, $group]]); If the third parameter is not +given, group 0 is assumed. Furthermore you should note that any changes to group 0 are also reflected in the bracket +style, i.e. a pass-through call to set_bracket_style is made.

        + +
        + +
        Note:
        + +

        Since GeSHi 1.0.8 multiple styles for strings and numbers are supported, though the API doesn’t provide full access yet.

        + +
        + +

        3.5 Case Sensitivity and Auto Casing

        + +

        Controlling the case of the outputted source is an easy job with GeSHi. You can control which keywords are converted in +case, and also control whether keywords are checked in a case sensitive manner.

        + +

        3.5.1 Auto-Caps/NoCaps

        + +

        Auto-Caps/NoCaps is a nifty little feature that capitalises or lowercases automatically certain lexics when they are +styled. I dabble in QuickBASIC, a dialect of BASIC which is well known for it’s capatalisation, and SQL is another +language well known for using caps for readability.

        + +

        To change what case lexics are rendered in, you call the set_case_keywords() method:

        + +

        $geshi->set_case_keywords($caps_modifier);

        + +

        The valid values to pass to this method are:

        + +
          +
        • GESHI_CAPS_NO_CHANGE - Don’t change the case of any lexics, leave as they are found
        • +
        • GESHI_CAPS_UPPER - Uppercase all lexics found
        • +
        • GESHI_CAPS_LOWER - Lowercase all lexics found
        • +
        + +
        + +
        Caution:
        + +

        When I say “lexic”, I mean “keywords”. Any keyword in any keyword array will be modified using this option! + This is one small area of inflexibility I hope to fix in 1.2.X.

        + +
        + +

        I suspect this will only be used to specify GESHI_CAPS_NO_CHANGE to turn off autocaps for languages like SQL +and BASIC variants, like so:

        + +
        PHP code
        1
        +2
        $geshi = new GeSHi($source, 'sql');
        +$geshi->set_case_keywords(GESHI_CAPS_NO_CHANGE); // don't want keywords capatalised
        + +

        All the same, it can be used for some interesting effects:

        + +
        PHP code
        1
        +23
        +4
        $geshi = new GeSHi($source, 'java');
        +// Anyone who's used java knows how picky it is about CapitalLetters...$geshi->set_case_keywords(GESHI_CAPS_LOWER);
        +// No *way* the source will look right now ;)
        + +

        3.5.2 Setting Case Sensitivity

        + +

        Some languages, like PHP, don’t mind what case function names and keywords are in, while others, like Java, depend on +such pickiness to maintain their bad reputations ;). In any event, you can use the set_case_sensitivity() +to change the case sensitiveness of a particular keyword group from the default:

        + +

        $geshi->set_case_sensitivity($key, $sensitivity);

        + +

        Where $key is the key of the group for which you wish to change case sensitivness for (see the language file +for that language), and $sensitivity is a boolean value - true if the keyword is case sensitive, and +false if not.

        + +

        3.6 Changing the Source, Language, Config Options

        + +

        What happens if you want to change the source to be highlighted on the fly, or the language. Or if you want to specify +any of those basic fields after you’ve created a GeSHi object? Well, that’s where these methods come in.

        + +

        3.6.1 Changing the Source Code

        + +

        To change the source code, you call the set_source() method:

        + +

        $geshi->set_source($newsource);

        + +

        Example:

        + +
        PHP code
        1
        +23
        +45
        +67
        +8
        $geshi = new GeSHi($source1, 'php');
        + // Method calls to specify various options...
        + $code1 = $geshi->parse_code();
        + $geshi->set_source($source2);
        +$code2 = $geshi->parse_code();
        + +

        3.6.2 Changing the Language

        + +

        What happens if you want to change the language used for highlighting? Just call set_language():

        + +

        $geshi->set_language('newlanguage');

        + +

        Example:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +10
        $geshi = new GeSHi($source, 'php');
        + $code = $geshi->parse_code();
        + // Highlight GeSHi's output
        +$geshi->set_source($code); 
        +$geshi->set_language('html4strict');$geshi->enable_classes(false);
        +echo $geshi->parse_code();
        + +

        As of GeSHi 1.0.5, you can use the method load_from_file() to load the source code and language from a file. +Simply pass this method a file name and it will attempt to load the source and set the language.

        + +

        $geshi->load_from_file($file_name, $lookup);

        + +

        $file_name is the file name to use, and $lookup is an optional parameter that contains a lookup +array to use for deciding which language to choose. You can use this to override GeSHi’s default lookup array, which +may not contain the extension of the file you’re after, or perhaps does have your extension but under a different +language. The lookup array is of the form:

        + +
        PHP code
        1
        +23
        +4
        array(
        +   'lang_name' => array('extension', 'extension', ...),   'lang_name' ...
        +);
        + +

        Also, you can use the method get_language_name_from_extension() if you need to convert a file extension +to a valid language name. This method will return the empty string if it could not find a match in the lookup, and +like load_from_file it accepts an optional second parameter that contains a lookup array.

        + +
        + +
        Note:
        + +

        Names are case-insensitive - they will be converted to lower case to match a language file however. So if you’re + making a language file, remember it should have a name in lower case.

        + +
        + +
        + +
        Note:
        + +

        What you pass to this method is the name of a language file, minus the .php extension. If you’re writing a plugin + for a particular application, it’s up to you to somehow convert user input into a valid language name.

        + +
        + +
        + +
        Note:
        + +

        Since GeSHi 1.0.8 this function does not reset language settings for an already loaded language. If you want + to highlight code in the same language with different settings add the optional + $force_reset parameter:

        + +

        $geshi->set_language('language', true);

        + +
        + +
        + +
        Caution:
        + +

        GeSHi include()s the language file, so be careful to make sure that users can’t pass some wierd + language name to include any old script! GeSHi tries to strip non-valid characters out of a language name, but + you should always do this your self anyway. In particular, language files are always lower-case, with either + alphanumeric characters, dashes or underscores in their name.

        + +

        At the very least, strip “/” characters out of a language name.

        + +
        + +

        3.6.3 Changing the Language Path

        + +

        What happens if all of a sudden you want to use language files from a different directory from the current +language file location? You call the set_language_path() method:

        + +

        $geshi->set_language_path($newpath);

        + +

        It doesn’t matter whether the path has a trailing slash after it or not - only that it points to a valid folder. +If it doesn’t, that’s your tough luck ;)

        + +

        3.6.4 Changing the Character Set

        + +
        + +
        Note:
        + +

        Although GeSHi itself does not require to know the exact charset of your source you + will need to set this option when processing sources where multi-byte characters can occur. + As of GeSHi 1.0.7.18 internally a rewrite of htmlspecialchars is used + due to a security flaw in that function that is unpatched in even the most recent PHP4 versions and in PHP5 < 5.2. + Although this does no longer explicitely require the charset it is required again + as of GeSHi 1.0.8 to properly handle multi-byte characters (e.g. after an escape char).

        + +
        + +
        + +
        Note:
        + +

        As of GeSHi 1.0.8 the default charset has been changed to UTF-8.

        + +
        + +

        As of version 1.0.3, you can use the method set_encoding() to specify the character set that your source +is in. Valid names are those names that are valid for the PHP mbstring library:

        + +

        $geshi->set_encoding($encoding);

        + +

        There is a table of valid strings for $encoding at the php.net manual linked to above. If you do not +specify an encoding, or specify an invalid encoding, the character set used is ISO-8859-1.

        + +

        3.7 Error Handling

        + +

        What happens if you try to highlight using a language that doesn’t exist? Or if GeSHi can’t read a required file? +The results you get may be confusing. You may check your code over and over, and never find anything wrong. GeSHi +provides ways of finding out if GeSHi itself found anything wrong with what you tried to do. After highlighting, +you can call the error() method:

        + +

        $geshi = new GeSHi('hi', 'thisLangIsNotSupported');

        + +

        echo $geshi->error(); // echoes error message

        + +

        The error message you will get will look like this:

        + +
        +

        GeSHi Error: GeSHi could not find the language thisLangIsNotSupported (using path geshi/) (code 2)

        +
        + +

        The error outputted will be the last error GeSHi came across, just like how mysql_error() works.

        + +

        3.8 Disabling styling of some Lexics

        + +

        One disadvantage of GeSHi is that for large source files using complex languages, it can be quite slow with +every option turned on. Although future releases will concentrate on the speed/resource side of highlighting, +you can gain speed by disabling some of the highlighting options. This is done by using a +series of set_*_highlighting methods:

        + +
        +
        set_keyword_group_highlighting($group, $flag):
        +
        Sets whether a particular $group of keywords is to be highlighted or not. Consult the necessary +language file(s) to see what $group should be for each group (typically a positive integer). +$flag is false if you want to disable highlighting of this group, and true if you want +to re-enable higlighting of this group. If you disable a keyword group then even if the keyword group has a +related URL one will not be generated for that keyword.
        + +
        set_comments_highlighting($group, $flag):
        +
        Sets whether a particular $group of comments is to be highlighted or not. Consult the necessary +language file(s) to see what $group should be for each group (typically a positive integer, or th +string 'MULTI' for multiline comments. $flag is false if you want to disable +highlighting of this group, and true if you want to re-enable highlighting of this group.
        + +
        set_regexps_highlighting($regexp, $flag):
        +
        Sets whether a particular $regexp is to be highlighted or not. Consult the necessary language file(s) +to see what $regexp should be for each regexp (typically a positive integer, or the string 'MULTI' +for multiline comments. $flag is false if you want to disable highlighting of this group, +and true if you want to re-enable highlighting of this group.
        +
        + +

        The following methods:

        + +
          +
        • set_escape_characters_highlighting($flag)
        • +
        • set_symbols_highlighting($flag)
        • +
        • set_strings_highlighting($flag)
        • +
        • set_numbers_highlighting($flag)
        • +
        • set_methods_highlighting($flag)
        • +
        + +

        Work on their respective lexics (e.g. set_methods_highlighting() will disable/enable highlighting of methods). +For each method, if $flag is false then the related lexics will not be highlighted at all (this +means no HTML will surround the lexic like usual, saving on time and bandwidth.

        + +

        In case all highlighting should be disabled or reenabled GeSHi provides two methods called disable_highlighting() +and enable_highlighting($flag). The optional paramter $flag has been added in 1.0.7.21 and specifies +the desired state, i.e. true (default) to turn all highlighting on, or false to turn all +highlighting off. Since 1.0.7.21 the method disnable_highlighting() has become deprecated.

        + +

        3.9 Setting the Tab Width

        + +

        If you’re using the <pre> header, tabs are handled automatically by your browser, and in general you can +count on good results. However, if you’re using the <div> header, you may want to specify a tab +width explicitly.

        + +

        Note that tabs created in this fashion won’t be like normal tabs - there won’t be “tab-stops” as such, instead +tabs will be replaced with the specified number of spaces - just like most editors do.

        + +

        To change the tab width, you call the set_tab_width() method:

        + +

        $geshi->set_tab_width($width);

        + +

        Where $width is the width in spaces that you’d like tabs to be.

        + +

        3.10 Using Strict Mode

        + +

        Some languages like to get tricky, and jump in and out of the file that they’re in. For example, the vast +majority of you reading this will have used a PHP file. And you know that PHP code is only executed if it’s +within delimiters like <?php and ?> (there are others of course…). So what happens if you do the +following in a php file?

        + +

        <img src="<?php echo rand(1, 100) ?>" />

        + +

        When using GeSHi without strict mode, or using a bad highlighter, you’ll end up with scrambled crap, +especially if you’re being slack about where you’re putting your quotes, you could end up with the rest +of your file as bright blue. Fortunately, you can tell GeSHi to be “strict” about just when it highlights +and when it does not, using the enable_strict_mode() method:

        + +

        $geshi->enable_strict_mode($mode);

        + +

        Where $mode is true or not specified to enable strict mode, or false to disable +strict mode if you’ve already turned it and don’t want it now.

        + +
        + +
        Note:
        + +

        As of GeSHi 1.0.8 there is a new way to tell GeSHi when to use Strict Mode + which is somewhat more intelligent than in previous releases. GeSHi now also + allows GESHI_MAYBE, GESHI_NEVER and GESHI_ALWAYS instead of true and false. + Basically GESHI_ALWAYS (true) always enables strict mode, + whereas GESHI_NEVER (false) completely disables strict mode. The new thing is + GESHI_MAYBE which enables strict mode if it finds any sequences of code + that look like strict block delimiters.

        + +

        By the way: That’s why this section had to be changed, as the new documentation + tool we now use, applies this feature and thus auto-detects when strict mode has to be used…

        + +
        + +

        3.11 Adding/Removing Keywords

        + +

        Lets say that you’re working on a large project, with many files, many classes and many functions. Perhaps also you +have the source code on the web and highlighted by GeSHi, perhaps as a front end to CVS, as a learning tool, something +to refer to, whatever. Well, why not highlight the names of the functions and classes your project uses, as well +as the standard functions and classes? Or perhaps you’re not interested in highlighting certain functions, and would +like to remove them? Or maybe you don’t mind if an entire function group goes west in the interest of speed? GeSHi +can handle all of this!

        + +

        3.11.1 Adding a Keyword

        + +

        If you want to add a keyword to an existing keyword group, you use the add_keyword method:

        + +

        $geshi->add_keyword($key, $word);

        + +

        Where $key is the index of the group of keywords you want to add this keyword to, and $word is +the word to add.

        + +

        This implies knowledge of the language file to know the correct index.

        + +

        3.11.2 Removing a Keyword

        + +

        Perhaps you want to remove a keyword from an existing group. Maybe you don’t use it and want to save yourself some time. Whatever the reason, you can remove it using the remove_keyword method:

        + +

        $geshi->remove_keyword($key, $word);

        + +

        Where $key is the index of the group of keywords that you want to remove this keyword from, and +$word is the word to remove.

        + +

        This implies knowledge of the language file to know the correct index - most of the time the keywords you’ll +want to remove will be in group 3, but this is not guaranteed and you should check the language file first.

        + +

        This function is silent - if the keyword is not in the group you specified, nothing awful will happen ;)

        + +

        3.11.3 Adding a Keyword Group

        + +

        Lets say for your big project you have several main functions and classes that you’d like highlighted. Why not +add them as their own group instead of having them highlighted the same way as other keywords? Then you can make +them stand out, and people can instantly see which functions and classes are user defined or inbuilt. Furthermore, +you could set the URL for this group to point at the API documentation of your project.

        + +

        You add a keyword group by using the add_keyword_group method:

        + +

        $geshi->add_keyword_group($key, $styles, $case_sensitive, $words);

        + +

        Where $key is the key that you want to use to refer to this group, $styles is the styles that +you want to use to style this group, $case_sensitive is true or false depending on whether you want +this group of keywords to be case sensitive or not and $words is an array of words (or a string) of which +words to add to this group. For example:

        + +

        $geshi->add_keyword_group(10, 'color: #600000;', false, array('myfunc_1', 'myfunc_2', 'myfunc_3'));

        + +

        Adds a keyword group referenced by index 10, of which all keywords in the group will be dark red, each keyword +can be in any case and which contains the keywords “myfunc_1”, “myfunc_2” and “myfunc_3”.

        + +

        After creating such a keyword group, you may call other GeSHi methods on it, just as you would for any other keyword group.

        + +
        + +
        Caution:
        + +

        If you specify a $key for which there is already a keyword group, the old keyword group will be + overwritten! Most language files don’t use numbers larger than 5, so I recommend you play it safe and use a number + like 10 or 42.

        + +
        + +

        3.11.4 Removing a Keyword Group

        + +

        Perhaps you really need speed? Why not just remove an entire keyword group? GeSHi won’t have to loop through +each keyword checking for its existance, saving much time. You remove a keyword group by using the +remove_keyword_group method:

        + +

        $geshi->remove_keyword_group($key);

        + +

        Where $key is the key of the group you wish to remove. This implies knowleged of the language file.

        + +

        3.12 Headers and Footers for Your Code

        + +

        So you want to add some special information to the highlighted source? GeSHi can do that too! You can specify headers +and footers for your code, style them, and insert information from the highlighted source into your header or footer.

        + +

        3.12.1 Keyword Substitution

        + +

        In your header and footer, you can put special keywords that will be replaced with actual configuration values for +this GeSHi object. The keywords you can use are:

        + +
          +
        • <TIME> or {TIME}: Is replaced by the time it took for the parse_code() method - i.e., +how long it took for your code to be highlighted. The time is returned to three decimal places.
        • +
        • <LANGUAGE> or {LANGUAGE}: Is replaced by a nice, friendly version of the language name used to +highlight this code.
        • +
        • <SPEED> or {SPEED}: Is replaced by the speed at which your source has been processed.
        • +
        • <VERSION> or {VERSION}: The GeSHi version used to highlight the code.
        • +
        + +

        3.12.2 Setting Header Content

        + +

        The header for your code is a <div>, which is inside the containing block. Therefore, it is affected by +the method set_overall_style, and should contain the sort of HTML that belongs in a <div>. +You may use any HTML you like, and format it as an HTML document. You should use valid HTML - convert to entities +any quotemarks or angle brackets you want displayed. You set the header content using the method +set_header_content():

        + +

        $geshi->set_header_content($content);

        + +

        Where $content is the HTML you want to use for the header.

        + + + +

        The footer for your code is a <div>, which is inside the containing block. Therefore, it is affected by +the method set_overall_style, and should contain the sort of HTML that belongs in a <div>. +You may use any HTML you like, and format it as an HTML document. You should use valid HTML - convert to entities +any quotemarks or angle brackets you want displayed. You set the footer content using the method +set_footer_content():

        + +

        $geshi->set_footer_content($content);

        + +

        Where $content is the HTML you want to use for the footer.

        + +

        3.12.4 Styling Header Content

        + +

        You can apply styles to the header content you have set with the set_header_content_style:

        + +

        $geshi->set_header_content_style($styles);

        + +

        Where $styles is the stylesheet declarations you want to use to style the header content.

        + + + +

        You can apply styles to the footer content you have set with the set_footer_content_style:

        + +

        $geshi->set_footer_content_style($styles);

        + +

        Where $styles is the stylesheet declarations you want to use to style the footer content.

        + +

        3.13 Keyword URLs

        + +

        As of version 1.0.2, GeSHi allows you to specify a URL for keyword groups. This URL is used by GeSHi to convert +the keywords in that group into URLs to appropriate documentation. And using add_keyword_group you +can add functions and classes from your own projects and use the URL functionality to provide a link to your +own API documentation.

        + +

        3.13.1 Setting a URL for a Keyword Group

        + +

        To set the URL to be used for a keyword group, you use the set_url_for_keyword_group() method:

        + +

        $geshi->set_url_for_keyword_group($group, $url);

        + +

        Where $group is the keyword group you want to assign the URL for, and $url is the URL for +this group of keywords.

        + +

        You may be wondering how to make each keyword in the group point to the correct URL. You do this by putting +{FNAME} in the URL at the correct place. For example, PHP makes it easy by linking www.php.net/function-name +to the documentation for that function, so the URL used is http://www.php.net/{FNAME}.

        + +

        Of course, when you get to a language like Java, that puts its class documentation in related folders, it gets a +little trickier to work out an appropriate URL (see the Java language file!). I hope to provide some kind of +redirection service at the GeSHi website in the future.

        + +
        + +
        Note:
        + +

        As of Version 1.0.7.21 there have been added two more symbols you can use to link to functions. {FNAMEL} + will generate the lowercase version of the keyword, {FNAMEU} will generate the uppercase version. {FNAME} + will provide the keyword as specified in the language file. Use one of these more specific placeholders + if possible, as they result in less overhead while linking for case insensitive languages.

        + +
        + +

        3.13.2 Disabling a URL for a Keyword Group

        + +

        It’s easy to disable a URL for a keyword group: Simply use the method set_url_for_keyword_group() to pass +an empty string as the URL:

        + +

        $geshi->set_url_for_keyword_group($group, '');

        + +

        3.13.3 Disabling all URLs for Keywords

        + +

        As of GeSHi 1.0.7.18, you can disable all URL linking for keywords:

        + +

        $geshi->enable_keyword_links(false);

        + + + +

        You can also style the function links. You can style their default status, hovered, active and visited status. +All of this is controlled by one method, set_link_styles():

        + +

        $geshi->set_link_styles($mode, $styles);

        + +

        Where $mode is one of four values:

        + +
          +
        • GESHI_LINK: The default style of the links.
        • +
        • GESHI_HOVER: The style of the links when they have focus (the mouse is hovering over them).
        • +
        • GESHI_ACTIVE: The style of the links when they are being clicked.
        • +
        • GESHI_VISITED: The style of links that the user has already visited.
        • +
        + +

        And $styles is the stylesheet declarations to apply to the links.

        + +
        + +
        Note:
        + +

        The names GESHI_LINK, GESHI_HOVER … are constants. Don’t put them in quotes!

        + +
        + +

        3.13.5 Setting the Link Target

        + +

        Perhaps you want to set the target of link attributes, so the manual pages open in a new window? Use the +set_link_target() method:

        + +

        $geshi->set_link_target($target, $styles);

        + +

        Where $target is any valid (X)HTML target value - _blank or _top for example.

        + +

        3.14 Using Contextual Importance

        + +
        + +
        Caution:
        + +

        This functionality is not only buggy, but is proving very hard to implement in 1.1.X. Therefore, this + functionality may well be removed in 1.2.0. You are hereby warned!

        + +
        + +

        This feature allows you to mark a part of your source as important. But as the +implementation its use is deprecated and you should consider using +the “Highlight Lines Extra” feature described below.

        + +

        3.15 Highlighting Special Lines “Extra”

        + +

        An alternative (and more stable) method of highlighting code that is important +is to use extra highlighting by line. Although you may not know what line numbers +contain the important lines, if you do this method is a much more flexible way of +making important lines stand out.

        + +

        3.15.1 Specifying the Lines to Highlight Extra

        + +

        To specify which lines to highlight extra, you pass an array containing the line numbers to highlight_lines_extra():

        + +

        $geshi->highlight_lines_extra($array);

        + +

        The array could be in the form array(2, 3, 4, 7, 12, 344, 4242), made from a DB query, generated +from looking through the source for certain important things and working out what line those things are… +However you get the line numbers, the array should simply be an array of integers.

        + +

        Here’s an example, using the same source as before:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +
        //
        +// Here we go again! This time we'll simply highlight the 8th line//
        +$source = 'public int[][] product ( n, m ){
        +  int [][] ans = new int[n][m];  for ( int i = 0; i < n; i++ )
        +  {    for ( int j = 0; i < m; j++ )
        +    {      ans[i][j] = i * j;
        +    }  }
        +  return ans;}';
        + $geshi = new GeSHi($source, 'java');
        + $geshi->highlight_lines_extra(array(8));
        + echo $geshi->parse_code();
        + +

        Which produces:

        + +
        Java code
        1
        +23
        +45
        +67
        +89
        +1011
        +12
        public int[][] product ( n, m )
        +{  int [][] ans = new int[n][m];
        +  for ( int i = 0; i < n; i++ )  {
        +    for ( int j = 0; i < m; j++ )    {
        +      ans[i][j] = i * j;    }
        +  }  return ans;
        +}
        + +

        What’s more, as you can see the code on a highlighted line is still actually highlighted itself.

        + +

        3.15.2 Styles for the Highlighted Lines

        + +

        Again as with contextual importance, you’re not chained to the yellow theme that is the default. You can +use the set_highlight_lines_extra_style method:

        + +

        $geshi->set_highlight_lines_extra_style($styles);

        + +

        Where $styles is the stylesheet declarations that you want to apply to highlighted lines.

        + +

        3.16 Adding IDs to Each Line

        + +

        Perhaps you’re a javascript junkie? GeSHi provides a way to give each line an ID so you can access that line with +javascript, or perhaps just by plain CSS (though if you want to access lines by CSS you should use the method +in the previous section). To enable IDs you call the enable_ids() method:

        + +

        $geshi->enable_ids($flag);

        + +

        Where $flag is true or not present to enable IDs, and false to disable them again if you need.

        + +

        The ID generated is in the form {overall-css-id}-{line-number}. So for example, if you set the overall CSS id to +be “mycode”, then the IDs for each line would by “mycode-1”, “mycode-2” etc. If there is no CSS ID set, then one is +made up in the form geshi-[4 random characters], but this is not so useful for if you want to do javascript manipulation.

        + +

        3.17 Getting the Time of Styling

        + +

        Once you’ve called parse_code(), you can get the time it took to run the highlighting by calling the +get_time() method:

        + +
        PHP code
        1
        +23
        +45
        +67
        +
        $geshi = new GeSHi($source, $language, $path);
        + $code = mysql_real_escape_string($geshi->parse_code());
        +$time = $geshi->get_time(); 
        +// do something with itmysql_query("INSERT INTO code VALUES ('$code', '$time')");
        + +

        4 Language Files

        + +

        So now you know what features GeSHi offers, and perhaps you’ve even meddled with the source. Or perhaps +you’d like a language file for language X but it doesn’t seem to be supported? Rubbish! GeSHi will highlight +anything, what do you think I coded this for? ^_^ You’ll just have to learn how to make a language file +yourself. And I promise it’s not too hard - and if you’re here you’re in the right place!

        + +

        4.1 An Example Language File

        + +

        Let’s begin by looking at an example language file - the language file for the first language ever supported, +PHP:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +2829
        +3031
        +3233
        +3435
        +3637
        +3839
        +4041
        +4243
        +4445
        +4647
        +4849
        +5051
        +5253
        +5455
        +5657
        +5859
        +6061
        +6263
        +6465
        +6667
        +6869
        +7071
        +7273
        +7475
        +7677
        +7879
        +8081
        +8283
        +8485
        +8687
        +8889
        +9091
        +9293
        +9495
        +9697
        +9899
        +100101
        +102103
        +104105
        +106107
        +108109
        +110111
        +112113
        +114115
        +116117
        +118119
        +120121
        +122123
        +124125
        +126127
        +128129
        +130131
        +132133
        +134135
        +136137
        +138139
        +140141
        +142143
        +144145
        +146147
        +148149
        +150151
        +152153
        +154155
        +156157
        +158159
        +160161
        +162163
        +164165
        +166167
        +168169
        +170171
        +172173
        +174175
        +176177
        +178179
        +180181
        +182183
        +184185
        +186187
        +188189
        +190191
        +192193
        +194195
        +196197
        +198199
        +200201
        +202203
        +204205
        +206207
        +208209
        +210211
        +212213
        +214215
        +216217
        +218219
        +220221
        +222223
        +224225
        +226227
        +228229
        +230231
        +232233
        +234235
        +236237
        +238239
        +240241
        +242243
        +244245
        +246247
        +248249
        +250251
        +252253
        +254255
        +256257
        +258259
        +260261
        +262263
        +264265
        +266267
        +268269
        +270271
        +272273
        +274275
        +276277
        +278279
        +280281
        +282283
        +284285
        +286287
        +288289
        +290291
        +292293
        +294295
        +296297
        +298299
        +300301
        +302303
        +304305
        +306307
        +308309
        +310311
        +312313
        +314315
        +316317
        +318319
        +320321
        +322323
        +324325
        +326327
        +328329
        +330331
        +332333
        +334335
        +336337
        +338339
        +340341
        +342343
        +344345
        +346347
        +348349
        +350351
        +352353
        +354355
        +356357
        +358359
        +360361
        +362363
        +364365
        +366367
        +368369
        +370371
        +372373
        +374375
        +376377
        +378379
        +380381
        +382383
        +384385
        +386387
        +388389
        +390391
        +392393
        +394395
        +396397
        +398399
        +400401
        +402403
        +404405
        +406407
        +408409
        +410411
        +412413
        +414415
        +416417
        +418419
        +420421
        +422423
        +424425
        +426427
        +428429
        +430431
        +432433
        +434435
        +436437
        +438439
        +440441
        +442443
        +444445
        +446447
        +448449
        +450451
        +452453
        +454455
        +456457
        +458459
        +460461
        +462463
        +464465
        +466467
        +468469
        +470471
        +472473
        +474475
        +476477
        +478479
        +480481
        +482483
        +484485
        +486487
        +488489
        +490491
        +492493
        +494495
        +496497
        +498499
        +500501
        +502503
        +504505
        +506507
        +508509
        +510511
        +512513
        +514515
        +516517
        +518519
        +520521
        +522523
        +524525
        +526527
        +528529
        +530531
        +532533
        +534535
        +536537
        +538539
        +540541
        +542543
        +544545
        +546547
        +548549
        +550551
        +552553
        +554555
        +556557
        +558559
        +560561
        +562563
        +564565
        +566567
        +568569
        +570571
        +572573
        +574575
        +576577
        +578579
        +580581
        +582583
        +584585
        +586587
        +588589
        +590591
        +592593
        +594595
        +596597
        +598599
        +600601
        +602603
        +604605
        +606607
        +608609
        +610611
        +612613
        +614615
        +616617
        +618619
        +620621
        +622623
        +624625
        +626627
        +628629
        +630631
        +632633
        +634635
        +636637
        +638639
        +640641
        +642643
        +644645
        +646647
        +648649
        +650651
        +652653
        +654655
        +656657
        +658659
        +660661
        +662663
        +664665
        +666667
        +668669
        +670671
        +672673
        +674675
        +676677
        +678679
        +680681
        +682683
        +684685
        +686687
        +688689
        +690691
        +692693
        +694695
        +696697
        +698699
        +700701
        +702703
        +704705
        +706707
        +708709
        +710711
        +712713
        +714715
        +716717
        +718719
        +720721
        +722723
        +724725
        +726727
        +728729
        +730731
        +732733
        +734735
        +736737
        +738739
        +740741
        +742743
        +744745
        +746747
        +748749
        +750751
        +752753
        +754755
        +756757
        +758759
        +760761
        +762763
        +764765
        +766767
        +768769
        +770771
        +772773
        +774775
        +776777
        +778779
        +780781
        +782783
        +784785
        +786787
        +788789
        +790791
        +792793
        +794795
        +796797
        +798799
        +800801
        +802803
        +804805
        +806807
        +808809
        +810811
        +812813
        +814815
        +816817
        +818819
        +820821
        +822823
        +824825
        +826827
        +828829
        +830831
        +832833
        +834835
        +836837
        +838839
        +840841
        +842843
        +844845
        +846847
        +848849
        +850851
        +852853
        +854855
        +856857
        +858859
        +860861
        +862863
        +864865
        +866867
        +868869
        +870871
        +872873
        +874875
        +876877
        +878879
        +880881
        +882883
        +884885
        +886887
        +888889
        +890891
        +892893
        +894895
        +896897
        +898899
        +900901
        +902903
        +904905
        +906907
        +908909
        +910911
        +912913
        +914915
        +916917
        +918919
        +920921
        +922923
        +924925
        +926927
        +928929
        +930931
        +932933
        +934935
        +936937
        +938939
        +940941
        +942943
        +944945
        +946947
        +948949
        +950951
        +952953
        +954955
        +956957
        +958959
        +960961
        +962963
        +964965
        +966967
        +968969
        +970971
        +972973
        +974975
        +976977
        +978979
        +980981
        +982983
        +984985
        +986987
        +988989
        +990991
        +992993
        +994995
        +996997
        +998999
        +10001001
        +10021003
        +10041005
        +10061007
        +10081009
        +10101011
        +10121013
        +10141015
        +10161017
        +10181019
        +10201021
        +10221023
        +10241025
        +10261027
        +10281029
        +10301031
        +10321033
        +10341035
        +10361037
        +10381039
        +10401041
        +10421043
        +10441045
        +10461047
        +10481049
        +10501051
        +10521053
        +10541055
        +10561057
        +10581059
        +10601061
        +10621063
        +10641065
        +10661067
        +10681069
        +10701071
        +10721073
        +10741075
        +10761077
        +10781079
        +10801081
        +10821083
        +10841085
        +10861087
        +10881089
        +10901091
        +10921093
        +1094
        <?php
        +/************************************************************************************* * php.php
        + * -------- * Author: Nigel McNie (nigel@geshi.org)
        + * Copyright: (c) 2004 Nigel McNie (http://qbnz.com/highlighter/) * Release Version: 1.0.8.3
        + * Date Started: 2004/06/20 *
        + * PHP language file for GeSHi. *
        + * CHANGES * -------
        + * 2008/05/23 (1.0.7.22) *  -  Added description of extra language features (SF#1970248)
        + * 2004/11/25 (1.0.3) *  -  Added support for multiple object splitters
        + *  -  Fixed &new problem * 2004/10/27 (1.0.2)
        + *  -  Added URL support *  -  Added extra constants
        + * 2004/08/05 (1.0.1) *  -  Added support for symbols
        + * 2004/07/14 (1.0.0) *  -  First Release
        + * * TODO (updated 2004/07/14)
        + * ------------------------- * * Make sure the last few function I may have missed
        + *   (like eval()) are included for highlighting * * Split to several files - php4, php5 etc
        + * *************************************************************************************
        + * *     This file is part of GeSHi.
        + * *   GeSHi is free software; you can redistribute it and/or modify
        + *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or
        + *   (at your option) any later version. *
        + *   GeSHi 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 GeSHi; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
        + * ************************************************************************************/
        + $language_data = array(
        +    'LANG_NAME' => 'PHP',    'COMMENT_SINGLE' => array(1 => '//', 2 => '#'),
        +    'COMMENT_MULTI' => array('/*' => '*/'),    'HARDQUOTE' => array("'", "'"),
        +    'HARDESCAPE' => array("'", "\\"),    'HARDCHAR' => "\\",
        +    'COMMENT_REGEXP' => array(        //Heredoc and Nowdoc syntax
        +        3 => '/<<<\s*?(\'?)([a-zA-Z0-9]+?)\1[^\n]*?\\n.*\\n\\2(?![a-zA-Z0-9])/siU',        // phpdoc comments
        +        4 => '#/\*\*(?![\*\/]).*\*/#sU',        // Advanced # handling
        +        2 => "/#.*?(?:(?=\?\>)|^)/smi"        ),
        +    'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,    'QUOTEMARKS' => array('"'),
        +    'ESCAPE_CHAR' => '',    'ESCAPE_REGEXP' => array(
        +        //Simple Single Char Escapes        1 => "#\\\\[nfrtv\$\"\n\\\\]#i",
        +        //Hexadecimal Char Specs        2 => "#\\\\x[\da-fA-F]{1,2}#i",
        +        //Octal Char Specs        3 => "#\\\\[0-7]{1,3}#",
        +        //String Parsing of Variable Names        4 => "#\\$[a-z0-9_]+(?:\\[[a-z0-9_]+\\]|->[a-z0-9_]+)?|(?:\\{\\$|\\$\\{)[a-z0-9_]+(?:\\[('?)[a-z0-9_]*\\1\\]|->[a-z0-9_]+)*\\}#i",
        +        //Experimental extension supporting cascaded {${$var}} syntax        5 => "#\$[a-z0-9_]+(?:\[[a-z0-9_]+\]|->[a-z0-9_]+)?|(?:\{\$|\$\{)[a-z0-9_]+(?:\[('?)[a-z0-9_]*\\1\]|->[a-z0-9_]+)*\}|\{\$(?R)\}#i",
        +        //Format String support in ""-Strings        6 => "#%(?:%|(?:\d+\\\\\\\$)?\\+?(?:\x20|0|'.)?-?(?:\d+|\\*)?(?:\.\d+)?[bcdefFosuxX])#"
        +        ),    'NUMBERS' =>
        +        GESHI_NUMBER_INT_BASIC |  GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX |        GESHI_NUMBER_FLT_SCI_ZERO,
        +    'KEYWORDS' => array(        1 => array(
        +            'as','break','case','continue','default','do','else','elseif',            'endfor','endforeach','endif','endswitch','endwhile','for',
        +            'foreach','if','include','include_once','require','require_once',            'return','switch','while',
        +             'echo','print'
        +            ),        2 => array(
        +            '&amp;new','&lt;/script&gt;','&lt;?php','&lt;script language',            'class','const','declare','extends','function','global','interface',
        +            'namespace','new','private','public','self','var'            ),
        +        3 => array(            'abs','acos','acosh','addcslashes','addslashes','aggregate',
        +            'aggregate_methods','aggregate_methods_by_list',            'aggregate_methods_by_regexp','aggregate_properties',
        +            'aggregate_properties_by_list','aggregate_properties_by_regexp',            'aggregation_info','apache_child_terminate','apache_get_modules',
        +            'apache_get_version','apache_getenv','apache_lookup_uri',            'apache_note','apache_request_headers','apache_response_headers',
        +            'apache_setenv','array','array_change_key_case','array_chunk',            'array_combine','array_count_values','array_diff',
        +            'array_diff_assoc','array_diff_key','array_diff_uassoc',            'array_diff_ukey','array_fill','array_fill_keys','array_filter',
        +            'array_flip','array_intersect','array_intersect_assoc',            'array_intersect_key','array_intersect_uassoc',
        +            'array_intersect_ukey','array_key_exists','array_keys','array_map',            'array_merge','array_merge_recursive','array_multisort','array_pad',
        +            'array_pop','array_product','array_push','array_rand',            'array_reduce','array_reverse','array_search','array_shift',
        +            'array_slice','array_splice','array_sum','array_udiff',            'array_udiff_assoc','array_udiff_uassoc','array_uintersect',
        +            'array_uintersect_assoc','array_uintersect_uassoc','array_unique',            'array_unshift','array_values','array_walk','array_walk_recursive',
        +            'arsort','asin','asinh','asort','assert','assert_options','atan',            'atan2','atanh','base_convert','base64_decode','base64_encode',
        +            'basename','bcadd','bccomp','bcdiv','bcmod','bcmul',            'bcompiler_load','bcompiler_load_exe','bcompiler_parse_class',
        +            'bcompiler_read','bcompiler_write_class','bcompiler_write_constant',            'bcompiler_write_exe_footer','bcompiler_write_file',
        +            'bcompiler_write_footer','bcompiler_write_function',            'bcompiler_write_functions_from_file','bcompiler_write_header',
        +            'bcompiler_write_included_filename','bcpow','bcpowmod','bcscale',            'bcsqrt','bcsub','bin2hex','bindec','bindtextdomain',
        +            'bind_textdomain_codeset','bitset_empty','bitset_equal',            'bitset_excl','bitset_fill','bitset_from_array','bitset_from_hash',
        +            'bitset_from_string','bitset_in','bitset_incl',            'bitset_intersection','bitset_invert','bitset_is_empty',
        +            'bitset_subset','bitset_to_array','bitset_to_hash',            'bitset_to_string','bitset_union','blenc_encrypt','bzclose',
        +            'bzcompress','bzdecompress','bzerrno','bzerror','bzerrstr',            'bzflush','bzopen','bzread','bzwrite','cal_days_in_month',
        +            'cal_from_jd','cal_info','cal_to_jd','call_user_func',            'call_user_func_array','call_user_method','call_user_method_array',
        +            'ceil','chdir','checkdate','checkdnsrr','chgrp','chmod','chop',            'chown','chr','chunk_split','class_exists','class_implements',
        +            'class_parents','classkit_aggregate_methods',            'classkit_doc_comments','classkit_import','classkit_method_add',
        +            'classkit_method_copy','classkit_method_redefine',            'classkit_method_remove','classkit_method_rename','clearstatcache',
        +            'closedir','closelog','com_create_guid','com_event_sink',            'com_get_active_object','com_load_typelib','com_message_pump',
        +            'com_print_typeinfo','compact','confirm_phpdoc_compiled',            'connection_aborted','connection_status','constant',
        +            'convert_cyr_string','convert_uudecode','convert_uuencode','copy',            'cos','cosh','count','count_chars','cpdf_add_annotation',
        +            'cpdf_add_outline','cpdf_arc','cpdf_begin_text','cpdf_circle',            'cpdf_clip','cpdf_close','cpdf_closepath',
        +            'cpdf_closepath_fill_stroke','cpdf_closepath_stroke',            'cpdf_continue_text','cpdf_curveto','cpdf_end_text','cpdf_fill',
        +            'cpdf_fill_stroke','cpdf_finalize','cpdf_finalize_page',            'cpdf_global_set_document_limits','cpdf_import_jpeg','cpdf_lineto',
        +            'cpdf_moveto','cpdf_newpath','cpdf_open','cpdf_output_buffer',            'cpdf_page_init','cpdf_rect','cpdf_restore','cpdf_rlineto',
        +            'cpdf_rmoveto','cpdf_rotate','cpdf_rotate_text','cpdf_save',            'cpdf_save_to_file','cpdf_scale','cpdf_set_action_url',
        +            'cpdf_set_char_spacing','cpdf_set_creator','cpdf_set_current_page',            'cpdf_set_font','cpdf_set_font_directories',
        +            'cpdf_set_font_map_file','cpdf_set_horiz_scaling',            'cpdf_set_keywords','cpdf_set_leading','cpdf_set_page_animation',
        +            'cpdf_set_subject','cpdf_set_text_matrix','cpdf_set_text_pos',            'cpdf_set_text_rendering','cpdf_set_text_rise','cpdf_set_title',
        +            'cpdf_set_viewer_preferences','cpdf_set_word_spacing',            'cpdf_setdash','cpdf_setflat','cpdf_setgray','cpdf_setgray_fill',
        +            'cpdf_setgray_stroke','cpdf_setlinecap','cpdf_setlinejoin',            'cpdf_setlinewidth','cpdf_setmiterlimit','cpdf_setrgbcolor',
        +            'cpdf_setrgbcolor_fill','cpdf_setrgbcolor_stroke','cpdf_show',            'cpdf_show_xy','cpdf_stringwidth','cpdf_stroke','cpdf_text',
        +            'cpdf_translate','crack_check','crack_closedict',            'crack_getlastmessage','crack_opendict','crc32','create_function',
        +            'crypt','ctype_alnum','ctype_alpha','ctype_cntrl','ctype_digit',            'ctype_graph','ctype_lower','ctype_print','ctype_punct',
        +            'ctype_space','ctype_upper','ctype_xdigit','curl_close',            'curl_copy_handle','curl_errno','curl_error','curl_exec',
        +            'curl_getinfo','curl_init','curl_multi_add_handle',            'curl_multi_close','curl_multi_exec','curl_multi_getcontent',
        +            'curl_multi_info_read','curl_multi_init','curl_multi_remove_handle',            'curl_multi_select','curl_setopt','curl_setopt_array',
        +            'curl_version','current','cvsclient_connect','cvsclient_log',            'cvsclient_login','cvsclient_retrieve','date','date_create',
        +            'date_date_set','date_default_timezone_get',            'date_default_timezone_set','date_format','date_isodate_set',
        +            'date_modify','date_offset_get','date_parse','date_sun_info',            'date_sunrise','date_sunset','date_time_set','date_timezone_get',
        +            'date_timezone_set','db_id_list','dba_close','dba_delete',            'dba_exists','dba_fetch','dba_firstkey','dba_handlers','dba_insert',
        +            'dba_key_split','dba_list','dba_nextkey','dba_open','dba_optimize',            'dba_popen','dba_replace','dba_sync','dbase_add_record',
        +            'dbase_close','dbase_create','dbase_delete_record',            'dbase_get_header_info','dbase_get_record',
        +            'dbase_get_record_with_names','dbase_numfields','dbase_numrecords',            'dbase_open','dbase_pack','dbase_replace_record',
        +            'dbg_get_all_contexts','dbg_get_all_module_names',            'dbg_get_all_source_lines','dbg_get_context_name',
        +            'dbg_get_module_name','dbg_get_profiler_results',            'dbg_get_source_context','dblist','dbmclose','dbmdelete',
        +            'dbmexists','dbmfetch','dbmfirstkey','dbminsert','dbmnextkey',            'dbmopen','dbmreplace','dbx_close','dbx_compare','dbx_connect',
        +            'dbx_error','dbx_escape_string','dbx_fetch_row','dbx_query',            'dbx_sort','dcgettext','dcngettext','deaggregate','debug_backtrace',
        +            'debug_zval_dump','debugbreak','decbin','dechex','decoct','define',            'defined','define_syslog_variables','deg2rad','dgettext','die',
        +            'dio_close','dio_open','dio_read','dio_seek','dio_stat','dio_write',            'dir','dirname','disk_free_space','disk_total_space',
        +            'diskfreespace','dl','dngettext','docblock_token_name',            'docblock_tokenize','dom_import_simplexml','domxml_add_root',
        +            'domxml_attributes','domxml_children','domxml_doc_add_root',            'domxml_doc_document_element','domxml_doc_get_element_by_id',
        +            'domxml_doc_get_elements_by_tagname','domxml_doc_get_root',            'domxml_doc_set_root','domxml_doc_validate','domxml_doc_xinclude',
        +            'domxml_dump_mem','domxml_dump_mem_file','domxml_dump_node',            'domxml_dumpmem','domxml_elem_get_attribute',
        +            'domxml_elem_set_attribute','domxml_get_attribute','domxml_getattr',            'domxml_html_dump_mem','domxml_new_child','domxml_new_doc',
        +            'domxml_new_xmldoc','domxml_node','domxml_node_add_namespace',            'domxml_node_attributes','domxml_node_children',
        +            'domxml_node_get_content','domxml_node_has_attributes',            'domxml_node_new_child','domxml_node_set_content',
        +            'domxml_node_set_namespace','domxml_node_unlink_node',            'domxml_open_file','domxml_open_mem','domxml_parser',
        +            'domxml_parser_add_chunk','domxml_parser_cdata_section',            'domxml_parser_characters','domxml_parser_comment',
        +            'domxml_parser_end','domxml_parser_end_document',            'domxml_parser_end_element','domxml_parser_entity_reference',
        +            'domxml_parser_get_document','domxml_parser_namespace_decl',            'domxml_parser_processing_instruction',
        +            'domxml_parser_start_document','domxml_parser_start_element',            'domxml_root','domxml_set_attribute','domxml_setattr',
        +            'domxml_substitute_entities_default','domxml_unlink_node',            'domxml_version','domxml_xmltree','doubleval','each','easter_date',
        +            'easter_days','empty','end','ereg','ereg_replace','eregi',            'eregi_replace','error_get_last','error_log','error_reporting',
        +            'escapeshellarg','escapeshellcmd','eval','event_deschedule',            'event_dispatch','event_free','event_handle_signal',
        +            'event_have_events','event_init','event_new','event_pending',            'event_priority_set','event_schedule','event_set','event_timeout',
        +            'exec','exif_imagetype','exif_read_data','exif_tagname',            'exif_thumbnail','exit','exp','explode','expm1','extension_loaded',
        +            'extract','ezmlm_hash','fbird_add_user','fbird_affected_rows',            'fbird_backup','fbird_blob_add','fbird_blob_cancel',
        +            'fbird_blob_close','fbird_blob_create','fbird_blob_echo',            'fbird_blob_get','fbird_blob_import','fbird_blob_info',
        +            'fbird_blob_open','fbird_close','fbird_commit','fbird_commit_ret',            'fbird_connect','fbird_db_info','fbird_delete_user','fbird_drop_db',
        +            'fbird_errcode','fbird_errmsg','fbird_execute','fbird_fetch_assoc',            'fbird_fetch_object','fbird_fetch_row','fbird_field_info',
        +            'fbird_free_event_handler','fbird_free_query','fbird_free_result',            'fbird_gen_id','fbird_maintain_db','fbird_modify_user',
        +            'fbird_name_result','fbird_num_fields','fbird_num_params',            'fbird_param_info','fbird_pconnect','fbird_prepare','fbird_query',
        +            'fbird_restore','fbird_rollback','fbird_rollback_ret',            'fbird_server_info','fbird_service_attach','fbird_service_detach',
        +            'fbird_set_event_handler','fbird_trans','fbird_wait_event','fclose',            'fdf_add_doc_javascript','fdf_add_template','fdf_close',
        +            'fdf_create','fdf_enum_values','fdf_errno','fdf_error','fdf_get_ap',            'fdf_get_attachment','fdf_get_encoding','fdf_get_file',
        +            'fdf_get_flags','fdf_get_opt','fdf_get_status','fdf_get_value',            'fdf_get_version','fdf_header','fdf_next_field_name','fdf_open',
        +            'fdf_open_string','fdf_remove_item','fdf_save','fdf_save_string',            'fdf_set_ap','fdf_set_encoding','fdf_set_file','fdf_set_flags',
        +            'fdf_set_javascript_action','fdf_set_on_import_javascript',            'fdf_set_opt','fdf_set_status','fdf_set_submit_form_action',
        +            'fdf_set_target_frame','fdf_set_value','fdf_set_version','feof',            'fflush','fgetc','fgetcsv','fgets','fgetss','file','file_exists',
        +            'file_get_contents','file_put_contents','fileatime','filectime',            'filegroup','fileinode','filemtime','fileowner','fileperms',
        +            'filepro','filepro_fieldcount','filepro_fieldname',            'filepro_fieldtype','filepro_fieldwidth','filepro_retrieve',
        +            'filepro_rowcount','filesize','filetype','filter_has_var',            'filter_id','filter_input','filter_input_array','filter_list',
        +            'filter_var','filter_var_array','finfo_buffer','finfo_close',            'finfo_file','finfo_open','finfo_set_flags','floatval','flock',
        +            'floor','flush','fmod','fnmatch','fopen','fpassthru','fprintf',            'fputcsv','fputs','fread','frenchtojd','fribidi_charset_info',
        +            'fribidi_get_charsets','fribidi_log2vis','fscanf','fseek',            'fsockopen','fstat','ftell','ftok','ftp_alloc','ftp_cdup',
        +            'ftp_chdir','ftp_chmod','ftp_close','ftp_connect','ftp_delete',            'ftp_exec','ftp_fget','ftp_fput','ftp_get','ftp_get_option',
        +            'ftp_login','ftp_mdtm','ftp_mkdir','ftp_nb_continue','ftp_nb_fget',            'ftp_nb_fput','ftp_nb_get','ftp_nb_put','ftp_nlist','ftp_pasv',
        +            'ftp_put','ftp_pwd','ftp_quit','ftp_raw','ftp_rawlist','ftp_rename',            'ftp_rmdir','ftp_set_option','ftp_site','ftp_size',
        +            'ftp_ssl_connect','ftp_systype','ftruncate','function_exists',            'func_get_arg','func_get_args','func_num_args','fwrite','gd_info',
        +            'getallheaders','getcwd','getdate','getenv','gethostbyaddr',            'gethostbyname','gethostbynamel','getimagesize','getlastmod',
        +            'getmxrr','getmygid','getmyinode','getmypid','getmyuid','getopt',            'getprotobyname','getprotobynumber','getrandmax','getrusage',
        +            'getservbyname','getservbyport','gettext','gettimeofday','gettype',            'get_browser','get_cfg_var','get_class','get_class_methods',
        +            'get_class_vars','get_current_user','get_declared_classes',            'get_defined_constants','get_defined_functions','get_defined_vars',
        +            'get_extension_funcs','get_headers','get_html_translation_table',            'get_included_files','get_include_path','get_loaded_extensions',
        +            'get_magic_quotes_gpc','get_magic_quotes_runtime','get_meta_tags',            'get_object_vars','get_parent_class','get_required_files',
        +            'get_resource_type','glob','gmdate','gmmktime','gmp_abs','gmp_add',            'gmp_and','gmp_clrbit','gmp_cmp','gmp_com','gmp_div','gmp_div_q',
        +            'gmp_div_qr','gmp_div_r','gmp_divexact','gmp_fact','gmp_gcd',            'gmp_gcdext','gmp_hamdist','gmp_init','gmp_intval','gmp_invert',
        +            'gmp_jacobi','gmp_legendre','gmp_mod','gmp_mul','gmp_neg',            'gmp_nextprime','gmp_or','gmp_perfect_square','gmp_popcount',
        +            'gmp_pow','gmp_powm','gmp_prob_prime','gmp_random','gmp_scan0',            'gmp_scan1','gmp_setbit','gmp_sign','gmp_sqrt','gmp_sqrtrem',
        +            'gmp_strval','gmp_sub','gmp_xor','gmstrftime','gopher_parsedir',            'gregoriantojd','gzclose','gzcompress','gzdeflate','gzencode',
        +            'gzeof','gzfile','gzgetc','gzgets','gzgetss','gzinflate','gzopen',            'gzpassthru','gzputs','gzread','gzrewind','gzseek','gztell',
        +            'gzuncompress','gzwrite','hash','hash_algos','hash_file',            'hash_final','hash_hmac','hash_hmac_file','hash_init','hash_update',
        +            'hash_update_file','hash_update_stream','header','headers_list',            'headers_sent','hebrev','hebrevc','hexdec','highlight_file',
        +            'highlight_string','html_doc','html_doc_file','html_entity_decode',            'htmlentities','htmlspecialchars','htmlspecialchars_decode',
        +            'http_build_cookie','http_build_query','http_build_str',            'http_build_url','http_cache_etag','http_cache_last_modified',
        +            'http_chunked_decode','http_date','http_deflate','http_get',            'http_get_request_body','http_get_request_body_stream',
        +            'http_get_request_headers','http_head','http_inflate',            'http_match_etag','http_match_modified','http_match_request_header',
        +            'http_negotiate_charset','http_negotiate_content_type',            'http_negotiate_language','http_parse_cookie','http_parse_headers',
        +            'http_parse_message','http_parse_params',            'http_persistent_handles_clean','http_persistent_handles_count',
        +            'http_persistent_handles_ident','http_post_data','http_post_fields',            'http_put_data','http_put_file','http_put_stream','http_redirect',
        +            'http_request','http_request_body_encode',            'http_request_method_exists','http_request_method_name',
        +            'http_request_method_register','http_request_method_unregister',            'http_send_content_disposition','http_send_content_type',
        +            'http_send_data','http_send_file','http_send_last_modified',            'http_send_status','http_send_stream','http_support',
        +            'http_throttle','hypot','i18n_convert','i18n_discover_encoding',            'i18n_http_input','i18n_http_output','i18n_internal_encoding',
        +            'i18n_ja_jp_hantozen','i18n_mime_header_decode',            'i18n_mime_header_encode','ibase_add_user','ibase_affected_rows',
        +            'ibase_backup','ibase_blob_add','ibase_blob_cancel',            'ibase_blob_close','ibase_blob_create','ibase_blob_echo',
        +            'ibase_blob_get','ibase_blob_import','ibase_blob_info',            'ibase_blob_open','ibase_close','ibase_commit','ibase_commit_ret',
        +            'ibase_connect','ibase_db_info','ibase_delete_user','ibase_drop_db',            'ibase_errcode','ibase_errmsg','ibase_execute','ibase_fetch_assoc',
        +            'ibase_fetch_object','ibase_fetch_row','ibase_field_info',            'ibase_free_event_handler','ibase_free_query','ibase_free_result',
        +            'ibase_gen_id','ibase_maintain_db','ibase_modify_user',            'ibase_name_result','ibase_num_fields','ibase_num_params',
        +            'ibase_param_info','ibase_pconnect','ibase_prepare','ibase_query',            'ibase_restore','ibase_rollback','ibase_rollback_ret',
        +            'ibase_server_info','ibase_service_attach','ibase_service_detach',            'ibase_set_event_handler','ibase_trans','ibase_wait_event','iconv',
        +            'iconv_get_encoding','iconv_mime_decode',            'iconv_mime_decode_headers','iconv_mime_encode',
        +            'iconv_set_encoding','iconv_strlen','iconv_strpos','iconv_strrpos',            'iconv_substr','id3_get_frame_long_name','id3_get_frame_short_name',
        +            'id3_get_genre_id','id3_get_genre_list','id3_get_genre_name',            'id3_get_tag','id3_get_version','id3_remove_tag','id3_set_tag',
        +            'idate','ignore_user_abort','image_type_to_extension',            'image_type_to_mime_type','image2wbmp','imagealphablending',
        +            'imageantialias','imagearc','imagechar','imagecharup',            'imagecolorallocate','imagecolorallocatealpha','imagecolorat',
        +            'imagecolorclosest','imagecolorclosestalpha','imagecolordeallocate',            'imagecolorexact','imagecolorexactalpha','imagecolormatch',
        +            'imagecolorresolve','imagecolorresolvealpha','imagecolorset',            'imagecolorsforindex','imagecolorstotal','imagecolortransparent',
        +            'imageconvolution','imagecopy','imagecopymerge',            'imagecopymergegray','imagecopyresampled','imagecopyresized',
        +            'imagecreate','imagecreatefromgd','imagecreatefromgd2',            'imagecreatefromgd2part','imagecreatefromgif','imagecreatefromjpeg',
        +            'imagecreatefrompng','imagecreatefromstring','imagecreatefromwbmp',            'imagecreatefromxbm','imagecreatetruecolor','imagedashedline',
        +            'imagedestroy','imageellipse','imagefill','imagefilledarc',            'imagefilledellipse','imagefilledpolygon','imagefilledrectangle',
        +            'imagefilltoborder','imagefilter','imagefontheight',            'imagefontwidth','imageftbbox','imagefttext','imagegammacorrect',
        +            'imagegd','imagegd2','imagegif','imagegrabscreen','imagegrabwindow',            'imageinterlace','imageistruecolor','imagejpeg','imagelayereffect',
        +            'imageline','imageloadfont','imagepalettecopy','imagepng',            'imagepolygon','imagepsbbox','imagepsencodefont',
        +            'imagepsextendfont','imagepsfreefont','imagepsloadfont',            'imagepsslantfont','imagepstext','imagerectangle','imagerotate',
        +            'imagesavealpha','imagesetbrush','imagesetpixel','imagesetstyle',            'imagesetthickness','imagesettile','imagestring','imagestringup',
        +            'imagesx','imagesy','imagetruecolortopalette','imagettfbbox',            'imagettftext','imagetypes','imagewbmp','imagexbm','imap_8bit',
        +            'imap_alerts','imap_append','imap_base64','imap_binary','imap_body',            'imap_bodystruct','imap_check','imap_clearflag_full','imap_close',
        +            'imap_create','imap_createmailbox','imap_delete',            'imap_deletemailbox','imap_errors','imap_expunge',
        +            'imap_fetch_overview','imap_fetchbody','imap_fetchheader',            'imap_fetchstructure','imap_fetchtext','imap_get_quota',
        +            'imap_get_quotaroot','imap_getacl','imap_getmailboxes',            'imap_getsubscribed','imap_header','imap_headerinfo','imap_headers',
        +            'imap_last_error','imap_list','imap_listmailbox',            'imap_listsubscribed','imap_lsub','imap_mail','imap_mail_compose',
        +            'imap_mail_copy','imap_mail_move','imap_mailboxmsginfo',            'imap_mime_header_decode','imap_msgno','imap_num_msg',
        +            'imap_num_recent','imap_open','imap_ping','imap_qprint',            'imap_rename','imap_renamemailbox','imap_reopen',
        +            'imap_rfc822_parse_adrlist','imap_rfc822_parse_headers',            'imap_rfc822_write_address','imap_savebody','imap_scan',
        +            'imap_scanmailbox','imap_search','imap_set_quota','imap_setacl',            'imap_setflag_full','imap_sort','imap_status','imap_subscribe',
        +            'imap_thread','imap_timeout','imap_uid','imap_undelete',            'imap_unsubscribe','imap_utf7_decode','imap_utf7_encode',
        +            'imap_utf8','implode','import_request_variables','in_array',            'ini_alter','ini_get','ini_get_all','ini_restore','ini_set',
        +            'intval','ip2long','iptcembed','iptcparse','isset','is_a',            'is_array','is_bool','is_callable','is_dir','is_double',
        +            'is_executable','is_file','is_finite','is_float','is_infinite',            'is_int','is_integer','is_link','is_long','is_nan','is_null',
        +            'is_numeric','is_object','is_readable','is_real','is_resource',            'is_scalar','is_soap_fault','is_string','is_subclass_of',
        +            'is_uploaded_file','is_writable','is_writeable','iterator_apply',            'iterator_count','iterator_to_array','java_last_exception_clear',
        +            'java_last_exception_get','jddayofweek','jdmonthname','jdtofrench',            'jdtogregorian','jdtojewish','jdtojulian','jdtounix','jewishtojd',
        +            'join','jpeg2wbmp','json_decode','json_encode','juliantojd','key',            'key_exists','krsort','ksort','lcg_value','ldap_add','ldap_bind',
        +            'ldap_close','ldap_compare','ldap_connect','ldap_count_entries',            'ldap_delete','ldap_dn2ufn','ldap_err2str','ldap_errno',
        +            'ldap_error','ldap_explode_dn','ldap_first_attribute',            'ldap_first_entry','ldap_first_reference','ldap_free_result',
        +            'ldap_get_attributes','ldap_get_dn','ldap_get_entries',            'ldap_get_option','ldap_get_values','ldap_get_values_len',
        +            'ldap_list','ldap_mod_add','ldap_mod_del','ldap_mod_replace',            'ldap_modify','ldap_next_attribute','ldap_next_entry',
        +            'ldap_next_reference','ldap_parse_reference','ldap_parse_result',            'ldap_read','ldap_rename','ldap_search','ldap_set_option',
        +            'ldap_sort','ldap_start_tls','ldap_unbind','levenshtein',            'libxml_clear_errors','libxml_get_errors','libxml_get_last_error',
        +            'libxml_set_streams_context','libxml_use_internal_errors','link',            'linkinfo','list','localeconv','localtime','log','log1p','log10',
        +            'long2ip','lstat','ltrim','lzf_compress','lzf_decompress',            'lzf_optimized_for','magic_quotes_runtime','mail','max','mbereg',
        +            'mberegi','mberegi_replace','mbereg_match','mbereg_replace',            'mbereg_search','mbereg_search_getpos','mbereg_search_getregs',
        +            'mbereg_search_init','mbereg_search_pos','mbereg_search_regs',            'mbereg_search_setpos','mbregex_encoding','mbsplit','mbstrcut',
        +            'mbstrlen','mbstrpos','mbstrrpos','mbsubstr','mb_check_encoding',            'mb_convert_case','mb_convert_encoding','mb_convert_kana',
        +            'mb_convert_variables','mb_decode_mimeheader',            'mb_decode_numericentity','mb_detect_encoding','mb_detect_order',
        +            'mb_encode_mimeheader','mb_encode_numericentity','mb_ereg',            'mb_eregi','mb_eregi_replace','mb_ereg_match','mb_ereg_replace',
        +            'mb_ereg_search','mb_ereg_search_getpos','mb_ereg_search_getregs',            'mb_ereg_search_init','mb_ereg_search_pos','mb_ereg_search_regs',
        +            'mb_ereg_search_setpos','mb_get_info','mb_http_input',            'mb_http_output','mb_internal_encoding','mb_language',
        +            'mb_list_encodings','mb_output_handler','mb_parse_str',            'mb_preferred_mime_name','mb_regex_encoding','mb_regex_set_options',
        +            'mb_send_mail','mb_split','mb_strcut','mb_strimwidth','mb_stripos',            'mb_stristr','mb_strlen','mb_strpos','mb_strrchr','mb_strrichr',
        +            'mb_strripos','mb_strrpos','mb_strstr','mb_strtolower',            'mb_strtoupper','mb_strwidth','mb_substitute_character','mb_substr',
        +            'mb_substr_count','mcrypt_cbc','mcrypt_cfb','mcrypt_create_iv',            'mcrypt_decrypt','mcrypt_ecb','mcrypt_enc_get_algorithms_name',
        +            'mcrypt_enc_get_block_size','mcrypt_enc_get_iv_size',            'mcrypt_enc_get_key_size','mcrypt_enc_get_modes_name',
        +            'mcrypt_enc_get_supported_key_sizes',            'mcrypt_enc_is_block_algorithm',
        +            'mcrypt_enc_is_block_algorithm_mode','mcrypt_enc_is_block_mode',            'mcrypt_enc_self_test','mcrypt_encrypt','mcrypt_generic',
        +            'mcrypt_generic_deinit','mcrypt_generic_end','mcrypt_generic_init',            'mcrypt_get_block_size','mcrypt_get_cipher_name',
        +            'mcrypt_get_iv_size','mcrypt_get_key_size','mcrypt_list_algorithms',            'mcrypt_list_modes','mcrypt_module_close',
        +            'mcrypt_module_get_algo_block_size',            'mcrypt_module_get_algo_key_size',
        +            'mcrypt_module_get_supported_key_sizes',            'mcrypt_module_is_block_algorithm',
        +            'mcrypt_module_is_block_algorithm_mode',            'mcrypt_module_is_block_mode','mcrypt_module_open',
        +            'mcrypt_module_self_test','mcrypt_ofb','md5','md5_file',            'mdecrypt_generic','memcache_add','memcache_add_server',
        +            'memcache_close','memcache_connect','memcache_debug',            'memcache_decrement','memcache_delete','memcache_flush',
        +            'memcache_get','memcache_get_extended_stats',            'memcache_get_server_status','memcache_get_stats',
        +            'memcache_get_version','memcache_increment','memcache_pconnect',            'memcache_replace','memcache_set','memcache_set_compress_threshold',
        +            'memcache_set_server_params','memory_get_peak_usage',            'memory_get_usage','metaphone','mhash','mhash_count',
        +            'mhash_get_block_size','mhash_get_hash_name','mhash_keygen_s2k',            'method_exists','microtime','mime_content_type','min',
        +            'ming_keypress','ming_setcubicthreshold','ming_setscale',            'ming_useconstants','ming_useswfversion','mkdir','mktime',
        +            'money_format','move_uploaded_file','msql','msql_affected_rows',            'msql_close','msql_connect','msql_create_db','msql_createdb',
        +            'msql_data_seek','msql_db_query','msql_dbname','msql_drop_db',            'msql_dropdb','msql_error','msql_fetch_array','msql_fetch_field',
        +            'msql_fetch_object','msql_fetch_row','msql_field_flags',            'msql_field_len','msql_field_name','msql_field_seek',
        +            'msql_field_table','msql_field_type','msql_fieldflags',            'msql_fieldlen','msql_fieldname','msql_fieldtable','msql_fieldtype',
        +            'msql_free_result','msql_freeresult','msql_list_dbs',            'msql_list_fields','msql_list_tables','msql_listdbs',
        +            'msql_listfields','msql_listtables','msql_num_fields',            'msql_num_rows','msql_numfields','msql_numrows','msql_pconnect',
        +            'msql_query','msql_regcase','msql_result','msql_select_db',            'msql_selectdb','msql_tablename','mssql_bind','mssql_close',
        +            'mssql_connect','mssql_data_seek','mssql_execute',            'mssql_fetch_array','mssql_fetch_assoc','mssql_fetch_batch',
        +            'mssql_fetch_field','mssql_fetch_object','mssql_fetch_row',            'mssql_field_length','mssql_field_name','mssql_field_seek',
        +            'mssql_field_type','mssql_free_result','mssql_free_statement',            'mssql_get_last_message','mssql_guid_string','mssql_init',
        +            'mssql_min_error_severity','mssql_min_message_severity',            'mssql_next_result','mssql_num_fields','mssql_num_rows',
        +            'mssql_pconnect','mssql_query','mssql_result','mssql_rows_affected',            'mssql_select_db','mt_getrandmax','mt_rand','mt_srand','mysql',
        +            'mysql_affected_rows','mysql_client_encoding','mysql_close',            'mysql_connect','mysql_createdb','mysql_create_db',
        +            'mysql_data_seek','mysql_dbname','mysql_db_name','mysql_db_query',            'mysql_dropdb','mysql_drop_db','mysql_errno','mysql_error',
        +            'mysql_escape_string','mysql_fetch_array','mysql_fetch_assoc',            'mysql_fetch_field','mysql_fetch_lengths','mysql_fetch_object',
        +            'mysql_fetch_row','mysql_fieldflags','mysql_fieldlen',            'mysql_fieldname','mysql_fieldtable','mysql_fieldtype',
        +            'mysql_field_flags','mysql_field_len','mysql_field_name',            'mysql_field_seek','mysql_field_table','mysql_field_type',
        +            'mysql_freeresult','mysql_free_result','mysql_get_client_info',            'mysql_get_host_info','mysql_get_proto_info',
        +            'mysql_get_server_info','mysql_info','mysql_insert_id',            'mysql_listdbs','mysql_listfields','mysql_listtables',
        +            'mysql_list_dbs','mysql_list_fields','mysql_list_processes',            'mysql_list_tables','mysql_numfields','mysql_numrows',
        +            'mysql_num_fields','mysql_num_rows','mysql_pconnect','mysql_ping',            'mysql_query','mysql_real_escape_string','mysql_result',
        +            'mysql_selectdb','mysql_select_db','mysql_set_charset','mysql_stat',            'mysql_tablename','mysql_table_name','mysql_thread_id',
        +            'mysql_unbuffered_query','mysqli_affected_rows','mysqli_autocommit',            'mysqli_bind_param','mysqli_bind_result','mysqli_change_user',
        +            'mysqli_character_set_name','mysqli_client_encoding','mysqli_close',            'mysqli_commit','mysqli_connect','mysqli_connect_errno',
        +            'mysqli_connect_error','mysqli_data_seek','mysqli_debug',            'mysqli_disable_reads_from_master','mysqli_disable_rpl_parse',
        +            'mysqli_dump_debug_info','mysqli_embedded_server_end',            'mysqli_embedded_server_start','mysqli_enable_reads_from_master',
        +            'mysqli_enable_rpl_parse','mysqli_errno','mysqli_error',            'mysqli_escape_string','mysqli_execute','mysqli_fetch',
        +            'mysqli_fetch_array','mysqli_fetch_assoc','mysqli_fetch_field',            'mysqli_fetch_field_direct','mysqli_fetch_fields',
        +            'mysqli_fetch_lengths','mysqli_fetch_object','mysqli_fetch_row',            'mysqli_field_count','mysqli_field_seek','mysqli_field_tell',
        +            'mysqli_free_result','mysqli_get_charset','mysqli_get_client_info',            'mysqli_get_client_version','mysqli_get_host_info',
        +            'mysqli_get_metadata','mysqli_get_proto_info',            'mysqli_get_server_info','mysqli_get_server_version',
        +            'mysqli_get_warnings','mysqli_info','mysqli_init',            'mysqli_insert_id','mysqli_kill','mysqli_master_query',
        +            'mysqli_more_results','mysqli_multi_query','mysqli_next_result',            'mysqli_num_fields','mysqli_num_rows','mysqli_options',
        +            'mysqli_param_count','mysqli_ping','mysqli_prepare','mysqli_query',            'mysqli_real_connect','mysqli_real_escape_string',
        +            'mysqli_real_query','mysqli_report','mysqli_rollback',            'mysqli_rpl_parse_enabled','mysqli_rpl_probe',
        +            'mysqli_rpl_query_type','mysqli_select_db','mysqli_send_long_data',            'mysqli_send_query','mysqli_set_charset',
        +            'mysqli_set_local_infile_default','mysqli_set_local_infile_handler',            'mysqli_set_opt','mysqli_slave_query','mysqli_sqlstate',
        +            'mysqli_ssl_set','mysqli_stat','mysqli_stmt_affected_rows',            'mysqli_stmt_attr_get','mysqli_stmt_attr_set',
        +            'mysqli_stmt_bind_param','mysqli_stmt_bind_result',            'mysqli_stmt_close','mysqli_stmt_data_seek','mysqli_stmt_errno',
        +            'mysqli_stmt_error','mysqli_stmt_execute','mysqli_stmt_fetch',            'mysqli_stmt_field_count','mysqli_stmt_free_result',
        +            'mysqli_stmt_get_warnings','mysqli_stmt_init',            'mysqli_stmt_insert_id','mysqli_stmt_num_rows',
        +            'mysqli_stmt_param_count','mysqli_stmt_prepare','mysqli_stmt_reset',            'mysqli_stmt_result_metadata','mysqli_stmt_send_long_data',
        +            'mysqli_stmt_sqlstate','mysqli_stmt_store_result',            'mysqli_store_result','mysqli_thread_id','mysqli_thread_safe',
        +            'mysqli_use_result','mysqli_warning_count','natcasesort','natsort',            'new_xmldoc','next','ngettext','nl2br','nl_langinfo',
        +            'ntuser_getdomaincontroller','ntuser_getusergroups',            'ntuser_getuserinfo','ntuser_getuserlist','number_format',
        +            'ob_clean','ob_deflatehandler','ob_end_clean','ob_end_flush',            'ob_etaghandler','ob_flush','ob_get_clean','ob_get_contents',
        +            'ob_get_flush','ob_get_length','ob_get_level','ob_get_status',            'ob_gzhandler','ob_iconv_handler','ob_implicit_flush',
        +            'ob_inflatehandler','ob_list_handlers','ob_start','ob_tidyhandler',            'octdec','odbc_autocommit','odbc_binmode','odbc_close',
        +            'odbc_close_all','odbc_columnprivileges','odbc_columns',            'odbc_commit','odbc_connect','odbc_cursor','odbc_data_source',
        +            'odbc_do','odbc_error','odbc_errormsg','odbc_exec','odbc_execute',            'odbc_fetch_array','odbc_fetch_into','odbc_fetch_object',
        +            'odbc_fetch_row','odbc_field_len','odbc_field_name',            'odbc_field_num','odbc_field_precision','odbc_field_scale',
        +            'odbc_field_type','odbc_foreignkeys','odbc_free_result',            'odbc_gettypeinfo','odbc_longreadlen','odbc_next_result',
        +            'odbc_num_fields','odbc_num_rows','odbc_pconnect','odbc_prepare',            'odbc_primarykeys','odbc_procedurecolumns','odbc_procedures',
        +            'odbc_result','odbc_result_all','odbc_rollback','odbc_setoption',            'odbc_specialcolumns','odbc_statistics','odbc_tableprivileges',
        +            'odbc_tables','opendir','openlog','openssl_csr_export',            'openssl_csr_export_to_file','openssl_csr_get_public_key',
        +            'openssl_csr_get_subject','openssl_csr_new','openssl_csr_sign',            'openssl_error_string','openssl_free_key','openssl_get_privatekey',
        +            'openssl_get_publickey','openssl_open','openssl_pkcs12_export',            'openssl_pkcs12_export_to_file','openssl_pkcs12_read',
        +            'openssl_pkcs7_decrypt','openssl_pkcs7_encrypt',            'openssl_pkcs7_sign','openssl_pkcs7_verify','openssl_pkey_export',
        +            'openssl_pkey_export_to_file','openssl_pkey_free',            'openssl_pkey_get_details','openssl_pkey_get_private',
        +            'openssl_pkey_get_public','openssl_pkey_new',            'openssl_private_decrypt','openssl_private_encrypt',
        +            'openssl_public_decrypt','openssl_public_encrypt','openssl_seal',            'openssl_sign','openssl_verify','openssl_x509_checkpurpose',
        +            'openssl_x509_check_private_key','openssl_x509_export',            'openssl_x509_export_to_file','openssl_x509_free',
        +            'openssl_x509_parse','openssl_x509_read','ord',            'output_add_rewrite_var','output_reset_rewrite_vars','overload',
        +            'outputdebugstring','pack','parse_ini_file','parse_str','parse_url',            'parsekit_compile_file','parsekit_compile_string',
        +            'parsekit_func_arginfo','parsekit_opcode_flags',            'parsekit_opcode_name','passthru','pathinfo','pclose',
        +            'pdf_add_bookmark','pdf_add_launchlink','pdf_add_locallink',            'pdf_add_nameddest','pdf_add_note','pdf_add_pdflink',
        +            'pdf_add_thumbnail','pdf_add_weblink','pdf_arc','pdf_arcn',            'pdf_attach_file','pdf_begin_font','pdf_begin_glyph',
        +            'pdf_begin_page','pdf_begin_pattern','pdf_begin_template',            'pdf_circle','pdf_clip','pdf_close','pdf_close_image',
        +            'pdf_close_pdi','pdf_close_pdi_page','pdf_closepath',            'pdf_closepath_fill_stroke','pdf_closepath_stroke','pdf_concat',
        +            'pdf_continue_text','pdf_create_gstate','pdf_create_pvf',            'pdf_curveto','pdf_delete','pdf_delete_pvf','pdf_encoding_set_char',
        +            'pdf_end_font','pdf_end_glyph','pdf_end_page','pdf_end_pattern',            'pdf_end_template','pdf_endpath','pdf_fill','pdf_fill_imageblock',
        +            'pdf_fill_pdfblock','pdf_fill_stroke','pdf_fill_textblock',            'pdf_findfont','pdf_fit_image','pdf_fit_pdi_page',
        +            'pdf_fit_textline','pdf_get_apiname','pdf_get_buffer',            'pdf_get_errmsg','pdf_get_errnum','pdf_get_parameter',
        +            'pdf_get_pdi_parameter','pdf_get_pdi_value','pdf_get_value',            'pdf_initgraphics','pdf_lineto','pdf_load_font',
        +            'pdf_load_iccprofile','pdf_load_image','pdf_makespotcolor',            'pdf_moveto','pdf_new','pdf_open_ccitt','pdf_open_file',
        +            'pdf_open_image','pdf_open_image_file','pdf_open_pdi',            'pdf_open_pdi_page','pdf_place_image','pdf_place_pdi_page',
        +            'pdf_process_pdi','pdf_rect','pdf_restore','pdf_rotate','pdf_save',            'pdf_scale','pdf_set_border_color','pdf_set_border_dash',
        +            'pdf_set_border_style','pdf_set_gstate','pdf_set_info',            'pdf_set_parameter','pdf_set_text_pos','pdf_set_value',
        +            'pdf_setcolor','pdf_setdash','pdf_setdashpattern','pdf_setflat',            'pdf_setfont','pdf_setlinecap','pdf_setlinejoin','pdf_setlinewidth',
        +            'pdf_setmatrix','pdf_setmiterlimit','pdf_setpolydash','pdf_shading',            'pdf_shading_pattern','pdf_shfill','pdf_show','pdf_show_boxed',
        +            'pdf_show_xy','pdf_skew','pdf_stringwidth','pdf_stroke',            'pdf_translate','pdo_drivers','pfsockopen','pg_affected_rows',
        +            'pg_cancel_query','pg_clientencoding','pg_client_encoding',            'pg_close','pg_cmdtuples','pg_connect','pg_connection_busy',
        +            'pg_connection_reset','pg_connection_status','pg_convert',            'pg_copy_from','pg_copy_to','pg_dbname','pg_delete','pg_end_copy',
        +            'pg_errormessage','pg_escape_bytea','pg_escape_string','pg_exec',            'pg_execute','pg_fetch_all','pg_fetch_all_columns','pg_fetch_array',
        +            'pg_fetch_assoc','pg_fetch_object','pg_fetch_result','pg_fetch_row',            'pg_fieldisnull','pg_fieldname','pg_fieldnum','pg_fieldprtlen',
        +            'pg_fieldsize','pg_fieldtype','pg_field_is_null','pg_field_name',            'pg_field_num','pg_field_prtlen','pg_field_size','pg_field_table',
        +            'pg_field_type','pg_field_type_oid','pg_free_result',            'pg_freeresult','pg_get_notify','pg_get_pid','pg_get_result',
        +            'pg_getlastoid','pg_host','pg_insert','pg_last_error',            'pg_last_notice','pg_last_oid','pg_loclose','pg_locreate',
        +            'pg_loexport','pg_loimport','pg_loopen','pg_loread','pg_loreadall',            'pg_lounlink','pg_lowrite','pg_lo_close','pg_lo_create',
        +            'pg_lo_export','pg_lo_import','pg_lo_open','pg_lo_read',            'pg_lo_read_all','pg_lo_seek','pg_lo_tell','pg_lo_unlink',
        +            'pg_lo_write','pg_meta_data','pg_numfields','pg_numrows',            'pg_num_fields','pg_num_rows','pg_options','pg_parameter_status',
        +            'pg_pconnect','pg_ping','pg_port','pg_prepare','pg_put_line',            'pg_query','pg_query_params','pg_result','pg_result_error',
        +            'pg_result_error_field','pg_result_seek','pg_result_status',            'pg_select','pg_send_execute','pg_send_prepare','pg_send_query',
        +            'pg_send_query_params','pg_set_client_encoding',            'pg_set_error_verbosity','pg_setclientencoding','pg_trace',
        +            'pg_transaction_status','pg_tty','pg_unescape_bytea','pg_untrace',            'pg_update','pg_version','php_egg_logo_guid','php_ini_loaded_file',
        +            'php_ini_scanned_files','php_logo_guid','php_real_logo_guid',            'php_sapi_name','php_strip_whitespace','php_uname','phpcredits',
        +            'phpdoc_xml_from_string','phpinfo','phpversion','pi','png2wbmp',            'pop3_close','pop3_delete_message','pop3_get_account_size',
        +            'pop3_get_message','pop3_get_message_count',            'pop3_get_message_header','pop3_get_message_ids',
        +            'pop3_get_message_size','pop3_get_message_sizes','pop3_open',            'pop3_undelete','popen','pos','posix_ctermid','posix_errno',
        +            'posix_getcwd','posix_getegid','posix_geteuid','posix_getgid',            'posix_getgrgid','posix_getgrnam','posix_getgroups',
        +            'posix_getlogin','posix_getpgid','posix_getpgrp','posix_getpid',            'posix_getppid','posix_getpwnam','posix_getpwuid','posix_getrlimit',
        +            'posix_getsid','posix_getuid','posix_get_last_error','posix_isatty',            'posix_kill','posix_mkfifo','posix_setegid','posix_seteuid',
        +            'posix_setgid','posix_setpgid','posix_setsid','posix_setuid',            'posix_strerror','posix_times','posix_ttyname','posix_uname','pow',
        +            'preg_grep','preg_last_error','preg_match','preg_match_all',            'preg_quote','preg_replace','preg_replace_callback','preg_split',
        +            'prev','print_r','printf','proc_close','proc_get_status',            'proc_open','proc_terminate','putenv','quoted_printable_decode',
        +            'quotemeta','rad2deg','radius_acct_open','radius_add_server',            'radius_auth_open','radius_close','radius_config',
        +            'radius_create_request','radius_cvt_addr','radius_cvt_int',            'radius_cvt_string','radius_demangle','radius_demangle_mppe_key',
        +            'radius_get_attr','radius_get_vendor_attr','radius_put_addr',            'radius_put_attr','radius_put_int','radius_put_string',
        +            'radius_put_vendor_addr','radius_put_vendor_attr',            'radius_put_vendor_int','radius_put_vendor_string',
        +            'radius_request_authenticator','radius_send_request',            'radius_server_secret','radius_strerror','rand','range',
        +            'rawurldecode','rawurlencode','read_exif_data','readdir','readfile',            'readgzfile','readlink','realpath','reg_close_key','reg_create_key',
        +            'reg_enum_key','reg_enum_value','reg_get_value','reg_open_key',            'reg_set_value','register_shutdown_function',
        +            'register_tick_function','rename','res_close','res_get','res_list',            'res_list_type','res_open','res_set','reset',
        +            'restore_error_handler','restore_include_path','rewind','rewinddir',            'rmdir','round','rsort','rtrim','runkit_class_adopt',
        +            'runkit_class_emancipate','runkit_constant_add',            'runkit_constant_redefine','runkit_constant_remove',
        +            'runkit_default_property_add','runkit_function_add',            'runkit_function_copy','runkit_function_redefine',
        +            'runkit_function_remove','runkit_function_rename','runkit_import',            'runkit_lint','runkit_lint_file','runkit_method_add',
        +            'runkit_method_copy','runkit_method_redefine',            'runkit_method_remove','runkit_method_rename','runkit_object_id',
        +            'runkit_return_value_used','runkit_sandbox_output_handler',            'runkit_superglobals','runkit_zval_inspect','scandir','sem_acquire',
        +            'sem_get','sem_release','sem_remove','serialize',            'session_cache_expire','session_cache_limiter','session_commit',
        +            'session_decode','session_destroy','session_encode',            'session_get_cookie_params','session_id','session_is_registered',
        +            'session_module_name','session_name','session_regenerate_id',            'session_register','session_save_path','session_set_cookie_params',
        +            'session_set_save_handler','session_start','session_unregister',            'session_unset','session_write_close','set_content',
        +            'set_error_handler','set_file_buffer','set_include_path',            'set_magic_quotes_runtime','set_socket_blocking','set_time_limit',
        +            'setcookie','setlocale','setrawcookie','settype','sha1','sha1_file',            'shell_exec','shmop_close','shmop_delete','shmop_open','shmop_read',
        +            'shmop_size','shmop_write','shm_attach','shm_detach','shm_get_var',            'shm_put_var','shm_remove','shm_remove_var','show_source','shuffle',
        +            'similar_text','simplexml_import_dom','simplexml_load_file',            'simplexml_load_string','sin','sinh','sizeof','sleep','smtp_close',
        +            'smtp_cmd_data','smtp_cmd_mail','smtp_cmd_rcpt','smtp_connect',            'snmp_get_quick_print','snmp_get_valueretrieval','snmp_read_mib',
        +            'snmp_set_quick_print','snmp_set_valueretrieval','snmp2_get',            'snmp2_getnext','snmp2_real_walk','snmp2_set','snmp2_walk',
        +            'snmp3_get','snmp3_getnext','snmp3_real_walk','snmp3_set',            'snmp3_walk','snmpget','snmpgetnext','snmprealwalk','snmpset',
        +            'snmpwalk','snmpwalkoid','socket_accept','socket_bind',            'socket_clear_error','socket_close','socket_connect',
        +            'socket_create','socket_create_listen','socket_create_pair',            'socket_getopt','socket_getpeername','socket_getsockname',
        +            'socket_get_option','socket_get_status','socket_iovec_add',            'socket_iovec_alloc','socket_iovec_delete','socket_iovec_fetch',
        +            'socket_iovec_free','socket_iovec_set','socket_last_error',            'socket_listen','socket_read','socket_readv','socket_recv',
        +            'socket_recvfrom','socket_recvmsg','socket_select','socket_send',            'socket_sendmsg','socket_sendto','socket_setopt','socket_set_block',
        +            'socket_set_blocking','socket_set_nonblock','socket_set_option',            'socket_set_timeout','socket_shutdown','socket_strerror',
        +            'socket_write','socket_writev','sort','soundex','spl_autoload',            'spl_autoload_call','spl_autoload_extensions',
        +            'spl_autoload_functions','spl_autoload_register',            'spl_autoload_unregister','spl_classes','spl_object_hash','split',
        +            'spliti','sprintf','sql_regcase','sqlite_array_query',            'sqlite_busy_timeout','sqlite_changes','sqlite_close',
        +            'sqlite_column','sqlite_create_aggregate','sqlite_create_function',            'sqlite_current','sqlite_error_string','sqlite_escape_string',
        +            'sqlite_exec','sqlite_factory','sqlite_fetch_all',            'sqlite_fetch_array','sqlite_fetch_column_types',
        +            'sqlite_fetch_object','sqlite_fetch_single','sqlite_fetch_string',            'sqlite_field_name','sqlite_has_more','sqlite_has_prev',
        +            'sqlite_last_error','sqlite_last_insert_rowid','sqlite_libencoding',            'sqlite_libversion','sqlite_next','sqlite_num_fields',
        +            'sqlite_num_rows','sqlite_open','sqlite_popen','sqlite_prev',            'sqlite_query','sqlite_rewind','sqlite_seek','sqlite_single_query',
        +            'sqlite_udf_decode_binary','sqlite_udf_encode_binary',            'sqlite_unbuffered_query','sqlite_valid','sqrt','srand','sscanf',
        +            'ssh2_auth_hostbased_file','ssh2_auth_none','ssh2_auth_password',            'ssh2_auth_pubkey_file','ssh2_connect','ssh2_exec',
        +            'ssh2_fetch_stream','ssh2_fingerprint','ssh2_forward_accept',            'ssh2_forward_listen','ssh2_methods_negotiated','ssh2_poll',
        +            'ssh2_publickey_add','ssh2_publickey_init','ssh2_publickey_list',            'ssh2_publickey_remove','ssh2_scp_recv','ssh2_scp_send','ssh2_sftp',
        +            'ssh2_sftp_lstat','ssh2_sftp_mkdir','ssh2_sftp_readlink',            'ssh2_sftp_realpath','ssh2_sftp_rename','ssh2_sftp_rmdir',
        +            'ssh2_sftp_stat','ssh2_sftp_symlink','ssh2_sftp_unlink',            'ssh2_shell','ssh2_tunnel','stat','stats_absolute_deviation',
        +            'stats_cdf_beta','stats_cdf_binomial','stats_cdf_cauchy',            'stats_cdf_chisquare','stats_cdf_exponential','stats_cdf_f',
        +            'stats_cdf_gamma','stats_cdf_laplace','stats_cdf_logistic',            'stats_cdf_negative_binomial','stats_cdf_noncentral_chisquare',
        +            'stats_cdf_noncentral_f','stats_cdf_noncentral_t',            'stats_cdf_normal','stats_cdf_poisson','stats_cdf_t',
        +            'stats_cdf_uniform','stats_cdf_weibull','stats_covariance',            'stats_dens_beta','stats_dens_cauchy','stats_dens_chisquare',
        +            'stats_dens_exponential','stats_dens_f','stats_dens_gamma',            'stats_dens_laplace','stats_dens_logistic','stats_dens_normal',
        +            'stats_dens_pmf_binomial','stats_dens_pmf_hypergeometric',            'stats_dens_pmf_negative_binomial','stats_dens_pmf_poisson',
        +            'stats_dens_t','stats_dens_uniform','stats_dens_weibull',            'stats_harmonic_mean','stats_kurtosis','stats_rand_gen_beta',
        +            'stats_rand_gen_chisquare','stats_rand_gen_exponential',            'stats_rand_gen_f','stats_rand_gen_funiform','stats_rand_gen_gamma',
        +            'stats_rand_gen_ipoisson','stats_rand_gen_iuniform',            'stats_rand_gen_noncenral_f','stats_rand_gen_noncentral_chisquare',
        +            'stats_rand_gen_noncentral_t','stats_rand_gen_normal',            'stats_rand_gen_t','stats_rand_getsd','stats_rand_ibinomial',
        +            'stats_rand_ibinomial_negative','stats_rand_ignlgi',            'stats_rand_phrase_to_seeds','stats_rand_ranf','stats_rand_setall',
        +            'stats_skew','stats_standard_deviation','stats_stat_binomial_coef',            'stats_stat_correlation','stats_stat_factorial',
        +            'stats_stat_independent_t','stats_stat_innerproduct',            'stats_stat_paired_t','stats_stat_percentile','stats_stat_powersum',
        +            'stats_variance','strcasecmp','strchr','strcmp','strcoll','strcspn',            'stream_bucket_append','stream_bucket_make_writeable',
        +            'stream_bucket_new','stream_bucket_prepend','stream_context_create',            'stream_context_get_default','stream_context_get_options',
        +            'stream_context_set_default','stream_context_set_option',            'stream_context_set_params','stream_copy_to_stream',
        +            'stream_encoding','stream_filter_append','stream_filter_prepend',            'stream_filter_register','stream_filter_remove',
        +            'stream_get_contents','stream_get_filters','stream_get_line',            'stream_get_meta_data','stream_get_transports',
        +            'stream_get_wrappers','stream_is_local',            'stream_notification_callback','stream_register_wrapper',
        +            'stream_resolve_include_path','stream_select','stream_set_blocking',            'stream_set_timeout','stream_set_write_buffer',
        +            'stream_socket_accept','stream_socket_client',            'stream_socket_enable_crypto','stream_socket_get_name',
        +            'stream_socket_pair','stream_socket_recvfrom',            'stream_socket_sendto','stream_socket_server',
        +            'stream_socket_shutdown','stream_supports_lock',            'stream_wrapper_register','stream_wrapper_restore',
        +            'stream_wrapper_unregister','strftime','stripcslashes','stripos',            'stripslashes','strip_tags','stristr','strlen','strnatcasecmp',
        +            'strnatcmp','strpbrk','strncasecmp','strncmp','strpos','strrchr',            'strrev','strripos','strrpos','strspn','strstr','strtok',
        +            'strtolower','strtotime','strtoupper','strtr','strval',            'str_ireplace','str_pad','str_repeat','str_replace','str_rot13',
        +            'str_split','str_shuffle','str_word_count','substr',            'substr_compare','substr_count','substr_replace','svn_add',
        +            'svn_auth_get_parameter','svn_auth_set_parameter','svn_cat',            'svn_checkout','svn_cleanup','svn_client_version','svn_commit',
        +            'svn_diff','svn_export','svn_fs_abort_txn','svn_fs_apply_text',            'svn_fs_begin_txn2','svn_fs_change_node_prop','svn_fs_check_path',
        +            'svn_fs_contents_changed','svn_fs_copy','svn_fs_delete',            'svn_fs_dir_entries','svn_fs_file_contents','svn_fs_file_length',
        +            'svn_fs_is_dir','svn_fs_is_file','svn_fs_make_dir',            'svn_fs_make_file','svn_fs_node_created_rev','svn_fs_node_prop',
        +            'svn_fs_props_changed','svn_fs_revision_prop',            'svn_fs_revision_root','svn_fs_txn_root','svn_fs_youngest_rev',
        +            'svn_import','svn_info','svn_log','svn_ls','svn_repos_create',            'svn_repos_fs','svn_repos_fs_begin_txn_for_commit',
        +            'svn_repos_fs_commit_txn','svn_repos_hotcopy','svn_repos_open',            'svn_repos_recover','svn_status','svn_update','symlink',
        +            'sys_get_temp_dir','syslog','system','tan','tanh','tempnam',            'textdomain','thread_get','thread_include','thread_lock',
        +            'thread_lock_try','thread_mutex_destroy','thread_mutex_init',            'thread_set','thread_start','thread_unlock','tidy_access_count',
        +            'tidy_clean_repair','tidy_config_count','tidy_diagnose',            'tidy_error_count','tidy_get_body','tidy_get_config',
        +            'tidy_get_error_buffer','tidy_get_head','tidy_get_html',            'tidy_get_html_ver','tidy_get_output','tidy_get_release',
        +            'tidy_get_root','tidy_get_status','tidy_getopt','tidy_is_xhtml',            'tidy_is_xml','tidy_parse_file','tidy_parse_string',
        +            'tidy_repair_file','tidy_repair_string','tidy_warning_count','time',            'timezone_abbreviations_list','timezone_identifiers_list',
        +            'timezone_name_from_abbr','timezone_name_get','timezone_offset_get',            'timezone_open','timezone_transitions_get','tmpfile',
        +            'token_get_all','token_name','touch','trigger_error',            'transliterate','transliterate_filters_get','trim','uasort',
        +            'ucfirst','ucwords','uksort','umask','uniqid','unixtojd','unlink',            'unpack','unregister_tick_function','unserialize','unset',
        +            'urldecode','urlencode','user_error','use_soap_error_handler',            'usleep','usort','utf8_decode','utf8_encode','var_dump',
        +            'var_export','variant_abs','variant_add','variant_and',            'variant_cast','variant_cat','variant_cmp',
        +            'variant_date_from_timestamp','variant_date_to_timestamp',            'variant_div','variant_eqv','variant_fix','variant_get_type',
        +            'variant_idiv','variant_imp','variant_int','variant_mod',            'variant_mul','variant_neg','variant_not','variant_or',
        +            'variant_pow','variant_round','variant_set','variant_set_type',            'variant_sub','variant_xor','version_compare','virtual','vfprintf',
        +            'vprintf','vsprintf','wddx_add_vars','wddx_deserialize',            'wddx_packet_end','wddx_packet_start','wddx_serialize_value',
        +            'wddx_serialize_vars','win_beep','win_browse_file',            'win_browse_folder','win_create_link','win_message_box',
        +            'win_play_wav','win_shell_execute','win32_create_service',            'win32_delete_service','win32_get_last_control_message',
        +            'win32_ps_list_procs','win32_ps_stat_mem','win32_ps_stat_proc',            'win32_query_service_status','win32_scheduler_delete_task',
        +            'win32_scheduler_enum_tasks','win32_scheduler_get_task_info',            'win32_scheduler_run','win32_scheduler_set_task_info',
        +            'win32_set_service_status','win32_start_service',            'win32_start_service_ctrl_dispatcher','win32_stop_service',
        +            'wordwrap','xml_error_string','xml_get_current_byte_index',            'xml_get_current_column_number','xml_get_current_line_number',
        +            'xml_get_error_code','xml_parse','xml_parser_create',            'xml_parser_create_ns','xml_parser_free','xml_parser_get_option',
        +            'xml_parser_set_option','xml_parse_into_struct',            'xml_set_character_data_handler','xml_set_default_handler',
        +            'xml_set_element_handler','xml_set_end_namespace_decl_handler',            'xml_set_external_entity_ref_handler',
        +            'xml_set_notation_decl_handler','xml_set_object',            'xml_set_processing_instruction_handler',
        +            'xml_set_start_namespace_decl_handler',            'xml_set_unparsed_entity_decl_handler','xmldoc','xmldocfile',
        +            'xmlrpc_decode','xmlrpc_decode_request','xmlrpc_encode',            'xmlrpc_encode_request','xmlrpc_get_type','xmlrpc_is_fault',
        +            'xmlrpc_parse_method_descriptions',            'xmlrpc_server_add_introspection_data','xmlrpc_server_call_method',
        +            'xmlrpc_server_create','xmlrpc_server_destroy',            'xmlrpc_server_register_introspection_callback',
        +            'xmlrpc_server_register_method','xmlrpc_set_type','xmltree',            'xmlwriter_end_attribute','xmlwriter_end_cdata',
        +            'xmlwriter_end_comment','xmlwriter_end_document',            'xmlwriter_end_dtd','xmlwriter_end_dtd_attlist',
        +            'xmlwriter_end_dtd_element','xmlwriter_end_dtd_entity',            'xmlwriter_end_element','xmlwriter_end_pi','xmlwriter_flush',
        +            'xmlwriter_full_end_element','xmlwriter_open_memory',            'xmlwriter_open_uri','xmlwriter_output_memory',
        +            'xmlwriter_set_indent','xmlwriter_set_indent_string',            'xmlwriter_start_attribute','xmlwriter_start_attribute_ns',
        +            'xmlwriter_start_cdata','xmlwriter_start_comment',            'xmlwriter_start_document','xmlwriter_start_dtd',
        +            'xmlwriter_start_dtd_attlist','xmlwriter_start_dtd_element',            'xmlwriter_start_dtd_entity','xmlwriter_start_element',
        +            'xmlwriter_start_element_ns','xmlwriter_start_pi','xmlwriter_text',            'xmlwriter_write_attribute','xmlwriter_write_attribute_ns',
        +            'xmlwriter_write_cdata','xmlwriter_write_comment',            'xmlwriter_write_dtd','xmlwriter_write_dtd_attlist',
        +            'xmlwriter_write_dtd_element','xmlwriter_write_dtd_entity',            'xmlwriter_write_element','xmlwriter_write_element_ns',
        +            'xmlwriter_write_pi','xmlwriter_write_raw','xpath_eval',            'xpath_eval_expression','xpath_new_context','xpath_register_ns',
        +            'xpath_register_ns_auto','xptr_eval','xptr_new_context','yp_all',            'yp_cat','yp_errno','yp_err_string','yp_first',
        +            'yp_get_default_domain','yp_master','yp_match','yp_next','yp_order',            'zend_current_obfuscation_level','zend_get_cfg_var','zend_get_id',
        +            'zend_loader_current_file','zend_loader_enabled',            'zend_loader_file_encoded','zend_loader_file_licensed',
        +            'zend_loader_install_license','zend_loader_version',            'zend_logo_guid','zend_match_hostmasks','zend_obfuscate_class_name',
        +            'zend_obfuscate_function_name','zend_optimizer_version',            'zend_runtime_obfuscate','zend_version','zip_close',
        +            'zip_entry_close','zip_entry_compressedsize',            'zip_entry_compressionmethod','zip_entry_filesize','zip_entry_name',
        +            'zip_entry_open','zip_entry_read','zip_open','zip_read',            'zlib_get_coding_type'
        +            ),        4 => array(
        +            'DEFAULT_INCLUDE_PATH', 'DIRECTORY_SEPARATOR', 'E_ALL',            'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_CORE_ERROR',
        +            'E_CORE_WARNING', 'E_ERROR', 'E_NOTICE', 'E_PARSE', 'E_STRICT',            'E_USER_ERROR', 'E_USER_NOTICE', 'E_USER_WARNING', 'E_WARNING',
        +            'ENT_COMPAT','ENT_QUOTES','ENT_NOQUOTES',            'false', 'null', 'PEAR_EXTENSION_DIR', 'PEAR_INSTALL_DIR',
        +            'PHP_BINDIR', 'PHP_CONFIG_FILE_PATH', 'PHP_DATADIR',            'PHP_EXTENSION_DIR', 'PHP_LIBDIR',
        +            'PHP_LOCALSTATEDIR', 'PHP_OS',            'PHP_OUTPUT_HANDLER_CONT', 'PHP_OUTPUT_HANDLER_END',
        +            'PHP_OUTPUT_HANDLER_START', 'PHP_SYSCONFDIR',            'PHP_VERSION', 'true', '__CLASS__', '__FILE__', '__FUNCTION__',
        +            '__LINE__', '__METHOD__'            )
        +        ),    'SYMBOLS' => array(
        +        1 => array(            '<%', '<%=', '%>', '<?', '<?=', '?>'
        +            ),        0 => array(
        +            '(', ')', '[', ']', '{', '}',            '!', '@', '%', '&', '|', '/',
        +            '<', '>',            '=', '-', '+', '*',
        +            '.', ':', ',', ';'            )
        +        ),    'CASE_SENSITIVE' => array(
        +        GESHI_COMMENTS => false,        1 => false,
        +        2 => false,        3 => false,
        +        4 => false        ),
        +    'STYLES' => array(        'KEYWORDS' => array(
        +            1 => 'color: #b1b100;',            2 => 'color: #000000; font-weight: bold;',
        +            3 => 'color: #990000;',            4 => 'color: #009900; font-weight: bold;'
        +            ),        'COMMENTS' => array(
        +            1 => 'color: #666666; font-style: italic;',            2 => 'color: #666666; font-style: italic;',
        +            3 => 'color: #0000cc; font-style: italic;',            4 => 'color: #009933; font-style: italic;',
        +            'MULTI' => 'color: #666666; font-style: italic;'            ),
        +        'ESCAPE_CHAR' => array(            0 => 'color: #000099; font-weight: bold;',
        +            1 => 'color: #000099; font-weight: bold;',            2 => 'color: #660099; font-weight: bold;',
        +            3 => 'color: #660099; font-weight: bold;',            4 => 'color: #006699; font-weight: bold;',
        +            5 => 'color: #006699; font-weight: bold; font-style: italic;',            6 => 'color: #009933; font-weight: bold;',
        +            'HARD' => 'color: #000099; font-weight: bold;'            ),
        +        'BRACKETS' => array(            0 => 'color: #009900;'
        +            ),        'STRINGS' => array(
        +            0 => 'color: #0000ff;',            'HARD' => 'color: #0000ff;'
        +            ),        'NUMBERS' => array(
        +            0 => 'color: #cc66cc;',            GESHI_NUMBER_OCT_PREFIX => 'color: #208080;',
        +            GESHI_NUMBER_HEX_PREFIX => 'color: #208080;',            GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;',
        +            ),        'METHODS' => array(
        +            1 => 'color: #004000;',            2 => 'color: #004000;'
        +            ),        'SYMBOLS' => array(
        +            0 => 'color: #339933;',            1 => 'color: #000000; font-weight: bold;'
        +            ),        'REGEXPS' => array(
        +            0 => 'color: #000088;'            ),
        +        'SCRIPT' => array(            0 => '',
        +            1 => '',            2 => '',
        +            3 => '',            4 => '',
        +            5 => ''            )
        +        ),    'URLS' => array(
        +        1 => '',        2 => '',
        +        3 => 'http://www.php.net/{FNAMEL}',        4 => ''
        +        ),    'OOLANG' => true,
        +    'OBJECT_SPLITTERS' => array(        1 => '-&gt;',
        +        2 => '::'        ),
        +    'REGEXPS' => array(        //Variables
        +        0 => "[\\$]{1,2}[a-zA-Z_][a-zA-Z0-9_]*"        ),
        +    'STRICT_MODE_APPLIES' => GESHI_MAYBE,    'SCRIPT_DELIMITERS' => array(
        +        0 => array(            '<?php' => '?>'
        +            ),        1 => array(
        +            '<?' => '?>'            ),
        +        2 => array(            '<%' => '%>'
        +            ),        3 => array(
        +            '<script language="php">' => '</script>'            ),
        +        4 => "/(<\?(?:php)?)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(\?>|\Z)/sm",        5 => "/(<%)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(%>|\Z)/sm"
        +        ),    'HIGHLIGHT_STRICT_BLOCK' => array(
        +        0 => true,        1 => true,
        +        2 => true,        3 => true,
        +        4 => true,        5 => true
        +        ),    'TAB_WIDTH' => 4
        +); 
        +?>
        + +

        If you’re remotely familiar with PHP (or even if you’re not), you can see that all that a language file consists of is +a glorified variable assignment. Easy! All a language file does is assign a variable $language_data. Though +still, there’s a lot of indices to that array… but this section is here to break each index down and explain it to you.

        + +

        4.2 Language File Conventions

        + +

        There are several conventions that are used in language files. For ease of use and readability, your language +files should obey the following rules:

        + +
          +
        • Indentation is 4 spaces, not tabs: Use spaces! as editors continiously screw up tabs there should be +no tabs in your documents since it would look differently on every computer otherwise.
        • +
        • Strings are in single quotes: Every string in a language file should be in single quotes (‘), unless you are +specifying a single quote as a quotemark or escape character, in which case they can be in double quotes for +readability; or if you are specifying a REGEXP (see below). This ensures that the language file can be loaded +as fast as possible by PHP as unnecessary parsing can be avoided.
        • +
        • Large arrays are multi-lined: An array with more than three or four values should be broken into multiple +lines. In any case, lines should not be wider than a full-screen window (about 100 chars per line max). +Don’t break the keywords arrays after every keyword.
        • +
        • Ending brackets for multi-lined arrays on a new line: Also with a comma after them, unless the array is +the last one in a parent array. See the PHP language file for examples of where to use commas.
        • +
        • Use GeSHi’s constants: For capatalisation, regular expressions etc. use the GeSHi constants, not +their actual values.
        • +
        • Verbatim header format: Copy the file header verbatim from other language files and modify the values +afterwards. Don’t try to invent own header formats, as your languages else will fail validation!
        • +
        + +

        There are more notes on each convention where it may appear in the language file sections below.

        + +

        4.3 Language File Sections

        + +

        This section will look at all the sections of a language file, and how they relate to the final highlighting result.

        + +

        4.3.1 The Header

        + +

        The header of a language file is the first lines with the big comment and the start of the variable +$language_data:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +2829
        +3031
        +3233
        +3435
        +3637
        +3839
        +4041
        +4243
        +
        <?php
        +/************************************************************************************* * <name-of-language-file.php>
        + * --------------------------------- * Author: <name> (<e-mail address>)
        + * Copyright: (c) 2008 <name> (<website URL>) * Release Version: <GeSHi release>
        + * Date Started: <date started> *
        + * <name-of-language> language file for GeSHi. *
        + * <any-comments...> *
        + * CHANGES * -------
        + * <date-of-release> (<GeSHi release>) *  -  First Release
        + * * TODO (updated <date-of-release>)
        + * ------------------------- * <things-to-do>
        + * *************************************************************************************
        + * *     This file is part of GeSHi.
        + * *   GeSHi is free software; you can redistribute it and/or modify
        + *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or
        + *   (at your option) any later version. *
        + *   GeSHi 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 GeSHi; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
        + * ************************************************************************************/
        + $language_data = array (
        + +

        The parts in angle brackets are the parts that you change for your language file. Everything else must remain the same!

        + +

        Here are the parts you should change:

        + +
          +
        • <name-of-language-file.php> - This should become the name of your language file. Language file names are in +lower case and contain only alphanumeric characters, dashes and underscores. Language files end with .php (which +you should put with the name of your language file, eg language.php)
        • +
        • <name> - Your name, or alias.
        • +
        • <e-mail address> - Your e-mail address. If you want your language file included with GeSHi you must +include an e-mail address that refers to an inbox controlled by you.
        • +
        • <website> - A URL of a website of yours (perhaps to a page that deals with your contribution to GeSHi, or +your home page/blog)
        • +
        • <date-started> - The date you started working on the language file. If you can’t remember, guestimate.
        • +
        • <name-of-language> - The name of the language you made this language file for (probably similar to +the language file name).
        • +
        • <any-comments> - Any comments you have to make about this language file, perhaps on where you got the keywords for, +what dialect of the language this language file is for etc etc. If you don’t have any comments, remove the space for them.
        • +
        • <date-of-release - The date you released the language file to the public. If you simply send it to me for inclusion +in a new GeSHi and don’t release it, leave this blank, and I’ll replace it with the date of the GeSHi release that +it is first added to.
        • +
        • <GeSHi release> - This is the version of the release that will contain the changes you made. +So if you have version 1.0.8 of GeSHi running this will be the next version to be released, e.g. 1.0.8.1.
        • +
        + +

        Everything should remain the same.

        + +

        Also: I’m not sure about the copyright on a new language file. I’m not a lawyer, could someone contact me about +whether the copyright for a new language file should be exclusivly the authors, or joint with me (if included in a +GeSHi release)?

        + +

        4.3.2 The First Indices

        + +

        Here is an example from the php language file of the first indices:

        + +
        PHP code
        1
        +23
        +45
        +6
        'LANG_NAME' => 'PHP',
        +'COMMENT_SINGLE' => array(1 => '//', 2 => '#'),'COMMENT_MULTI' => array('/*' => '*/'),
        +'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,'QUOTEMARKS' => array("'", '"'),
        +'ESCAPE_CHAR' => '\\',
        + +

        The first indices are the first few lines of a language file before the KEYWORDS index. These indices specify:

        + +
          +
        • ‘LANG_NAME’: The name of the language. This name should be a human-readable version of the name +(e.g. HTML 4 (transitional) instead of html4trans)
        • +
        • ‘COMMENT_SINGLE’: An array of single-line comments in your language, indexed by integers starting +from 1. A single line comment is a comment that starts at the marker and goes until the end of the line. These +comments may be any length > 0, and since they can be styled individually, can be used for other things than comments +(for example the Java language file defines “import” as a single line comment). If you are making a language that +uses a ’ (apostrophe) as a comment (or in the comment marker somewhere), use double quotes. e.g.: “’”
        • +
        • ‘COMMENT_MULTI’: Used to specify multiline comments, an array in the form ‘OPEN’ => ‘CLOSE’. Unfortunately, +all of these comments you add here will be styled the same way (an area of improvement for GeSHi 1.2.X). +These comment markers may be any length > 0.
        • +
        • ‘CASE_KEYWORDS’: Used to set whether the case of keywords should be changed automatically as they are found. +For example, in an SQL or BASIC dialect you may want all keywords to be upper case. The accepted values for this are:
        • +
        • GESHI_CAPS_UPPER: Convert the case of all keywords to upper case.
        • +
        • GESHI_CAPS_LOWER: Convert the case of all keywords to lower case.
        • +
        • GESHI_CAPS_NO_CHANGE: Don’t change the case of any keyword.
        • +
        • ‘QUOTEMARKS’: Specifies the characters that mark the beginning and end of a string. This is another example +where if your language includes the ’ string delimiter you should use double quotes around it.
        • +
        • ‘ESCAPE_CHAR’: Specifies the escape character used in all strings. If your language does not have an escape +character then make this the empty string (''). This is not an array! If found, any character after an +escape character and the escape character itself will be highlighted differently, and the character after the +escape character cannot end a string.
        • +
        + +

        In some language files you might see here other indices too, but those are dealt with later on.

        + +

        4.3.3 Keywords

        + +

        Keywords will make up the bulk of a language file. In this part you add keywords for your language, including +inbuilt functions, data types, predefined constants etc etc.

        + +

        Here’s a (shortened) example from the php language file:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +2829
        +3031
        +3233
        +3435
        +3637
        +3839
        +40
        'KEYWORDS' => array(
        +    1 => array(        'as', 'break', 'case', 'do', 'else', 'elseif', 'endif',
        +        'endswitch', 'endwhile', 'for', 'foreach', 'if', 'include',        'include_once', 'require', 'require_once', 'return',
        +        'switch', 'while'        ),
        +    2 => array(        '&lt;/script>', '&lt;?', '&lt;?php', '&lt;script language=',
        +        '?>', 'class', 'default', 'DEFAULT_INCLUDE_PATH', 'E_ALL',        'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_CORE_ERROR',
        +        'E_CORE_WARNING', 'E_ERROR', 'E_NOTICE', 'E_PARSE',        'E_USER_ERROR', 'E_USER_NOTICE', 'E_USER_WARNING',
        +        'E_WARNING', 'false', 'function', 'new', 'null',        'PEAR_EXTENSION_DIR', 'PEAR_INSTALL_DIR', 'PHP_BINDIR',
        +        'PHP_CONFIG_FILE_PATH', 'PHP_DATADIR', 'PHP_EXTENSION_DIR',        'PHP_LIBDIR', 'PHP_LOCALSTATEDIR', 'PHP_OS',
        +        'PHP_OUTPUT_HANDLER_CONT', 'PHP_OUTPUT_HANDLER_END',        'PHP_OUTPUT_HANDLER_START', 'PHP_SYSCONFDIR', 'PHP_VERSION',
        +        'true', 'var', '__CLASS__', '__FILE__', '__FUNCTION__',        '__LINE__', '__METHOD__'
        +        ),    3 => array(
        +        'xml_parser_create', 'xml_parser_create_ns',        'xml_parser_free', 'xml_parser_get_option',
        +        'xml_parser_set_option', 'xml_parse_into_struct',        'xml_set_character_data_handler', 'xml_set_default_handler',
        +        'xml_set_element_handler',        'xml_set_end_namespace_decl_handler',
        +        'xml_set_external_entity_ref_handler',        'xml_set_notation_decl_handler', 'xml_set_object',
        +        'xml_set_processing_instruction_handler',        'xml_set_start_namespace_decl_handler',
        +        'xml_set_unparsed_entity_decl_handler', 'yp_all', 'yp_cat',        'yp_errno', 'yp_err_string', 'yp_first',
        +        'yp_get_default_domain', 'yp_master', 'yp_match', 'yp_next',        'yp_order', 'zend_logo_guid', 'zend_version',
        +        'zlib_get_coding_type'        )
        +    ),
        + +

        You can see that the index ‘KEYWORDS’ refers to an array of arrays, indexed by positive integers. In each array, +there are some keywords (in the actual php language file there is in fact many more keywords in the array indexed by 3). +Here are some points to note about these keywords:

        + +
          +
        • Indexed by positive integers: Use nothing else! I may change this in 1.2.X, but for the 1.0.X series, +use positive integers only. Using strings here results in unnecessary overhead degrading performance when +highlighting code with your language file!
        • +
        • Keywords sorted ascending: Keywords should be sorted in ascending order. This is mainly for +readability. An issue with versions before 1.0.8 has been solved, so the reverse sorting order +is no longer required and should thus be avoided. GeSHi itself sorts the keywords internally when +building some of its caches, so the order doesn’t matter, but makes things easier to read and maintain.
        • +
        • Keywords are case sensitive (sometimes): If your language is case-sensitive, the correct casing of the +keywords is defined as the case of the keywords in these keyword arrays. If you check the java language file you +will see that everything is in exact casing. So if any of these keyword arrays are case sensitive, put the +keywords in as their correct case! (note that which groups are case sensitive and which are not is configurable, +see later on). If a keyword group is case insensitive, put the lowercase version of the keyword here +OR in case documentation links require a special casing (other than all lowercase or all uppercase) +the casing required for them use their casing.
        • +
        • Keywords must be in htmlentities() form: All keywords should be written as if they had been +run through the php function htmlentities(). E.g, the keyword is &lt;foo&gt;, not +<foo>
        • +
        • Don’t use keywords to highlight symbols: Just don’t!!! It doesn’t work, and there is seperate support +for symbols since GeSHi 1.0.7.21.
        • +
        • Markup Languages are special cases: Check the html4strict language file for an example: You need to tweak +the Parser control here to tell the surroundings of tagnames. In case of doubt, feel free to ask.
        • +
        + +

        4.3.4 Symbols and Case Sensitivity

        + +

        So you’ve put all the keywords for your language in? Now for a breather before we style them :). Symbols define +what symbols your language uses. These are things like colons, brackets/braces, and other such general punctuation. +No alphanumeric stuff belongs here, just the same as no symbols belong into the keywords section.

        + +

        As of GeSHi version 1.0.7.21 the symbols section can be used in two ways:

        + +
        +
        Flat usage:
        +
        This mode is the suggested way for existing language files and languages that only need few symbols where no +further differentiation is needed or desired. You simply put all the characters in an array under symbols as shown +in the first example below. All symbols in flat usage belong to symbol style group 0.
        + +
        Group usage:
        +
        This is a slightly more enhanced way to provide GeSHi symbol information. To use group you create several subarrays +each containing only a subset of the symbols to highlight. Every array will need to have an unique index thus +you can assign the appropriate styles later.
        +
        + +

        Here’s an example for flat symbol usage

        + +
        PHP code
        1
        +23
        +
        'SYMBOLS' => array(
        +  '(', ')', '[', ']', '{', '}', '!', '@', '|', '&', '+', '-', '*', '/', '%', '=', '<', '>'),
        + +

        which is not too different from the newly introduced group usage shown below:

        + +
        PHP code
        1
        +23
        +45
        +6
        'SYMBOLS' => array(
        +  0 => array('(', ')', '[', ']', '{', '}'),  1 => array('!', '@', '|', '&'),
        +  2 => array('+', '-', '*', '/', '%'),  3 => array('=', '&lt;', '>')
        +),
        + +
        + +
        Note:
        + +

        Please note that versions before 1.0.7.21 will silently ignore this setting.

        + +

        Also note that GeSHi 1.0.7.21 itself had some bugs in Symbol highlighting that could cause + heavily scrambled code output.

        + +
        + +

        The following case sensitivity group alludes to the keywords section: here you can set which keyword groups are case sensitive.

        + +

        In the ‘CASE_SENSITIVE’ group there’s a special key GESHI_COMMENTS which is used to set whether comments are +case sensitive or not (for example, BASIC has the REM statement which while not being case sensitive is still alphanumeric, and +as in the example given before about the Java language file using “import” as a single line comment, this can be +useful sometimes. true if comments are case sensitive, false otherwise. All of the other indices +correspond to indices in the 'KEYWORDS' section (see above).

        + +

        4.3.5 Styles for your Language File

        + +

        This is the fun part! Here you get to choose the colours, fonts, backgrounds and anything else you’d like for your +language file.

        + +

        Here’s an example:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +2829
        +3031
        +3233
        +3435
        +3637
        +3839
        +
        'STYLES' => array(
        +    'KEYWORDS' => array(        1 => 'color: #b1b100;',
        +        2 => 'color: #000000; font-weight: bold;',        3 => 'color: #000066;'
        +        ),    'COMMENTS' => array(
        +        1 => 'color: #808080; font-style: italic;',        2 => 'color: #808080; font-style: italic;',
        +        'MULTI' => 'color: #808080; font-style: italic;'        ),
        +    'ESCAPE_CHAR' => array(        0 => 'color: #000099; font-weight: bold;'
        +        ),    'BRACKETS' => array(
        +        0 => 'color: #66cc66;'        ),
        +    'STRINGS' => array(        0 => 'color: #ff0000;'
        +        ),    'NUMBERS' => array(
        +        0 => 'color: #cc66cc;'        ),
        +    'METHODS' => array(        0 => 'color: #006600;'
        +        ),    'SYMBOLS' => array(
        +        0 => 'color: #66cc66;'        ),
        +    'REGEXPS' => array(        0 => 'color: #0000ff;'
        +        ),    'SCRIPT' => array(
        +        0 => '',        1 => '',
        +        2 => '',        3 => ''
        +        )    ),
        + +

        Note that all style rules should end with a semi-colon! This is important: GeSHi may add extra rules to the rules you +specify (and will do so if a user tries to change your styles on the fly), so the last semi-colon in any stylesheet +rule is important!

        + +

        All strings here should contain valid stylesheet declarations (it’s also fine to have the empty string).

        + +
          +
        • ‘KEYWORDS’: This is an array, from keyword index to style. The index you use is the index you used in +the keywords section to specify the keywords belonging to that group.
        • +
        • ‘COMMENTS’: This is an array, from single-line comment index to style for that index. The index ‘MULTI’ is +used for multiline comments (and cannot be an array). COMMENT_REGEXP use the style given for their key as +if they were single-line comments.
        • +
        • ‘ESCAPE_CHAR’, ‘BRACKETS’ and ‘METHODS’: These are arrays with only one index: 0. You cannot add other indices to +these arrays.
        • +
        • ‘STRINGS’: This defines the various styles for the Quotemarks you defined earlier. If you don’t use +multiple styles for strings there’s only one index: 0. Please also add this index in case no strings are present.
        • +
        • ‘NUMBERS’: This sets the styles used to highlight numbers. The format used here depends on the format used to +set the formats of numbers to highlight. If you just used an integer (bitmask) for numbers, you have to either +specify one key with the respective constant, and\or include a key 0 as a default style. If you used an +array for the number markup, copy the keys used there and assign the styles accordingly.
        • +
        • ‘SYMBOLS’: This provides one key for each symbol group you defined above. If you used the flat usage +make sure you include a key for symbols group 0.
        • +
        • ‘REGEXPS’: This is an array with a style for each matching regex. Also, since 1.0.7.21, you can specify the +name of a function to be called, that will be given the text matched by the regex, each time a match is found. +Note that my testing found that create_function would not work with this due to a PHP bug, so you have to +put the function definition at the top of the language file. Be sure to prefix the function name +with geshi_[languagename]_ as to not conflict with other functions!
        • +
        • ‘SCRIPT’: For languages that use script delimiters, this is where you can style each block of script. For +example, HTML and XML have blocks that begin with < and end with > (i.e. tags) and blocks that begin with & and +end with ; (i.e. character entities), and you can set a style to apply to each whole block. You specify the +delimiters for the blocks below. Note that many languages will not need this feature.
        • +
        + +

        4.3.6 URLs for Functions

        + +

        This section lets you specify a url to visit for each keyword group. Useful for pointing functions at their online +manual entries.

        + +

        Here is an example:

        + +
        PHP code
        1
        +23
        +45
        +6
        'URLS' => array(
        +    1 => '',    2 => '',
        +    3 => 'http://www.php.net/{FNAME}',    4 => ''
        +    ),
        + +

        The indices of this array correspond to the keyword groups you specified in the keywords section. The string {FNAME} +marks where the name of the function is substituted in. So for the example above, if the keyword being highlighted is +“echo”, then the keyword will be a URL pointing to http://www.php.net/echo. Because some languages (Java!) don’t +keep a uniform URL for functions/classes, you may have trouble in creating a URL for that language (though look in the +java language file for a novel solution to it’s problem)

        + +

        4.3.7 Number Highlighting Support

        + +

        If your language supports different formats of numbers (e.g. integers and float representations) and you want +GeSHi to handle them differently you can select from a set of predefined formats.

        + +
        PHP code
        1
        +23
        +4
            'NUMBERS' =>
        +        GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE | GESHI_NUMBER_BIN_PREFIX_0B |        GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | GESHI_NUMBER_FLT_NONSCI |
        +        GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO,
        + +

        All the formats you want GeSHi to recognize are selected via a bitmask that is built by bitwise OR-ing the format constants. +When styling you use these constants to assign the proper styles. A style not assigned will automatically fallback to style group 0.

        + +
        + +
        Note:
        + +

        For a complete list of formats supported by GeSHi have a look into the sources of geshi.php.

        + +
        + +

        If you want to define your own formats for numbers or when you want to group the style for two or more formats you can use the array syntax.

        + +
        PHP code
        1
        +23
        +45
        +67
        +
            'NUMBERS' => array(
        +        1 => GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE,        2 => GESHI_NUMBER_BIN_PREFIX_0B,
        +        3 => GESHI_NUMBER_OCT_PREFIX,        4 => GESHI_NUMBER_HEX_PREFIX,
        +        5 => GESHI_NUMBER_FLT_NONSCI | GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO        ),
        + +

        This creates 5 style groups 1..5 that will highlight each of the formats specified for each group. +Styling of these groups doesn’t use the constants but uses the indices you just defined.

        + +

        Instead of using those predefined constants you also can assign a PCRE that matches a number when using this advanced format.

        + +
        + +
        Note:
        + +

        The extended format hasn’t been exhaustively been tested. So beware of bugs there.

        + +
        + +

        4.3.8 Object Orientation Support

        + +

        Now we’re reaching the most little-used section of a language file, which includes such goodies as object orientation +support and context support. GeSHi can highlight methods and data fields of objects easily, all you need to do is to +tell it to do so and what the “splitter” is between object/method etc.

        + +

        Here’s an example:

        + +
        PHP code
        1
        +2
        'OOLANG' => true,
        +'OBJECT_SPLITTER' => '-&gt;',
        + +

        If your language has object orientation, the value of 'OOLANG' is true, otherwise it is false. If it is object +orientated, in the 'OBJECT_SPLITTER' value you put the htmlentities() version of the “splitter” between +objects and methods/fields. If it is not, then make this the empty string.

        + +

        4.3.9 Using Regular Expressions

        + +

        Regular expressions are a good way to catch any other lexic that fits certain rules but can’t be listed as a keyword. +A good example is variables in PHP: variables always start with either one or two “$” signs, then alphanumeric +characters (a simplification). This is easy to catch with regular expressions.

        + +

        And new to version 1.0.2, there is an advanced way of using regular expressions to catch certain things but highlight +only part of those things. This is particularly useful for languages like XML.

        + +
        + +
        Caution:
        + +

        Regular expressions use the PCRE syntax (perl-style), not the ereg() style!

        + +
        + +

        Here is an example (this time the PHP file merged with the XML file):

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +
        0 => array(
        +    GESHI_SEARCH => '(((xml:)?[a-z\-]+))(=)',    GESHI_REPLACE => '\\1',
        +    GESHI_MODIFIERS => '',    GESHI_BEFORE => '',
        +    GESHI_AFTER => '\\4'    ),
        +1 => array(    GESHI_SEARCH => '(>/?[a-z0-9]*(>)?)',
        +    GESHI_REPLACE => '\\1',    GESHI_MODIFIERS => '',
        +    GESHI_BEFORE => '',    GESHI_AFTER => ''
        +    ),2 => "[\\$]{1,2}[a-zA-Z_][a-zA-Z0-9_]*"
        + +

        As you can see there are two formats. One is the “simple” format used in GeSHi < 1.0.2, and the other is a more +advanced syntax. Firstly, the simple syntax:

        + +
          +
        • May be in double quotes: To make it easier for those who always place their regular expressions in double quotes, +you may place any regular expression here in double quotes if you wish.
        • +
        • Don’t use curly brackets where possible: If you want to use curly brackets (()) then by all means give it a try, +but I’m not sure whether under some circumstances GeSHi may throw a wobbly. You have been warned! If you want to +use brackets, it would be better to use the advanced syntax.
        • +
        • Don’t use the “everything” regex: (That’s the .*? regex). Use advanced syntax instead.
        • +
        + +

        And now for advanced syntax, which gives you much more control over exactly what is highlighted:

        + +
          +
        • GESHI_SEARCH: This element specifies the regular expression to search for. If you plan to capture the output, +use brackets (()). See how in the first example above, most of the regular expression is in one set of brackets +(with the equals sign in other brackets). You should make sure that the part of the regular expression that is +supposed to match what is highlighted is in brackets.
        • +
        • GESHI_REPLACE: This is what the stuff matched by the regular expression will be replaced with. If you’ve +grouped the stuff you want highlighted into brackets in the GESHI_SEARCH element, then you can use \\number +to match that group, where number is a number corresponding to how many open brackets are between the open +bracket of the group you want highlighted and the start of the GESHI_SEARCH string + 1. This may sound confusing, +and it probably is, but if you’re familiar with how PHP’s regular expressions work you should understand. In the +example above, the opening bracket for the stuff we want highlighted is the very first bracket in the string, so +the number of brackets before that bracket and the start of the string is 0. So we add 1 and get our replacement +string of \\1 (whew!).
        • +
        + +

        If you didn’t understand a word of that, make sure that there are brackets around the string in GESHI_SEARCH +and use \\1 for GESHI_REPLACE ;)

        + +
          +
        • GESHI_MODIFIERS: Specify modifiers for your regular expression. If your regular expression includes the +everything matcher (.*?), then your modifiers should include “s” and “i” (e.g. use ‘si’ for this).
        • +
        • GESHI_BEFORE:Specifies a bracket group that should appear before the highlighted match (this bracketed group will +not be highlighted). Use this if you had to match what you wanted by matching part of your regexp string to something +before what you wanted to highlight, and you don’t want that part to disappear in the highlighted result.
        • +
        • GESHI_AFTER:Specifies a bracket group that should appear after the highlighted match (this bracketed group will +not be highlighted). Use this if you had to match what you wanted by matching part of your regexp string to something +after what you wanted to highlight, and you don’t want that part to disappear in the highlighted result.
        • +
        + +

        Is that totally confusing? Here’s the test for if you’re an android or not: If you found that perfectly understandable +then you’re an android ;). Here’s a better example:

        + +

        Let’s say that I’m making a language, and variables in this language always start with a dollar sign ($), are always +written in lowercase letters and always end with an ampersand (&). eg:

        + +

        $foo& = 'bar'

        + +

        I want to highlight only the text between the $ and the &. How do I do that? With simple regular expressions I can’t, +but with advanced, it’s relatively easy:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +14
        1 => array(
        +    // search for a dollar sign, then one or more of the characters a-z, then an ampersand    GESHI_SEARCH => '(\$)([a-z]+)(&)',
        +    // we wanna highlight the characters, which are in the second bracketed group    GESHI_REPLACE => '\\2',
        +    // no modifiers, since we're not matching the "anything" regex    GESHI_MODIFIERS => '',
        +    // before the highlighted characters should be the first    // bracketed group (always a dollar sign in this example)
        +    GESHI_BEFORE => '\\1',    // after the highlighted characters should be the third
        +    // bracketed group (always an ampersand in this example)    GESHI_AFTER => '\\3'
        +    ),
        + +

        So if someone tried to highlight using my language, all cases of $foo& would turn into:

        + +

        $<span style="color: blue;">foo</span><span style="color: green;">&amp;</span>

        + +

        (which would of course be viewed in a browser to get something like $foo&)

        + +

        4.3.10 Contextual Highlighting and Strict Mode

        + +

        For languages like HTML, it’s good if we can highlight a tag (like <a> for example). But how do we stop +every single “a” in the source getting highlighted? What about for attributes? If I’ve got the word “colspan” in my +text I don’t want that highlighted! So how do you tell GeSHi not to highlight in that case? You do it with “Strict Blocks”.

        + +

        Here is an example:

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +1213
        +1415
        +1617
        +1819
        +2021
        +2223
        +2425
        +2627
        +
        <? /* ... */
        +'STRICT_MODE_APPLIES' => GESHI_MAYBE,'SCRIPT_DELIMITERS' => array(
        +    0 => array(        '<?php' => '?>'
        +        ),    1 => array(
        +        '<?' => '?>'        ),
        +    2 => array(        '<%' => '%>'
        +        ),    3 => array(
        +        '<script language="php">' => '</script>'        )
        +    4 => "/(<\?(?:php)?)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(\?>|\Z)/sm",    5 => "/(<%)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(%>|\Z)/sm"
        +    ),'HIGHLIGHT_STRICT_BLOCK' => array(
        +    0 => true,    1 => true,
        +    2 => true,    3 => true,
        +    4 => true,    5 => true
        +    )/* ... */ ?>
        + +

        What is strict mode? Strict mode says that highlighting only occurs inside the blocks you specify. You can see from +the example above that highlighting will only occur if the source is inside <?php ... ?> (though note the +GESHI_MAYBE!). Here are some points about strict highlighting:

        + +
          +
        • ‘STRICT_MODE_APPLIES’: This takes three values (all constants): + +
            +
          • GESHI_ALWAYS: Strict mode always applies for all of the blocks you specify. Users of your language +file cannot turn strict mode off. This should be used for markup languages.
          • +
          • GESHI_NEVER: Strict mode is never used. Users of your language file cannot turn strict mode on. Use this +value if there is no such thing as a block of code that would not be highlighted in your language +(most languages, like C, Java etc. use this because anything in a C file should be highlighted).
          • +
          • GESHI_MAYBE: Strict mode *sometimes* applies. It defaults to “off”. Users can turn strict mode on if +they please. If strict mode is off then everything in the source will be highlighted, even things outside +the strict block markers. If strict mode is on the nothing outside strict block markers will be highlighted.
          • +
        • +
        • ‘SCRIPT_DELIMITERS’: This is an array of script delimiters, in the format of the above. The indices are use in the +‘SCRIPT’ part of the styles section for highlighting everything in a strict block in a certain way. +For example, you could set up your language file to make the background yellow of any code inside a strict +block this way. The delimiters are in the form 'OPEN' => 'CLOSE'. Delimiters can be of any +length > 0. Delimiters are not formatted as if they were run through htmlentities()!
        • +
        • ‘HIGHLIGHT_STRICT_BLOCK’: specifies whether any highlighting should go on inside each block. Most of +the time this should be true, but for example, in the XML language file highlighting is turned off for +blocks beginning with <!DOCTYPE and ending with >. However, you can still +style the overall block using the method described above, and the XML language file does just that.
        • +
        + +
        + +
        Note:
        + +

        The delimiters should be in reverse alphabetical order. Note that in the above example, <?php + comes before <?.

        + +
        + +

        Since GeSHi 1.0.8 instead of specifying an array with starter and ender you may also provide a regular expression +that matches the full block you wish to highlight. If the regular expression match starts at the same position +as a previous array declaration the Regexp match is taken. This is to allow for a fall-back when a preg_match +doesn’t quite work as expected so you still get reasonably well results.

        + +

        If you didn’t get this, you might want to look into the PHP or HTML language files as this feature is used there +to fix some issues that have been there for about 3 years.

        + +
        + +
        Caution:
        + +

        For PHP versions <4.3.3 Strict Block Regexps are completely ignored due to problems in those version + that would cause loads of warning messages otherwise.

        + +
        + +

        4.3.11 Special Parser Settings (Experimental)

        + +

        Sometimes it is necessary for a language to render correctly to tweak some of the assumptions GeSHi usually makes to match the behaviour your language expects. +To achieve this there is an experimental section called 'PARSER_CONTROL' which is optional and should be used only if necessary. +With the help of this section some internal parameters of GeSHi can be set which are not overrideable by the API and thus their use should be limited as much as possible.

        + +

        The syntax of the PARSER_CONTROL basically resembles an array structure simular to the one found in the rest of the language file. All subsections of the PARSER_CONTROL are optional. +If a given setting isn’t present the usual default values of GeSHi are used. +No validation of settings is performed for these settings. Also note that unknown settings are silently ignored.

        + +
        + +
        Caution:
        + +

        All PARSER_CONTROL settings are experimental and subject to change. + So if you need a special setting in a public language file you should consider requesting it upstream. + This is also the reason why documentation on these settings will only cover broad usage information as the underlying implementation might change without further notice.

        + +
        + +

        One of the most common reasons why you might want to use the PARSER_CONTROL settings is to tweak what characters are allowed to surround a keyword. +Usually GeSHi checks for a fixed set of characters like brackets and common symbols that denote the word boundary for a keyword. +If this set conflicts with your language (e.g. - is allowed inside a keyword) or you want to limit the usage of a keyword to certain areas (e.g. for HTML tag names only match after <) you can change those conditions here.

        + +

        Keyword boundary rules can either be set globally (directly within the PARSER_CONTROL’s KEYWORDS section or on a per-group basis. +E.g. the following sample from the HTML language file sets different settings for keyword matching only for Keyword Group 2 and leaves the other groups alone.

        + +
        PHP code
        1
        +23
        +45
        +67
        +8
            'PARSER_CONTROL' => array(
        +        'KEYWORDS' => array(            2 => array(
        +                'DISALLOWED_BEFORE' => '(?<=&lt;|&lt;\/)',                'DISALLOWED_AFTER' => '(?=\s|\/|&gt;)',
        +            )        )
        +    )
        + +
        + +
        Note:
        + +

        The name 'DISALLOWED_BEFORE' and 'DISALLOWED_AFTER' might sound confusing at first, since they don’t define what to prevent, but what to match in order to find a keyword. + The reason for this strange naming is based in the original implementation of this feature when Nigel implemented this in the old parser statically. + When this implementation was brought out via the PARSER_CONTROL settings the original naming wasn’t altered since at that time this really was a blacklist of characters. + Later on this implementation was changed from a blacklist of characters to a part of a PCRE regexp, but leaving the name. + The naming might be subject to change though.

        + +
        + +

        Another option you can change since GeSHi 1.0.8.3 is whether to treat spaces within keywords as literals (only a single space as given) or if the space should match any whitespace at that location. +The following code will enable this behaviour for the whole keyword set. As said above you can choose to enable this for single keyword groups only though.

        + +
        PHP code
        1
        +23
        +45
        +
            'PARSER_CONTROL' => array(
        +        'KEYWORDS' => array(            'SPACE_AS_WHITESPACE' => true
        +        )    ),
        + +

        Another option of interest might be disabling certain features for a given language. +This might come in handy if the language file you are working on doesn’t support a given function or highlighting certain aspects won’t work properly or would interfere with custom implementations using regular expressions.

        + +
        PHP code
        1
        +23
        +45
        +67
        +89
        +1011
        +12
            'PARSER_CONTROL' => array(
        +        'ENABLE_FLAGS' => array(            'ALL' => GESHI_NEVER,
        +            'NUMBERS' => GESHI_NEVER,            'METHODS' => GESHI_NEVER,
        +            'SCRIPT' => GESHI_NEVER,            'SYMBOLS' => GESHI_NEVER,
        +            'ESCAPE_CHAR' => GESHI_NEVER,            'BRACKETS' => GESHI_NEVER,
        +            'STRINGS' => GESHI_NEVER,        )
        +    )
        + +

        Inside the 'ENABLE_FLAGS' section follows an array of 'name'=>value pairs. +Valid names are the sections below the 'STYLES' section (well, not exactly, but you can look there for what the features are called inside GeSHi). +Valid values are the GeSHi constants GESHI_NEVER (don’t process this feature), GESHI_ALWAYS (always process this feature, ignore the user) and GESHI_MAYBE (listen to the user if he want’s this highlighted). +The value GESHI_MAYBE is the default one and thus needs not to be set explicitely.

        + +

        Another setting available through the PARSER_CONTROL settings is the possibility to limit the allowed characters before an single line comment.

        + +
        PHP code
        1
        +23
        +45
        +
            'PARSER_CONTROL' => array(
        +        'COMMENTS' => array(            'DISALLOWED_BEFORE' => '$'
        +        )    )
        + +

        With the current implementation the DISALLOWED_BEFORE COMMENT-specific setting is a list of characters. But this is subject to change.

        + +
        + +
        Note:
        + +

        There is no 'DISALLOWED_AFTER' setting with the 'COMMENTS'-PARSER_CONTROL.

        + +
        + +

        Another PARSER_CONTROL setting for the environment around certain syntactic constructs refers to the handling of object-oriented languages.

        + +
        PHP code
        1
        +23
        +45
        +67
        +
            'PARSER_CONTROL' => array(
        +        'OOLANG' => array(            'MATCH_BEFORE' => '',
        +            'MATCH_AFTER' => '[a-zA-Z_][a-zA-Z0-9_]*',            'MATCH_SPACES' => '[\s]*'
        +        )    )
        + +
        + +
        Caution:
        + +

        Please note that the settings discussed in this section are experimental and might be changed, removed or altered in their meaning at any time.

        + +
        + +

        4.3.12 Tidying Up

        + +

        All language files should end with:

        + +
        PHP code
        1
        +23
        +
        );
        + ?>
        + +

        That is the string content "\n);\n?>\n".

        + +
        + +
        Caution:
        + +

        Make sure that there is EXACTLY one linebreak character at the end. If you accidentially include more + you might end up with messages like “Headers already sent”.

        + +
        + +

        4.4 Validating your language file

        + +

        Since GeSHi 1.0.8 there is a new script langcheck.php in the contrib directory that scans all +language files it finds in the geshi/ subdirectory of the GeSHi installation for mistakes.

        + +

        Please make sure that your language does not contain any mistakes that this script shows you when sending in +your language file for inclusion into the official release as this saves work for us when including your file. +Also you can be sure your language file will work as expected once your language file validates correctly.

        + +

        Please note that not all of the language files shipped with GeSHi are fully valid yet, but we’re working on it +and are happy about every patch we get!

        + +

        5 Method/Constant Reference

        + +

        I’m afraid I have been lying for a little while about this now! Since 1.0.7 I have been including a phpdoc API for +the sourcecode in the api directory, but have forgot to update the documentation! However, it is available, +and may assist you in coding, especially for plugin coders.

        + +
        + +

        That’s all, folks!

        + +

        I’ve improved the documentation greatly from version 1.0.1, but there may still be problems with it, or it may still +be confusing for you. Or perhaps I was just plain wrong about one point! If so, contact me and I’ll do my best to sort it out.

        + +

        In case you were wondering, I’ve finished development of the 1.0.X thread of GeSHi. The only releases I’ll make in this +thread will be of the bug-fix/add language files type. In particular, version 1.0.2 was a “concept” release - testing +how far I could take the highlighting idea (as well as ideas from others).

        + +

        I’m planning a code rewrite for 1.2.X, which will be based on a new engine - a “psuedo-tokenizer” engine. Hopefully +it will massively reduce the server load and time taken (by almost eliminating regexps), while providing +superior highlighting. But fear not! The interface and method names should all remain the same ^_^ (though I can’t +say the same for language files!)

        + +

        And finally, a couple of people have been asking me: how did you generate that documentation? The amazing answer is: my +brain. And yes, it took a long time, and I don’t recommend doing it this way. And yes, you can borrow the styles if +you like, though flick me an e-mail if you do.

        + +

        Anyway, enough blather from me. Get GeSHi working for you already! :D

        + +
        + +
        +
        Authors:
        +
        © 2004 - 2007 Nigel McNie
        + +
        © 2007 - 2008 Benny Baumann
        + +
        © 2008 Milian Wolff
        + +
        GeSHi Website:
        +
        http://qbnz.com/highlighter
        +
        + +
        + +
        +
        +
          + +
        1. +

          The PRE header (see The Code Container) is not valid HTML, you might want +to use one of the other header types instead. 

          +
        2. + +
        3. +

          Support is granted for PHP 4.3.0 and above, but especially 4.3.x cannot be guaranteed to +work due to a lack of test systems. If you are forced to use such old PHP versions complain at your hoster or +contact us if you find compatibility issues so we can try to resolve them. It’s only PHP 4.4.X and above that +is verified to work. 

          +
        4. + +
        5. +

          I am no longer working on this MOD, however if someone else wants to they can contact me for more +information. 

          +
        6. + +
        7. +

          Available as plugin only. In addition, some of the other entries mentioned +here may only have GeSHi available as a plugin. 

          +
        8. + +
        +
        + + \ No newline at end of file diff --git a/examples/includes/geshi/docs/geshi-doc.txt b/examples/includes/geshi/docs/geshi-doc.txt new file mode 100644 index 0000000..4aae137 --- /dev/null +++ b/examples/includes/geshi/docs/geshi-doc.txt @@ -0,0 +1,1740 @@ +[NOTE: This documentation has simply been copy-pasted from the HTML form and is NOT up to date, I recommend you +read that instead] + +GeSHi Documentation +Version 1.0.7.22 + +Author: Nigel McNie, Benny Baumann +Copyright: © 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann +Email: nigel@geshi.org, BenBE@omorphia.de +GeSHi Website: http://qbnz.com/highlighter + +This is the documentation for GeSHi - Generic Syntax Highlighter. The most modern version of this document is available on the web - go to http://qbnz.com/highlighter/documentation.php to view it. + +Any comments, questions, confusing points? Please contact me! I need all the information I can get to make the use of GeSHi and everything related to it (including this documentation) a breeze. +Contents + + * 1. Introduction + o 1.1 Features + o 1.2 About GeSHi + o 1.3 Credits + o 1.4 Feedback + * 2. The Basics + o 2.1 Getting GeSHi + o 2.2 Installing GeSHi + + 2.2.1 Requirements + + 2.2.2 Extracting GeSHi + + 2.2.3 Installation + o 2.3 Basic Usage + * 3. Advanced Features + o 3.1 The Code Container + o 3.2 Line Numbers + + 3.2.1 Enabling Line Numbers + + 3.2.2 Styling Line Numbers + + 3.2.3 Choosing a Start Number + o 3.3 Using CSS Classes + + 3.3.1 Enabling CSS Classes + + 3.3.2 Setting the CSS Class/ID + + 3.3.3 Getting the Stylesheet + + 3.3.4 Using an External Stylesheet + o 3.4 Changing Styles + + 3.4.1 The Overall Styles + + 3.4.2 Line Number Styles + + 3.4.3 Setting Keyword Styles + + 3.4.4 Setting Comment Styles + + 3.4.5 Setting Other Styles + o 3.5 Case Sensitivity and Auto Casing + + 3.5.1 Auto Caps/Nocaps + + 3.5.2 Setting Case Sensitivity + o 3.6 Changing the Source/Language/Path/Charset + + 3.6.1 Changing the Source Code + + 3.6.2 Changing the Language + + 3.6.3 Changing the Path + + 3.6.4 Changing the Character Set + + 3.6.5 Using load_from_file to change the language and source code + o 3.7 Error Handling + o 3.8 Disabling Styling of Some Lexics + o 3.9 Setting the Tab Width + o 3.10 Using Strict Mode + o 3.11 Adding/Removing Keywords + + 3.11.1 Adding a Keyword + + 3.11.2 Removing a Keyword + + 3.11.3 Adding a Keyword Group + + 3.11.4 Removing a Keyword Group + o 3.12 Headers and Footers for your code + + 3.12.1 Keyword Substitution + + 3.12.2 Setting Header Content + + 3.12.3 Setting Footer Content + + 3.12.4 Styling Header Content + + 3.12.5 Styling Footer Content + o 3.13 Keyword URLs + + 3.13.1 Setting a URL for a Keyword Group + + 3.13.2 Disabling URLs for a Keyword Group + + 3.13.3 Disabling all URLs for Keywords + + 3.13.4 Styling Links + + 3.13.5 Setting the Link Target + o 3.14 Using Contextual Importance + o 3.15 Highlighting Special Lines "Extra" + + Specifying the Lines to Highlight Extra + + Styles for the Highlighted Lines + o 3.16 Adding IDs to Each Line + o 3.17 Getting the Time of Styling + * 4 Language Files + o 4.1 An Example Language File + o 4.2 Language File Conventions + o 4.3 Language File Sections + + 4.3.1 The Header + + 4.3.2 The First Indices + + 4.3.3 Keywords + + 4.3.4 Symbols and Case Sensitivity + + 4.3.5 Styles for your Language Files + + 4.3.6 URLs for Functions + + 4.3.7 Object Orientation Support + + 4.3.8 Using Regular Expressions + + 4.3.9 Contextual Highlighting and Strict Mode + + 4.3.10 Tidying Up + * 5 Method/Constant Reference + +1: Introduction +Top | Contents | Next | Previous + +GeSHi is exactly what the acronym stands for: a Generic Syntax Highlighter. As long as you have a language file for almost any computer language - whether it be a scripting language, object orientated, markup or anything in between - GeSHi can highlight it! GeSHi is extremely customisable - the same source can be highlighted multiple times in multiple ways - the same source even with a different language. GeSHi outputs XHTML strict compliant code*, and can make use of CSS to save on the amount of output. And what is the cost for all of this? You need PHP. That's all! + +*Most of the time. Some languages do not output XHTML strict code, and using line numbers with the PRE header is not legal either. These problems will be fixed in 1.2. +1.1: Features +Top | Contents | Next | Previous + +Here are some of the standout features of GeSHi: + + * Programmed in PHP: GeSHi is coded entirely in PHP. This means that where ever you have PHP, you can have GeSHi! Almost any free webhost supports PHP, and GeSHi works fine with PHP > 4.3.0*. + * Support for many languages: GeSHi comes with about 100 languages, including PHP, HTML, CSS, Java, C, Lisp, XML, Perl, Python, ASM and many more! + * XHTML compliant output: GeSHi produces XHTML compliant output, using stylesheets, so you need not worry about GeSHi ruining your claims to perfection in the standards department ;) + * Highly customisable: GeSHi allows you to change the style of the output on the fly, use CSS classes or not, use an external stylesheet or not, use line numbering, change the case of output keywords... the list goes on and on! + * Flexible: Unfortunately, GeSHi is quite load/time intensive for large blocks of code. However, you want speed? Turn off any features you don't like, pre-make a stylesheet and use CSS classes to reduce the amount of output and more - it's easy to strike a balance that suits you. + +This is just a taste of what you get with GeSHi - the best syntax highlighter for the web in the world! + +*Support is granted for PHP 4.3.0 and above, but especially 4.3.x cannot be guaranteed to work due to a lack of test systems. If you are forced to use such old PHP versions complain at your hoster or contact us if you find compatibility issues so we can try to resolve them. It's only PHP 4.4.X and above that is verified to work. +1.2: About GeSHi +Top | Contents | Next | Previous + +GeSHi started as a mod for the phpBB forum system, to enable highlighting of more languages than the available (which can be roughly estimated to exactly 0 ;)). However, it quickly spawned into an entire project on its own. But now it has been released, work continues on a mod for phpBB* - and hopefully for many forum systems, blogs and other web-based systems. + +*I am no longer working on this MOD, however if someone else wants to they can contact me for more information. + +Several systems are using GeSHi now, including: + + * Dokuwiki - An advanced wiki engine + * gtk.php.net - Their manual uses GeSHi for syntax highlighting + * WordPress - A powerful blogging system* + * PHP-Fusion - A constantly evovling CMS + * SQL Manager - A Postgres DBAL + * Mambo - A popular open source CMS + * MediaWiki - A leader in Wikis* + * TikiWiki - A megapowerful Wiki/CMS + * TikiPro - Another powerful Wiki based on Tikiwiki + * RWeb - A site-building tool + +* Available as plugin only. In addition, some of the other entries mentioned here may only have GeSHi available as a plugin. + +GeSHi is the original work of Nigel McNie. The project was later handed over to Benny Baumann. Others have helped with aspects of GeSHi also, they're mentioned in the THANKS file. +1.3: Credits +Top | Contents | Next | Previous + +Many people have helped out with GeSHi, whether by creating language files, submitting bug reports, suggesting new ideas or simply pointing out a new idea or something I'd missed. All of these people have helped to build a better GeSHi, you can see them in the THANKS file. + +Do you want your name on this list? Why not make a language file, or submit a valid bug? Or perhaps help me with an added feature I can't get my head around, or suggest a new feature, or even port GeSHi to anothe language? There's lots you can do to help out, and I need it all :) +1.4: Feedback +Top | Contents | Next | Previous + +I need your feedback! ANYthing you have to say is fine, whether it be a query, congratulations, a bug report or complaint, I don't care! I want to make this software the best it can be, and I need your help! You can contact me in the following ways: + + * E-mail: nigel@geshi.org + * Forums: Sourceforge.net Forums or GeSHi home forums + +Remember, any help I am grateful for :) +2: The Basics +Top | Contents | Next | Previous + +In this section, you'll learn a bit about GeSHi, how it works and what it uses, how to install it and how to use it to perform basic highlighting. +2.1: Getting GeSHi +Top | Contents | Next | Previous + +If you're reading this and don't have GeSHi, that's a problem ;). So, how do you get your hands on it? Visit http://qbnz.com/highlighter/downloads.php to obtain the latest version. +2.2: Installing GeSHi +Top | Contents | Next | Previous + +Installing GeSHi is a snap, even for those most new to PHP. There's no tricks involved. Honest! +2.2.1: Requirements +Top | Contents | Next | Previous + +GeSHi requires the following to be installable: + + * PHP. It's untested with anything other below 4.4.X. I hope to extend this range soon. I see no reason why it won't work with any version of PHP above 4.3.0. + * Approximately 2 megabytes of space. The actual script is small - around 150K - but most of the size comes from the large number of language files (over 100!). If you're pushed for space, make sure you don't upload to your server the docs/ or contrib/ directory, and you may want to leave out any language files that don't take your fancy either. + +As you can see, the requirements are very small. If GeSHi does NOT work for you in a particular version of PHP, let me know why and I'll fix it. + +Packages come in .zip, .tar.gz and .tar.bz2 format, so there's no complaining about whether it's available for you. *nix users probably want .tar.gz or .tar.bz2 and windows users probably want .zip. +2.2.2: Extracting GeSHi +Top | Contents | Next | Previous + +To extract GeSHi in Linux (.tar.gz): + + 1. Open a shell + 2. cd to the directory where the archive lies + 3. Type tar -xzvf [filename] where [filename] is the name of the archive (typically GeSHi-1.X.X.tar.gz) + 4. GeSHi will be extracted to its own directory + +To extract GeSHi in Windows (.zip): + + 1. Open Explorer + 2. Navigate to the directory where the archive lies + 3. Extract the archive. The method you use will depend on your configuration. Some people can right-click upon the archive and select "Extract" from there, others may have to drag the archive and drop it upon an extraction program. + +To extract from .zip you'll need an unzipping program - unzip in Linux, or Winzip, Winrar or similar for Windows. +2.2.3: Installation +Top | Contents | Next | Previous + +GeSHi is nothing more than a PHP class with related language support files. Those of you familiar with PHP can then guess how easy the installation will be: simply copy it into your include path somewhere. You can put it wherever you like in this include path. I recommend that you put the language files in a subdirectory of your include path too - perhaps the same subdirectory that geshi.php is in. Remember this path for later. + +If you don't know what an include path is, don't worry. Simply copy GeSHi to your webserver. So for example, say your site is at http://mysite.com/myfolder, you can copy GeSHi to your site so the directory structure is like this: + +http://mysite.com/myfolder/geshi/[language files] +http://mysite.com/myfolder/geshi.php + +Or you can put it in any subdirectory you like: + +http://mysite.com/myfolder/includes/geshi/[language files] +http://mysite.com/myfolder/includes/geshi.php + +Caution: + +When using GeSHi on a live site, the only directory required is the geshi/ subdirectory. Both contrib/ and docs/ are worthless, and furthermore, as some people discovered, one of the files in contrib had a security hole (fixed as of 1.0.7.3). I suggest you delete these directories from any live site they are on. +2.3: Basic Usage +Top | Contents | Next | Previous + +Use of GeSHi is very easy. Here's a simple example: +// +// Include the GeSHi library +// +include_once('geshi.php'); + +// +// Define some source to highlight, a language to use +// and the path to the language files +// +$source = '$foo = 45; +for ( $i = 1; $i < $foo; $i++ ) +{ + echo "$foo
        \n"; + --$foo; +}'; +$language = 'php'; +// +// Create a GeSHi object +// +$geshi =& new GeSHi($source, $language); + +// +// And echo the result! +// +echo $geshi->parse_code(); + +As you can see, there's only three really important lines: +include_once('geshi.php'); + +This line includes the GeSHi class for use +$geshi = new GeSHi($source, $language); + +This line creates a new GeSHi object, holding the source and the language you want to use for highlighting. +echo $geshi->parse_code(); + +This line spits out the result :) + +So as you can see, simple usage of GeSHi is really easy. Just create a new GeSHi object and get the code! + +Since version 1.0.2, there is a function included with GeSHi called geshi_highlight. This behaves exactly as the php function highlight_string behaves - all you do is pass it the language you want to use to highlight and the path to the language files as well as the source. Here are some examples: +// Simply echo the highlighted code +geshi_highlight($source, 'php', $path); + +// Get the code back, for use later +$code = geshi_highlight($source, 'java', $path, true) + +// Check if there is an error with parsing this code +ob_start(); +$result = geshi_highlight($source, 'perl', $path); +$code = ob_get_contents(); +ob_end_clean(); +if ( !$result ) +{ + // There was an error with highlighting... +} +else +{ + // All OK :) +} + +However, these are really simple examples and doesn't even begin to cover all the advanced features of GeSHi. If you want to learn more, continue on to section 3: Advanced Features. +3: Advanced Features +Top | Contents | Next | Previous + +This section documents the advanced features of GeSHi - strict mode, using CSS classes, changing styles on the fly, disabling highlighting of some things and more. + +In this section there are many code snippets. For all of these, you should assume that the GeSHi library has been included, and a GeSHi object has been created and is referenced by the variable $geshi. Normally, the source, language and path used are arbitary. +3.1 The Code Container +Top | Contents | Next | Previous + +The Code Container has a fundamental effect on the layout of your code before you even begin to style. What is the Code Container? It's the bit of markup that goes around your code to contain it. By default your code is surrounded by a
        , but you can also specify a 
        . + +The
         header is the default. If you're familiar with HTML you'll know that whitespace is rendered "as is" by a 
         element. The advantage for you is that if you use 
         the whitespace you use will appear pretty much exactly how it is in the source, and what's more GeSHi won't have to add a whole lot of 
        's and non-breaking spaces ( ) to your code to indent it. This saves you source code (and your valuable visitors waiting time and your bandwidth). + +But if you don't like
         or it looks stupid in your browser no matter what styles you try to apply to it or something similar, you might want to use a 
        instead. A
        will result in more source - GeSHi will have to insert whitespace markup - but in return you can wrap long lines of code that would otherwise have your browser's horizontal scrollbar appear. Of course with
        you can *not* wrap lines if you please. The highlighter demo at the GeSHi home page uses the
        approach for this reason. + +At this stage there isn't an option to wrap the code in tags (unless you use the function geshi_highlight), partly because of the inconsistent and unexpected ways stuff in tags is highlighted. Besides, is an inline element. But this may become an option in future versions. + +As of GeSHi 1.0.7.2 there is a new header type, that specifies that the code should not be wrapped in anything at all. + +Another requested addition has been made in GeSHi 1.0.7.20 to force GeSHi to create a block around the highlighted source even if this wasn't necessary, thus styles that are applied to the output of GeSHi can directly influence the code only even if headers and footers are present. + +To change/set the header to use, you call the set_header_type() method: +$geshi->set_header_type(GESHI_HEADER_DIV); +// or... +$geshi->set_header_type(GESHI_HEADER_PRE); // or... +$geshi->set_header_type(GESHI_HEADER_NONE); + +Those are the only three arguments you should pass to set_header_type. Passing anything else may cause inconsistencies in what is used as the Code Container (although it *should* simply use a
        ). Better not to risk it.
        +Note:
        +
        +GESHI_HEADER_DIV, GESHI_HEADER_PRE and GESHI_HEADER_NONE are constants, so don't put them in strings!
        +Caution:
        +
        +The default styles for the 
         and 
        will be different, especially if you use line numbers!. I have found that a
         results in code that is smaller than for that of a 
        , you should rectify this difference by using set_overall_style() if you need to. But be aware of this difference for if you are changing the header type! +3.2: Line Numbers +Top | Contents | Next | Previous + +GeSHi has the ability to add line numbers to your code (see the demo available at http://qbnz.com/highlighter/demo.php to see what can be achieved). Line numbers are a great way to make your code look professional, especially if you use the fancy line numbers feature. +3.2.1: Enabling Line Numbers +Top | Contents | Next | Previous + +To highlight a source with line numbers, you call the enable_line_numbers() method: +$geshi->enable_line_numbers($flag); + +Where $flag is one of the following: + + * GESHI_NORMAL_LINE_NUMBERS - Use normal line numbering + * GESHI_FANCY_LINE_NUMBERS - Use fancy line numbering + * GESHI_NO_LINE_NUMBERS - Disable line numbers (default) + +Normal line numbers means you specify a style for them, and that style gets applied to all of them. Fancy line numbers means that you can specify a different style for each nth line number. You change the value of n (default 5): +$geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 37); + +The second parameter is not used in any other mode. Setting it to 0 is the same as simply using normal line numbers. Setting it to 1 applies the fancy style to every line number. +Note: + +The values above are CONSTANTS - so don't put them in strings! +3.2.2 Styling Line Numbers +Top | Contents | Next | Previous + +As of GeSHi 1.0.2, line numbers are added by the use of ordered lists. This solves the old issues of line number styles inheriting from styles meant for the code. Also, this solves an important issue about selecting code. For example, line numbers look nice, but when you go to select the code in your browser to copy it? You got the line numbers too! Not such a good thing, but thankfully this issue is now solved. What is the price? Unfortunately the whole way that styles are inherited/used has changed for those of you who were familiar with 1.0.1, and there is quite a bit more HTML involved. So think carefully about these things before you enable line numbers. + +Now, onto how to style line numbers: + +Styles are set for line numbers using the set_line_style() method: +$geshi->set_line_style('background: #fcfcfc;'); + +If you're using Fancy Line Numbers mode, you pass a second string for the style of the nth line number: +$geshi->set_line_style('background: #fcfcfc;', 'background: #f0f0f0;'); + +The second style will have no effect if you're not using Fancy Line Numbers mode. + +By default, the styles you pass overwrite the current styles. Add a boolean "true" after the styles you specify to combine them with the current styles: +$geshi->set_line_style('background: red;', true); +// or, for fancy line numbers +$geshi->set_line_style('background: red;', 'background: blue;', true); +Note: + +Due to a bug with Firefox the issue that should have been fixed with 1.0.2 has reappeared in another form as Firefox includes extra text\markup into plaintext versions of webpage copies. This can sometimes be useful (actually it's used to get the plaintext version of this documentation), but more often is quite annoying. Best practice so far is to either not use line numbers, or offer the visitor of your page a plaintext version of your source. To learn more have a look at the SF.net BugTracker Issue #1651996. This will hopefully be fixed in GeSHi version 1.2 or as soon as Firefox provides webdevelopers with adequate ways to control this feature - whichever comes first! +Caution: + +When you set line number styles, the code will inherit those styles! This is the main issue to come out of the 1.0.2 release. If you want your code to be styled in a predictable manner, you'll have to call the set_code_style() method to rectify this problem. + +Note also that you cannot apply background colours to line numbers unless you use set_overall_style(). Here's how you'd style: + + 1. Use set_overall_style() to style the overall code block. For example, you can set the border style/colour, any margins and padding etc. using this method. In addition: set the background colour for all the line numbers using this method. + 2. Use set_line_style() to style the foreground of the line numbers. For example, you can set the colour, weight, font, padding etc. of the line numbers using this method. + 3. Use set_code_style() to explicitly override the styles you set for line numbers using set_line_style. For example, if you'd set the line numbers to be bold (or even if you'd only set the fancy line number style to be bold), and you didn't actually want your code to be bold, you'd make sure that font-weight: normal; was in the stylesheet rule you passed to set_code_style + +This is the one major change from GeSHi 1.0.1 - make sure you become familiar with this, and make sure that you check any code you have already styled with 1.0.1 when you upgrade to make sure nothing bad happens to it. +3.2.3: Choosing a Start Number +Top | Contents | Next | Previous + +As of GeSHi 1.0.2, you can now make the line numbers start at any number, rather than just 1. This feature is useful if you're highlighting code from a file from around a certain line number in that file, as an additional guide to those who will view the code. You set the line numbers by calling the start_line_numbers_at() method: +$geshi->start_line_numbers_at($number); + +$number must be a positive integer (or zero). If it is not, GeSHi will convert it anyway. + +If you have not enabled line numbers, this will have no effect. +Caution: + +Although I'd like GeSHi to have XHTML strict compliance, this feature will break compliancy (however transitional compliancy remains). This is because the only widely supported way to change the start value for line numbers is by using the start="number" attribute of the
          tag. Although CSS does provide a mechanism for doing this, it is only supported in Opera versions 7.5 and above (not even Firefox supports this). +3.3: Using CSS Classes +Top | Contents | Next | Previous + +Using CSS to highlight your code instead of in-lining the styles is a definate bonus. Not only is it more compliant (the w3c is deprecating the style attribute in XHTML 2.0) but it results in far less outputted code - up to a whopping 90% saving - which makes a *huge* difference to those unlucky of us on modems! +3.3.1: Enabling CSS Classes +Top | Contents | Next | Previous + +By default, GeSHi doesn't use the classes, so it's easy just to whack out some highlighted code if you need without worrying about stylesheets. However, if you're a bit more organised about it, you should use the classes ;). To turn the use of classes on, you call the enable_classes() method: +$geshi->enable_classes(); + +If you want to turn classes OFF for some reason later: +$geshi->enable_classes(false); + +If classes are enabled when parse_code() is called, then the resultant source will use CSS classes in the output, otherwise it will in-line the styles. The advantages of using classes are great - the reduction in source will be very noticeable, and what's more you can use one stylesheet for several different highlights on the same page. In fact, you can even use an external stylesheet and link to that, saving even more time and source (because stylesheets are cached by browsers). +Note: + +There have been problems with inline styles and the Symbol Highlighting added in 1.0.7.21. If you can you should therefore turn CSS classes ON to avoid those issues. +Caution: + +This should be the very first method you call after creating a new GeSHi object! That way, various other methods can act upon your choice to use classes correctly. In theory, you could call this method just before parsing the code, but this may result in unexpected behaviour. +3.3.2: Setting the CSS class and ID +Top | Contents | Next | Previous + +You can set an overall CSS class and id for the code. This is a good feature that allows you to use the same stylesheet for many different snippets of code. You call set_overall_class() and set_overall_id to accomplish this: +$geshi->set_overall_class('mycode'); +$geshi->set_overall_id('dk48ck'); + +The default classname is the name of the language being used. This means you can use just the one stylesheet for all sources that use the same language, and incidentally means that you probably won't have to call these methods too often. + +CSS IDs are supposed to be unique, and you should use them as such. Basically, you can specify an ID for your code and then use that ID to highlight that code in a unique way. You'd do this for a block of code that you expressly wanted to be highlighted in a different way (see the section below on gettting the stylesheet for your code for an example). +3.3.3: Getting the stylesheet for your code +Top | Contents | Next | Previous + +The other half of using CSS classes is getting the stylesheet for use with the classes. GeSHi makes it very easy to get a stylesheet for your code, with one easy method call: +$geshi->enable_classes(); + +// Here we have code that will spit out a header for +// a stylesheet. For example: + +echo ' +Code + +'; + +The get_stylesheet() method gets the stylesheet for your code in one easy call. All you need to do is output it in the correct place. As you can also see, you don't even have to enable class usage to get the stylesheet nessecary either - however not enabling classes but using the stylesheet may result in problems later. + +By default, get_stylesheet() tries to echo the least amount of code possible. Although currently it doesn't check to see if a certain lexic is even in the source, you can expect this feature in the future. At least for the present however, if you explicitly disable the highlighting of a certain lexic, or disable line numbers, the related CSS will not be outputted. This may be a bad thing for you perhaps you're going to use the stylesheet for many blocks of code, some with line numbers, others with some lexic enabled where this source has it disabled. Or perhaps you're building an external stylesheet and want all lexics included. So to get around this problem, you do this: +$geshi->get_stylesheet(false); + +This turns economy mode off, and all of the stylesheet will be outputted regardless. + +Now lets say you have several snippets of code, using the same language. In most of them you don't mind if they're highlighted the same way (in fact, that's exactly what you want) but in one of them you'd like the source to be highlighted differently. Here's how you can do that: +// assume path is the default "geshi/" relative to the current directory +$geshi1 = new GeSHi($source1, $lang); +$geshi2 = new GeSHi($source2, $lang); +$geshi3 = new GeSHi($source3, $lang); + +// Turn classes on for all sources +$geshi1->enable_classes(); +$geshi2->enable_classes(); +$geshi3->enable_classes(); + +// Make $geshi3 unique +$geshi3->set_overall_id('different'); + +// +// Methods are called on $geshi3 to change styles... +// + +echo ' +Code + +'; + + +echo 'Code snippet 1:'; +echo $geshi1->parse_code(); +echo 'Code snippet 2 (same highlighting as 1):'; +echo $geshi2->parse_code(); +echo 'Code snippet 3 (DIFFERENT highlighting):'; +echo $geshi3->parse_code(); + +echo ''; + +Before version 1.0.2, you needed to set the class of the code you wanted to be unique to the empty string. This limitation has been removed in version 1.0.2 - if you set the ID of a block of code, all styling will be done based on that ID alone. +3.3.4: Using an External Stylesheet +Top | Contents | Next | Previous + +An external stylesheet can reduce even more the amount of code needed to highlight some source. However there are some drawbacks with this. To use an external stylesheet, it's up to you to link it in to your document, normally with the following HTML: + + + + +In your external stylesheet you put CSS declarations for your code. Then just make sure you're using the correct class (use set_overall_class() to ensure this) and this should work fine. + +This method is great if you don't mind the source always being highlighted the same (in particular, if you're making a plugin for a forum/wiki/other system, using an external stylesheet is a good idea!). It saves a small amount of code and your bandwidth, and it's relatively easy to just change the stylesheet should you need to. However, using this will render the methods that change the styles of the code useless, because of course the stylesheet is no longer being dynamically generated. You can still disable highlighting of certain lexics dynamically, however. +Note: + +As of version 1.0.2, GeSHi comes with a contrib/ directory, which in it contains a "wizard" script for creating a stylesheet. Although this script is by no means a complete solution, it will create the necessary rules for the basic lexics - comments, strings for example. Things not included in the wizard include regular expressions for any language that uses them (PHP and XML are two languages that use them), and keyword-link styles. However, this script should take some of the tedium out of the job of making an external stylesheet. Expect a much better version of this script in version 1.2! +3.4: Changing Styles +Top | Contents | Next | Previous + +One of the more powerful features of GeSHi is the ability to change the style of the output dynamically. Why be chained to the boring styles the language authors make up? You can change almost every single aspect of highlighted code - and can even say whether something is to be highlighted at all. + +If you're confused about "styles", you probably want to have a quick tutorial in them so you know what you can do with them. Checkout the homepage of CSS at http://www.w3.org/Style/CSS. +3.4.1: The Overall Styles +Top | Contents | Next | Previous + +The code outputted by GeSHi is either in a
          or a
           (see the section entitled "The Code Container"), and this can be styled.
          +$geshi->set_overall_style('... styles ...');
          +
          +Where styles is a string containing valid CSS declarations. By default, these styles overwrite the current styles, but you can change this by adding a second parameter:
          +$geshi->set_overall_style('color: blue;', true);
          +
          +The default styles "shine through" wherever anything isn't highlighted. Also, you can apply more advanced styles, like position: (fixed|relative) etc, because a 
          /
           is a block level element.
          +Note:
          +
          +Remember that a 
          will by default have a larger font size than a
          , as discussed in the section "The Code Container".
          +3.4.2: Line Number Styles
          +Top | Contents | Next | Previous
          +
          +You may wish to refer to the section Styling Line Numbers before reading this section.
          +
          +As of version 1.0.2, the way line numbers are generated is different, so therefore the way that they are styled is different. In particular, now you cannot set the background style of the fancy line numbers to be different from that of the normal line numbers.
          +
          +Line number styles are set by using the method set_line_style:
          +$geshi->set_line_style($style1, $style2);
          +
          +$style1 is the style of the line numbers by default, and $style2 is the style of the fancy line numbers.
          +Caution:
          +
          +Things have changed since 1.0.1! This note is very important - please make sure you check this twice before complaining about line numbers!
          +
          +Because of the way that ordered lists are done in HTML, there really isn't normally a way to style the actual numbers in the list. I've cheated somewhat with GeSHi - I've made it possible to use CSS to style the foreground of the line numbers. So therefore, you can change the color, font size and type, and padding on them. If you want to have a pretty background, you must use set_overall_style() to do this, and use set_code_style() to style the actual code! This is explained in the section above: Styling Line Numbers.
          +
          +In addition, the styles for fancy line numbers is now the difference between the normal styles and the styles you want to achieve. For example, in GeSHi prior to 1.0.2 you may have done this to style line numbers:
          +$geshi->set_line_style('color: red; font-weight: bold;', 'color: green; font-weight: bold');
          +
          +Now you instead can do this:
          +$geshi->set_line_style('color: red; font-weight: bold;', 'color: green;');
          +
          +The font-weight: bold; will automatically carry through to the fancy styles. This is actually a small saving in code - but the difference may be confusing for anyone using 1.0.1 at first.
          +3.4.3: Setting Keyword Styles
          +Top | Contents | Next | Previous
          +
          +Perhaps the most regular change you will make will be to the styles of a keyword set. In order to change the styles for a particular set, you'll have to know what the set is called first. Sets are numbered from 1 up. Typically, set 1 contains keywords like if, while, do, for, switch etc, set 2 contains null, false, true etc, set 3 contains function inbuilt into the language (echo, htmlspecialchars etc. in PHP) and set 4 contains data types and similar variable modifiers: int, double, real, static etc. However these things are not fixed, and you should check the language file to see what key you want. Having a familiarity with a language file is definately a plus for using it.
          +
          +To change the styles for a keyword set, call the set_keyword_group_style() method:
          +$geshi->set_keyword_group_style($group, $styles);
          +
          +Where $group is the group to change the styles for and $styles is a string containing the styles to apply to that group.
          +
          +By default, the styles you pass overwrite the current styles. Add a boolean true after the styles you specify to combine them with the current styles:
          +$geshi->set_keyword_group_style(3, 'color: white;', true);
          +3.4.4: Setting Comment Styles
          +Top | Contents | Next | Previous
          +
          +To change the styles for a comment group, call the set_comments_style() method:
          +$geshi->set_comments_style($group, $styles);
          +
          +Where $group is either a number corresponding to a single-line comment, or the string 'MULTI' to specify multiline comments:
          +$geshi->set_comments_style(1, 'font-style: italic;');
          +$geshi->set_comments_style('MULTI', 'display: hidden;');
          +
          +By default, the styles you pass overwrite the current styles. Add a boolean true after the styles you specify to combine them with the current styles:
          +$geshi->set_comments_style(1, 'font-weight: 100;', true);
          +Note:
          +
          +In 1.0.7.22 a new kind of Comments called "COMMENT_REGEXP" has been added. Those are handled by setting single line comment styles.
          +3.4.5: Setting Other Styles
          +Top | Contents | Next | Previous
          +
          +GeSHi can highlight many other aspects of your source other than just keywords and comments. Strings, Numbers, Methods and Brackets among other things can all also be highlighted. Here are the related methods:
          +$geshi->set_escape_characters_style($styles[, $preserve_defaults]);
          +$geshi->set_symbols_style($styles[, $preserve_defaults]);
          +$geshi->set_strings_style($styles[, $preserve_defaults]);
          +$geshi->set_numbers_style($styles[, $preserve_defaults]);
          +$geshi->set_methods_style($key, $styles[, $preserve_defaults]);
          +$geshi->set_regexps_style($key, $styles[, $preserve_defaults]);
          +
          +$styles is a string containing valid stylesheet declarations, while $preserve_defaults should be set to true if you want your styles to be merged with the previous styles. In the case of set_methods_style, you should select a group to set the styles of, check the language files for the number used for each "object splitter".
          +
          +Like this was possible for set_method_style a new parameter has been introduced for set_symbols_style too which allows you to select the group of symbols for which you'd like to change your style. $geshi->set_symbols_style($styles[, $preserve_defaults[, $group]]);
          +If the third parameter is not given, group 0 is assumed. Furthermore you should note that any changes to group 0 are also reflected in the bracket style, i.e. a pass-through call to set_bracket_style is made.
          +3.5: Case Sensitivity and Auto Casing
          +Top | Contents | Next | Previous
          +
          +Controlling the case of the outputted source is an easy job with GeSHi. You can control which keywords are converted in case, and also control whether keywords are checked in a case sensitive manner.
          +3.5.1: Auto-Caps/Nocaps
          +Top | Contents | Next | Previous
          +
          +Auto-Caps/Nocaps is a nifty little feature that capitalises or lowercases automatically certain lexics when they are styled. I dabble in QuickBASIC, a dialect of BASIC which is well known for it's capatalisation, and SQL is another language well known for using caps for readability.
          +
          +To change what case lexics are rendered in, you call the set_case_keywords() method:
          +$geshi->set_case_keywords($caps_modifier);
          +
          +The valid values to pass to this method are:
          +
          +    * GESHI_CAPS_NO_CHANGE - Don't change the case of any lexics, leave as they are found
          +    * GESHI_CAPS_UPPER - Uppercase all lexics found
          +    * GESHI_CAPS_LOWER - Lowercase all lexics found
          +
          +Caution:
          +
          +When I say "lexic", I mean "keywords". Any keyword in any keyword array will be modified using this option! This is one small area of inflexibility I hope to fix in 1.2.X.
          +
          +I suspect this will only be used to specify GESHI_CAPS_NO_CHANGE to turn off autocaps for languages like SQL and BASIC variants, like so:
          +$geshi = new GeSHi($source, 'sql');
          +$geshi->set_case_keywords(GESHI_CAPS_NO_CHANGE); // don't want keywords capatalised
          +
          +All the same, it can be used for some interesting effects:
          +$geshi = new GeSHi($source, 'java');
          +// Anyone who's used java knows how picky it is about CapitalLetters...
          +$geshi->set_case_keywords(GESHI_CAPS_LOWER);
          +// No *way* the source will look right now ;)
          +3.5.2: Setting Case Sensitivity
          +Top | Contents | Next | Previous
          +
          +Some languages, like PHP, don't mind what case function names and keywords are in, while others, like Java, depend on such pickiness to maintain their bad reputations ;). In any event, you can use the set_case_sensitivity to change the case sensitiveness of a particular keyword group from the default:
          +$geshi->set_case_sensitivity($key, $sensitivity);
          +
          +Where $key is the key of the group for which you wish to change case sensitivness for (see the language file for that language), and $sensitivity is a boolean value - true if the keyword is case sensitive, and false if not.
          +3.6: Changing the Source, Language, Config Options
          +Top | Contents | Next | Previous
          +
          +What happens if you want to change the source to be highlighted on the fly, or the language. Or if you want to specify any of those basic fields after you've created a GeSHi object? Well, that's where these methods come in.
          +3.6.1: Changing the Source Code
          +Top | Contents | Next | Previous
          +
          +To change the source code, you call the set_source() method:
          +$geshi->set_source($newsource);
          +
          +Example:
          +$geshi = new GeSHi($source1, 'php');
          +
          +// Method calls to specify various options...
          +
          +$code1 = $geshi->parse_code();
          +
          +$geshi->set_source($source2);
          +$code2 = $geshi->parse_code();
          +3.6.2: Changing the Language
          +Top | Contents | Next | Previous
          +
          +What happens if you want to change the language used for highlighting? Just call set_language():
          +$geshi->set_language('newlanguage');
          +
          +Example:
          +$geshi = new GeSHi($source, 'php');
          +
          +$code = $geshi->parse_code();
          +
          +// Highlight GeSHi's output
          +$geshi->set_source($code);
          +$geshi->set_language('html4strict');
          +$geshi->enable_classes(false);
          +echo $geshi->parse_code();
          +Note:
          +
          +Names are case-insensitive - they will be converted to lower case to match a language file however. So if you're making a language file, remember it should have a name in lower case.
          +Note:
          +
          +What you pass to this method is the name of a language file, minus the .php extension. If you're writing a plugin for a particular application, it's up to you to somehow convert user input into a valid language name.
          +Caution:
          +
          +GeSHi include()s the language file, so be careful to make sure that users can't pass some wierd language name to include any old script! GeSHi tries to strip non-valid characters out of a language name, but you should always do this your self anyway. In particular, language files are always lower-case, with either alphanumeric characters, dashes or underscores in their name.
          +
          +At the very least, strip "/" characters out of a language name.
          +3.6.3: Changing the Language Path
          +Top | Contents | Next | Previous
          +
          +What happens if all of a sudden you want to use language files from a different directory from the current language file location? You call the set_language_path() method:
          +$geshi->set_language_path($newpath);
          +
          +It doesn't matter whether the path has a trailing slash after it or not - only that it points to a valid folder. If it doesn't, that's your tough luck ;)
          +3.6.4: Changing the Character Set
          +Top | Contents | Next | Previous
          +Note:
          +
          +As of GeSHi 1.0.7.18, you don't need to use this, as htmlspecialchars is not being used due to a security flaw in it (that is unpatched in even the most recent PHP4 versions, and in PHP5 < 5.2). As long as you set the encoding properly with a php header() call, your foreign characters will be displayed correctly.
          +
          +As of version 1.0.3, you can use the method set_encoding to specify the character set that your source is in. Valid names are those names that are valid for the PHP function htmlentities():
          +$geshi->set_encoding($encoding);
          +
          +There is a table of valid strings for $encoding at the php.net manual linked to above. If you do not specify an encoding, or specify an invalid encoding, the character set used is ISO-8859-1.
          +Using load_from_file to Change the Language and Source Code
          +Top | Contents | Next | Previous
          +
          +As of GeSHi 1.0.5, you can use the method load_from_file to load the source code and language from a file. Simply pass this method a file name and it will attempt to load the source and set the language.
          +$geshi->load_from_file($file_name, $lookup);
          +
          +$file_name is the file name to use, and $lookup is an optional parameter that contains a lookup array to use for deciding which language to choose. You can use this to override GeSHi's default lookup array, which may not contain the extension of the file you're after, or perhaps does have your extension but under a different language. The lookup array is of the form:
          +
          +array(
          +	 *   'lang_name' => array('extension', 'extension', ...),
          +	 *   'lang_name' ...
          +	 * );
          +
          +Also, you can use the method get_language_name_from_extension if you need to convert a file extension to a valid language name. This method will return the empty string if it could not find a match in the lookup, and like load_from_file it accepts an optional second parameter that contains a lookup array.
          +3.7: Error Handling
          +Top | Contents | Next | Previous
          +
          +What happens if you try to highlight using a language that doesn't exist? Or if GeSHi can't read a required file? The results you get may be confusing. You may check your code over and over, and never find anything wrong. GeSHi provides ways of finding out if GeSHi itself found anything wrong with what you tried to do. After highlighting, you can call the error() method:
          +$geshi = new GeSHi('hi', 'thisLangIsNotSupported');
          +
          +echo $geshi->error();  // echoes error message
          +
          +The error message you will get will look like this:
          +
          +    GeSHi Error: GeSHi could not find the language thisLangIsNotSupported (using path geshi/) (code 2)
          +
          +The error outputted will be the last error GeSHi came across, just like how mysql_error() works.
          +3.8: Disabling styling of some Lexics
          +Top | Contents | Next | Previous
          +
          +One disadvantage of GeSHi is that for large source files using complex languages, it can be quite slow with every option turned on. Although future releases will concentrate on the speed/resource side of highlighting, for now you can gain speed increases by disabling some of the highlighting options. This is done by using a series of set_*_highlighting methods:
          +
          +    * set_keyword_group_highlighting($group, $flag): Sets whether a particular $group of keywords is to be highlighted or not. Consult the necessary language file(s) to see what $group should be for each group (typically a positive integer). $flag is false if you want to disable highlighting of this group, and true if you want to re-enable higlighting of this group. If you disable a keyword group then even if the keyword group has a related URL one will not be generated for that keyword.
          +    * set_comments_highlighting($group, $flag): Sets whether a particular $group of comments is to be highlighted or not. Consult the necessary language file(s) to see what $group should be for each group (typically a positive integer, or the string 'MULTI' for multiline comments. $flag is false if you want to disable highlighting of this group, and true if you want to re-enable highlighting of this group.
          +    * set_regexps_highlighting($regexp, $flag): Sets whether a particular $regexp is to be highlighted or not. Consult the necessary language file(s) to see what $regexp should be for each regexp (typically a positive integer, or the string 'MULTI' for multiline comments. $flag is false if you want to disable highlighting of this group, and true if you want to re-enable highlighting of this group.
          +    * The following methods:
          +          o set_escape_characters_highlighting($flag)
          +          o set_symbols_highlighting($flag)
          +          o set_strings_highlighting($flag)
          +          o set_numbers_highlighting($flag)
          +          o set_methods_highlighting($flag)
          +      Work on their respective lexics (e.g. set_methods_highlighting will disable/enable highlighting of methods). For each method, if $flag is false then the related lexics will not be highlighted at all (this means no HTML will surround the lexic like usual, saving on time and bandwidth.
          +
          +In case all highlighting should be disabled or reenabled GeSHi provides two methods called disable_highlighting() and enable_highlighting($flag). The optional paramter $flag has been added in 1.0.7.21 and specifies the desired state, i.e. true (default) to turn all highlighting on, or false to turn all highlighting off. Since 1.0.7.21 the method disnable_highlighting() has become deprecated.
          +3.9: Setting the Tab Width
          +Top | Contents | Next | Previous
          +
          +If you're using the 
           header, tabs are handled automatically by your browser, and in general you can count on good results. However, if you're using the 
          header, you may want to specify a tab width explicitly. + +Note that tabs created in this fashion won't be like normal tabs - there won't be "tab-stops" as such, instead tabs will be replaced with the specified number of spaces. + +To change the tab width, you call the set_tab_width() method: +$geshi->set_tab_width($width); + +Where $width is the width in spaces that you'd like tabs to be. +3.10: Using Strict Mode +Top | Contents | Next | Previous + +Some languages like to get tricky, and jump in and out of the file that they're in. For example, the vast majority of you reading this will have used a PHP file. And you know that PHP code is only executed if it's within delimiters like (there are others of course...). So what happens if you do the following in a php file? + + +Well normally using GeSHi with PHP, or using a bad highlighter, you'll end up with this: + + +What a mess! Especially if you're being slack about where you're putting your quotes, you could end up with the rest of your file as bright red. Fortunately, you can tell GeSHi to be "strict" about just when it highlights and when it does not, using the enable_strict_mode method: +$geshi->enable_strict_mode($mode); + +Where $mode is true or not specified to enable strict mode, or false to disable strict mode if you've already turned it and don't want it now. + +Here's the result: much better! + +3.11: Adding/Removing Keywords +Top | Contents | Next | Previous + +Lets say that you're working on a large project, with many files, many classes and many functions. Perhaps also you have the source code on the web and highlighted by GeSHi, perhaps as a front end to CVS, as a learning tool, something to refer to, whatever. Well, why not highlight the names of the functions and classes *your* project uses, as well as the standard functions and classes? Or perhaps you're not interested in highlighting certain functions, and would like to remove them? Or maybe you don't mind if an entire function group goes west in the interest of speed? GeSHi can handle all of this! +3.11.1: Adding a Keyword +Top | Contents | Next | Previous + +If you want to add a keyword to an existing keyword group, you use the add_keyword method: +$geshi->add_keyword($key, $word); + +Where $key is the index of the group of keywords you want to add this keyword to, and $word is the word to add. + +This implies knowledge of the language file to know the correct index. +Note: + +Keywords should contain at least two alphabetical characters (lower or upper case letters only). This is to enable GeSHi to work much faster by not bothering to try to detect keywords in parts of your source where there is no alphabetical characters. +3.11.2: Removing a Keyword +Top | Contents | Next | Previous + +Perhaps you want to remove a keyword from an existing group. Maybe you don't use it and want to save yourself some time. Whatever the reason, you can remove it using the remove_keyword method: +$geshi->remove_keyword($key, $word); + +Where $key is the index of the gropu of keywords that you want to remove this keyword from, and $word is the word to remove. + +This implies knowledge of the language file to know the correct index - most of the time the keywords you'll want to remove will be in group 3, but this is not guaranteed and you should check the language file first. + +This function is silent - if the keyword is not in the group you specified, nothing awful will happen ;) +3.11.3: Adding a Keyword Group +Top | Contents | Next | Previous + +Lets say for your big project you have several main functions and classes that you'd like highlighted. Why not add them as their own group instead of having them highlighted the same way as other keywords? Then you can make them stand out, and people can instantly see which functions and classes are user defined or inbuilt. Furthermore, you could set the URL for this group to point at the API documentation of your project. + +You add a keyword group by using the add_keyword_group method: +$geshi->add_keyword_group($key, $styles, $case_sensitive, $words); + +Where $key is the key that you want to use to refer to this group, $styles is the styles that you want to use to style this group, $case_sensitive is true or false depending on whether you want this group of keywords to be case sensitive or not and $words is an array of words (or a string) of which words to add to this group. For example: +$geshi->add_keyword_group(10, 'color: #600000;', false, array('myfunc_1', 'myfunc_2', 'myfunc_3')); + +Adds a keyword group referenced by index 10, of which all keywords in the group will be dark red, each keyword can be in any case and which contains the keywords "myfunc_1", "myfunc_2" and "myfunc_3". + +After creating such a keyword group, you may call other GeSHi methods on it, just as you would for any other keyword group. +Caution: + +If you specify a $key for which there is already a keyword group, the old keyword group will be overwritten! Most language files don't use numbers larger than 5, so I recommend you play it safe and use a number like 10 or 42. +3.11.4: Removing a Keyword Group +Top | Contents | Next | Previous + +Perhaps you *really* need speed? Why not just remove an entire keyword group? GeSHi won't have to loop through each keyword checking for its existance, saving much time. You remove a keyword group by using the remove_keyword_group method: +$geshi->remove_keyword_group($key); + +Where $key is the key of the group you wish to remove. This implies knowleged of the language file. +3.12: Headers and Footers for Your Code +Top | Contents | Next | Previous + +So you want to add some special information to the highlighted source? GeSHi can do that too! You can specify headers and footers for your code, style them, and insert information from the highlighted source into your header or footer. +3.12.1: Keyword Substitution +Top | Contents | Next | Previous + +In your header and footer, you can put special keywords that will be replaced with actual configuration values for this GeSHi object. The keywords you can use are: + + *
          '; + } + $parsed_code .= ''; + } + // No line numbers, but still need to handle highlighting lines extra. + // Have to use divs so the full width of the code is highlighted + $close = 0; + for ($i = 0; $i < $n; ++$i) { + // Make lines have at least one space in them if they're empty + // BenBE: Checking emptiness using trim instead of relying on blanks + if ('' == trim($code[$i])) { + $code[$i] = ' '; + } + // fancy lines + if ($this->line_numbers == GESHI_FANCY_LINE_NUMBERS && + $i % $this->line_nth_row == ($this->line_nth_row - 1)) { + // Set the attributes to style the line + if ($this->use_classes) { + $parsed_code .= ''; + } else { + // This style "covers up" the special styles set for special lines + // so that styles applied to special lines don't apply to the actual + // code on that line + $parsed_code .= '' + .''; + } + $close += 2; + } + //Is this some line with extra styles??? + if (in_array($i + 1, $this->highlight_extra_lines)) { + if ($this->use_classes) { + if (isset($this->highlight_extra_lines_styles[$i])) { + $parsed_code .= ""; + } else { + $parsed_code .= ""; + } + } else { + $parsed_code .= "get_line_style($i) . "\">"; + } + ++$close; + } + + $parsed_code .= $code[$i]; + + if ($close) { + $parsed_code .= str_repeat('', $close); + $close = 0; + } + elseif ($i + 1 < $n) { + $parsed_code .= "\n"; + } + unset($code[$i]); + } + + if ($this->header_type == GESHI_HEADER_PRE_VALID || $this->header_type == GESHI_HEADER_PRE_TABLE) { + $parsed_code .= '
          '; + } + if ($this->header_type == GESHI_HEADER_PRE_TABLE && $this->line_numbers != GESHI_NO_LINE_NUMBERS) { + $parsed_code .= ''; + } + } + + $parsed_code .= $this->footer(); + } + + /** + * Creates the header for the code block (with correct attributes) + * + * @return string The header for the code block + * @since 1.0.0 + * @access private + */ + function header() { + // Get attributes needed + /** + * @todo Document behaviour change - class is outputted regardless of whether + * we're using classes or not. Same with style + */ + $attributes = ' class="' . $this->language; + if ($this->overall_class != '') { + $attributes .= " ".$this->overall_class; + } + $attributes .= '"'; + + if ($this->overall_id != '') { + $attributes .= " id=\"{$this->overall_id}\""; + } + if ($this->overall_style != '') { + $attributes .= ' style="' . $this->overall_style . '"'; + } + + $ol_attributes = ''; + + if ($this->line_numbers_start != 1) { + $ol_attributes .= ' start="' . $this->line_numbers_start . '"'; + } + + // Get the header HTML + $header = $this->header_content; + if ($header) { + if ($this->header_type == GESHI_HEADER_PRE || $this->header_type == GESHI_HEADER_PRE_VALID) { + $header = str_replace("\n", '', $header); + } + $header = $this->replace_keywords($header); + + if ($this->use_classes) { + $attr = ' class="head"'; + } else { + $attr = " style=\"{$this->header_content_style}\""; + } + if ($this->header_type == GESHI_HEADER_PRE_TABLE && $this->line_numbers != GESHI_NO_LINE_NUMBERS) { + $header = "$header"; + } else { + $header = "$header
          "; + } + } + + if (GESHI_HEADER_NONE == $this->header_type) { + if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { + return "$header"; + } + return $header . ($this->force_code_block ? '
          ' : ''); + } + + // Work out what to return and do it + if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { + if ($this->header_type == GESHI_HEADER_PRE) { + return "$header"; + } else if ($this->header_type == GESHI_HEADER_DIV || + $this->header_type == GESHI_HEADER_PRE_VALID) { + return "$header"; + } else if ($this->header_type == GESHI_HEADER_PRE_TABLE) { + return "$header"; + } + } else { + if ($this->header_type == GESHI_HEADER_PRE) { + return "$header" . + ($this->force_code_block ? '
          ' : ''); + } else { + return "$header" . + ($this->force_code_block ? '
          ' : ''); + } + } + } + + /** + * Returns the footer for the code block. + * + * @return string The footer for the code block + * @since 1.0.0 + * @access private + */ + function footer() { + $footer = $this->footer_content; + if ($footer) { + if ($this->header_type == GESHI_HEADER_PRE) { + $footer = str_replace("\n", '', $footer);; + } + $footer = $this->replace_keywords($footer); + + if ($this->use_classes) { + $attr = ' class="foot"'; + } else { + $attr = " style=\"{$this->footer_content_style}\""; + } + if ($this->header_type == GESHI_HEADER_PRE_TABLE && $this->line_numbers != GESHI_NO_LINE_NUMBERS) { + $footer = "$footer"; + } else { + $footer = "$footer
          "; + } + } + + if (GESHI_HEADER_NONE == $this->header_type) { + return ($this->line_numbers != GESHI_NO_LINE_NUMBERS) ? '
        ' . $footer : $footer; + } + + if ($this->header_type == GESHI_HEADER_DIV || $this->header_type == GESHI_HEADER_PRE_VALID) { + if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { + return "
      $footer
      "; + } + return ($this->force_code_block ? '
    2. ' : '') . + "$footer
  • "; + } + elseif ($this->header_type == GESHI_HEADER_PRE_TABLE) { + if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { + return "$footer"; + } + return ($this->force_code_block ? '' : '') . + "$footer"; + } + else { + if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { + return "$footer"; + } + return ($this->force_code_block ? '' : '') . + "$footer"; + } + } + + /** + * Replaces certain keywords in the header and footer with + * certain configuration values + * + * @param string The header or footer content to do replacement on + * @return string The header or footer with replaced keywords + * @since 1.0.2 + * @access private + */ + function replace_keywords($instr) { + $keywords = $replacements = array(); + + $keywords[] = '
      to have no effect at all if there are line numbers + // (
        s have margins that should be destroyed so all layout is + // controlled by the set_overall_style method, which works on the + //
         or 
        container). Additionally, set default styles for lines + if (!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) { + //$stylesheet .= "$selector, {$selector}ol, {$selector}ol li {margin: 0;}\n"; + $stylesheet .= "$selector.de1, $selector.de2 {{$this->code_style}}\n"; + } + + // Add overall styles + // note: neglect economy_mode, empty styles are meaningless + if ($this->overall_style != '') { + $stylesheet .= "$selector {{$this->overall_style}}\n"; + } + + // Add styles for links + // note: economy mode does not make _any_ sense here + // either the style is empty and thus no selector is needed + // or the appropriate key is given. + foreach ($this->link_styles as $key => $style) { + if ($style != '') { + switch ($key) { + case GESHI_LINK: + $stylesheet .= "{$selector}a:link {{$style}}\n"; + break; + case GESHI_HOVER: + $stylesheet .= "{$selector}a:hover {{$style}}\n"; + break; + case GESHI_ACTIVE: + $stylesheet .= "{$selector}a:active {{$style}}\n"; + break; + case GESHI_VISITED: + $stylesheet .= "{$selector}a:visited {{$style}}\n"; + break; + } + } + } + + // Header and footer + // note: neglect economy_mode, empty styles are meaningless + if ($this->header_content_style != '') { + $stylesheet .= "$selector.head {{$this->header_content_style}}\n"; + } + if ($this->footer_content_style != '') { + $stylesheet .= "$selector.foot {{$this->footer_content_style}}\n"; + } + + // Styles for important stuff + // note: neglect economy_mode, empty styles are meaningless + if ($this->important_styles != '') { + $stylesheet .= "$selector.imp {{$this->important_styles}}\n"; + } + + // Simple line number styles + if ((!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) && $this->line_style1 != '') { + $stylesheet .= "{$selector}li, {$selector}.li1 {{$this->line_style1}}\n"; + } + if ((!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) && $this->table_linenumber_style != '') { + $stylesheet .= "{$selector}.ln {{$this->table_linenumber_style}}\n"; + } + // If there is a style set for fancy line numbers, echo it out + if ((!$economy_mode || $this->line_numbers == GESHI_FANCY_LINE_NUMBERS) && $this->line_style2 != '') { + $stylesheet .= "{$selector}.li2 {{$this->line_style2}}\n"; + } + + // note: empty styles are meaningless + foreach ($this->language_data['STYLES']['KEYWORDS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || + (isset($this->lexic_permissions['KEYWORDS'][$group]) && + $this->lexic_permissions['KEYWORDS'][$group]))) { + $stylesheet .= "$selector.kw$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['COMMENTS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || + (isset($this->lexic_permissions['COMMENTS'][$group]) && + $this->lexic_permissions['COMMENTS'][$group]) || + (!empty($this->language_data['COMMENT_REGEXP']) && + !empty($this->language_data['COMMENT_REGEXP'][$group])))) { + $stylesheet .= "$selector.co$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['ESCAPE_CHAR'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || $this->lexic_permissions['ESCAPE_CHAR'])) { + // NEW: since 1.0.8 we have to handle hardescapes + if ($group === 'HARD') { + $group = '_h'; + } + $stylesheet .= "$selector.es$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['BRACKETS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || $this->lexic_permissions['BRACKETS'])) { + $stylesheet .= "$selector.br$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['SYMBOLS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || $this->lexic_permissions['SYMBOLS'])) { + $stylesheet .= "$selector.sy$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['STRINGS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || $this->lexic_permissions['STRINGS'])) { + // NEW: since 1.0.8 we have to handle hardquotes + if ($group === 'HARD') { + $group = '_h'; + } + $stylesheet .= "$selector.st$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['NUMBERS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || $this->lexic_permissions['NUMBERS'])) { + $stylesheet .= "$selector.nu$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['METHODS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || $this->lexic_permissions['METHODS'])) { + $stylesheet .= "$selector.me$group {{$styles}}\n"; + } + } + // note: neglect economy_mode, empty styles are meaningless + foreach ($this->language_data['STYLES']['SCRIPT'] as $group => $styles) { + if ($styles != '') { + $stylesheet .= "$selector.sc$group {{$styles}}\n"; + } + } + foreach ($this->language_data['STYLES']['REGEXPS'] as $group => $styles) { + if ($styles != '' && (!$economy_mode || + (isset($this->lexic_permissions['REGEXPS'][$group]) && + $this->lexic_permissions['REGEXPS'][$group]))) { + if (is_array($this->language_data['REGEXPS'][$group]) && + array_key_exists(GESHI_CLASS, $this->language_data['REGEXPS'][$group])) { + $stylesheet .= "$selector."; + $stylesheet .= $this->language_data['REGEXPS'][$group][GESHI_CLASS]; + $stylesheet .= " {{$styles}}\n"; + } else { + $stylesheet .= "$selector.re$group {{$styles}}\n"; + } + } + } + // Styles for lines being highlighted extra + if (!$economy_mode || (count($this->highlight_extra_lines)!=count($this->highlight_extra_lines_styles))) { + $stylesheet .= "{$selector}.ln-xtra, {$selector}li.ln-xtra, {$selector}div.ln-xtra {{$this->highlight_extra_lines_style}}\n"; + } + $stylesheet .= "{$selector}span.xtra { display:block; }\n"; + foreach ($this->highlight_extra_lines_styles as $lineid => $linestyle) { + $stylesheet .= "{$selector}.lx$lineid, {$selector}li.lx$lineid, {$selector}div.lx$lineid {{$linestyle}}\n"; + } + + return $stylesheet; + } + + /** + * Get's the style that is used for the specified line + * + * @param int The line number information is requested for + * @access private + * @since 1.0.7.21 + */ + function get_line_style($line) { + //$style = null; + $style = null; + if (isset($this->highlight_extra_lines_styles[$line])) { + $style = $this->highlight_extra_lines_styles[$line]; + } else { // if no "extra" style assigned + $style = $this->highlight_extra_lines_style; + } + + return $style; + } + + /** + * this functions creates an optimized regular expression list + * of an array of strings. + * + * Example: + * $list = array('faa', 'foo', 'foobar'); + * => string 'f(aa|oo(bar)?)' + * + * @param $list array of (unquoted) strings + * @param $regexp_delimiter your regular expression delimiter, @see preg_quote() + * @return string for regular expression + * @author Milian Wolff + * @since 1.0.8 + * @access private + */ + function optimize_regexp_list($list, $regexp_delimiter = '/') { + $regex_chars = array('.', '\\', '+', '*', '?', '[', '^', ']', '$', + '(', ')', '{', '}', '=', '!', '<', '>', '|', ':', $regexp_delimiter); + sort($list); + $regexp_list = array(''); + $num_subpatterns = 0; + $list_key = 0; + + // the tokens which we will use to generate the regexp list + $tokens = array(); + $prev_keys = array(); + // go through all entries of the list and generate the token list + $cur_len = 0; + for ($i = 0, $i_max = count($list); $i < $i_max; ++$i) { + if ($cur_len > GESHI_MAX_PCRE_LENGTH) { + // seems like the length of this pcre is growing exorbitantly + $regexp_list[++$list_key] = $this->_optimize_regexp_list_tokens_to_string($tokens); + $num_subpatterns = substr_count($regexp_list[$list_key], '(?:'); + $tokens = array(); + $cur_len = 0; + } + $level = 0; + $entry = preg_quote((string) $list[$i], $regexp_delimiter); + $pointer = &$tokens; + // properly assign the new entry to the correct position in the token array + // possibly generate smaller common denominator keys + while (true) { + // get the common denominator + if (isset($prev_keys[$level])) { + if ($prev_keys[$level] == $entry) { + // this is a duplicate entry, skip it + continue 2; + } + $char = 0; + while (isset($entry[$char]) && isset($prev_keys[$level][$char]) + && $entry[$char] == $prev_keys[$level][$char]) { + ++$char; + } + if ($char > 0) { + // this entry has at least some chars in common with the current key + if ($char == strlen($prev_keys[$level])) { + // current key is totally matched, i.e. this entry has just some bits appended + $pointer = &$pointer[$prev_keys[$level]]; + } else { + // only part of the keys match + $new_key_part1 = substr($prev_keys[$level], 0, $char); + $new_key_part2 = substr($prev_keys[$level], $char); + + if (in_array($new_key_part1[0], $regex_chars) + || in_array($new_key_part2[0], $regex_chars)) { + // this is bad, a regex char as first character + $pointer[$entry] = array('' => true); + array_splice($prev_keys, $level, count($prev_keys), $entry); + $cur_len += strlen($entry); + continue; + } else { + // relocate previous tokens + $pointer[$new_key_part1] = array($new_key_part2 => $pointer[$prev_keys[$level]]); + unset($pointer[$prev_keys[$level]]); + $pointer = &$pointer[$new_key_part1]; + // recreate key index + array_splice($prev_keys, $level, count($prev_keys), array($new_key_part1, $new_key_part2)); + $cur_len += strlen($new_key_part2); + } + } + ++$level; + $entry = substr($entry, $char); + continue; + } + // else: fall trough, i.e. no common denominator was found + } + if ($level == 0 && !empty($tokens)) { + // we can dump current tokens into the string and throw them away afterwards + $new_entry = $this->_optimize_regexp_list_tokens_to_string($tokens); + $new_subpatterns = substr_count($new_entry, '(?:'); + if (GESHI_MAX_PCRE_SUBPATTERNS && $num_subpatterns + $new_subpatterns > GESHI_MAX_PCRE_SUBPATTERNS) { + $regexp_list[++$list_key] = $new_entry; + $num_subpatterns = $new_subpatterns; + } else { + if (!empty($regexp_list[$list_key])) { + $new_entry = '|' . $new_entry; + } + $regexp_list[$list_key] .= $new_entry; + $num_subpatterns += $new_subpatterns; + } + $tokens = array(); + $cur_len = 0; + } + // no further common denominator found + $pointer[$entry] = array('' => true); + array_splice($prev_keys, $level, count($prev_keys), $entry); + + $cur_len += strlen($entry); + break; + } + unset($list[$i]); + } + // make sure the last tokens get converted as well + $new_entry = $this->_optimize_regexp_list_tokens_to_string($tokens); + if (GESHI_MAX_PCRE_SUBPATTERNS && $num_subpatterns + substr_count($new_entry, '(?:') > GESHI_MAX_PCRE_SUBPATTERNS) { + $regexp_list[++$list_key] = $new_entry; + } else { + if (!empty($regexp_list[$list_key])) { + $new_entry = '|' . $new_entry; + } + $regexp_list[$list_key] .= $new_entry; + } + return $regexp_list; + } + /** + * this function creates the appropriate regexp string of an token array + * you should not call this function directly, @see $this->optimize_regexp_list(). + * + * @param &$tokens array of tokens + * @param $recursed bool to know wether we recursed or not + * @return string + * @author Milian Wolff + * @since 1.0.8 + * @access private + */ + function _optimize_regexp_list_tokens_to_string(&$tokens, $recursed = false) { + $list = ''; + foreach ($tokens as $token => $sub_tokens) { + $list .= $token; + $close_entry = isset($sub_tokens['']); + unset($sub_tokens['']); + if (!empty($sub_tokens)) { + $list .= '(?:' . $this->_optimize_regexp_list_tokens_to_string($sub_tokens, true) . ')'; + if ($close_entry) { + // make sub_tokens optional + $list .= '?'; + } + } + $list .= '|'; + } + if (!$recursed) { + // do some optimizations + // common trailing strings + // BUGGY! + //$list = preg_replace_callback('#(?<=^|\:|\|)\w+?(\w+)(?:\|.+\1)+(?=\|)#', create_function( + // '$matches', 'return "(?:" . preg_replace("#" . preg_quote($matches[1], "#") . "(?=\||$)#", "", $matches[0]) . ")" . $matches[1];'), $list); + // (?:p)? => p? + $list = preg_replace('#\(\?\:(.)\)\?#', '\1?', $list); + // (?:a|b|c|d|...)? => [abcd...]? + // TODO: a|bb|c => [ac]|bb + static $callback_2; + if (!isset($callback_2)) { + $callback_2 = create_function('$matches', 'return "[" . str_replace("|", "", $matches[1]) . "]";'); + } + $list = preg_replace_callback('#\(\?\:((?:.\|)+.)\)#', $callback_2, $list); + } + // return $list without trailing pipe + return substr($list, 0, -1); + } +} // End Class GeSHi + + +if (!function_exists('geshi_highlight')) { + /** + * Easy way to highlight stuff. Behaves just like highlight_string + * + * @param string The code to highlight + * @param string The language to highlight the code in + * @param string The path to the language files. You can leave this blank if you need + * as from version 1.0.7 the path should be automatically detected + * @param boolean Whether to return the result or to echo + * @return string The code highlighted (if $return is true) + * @since 1.0.2 + */ + function geshi_highlight($string, $language, $path = null, $return = false) { + $geshi = new GeSHi($string, $language, $path); + $geshi->set_header_type(GESHI_HEADER_NONE); + + if ($return) { + return '' . $geshi->parse_code() . ''; + } + + echo '' . $geshi->parse_code() . ''; + + if ($geshi->error()) { + return false; + } + return true; + } +} + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/abap.php b/examples/includes/geshi/geshi/abap.php new file mode 100644 index 0000000..ffd8d10 --- /dev/null +++ b/examples/includes/geshi/geshi/abap.php @@ -0,0 +1,1419 @@ +.htm + * + * CHANGES + * ------- + * 2009/02/25 (1.0.8.3) + * - Some more rework of the language file + * 2009/01/04 (1.0.8.2) + * - Major Release, more than 1000 statements and keywords added = whole abap 7.1 (Sandra Rossi) + * 2007/06/27 (1.0.0) + * - First Release + * + * TODO + * ---- + * - in DATA data TYPE type, 2nd "data" and 2nd "type" are highlighted with data + * style, but should be ignored. Same problem for all words!!! This is quite impossible to + * solve it as we should define syntaxes of all statements (huge effort!) and use a lex + * or something like that instead of regexp I guess. + * - Some words are considered as being statement names (report, tables, etc.) though they + * are used as keyword in some statements. For example: FORM xxxx TABLES itab. It was + * arbitrary decided to define them as statement instead of keyword, because it may be + * useful to have the URL to SAP help for some of them. + * - if a comment is between 2 words of a keyword (for example SEPARATED "comment \n BY), + * it is not considered as a keyword, but it should! + * - for statements like "READ DATASET", GeSHi does not allow to set URLs because these + * statements are determined by REGEXPS. For "READ DATASET", the URL should be + * ABAPREAD_DATASET.htm. If a technical solution is found, be careful : URLs + * are sometimes not valid because the URL does not exist. For example, for "AT NEW" + * statement, the URL should be ABAPAT_ITAB.htm (not ABAPAT_NEW.htm). + * There are many other exceptions. + * Note: for adding this functionality within your php program, you can execute this code: + * function add_urls_to_multi_tokens( $matches ) { + * $url = preg_replace( "/[ \n]+/" , "_" , $matches[3] ); + * if( $url == $matches[3] ) return $matches[0] ; + * else return $matches[1]."".$matches[3]."".$matches[4]; + * } + * $html = $geshi->parse_code(); + * $html = preg_replace_callback( "£(zzz:(control|statement|data);\">)(.+?)()£s", "add_urls_to_multi_tokens", $html ); + * echo $html; + * - Numbers followed by a dot terminating the statement are not properly recognized + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array( + 'LANG_NAME' => 'ABAP', + 'COMMENT_SINGLE' => array( + 1 => '"' + ), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + // lines beginning with star at 1st position are comments + // (star anywhere else is not a comment, especially be careful with + // "assign dref->* to " statement) + 2 => '/^\*.*?$/m' + ), + 'CASE_KEYWORDS' => 0, + 'QUOTEMARKS' => array( + 1 => "'", + 2 => "`" + ), + 'ESCAPE_CHAR' => '', + + 'KEYWORDS' => array( + //*********************************************** + // Section 2 : process sequences of several tokens + //*********************************************** + + 7 => array( + 'at new', + 'at end of', + 'at first', + 'at last', + 'loop at', + 'loop at screen', + ), + + 8 => array( + 'private section', + 'protected section', + 'public section', + 'at line-selection', + 'at selection-screen', + 'at user-command', + 'assign component', + 'assign table field', + 'call badi', + 'call customer-function', + 'call customer subscreen', + 'call dialog', + 'call function', + 'call method', + 'call screen', + 'call selection-screen', + 'call transaction', + 'call transformation', + 'close cursor', + 'close dataset', + 'commit work', + 'convert date', + 'convert text', + 'convert time stamp', + 'create data', + 'create object', + 'delete dataset', + 'delete from', + 'describe distance', + 'describe field', + 'describe list', + 'describe table', + 'exec sql', + 'exit from sql', + 'exit from step-loop', + 'export dynpro', + 'export nametab', + 'free memory', + 'generate subroutine-pool', + 'get badi', + 'get bit', + 'get cursor', + 'get dataset', + 'get locale', + 'get parameter', + 'get pf-status', + 'get property', + 'get reference', + 'get run time', + 'get time', + 'get time stamp', + 'import directory', + 'insert report', + 'insert text-pool', + 'leave list-processing', + 'leave program', + 'leave screen', + 'leave to list-processing', + 'leave to transaction', + 'modify line', + 'modify screen', + 'move percentage', + 'open cursor', + 'open dataset', + 'raise event', + 'raise exception', + 'read dataset', + 'read line', + 'read report', + 'read table', + 'read textpool', + 'receive results from function', + 'refresh control', + 'rollback work', + 'set bit', + 'set blank lines', + 'set country', + 'set cursor', + 'set dataset', + 'set extended check', + 'set handler', + 'set hold data', + 'set language', + 'set left scroll-boundary', + 'set locale', + 'set margin', + 'set parameter', + 'set pf-status', + 'set property', + 'set run time analyzer', + 'set run time clock', + 'set screen', + 'set titlebar', + 'set update task', + 'set user-command', + 'suppress dialog', + 'truncate dataset', + 'wait until', + 'wait up to', + ), + + 9 => array( + 'accepting duplicate keys', + 'accepting padding', + 'accepting truncation', + 'according to', + 'actual length', + 'adjacent duplicates', + 'after input', + 'all blob columns', + 'all clob columns', + 'all fields', + 'all methods', + 'all other columns', + 'and mark', + 'and return to screen', + 'and return', + 'and skip first screen', + 'and wait', + 'any table', + 'appendage type', + 'archive mode', + 'archiving parameters', + 'area handle', + 'as checkbox', + 'as icon', + 'as line', + 'as listbox', + 'as person table', + 'as search patterns', + 'as separate unit', + 'as subscreen', + 'as symbol', + 'as text', + 'as window', + 'at cursor-selection', + 'at exit-command', + 'at next application statement', + 'at position', + + 'backup into', + 'before output', + 'before unwind', + 'begin of block', + 'begin of common part', + 'begin of line', + 'begin of screen', + 'begin of tabbed block', + 'begin of version', + 'begin of', + 'big endian', + 'binary mode', + 'binary search', + 'by kernel module', + 'bypassing buffer', + + 'client specified', + 'code page', + 'code page hint', + 'code page into', + 'color black', + 'color blue', + 'color green', + 'color pink', + 'color red', + 'color yellow', + 'compression off', + 'compression on', + 'connect to', + 'corresponding fields of table', + 'corresponding fields of', + 'cover page', + 'cover text', + 'create package', + 'create private', + 'create protected', + 'create public', + 'current position', + + 'data buffer', + 'data values', + 'dataset expiration', + 'daylight saving time', + 'default key', + 'default program', + 'default screen', + 'defining database', + 'deleting leading', + 'deleting trailing', + 'directory entry', + 'display like', + 'display offset', + 'during line-selection', + 'dynamic selections', + + 'edit mask', + 'end of block', + 'end of common part', + 'end of file', + 'end of line', + 'end of screen', + 'end of tabbed block', + 'end of version', + 'end of', + 'endian into', + 'ending at', + 'enhancement options into', + 'enhancement into', + 'environment time format', + 'execute procedure', + 'exporting list to memory', + 'extension type', + + 'field format', + 'field selection', + 'field value into', + 'final methods', + 'first occurrence of', + 'fixed-point arithmetic', + 'for all entries', + 'for all instances', + 'for appending', + 'for columns', + 'for event of', + 'for field', + 'for high', + 'for input', + 'for lines', + 'for low', + 'for node', + 'for output', + 'for select', + 'for table', + 'for testing', + 'for update', + 'for user', + 'frame entry', + 'frame program from', + 'from code page', + 'from context', + 'from database', + 'from logfile id', + 'from number format', + 'from screen', + 'from table', + 'function key', + + 'get connection', + 'global friends', + 'group by', + + 'hashed table of', + 'hashed table', + + 'if found', + 'ignoring case', + 'ignoring conversion errors', + 'ignoring structure boundaries', + 'implementations from', + 'in background', + 'in background task', + 'in background unit', + 'in binary mode', + 'in byte mode', + 'in char-to-hex mode', + 'in character mode', + 'in group', + 'in legacy binary mode', + 'in legacy text mode', + 'in program', + 'in remote task', + 'in text mode', + 'in table', + 'in update task', + 'include bound', + 'include into', + 'include program from', + 'include structure', + 'include type', + 'including gaps', + 'index table', + 'inheriting from', + 'init destination', + 'initial line of', + 'initial line', + 'initial size', + 'internal table', + 'into sortable code', + + 'keep in spool', + 'keeping directory entry', + 'keeping logical unit of work', + 'keeping task', + 'keywords from', + + 'left margin', + 'left outer', + 'levels into', + 'line format', + 'line into', + 'line of', + 'line page', + 'line value from', + 'line value into', + 'lines of', + 'list authority', + 'list dataset', + 'list name', + 'little endian', + 'lob handle for', + 'local friends', + 'locator for', + 'lower case', + + 'main table field', + 'match count', + 'match length', + 'match line', + 'match offset', + 'matchcode object', + 'maximum length', + 'maximum width into', + 'memory id', + 'message into', + 'messages into', + 'modif id', + + 'nesting level', + 'new list identification', + 'next cursor', + 'no database selection', + 'no dialog', + 'no end of line', + 'no fields', + 'no flush', + 'no intervals', + 'no intervals off', + 'no standard page heading', + 'no-extension off', + 'non-unique key', + 'non-unique sorted key', + 'not at end of mode', + 'number of lines', + 'number of pages', + + 'object key', + 'obligatory off', + 'of current page', + 'of page', + 'of program', + 'offset into', + 'on block', + 'on commit', + 'on end of task', + 'on end of', + 'on exit-command', + 'on help-request for', + 'on radiobutton group', + 'on rollback', + 'on value-request for', + 'open for package', + 'option class-coding', + 'option class', + 'option coding', + 'option expand', + 'option syncpoints', + 'options from', + 'order by', + 'overflow into', + + 'package section', + 'package size', + 'preferred parameter', + 'preserving identifier escaping', + 'primary key', + 'print off', + 'print on', + 'program from', + 'program type', + + 'radiobutton groups', + 'radiobutton group', + 'range of', + 'reader for', + 'receive buffer', + 'reduced functionality', + 'ref to data', + 'ref to object', + 'ref to', + + 'reference into', + 'renaming with suffix', + 'replacement character', + 'replacement count', + 'replacement length', + 'replacement line', + 'replacement offset', + 'respecting blanks', + 'respecting case', + 'result into', + 'risk level', + + 'sap cover page', + 'search fkeq', + 'search fkge', + 'search gkeq', + 'search gkge', + 'section of', + 'send buffer', + 'separated by', + 'shared buffer', + 'shared memory', + 'shared memory enabled', + 'skipping byte-order mark', + 'sorted by', + 'sorted table of', + 'sorted table', + 'spool parameters', + 'standard table of', + 'standard table', + 'starting at', + 'starting new task', + 'statements into', + 'structure default', + 'structures into', + + 'table field', + 'table of', + 'text mode', + 'time stamp', + 'time zone', + 'to code page', + 'to column', + 'to context', + 'to first page', + 'to last page', + 'to last line', + 'to line', + 'to lower case', + 'to number format', + 'to page', + 'to sap spool', + 'to upper case', + 'tokens into', + 'transporting no fields', + 'type tableview', + 'type tabstrip', + + 'unicode enabling', + 'up to', + 'upper case', + 'using edit mask', + 'using key', + 'using no edit mask', + 'using screen', + 'using selection-screen', + 'using selection-set', + 'using selection-sets of program', + + 'valid between', + 'valid from', + 'value check', + 'via job', + 'via selection-screen', + 'visible length', + + 'whenever found', + 'with analysis', + 'with byte-order mark', + 'with comments', + 'with current switchstates', + 'with explicit enhancements', + 'with frame', + 'with free selections', + 'with further secondary keys', + 'with header line', + 'with hold', + 'with implicit enhancements', + 'with inactive enhancements', + 'with includes', + 'with key', + 'with linefeed', + 'with list tokenization', + 'with native linefeed', + 'with non-unique key', + 'with null', + 'with pragmas', + 'with precompiled headers', + 'with selection-table', + 'with smart linefeed', + 'with table key', + 'with test code', + 'with type-pools', + 'with unique key', + 'with unix linefeed', + 'with windows linefeed', + 'without further secondary keys', + 'without selection-screen', + 'without spool dynpro', + 'without trmac', + 'word into', + 'writer for' + ), + + //********************************************************** + // Other abap statements + //********************************************************** + 3 => array( + 'add', + 'add-corresponding', + 'aliases', + 'append', + 'assign', + 'at', + 'authority-check', + + 'break-point', + + 'clear', + 'collect', + 'compute', + 'concatenate', + 'condense', + 'class', + 'class-events', + 'class-methods', + 'class-pool', + + 'define', + 'delete', + 'demand', + 'detail', + 'divide', + 'divide-corresponding', + + 'editor-call', + 'end-of-file', + 'end-enhancement-section', + 'end-of-definition', + 'end-of-page', + 'end-of-selection', + 'endclass', + 'endenhancement', + 'endexec', + 'endform', + 'endfunction', + 'endinterface', + 'endmethod', + 'endmodule', + 'endon', + 'endprovide', + 'endselect', + 'enhancement', + 'enhancement-point', + 'enhancement-section', + 'export', + 'extract', + 'events', + + 'fetch', + 'field-groups', + 'find', + 'format', + 'form', + 'free', + 'function-pool', + 'function', + + 'get', + + 'hide', + + 'import', + 'infotypes', + 'input', + 'insert', + 'include', + 'initialization', + 'interface', + 'interface-pool', + 'interfaces', + + 'leave', + 'load-of-program', + 'log-point', + + 'maximum', + 'message', + 'methods', + 'method', + 'minimum', + 'modify', + 'move', + 'move-corresponding', + 'multiply', + 'multiply-corresponding', + + 'new-line', + 'new-page', + 'new-section', + + 'overlay', + + 'pack', + 'perform', + 'position', + 'print-control', + 'program', + 'provide', + 'put', + + 'raise', + 'refresh', + 'reject', + 'replace', + 'report', + 'reserve', + + 'scroll', + 'search', + 'select', + 'selection-screen', + 'shift', + 'skip', + 'sort', + 'split', + 'start-of-selection', + 'submit', + 'subtract', + 'subtract-corresponding', + 'sum', + 'summary', + 'summing', + 'supply', + 'syntax-check', + + 'top-of-page', + 'transfer', + 'translate', + 'type-pool', + + 'uline', + 'unpack', + 'update', + + 'window', + 'write' + + ), + + //********************************************************** + // keywords + //********************************************************** + + 4 => array( + 'abbreviated', + 'abstract', + 'accept', + 'acos', + 'activation', + 'alias', + 'align', + 'all', + 'allocate', + 'and', + 'assigned', + 'any', + 'appending', + 'area', + 'as', + 'ascending', + 'asin', + 'assigning', + 'atan', + 'attributes', + 'avg', + + 'backward', + 'between', + 'bit-and', + 'bit-not', + 'bit-or', + 'bit-set', + 'bit-xor', + 'boolc', + 'boolx', + 'bound', + 'bt', + 'blocks', + 'bounds', + 'boxed', + 'by', + 'byte-ca', + 'byte-cn', + 'byte-co', + 'byte-cs', + 'byte-na', + 'byte-ns', + + 'c', + 'ca', + 'calling', + 'casting', + 'ceil', + 'center', + 'centered', + 'changing', + 'char_off', + 'charlen', + 'circular', + 'class_constructor', + 'client', + 'clike', + 'close', + 'cmax', + 'cmin', + 'cn', + 'cnt', + 'co', + 'col_background', + 'col_group', + 'col_heading', + 'col_key', + 'col_negative', + 'col_normal', + 'col_positive', + 'col_total', + 'color', + 'column', + 'comment', + 'comparing', + 'components', + 'condition', + 'constructor', + 'context', + 'copies', + 'count', + 'country', + 'cpi', + 'creating', + 'critical', + 'concat_lines_of', + 'cos', + 'cosh', + 'count_any_not_of', + 'count_any_of', + 'cp', + 'cs', + 'csequence', + 'currency', + 'current', + 'cx_static_check', + 'cx_root', + 'cx_dynamic_check', + + 'd', + 'dangerous', + 'database', + 'datainfo', + 'date', + 'dbmaxlen', + 'dd/mm/yy', + 'dd/mm/yyyy', + 'ddmmyy', + 'deallocate', + 'decfloat', + 'decfloat16', + 'decfloat34', + 'decimals', + 'default', + 'deferred', + 'definition', + 'department', + 'descending', + 'destination', + 'disconnect', + 'display-mode', + 'distance', + 'distinct', + 'div', + 'dummy', + + 'e', + 'encoding', + 'end-lines', + 'engineering', + 'environment', + 'eq', + 'equiv', + 'error_message', + 'errormessage', + 'escape', + 'exact', + 'exception-table', + 'exceptions', + 'exclude', + 'excluding', + 'exists', + 'exp', + 'exponent', + 'exporting', + 'extended_monetary', + + 'field', + 'filter-table', + 'filters', + 'filter', + 'final', + 'find_any_not_of', + 'find_any_of', + 'find_end', + 'floor', + 'first-line', + 'font', + 'forward', + 'for', + 'frac', + 'from_mixed', + 'friends', + 'from', + 'f', + + 'giving', + 'ge', + 'gt', + + 'handle', + 'harmless', + 'having', + 'head-lines', + 'help-id', + 'help-request', + 'high', + 'hold', + 'hotspot', + + 'i', + 'id', + 'ids', + 'immediately', + 'implementation', + 'importing', + 'in', + 'initial', + 'incl', + 'including', + 'increment', + 'index', + 'index-line', + 'inner', + 'inout', + 'intensified', + 'into', + 'inverse', + 'is', + 'iso', + + 'join', + + 'key', + 'kind', + + 'log10', + 'language', + 'late', + 'layout', + 'le', + 'lt', + 'left-justified', + 'leftplus', + 'leftspace', + 'left', + 'length', + 'level', + 'like', + 'line-count', + 'line-size', + 'lines', + 'line', + 'load', + 'long', + 'lower', + 'low', + 'lpi', + + 'matches', + 'match', + 'mail', + 'major-id', + 'max', + 'medium', + 'memory', + 'message-id', + 'module', + 'minor-id', + 'min', + 'mm/dd/yyyy', + 'mm/dd/yy', + 'mmddyy', + 'mode', + 'modifier', + 'mod', + 'monetary', + + 'name', + 'nb', + 'ne', + 'next', + 'no-display', + 'no-extension', + 'no-gap', + 'no-gaps', + 'no-grouping', + 'no-heading', + 'no-scrolling', + 'no-sign', + 'no-title', + 'no-topofpage', + 'no-zero', + 'nodes', + 'non-unicode', + 'no', + 'number', + 'n', + 'nmax', + 'nmin', + 'not', + 'null', + 'numeric', + 'numofchar', + + 'o', + 'objects', + 'obligatory', + 'occurs', + 'offset', + 'off', + 'of', + 'only', + 'open', + 'option', + 'optional', + 'options', + 'output-length', + 'output', + 'out', + 'on change of', + 'or', + 'others', + + 'pad', + 'page', + 'pages', + 'parameter-table', + 'part', + 'performing', + 'pos_high', + 'pos_low', + 'priority', + 'public', + 'pushbutton', + 'p', + + 'queue-only', + 'quickinfo', + + 'raising', + 'range', + 'read-only', + 'received', + 'receiver', + 'receiving', + 'redefinition', + 'reference', + 'regex', + 'replacing', + 'reset', + 'responsible', + 'result', + 'results', + 'resumable', + 'returncode', + 'returning', + 'right', + 'right-specified', + 'rightplus', + 'rightspace', + 'round', + 'rows', + 'repeat', + 'requested', + 'rescale', + 'reverse', + + 'scale_preserving', + 'scale_preserving_scientific', + 'scientific', + 'scientific_with_leading_zero', + 'screen', + 'scrolling', + 'seconds', + 'segment', + 'shift_left', + 'shift_right', + 'sign', + 'simple', + 'sin', + 'sinh', + 'short', + 'shortdump-id', + 'sign_as_postfix', + 'single', + 'size', + 'some', + 'source', + 'space', + 'spots', + 'stable', + 'state', + 'static', + 'statusinfo', + 'sqrt', + 'string', + 'strlen', + 'structure', + 'style', + 'subkey', + 'submatches', + 'substring', + 'substring_after', + 'substring_before', + 'substring_from', + 'substring_to', + 'super', + 'supplied', + 'switch', + + 't', + 'tan', + 'tanh', + 'table_line', + 'table', + 'tab', + 'then', + 'timestamp', + 'times', + 'time', + 'timezone', + 'title-lines', + 'title', + 'top-lines', + 'to', + 'to_lower', + 'to_mixed', + 'to_upper', + 'trace-file', + 'trace-table', + 'transporting', + 'trunc', + 'type', + + 'under', + 'unique', + 'unit', + 'user-command', + 'using', + 'utf-8', + + 'valid', + 'value', + 'value-request', + 'values', + 'vary', + 'varying', + 'version', + + 'warning', + 'where', + 'width', + 'with', + 'word', + 'with-heading', + 'with-title', + + 'x', + 'xsequence', + 'xstring', + 'xstrlen', + + 'yes', + 'yymmdd', + + 'z', + 'zero' + + ), + + //********************************************************** + // screen statements + //********************************************************** + + 5 => array( + 'call subscreen', + 'chain', + 'endchain', + 'on chain-input', + 'on chain-request', + 'on help-request', + 'on input', + 'on request', + 'on value-request', + 'process' + ), + + //********************************************************** + // internal statements + //********************************************************** + + 6 => array( + 'generate dynpro', + 'generate report', + 'import dynpro', + 'import nametab', + 'include methods', + 'load report', + 'scan abap-source', + 'scan and check abap-source', + 'syntax-check for dynpro', + 'syntax-check for program', + 'syntax-trace', + 'system-call', + 'system-exit', + 'verification-message' + ), + + //********************************************************** + // Control statements + //********************************************************** + + 1 => array( + 'assert', + 'case', + 'catch', + 'check', + 'cleanup', + 'continue', + 'do', + 'else', + 'elseif', + 'endat', + 'endcase', + 'endcatch', + 'endif', + 'enddo', + 'endloop', + 'endtry', + 'endwhile', + 'exit', + 'if', + 'loop', + 'resume', + 'retry', + 'return', + 'stop', + 'try', + 'when', + 'while' + + ), + + //********************************************************** + // variable declaration statements + //********************************************************** + + 2 => array( + 'class-data', + 'controls', + 'constants', + 'data', + 'field-symbols', + 'fields', + 'local', + 'parameters', + 'ranges', + 'select-options', + 'statics', + 'tables', + 'type-pools', + 'types' + ) + ), + 'SYMBOLS' => array( + 0 => array( + '=' + ), + 1 => array( + '(', ')', '{', '}', '[', ']', '+', '-', '*', '/', '!', '%', '^', '&', ':' + ) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false, + 8 => false, + 9 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000066; text-transform: uppercase; font-weight: bold; zzz:control;', //control statements + 2 => 'color: #cc4050; text-transform: uppercase; font-weight: bold; zzz:data;', //data statements + 3 => 'color: #005066; text-transform: uppercase; font-weight: bold; zzz:statement;', //first token of other statements + 4 => 'color: #500066; text-transform: uppercase; font-weight: bold; zzz:keyword;', // next tokens of other statements ("keywords") + 5 => 'color: #005066; text-transform: uppercase; font-weight: bold; zzz:statement;', + 6 => 'color: #000066; text-transform: uppercase; font-weight: bold; zzz:control;', + 7 => 'color: #000066; text-transform: uppercase; font-weight: bold; zzz:control;', + 8 => 'color: #005066; text-transform: uppercase; font-weight: bold; zzz:statement;', + 9 => 'color: #500066; text-transform: uppercase; font-weight: bold; zzz:keyword;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #339933;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #808080;' + ), + 'STRINGS' => array( + 0 => 'color: #4da619;' + ), + 'NUMBERS' => array( + 0 => 'color: #3399ff;' + ), + 'METHODS' => array( + 1 => 'color: #202020;', + 2 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #800080;', + 1 => 'color: #808080;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://help.sap.com/abapdocu/en/ABAP{FNAMEU}.htm', + 2 => 'http://help.sap.com/abapdocu/en/ABAP{FNAMEU}.htm', + 3 => 'http://help.sap.com/abapdocu/en/ABAP{FNAMEU}.htm', + 4 => '', + 5 => '', + 6 => '', + 7 => '', + 8 => '', + 9 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '->', + 2 => '=>' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 7 => array( + 'SPACE_AS_WHITESPACE' => true + ), + 8 => array( + 'SPACE_AS_WHITESPACE' => true + ), + 9 => array( + 'SPACE_AS_WHITESPACE' => true + ) + ) + ), + 'TAB_WIDTH' => 4 +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/actionscript.php b/examples/includes/geshi/geshi/actionscript.php new file mode 100644 index 0000000..658491d --- /dev/null +++ b/examples/includes/geshi/geshi/actionscript.php @@ -0,0 +1,197 @@ + 'ActionScript', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + '#include', 'for', 'foreach', 'if', 'elseif', 'else', 'while', 'do', 'dowhile', + 'endwhile', 'endif', 'switch', 'case', 'endswitch', 'return', 'break', 'continue', 'in' + ), + 2 => array( + 'null', 'false', 'true', 'var', + 'default', 'function', 'class', + 'new', '_global' + ), + 3 => array( + '#endinitclip', '#initclip', '__proto__', '_accProps', '_alpha', '_currentframe', + '_droptarget', '_focusrect', '_framesloaded', '_height', '_highquality', '_lockroot', + '_name', '_parent', '_quality', '_root', '_rotation', '_soundbuftime', '_target', '_totalframes', + '_url', '_visible', '_width', '_x', '_xmouse', '_xscale', '_y', '_ymouse', '_yscale', 'abs', + 'Accessibility', 'acos', 'activityLevel', 'add', 'addListener', 'addPage', 'addProperty', + 'addRequestHeader', 'align', 'allowDomain', 'allowInsecureDomain', 'and', 'appendChild', + 'apply', 'Arguments', 'Array', 'asfunction', 'asin', 'atan', 'atan2', 'attachAudio', 'attachMovie', + 'attachSound', 'attachVideo', 'attributes', 'autosize', 'avHardwareDisable', 'background', + 'backgroundColor', 'BACKSPACE', 'bandwidth', 'beginFill', 'beginGradientFill', 'blockIndent', + 'bold', 'Boolean', 'border', 'borderColor', 'bottomScroll', 'bufferLength', 'bufferTime', + 'builtInItems', 'bullet', 'Button', 'bytesLoaded', 'bytesTotal', 'call', 'callee', 'caller', + 'Camera', 'capabilities', 'CAPSLOCK', 'caption', 'catch', 'ceil', 'charAt', 'charCodeAt', + 'childNodes', 'chr', 'clear', 'clearInterval', 'cloneNode', 'close', 'Color', 'concat', + 'connect', 'condenseWhite', 'constructor', 'contentType', 'ContextMenu', 'ContextMenuItem', + 'CONTROL', 'copy', 'cos', 'createElement', 'createEmptyMovieClip', 'createTextField', + 'createTextNode', 'currentFps', 'curveTo', 'CustomActions', 'customItems', 'data', 'Date', + 'deblocking', 'delete', 'DELETEKEY', 'docTypeDecl', 'domain', 'DOWN', + 'duplicateMovieClip', 'duration', 'dynamic', 'E', 'embedFonts', 'enabled', + 'END', 'endFill', 'ENTER', 'eq', 'Error', 'ESCAPE(Konstante)', 'escape(Funktion)', 'eval', + 'exactSettings', 'exp', 'extends', 'finally', 'findText', 'firstChild', 'floor', + 'flush', 'focusEnabled', 'font', 'fps', 'fromCharCode', 'fscommand', + 'gain', 'ge', 'get', 'getAscii', 'getBeginIndex', 'getBounds', 'getBytesLoaded', 'getBytesTotal', + 'getCaretIndex', 'getCode', 'getCount', 'getDate', 'getDay', 'getDepth', 'getEndIndex', 'getFocus', + 'getFontList', 'getFullYear', 'getHours', 'getInstanceAtDepth', 'getLocal', 'getMilliseconds', + 'getMinutes', 'getMonth', 'getNewTextFormat', 'getNextHighestDepth', 'getPan', 'getProgress', + 'getProperty', 'getRGB', 'getSeconds', 'getSelected', 'getSelectedText', 'getSize', 'getStyle', + 'getStyleNames', 'getSWFVersion', 'getText', 'getTextExtent', 'getTextFormat', 'getTextSnapshot', + 'getTime', 'getTimer', 'getTimezoneOffset', 'getTransform', 'getURL', 'getUTCDate', 'getUTCDay', + 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', + 'getVersion', 'getVolume', 'getYear', 'globalToLocal', 'goto', 'gotoAndPlay', 'gotoAndStop', + 'hasAccessibility', 'hasAudio', 'hasAudioEncoder', 'hasChildNodes', 'hasEmbeddedVideo', 'hasMP3', + 'hasPrinting', 'hasScreenBroadcast', 'hasScreenPlayback', 'hasStreamingAudio', 'hasStreamingVideo', + 'hasVideoEncoder', 'height', 'hide', 'hideBuiltInItems', 'hitArea', 'hitTest', 'hitTestTextNearPos', + 'HOME', 'hscroll', 'html', 'htmlText', 'ID3', 'ifFrameLoaded', 'ignoreWhite', 'implements', + 'import', 'indent', 'index', 'indexOf', 'Infinity', '-Infinity', 'INSERT', 'insertBefore', 'install', + 'instanceof', 'int', 'interface', 'isActive', 'isDebugger', 'isDown', 'isFinite', 'isNaN', 'isToggled', + 'italic', 'join', 'Key', 'language', 'lastChild', 'lastIndexOf', 'le', 'leading', 'LEFT', 'leftMargin', + 'length', 'level', 'lineStyle', 'lineTo', 'list', 'LN10', 'LN2', 'load', 'loadClip', 'loaded', 'loadMovie', + 'loadMovieNum', 'loadSound', 'loadVariables', 'loadVariablesNum', 'LoadVars', 'LocalConnection', + 'localFileReadDisable', 'localToGlobal', 'log', 'LOG10E', 'LOG2E', 'manufacturer', 'Math', 'max', + 'MAX_VALUE', 'maxChars', 'maxhscroll', 'maxscroll', 'mbchr', 'mblength', 'mbord', 'mbsubstring', 'menu', + 'message', 'Microphone', 'min', 'MIN_VALUE', 'MMExecute', 'motionLevel', 'motionTimeOut', 'Mouse', + 'mouseWheelEnabled', 'moveTo', 'Movieclip', 'MovieClipLoader', 'multiline', 'muted', 'name', 'names', 'NaN', + 'ne', 'NEGATIVE_INFINITY', 'NetConnection', 'NetStream', 'newline', 'nextFrame', + 'nextScene', 'nextSibling', 'nodeName', 'nodeType', 'nodeValue', 'not', 'Number', 'Object', + 'on', 'onActivity', 'onChanged', 'onClipEvent', 'onClose', 'onConnect', 'onData', 'onDragOut', + 'onDragOver', 'onEnterFrame', 'onID3', 'onKeyDown', 'onKeyUp', 'onKillFocus', 'onLoad', 'onLoadComplete', + 'onLoadError', 'onLoadInit', 'onLoadProgress', 'onLoadStart', 'onMouseDown', 'onMouseMove', 'onMouseUp', + 'onMouseWheel', 'onPress', 'onRelease', 'onReleaseOutside', 'onResize', 'onRollOut', 'onRollOver', + 'onScroller', 'onSelect', 'onSetFocus', 'onSoundComplete', 'onStatus', 'onUnload', 'onUpdate', 'onXML', + 'or(logischesOR)', 'ord', 'os', 'parentNode', 'parseCSS', 'parseFloat', 'parseInt', 'parseXML', 'password', + 'pause', 'PGDN', 'PGUP', 'PI', 'pixelAspectRatio', 'play', 'playerType', 'pop', 'position', + 'POSITIVE_INFINITY', 'pow', 'prevFrame', 'previousSibling', 'prevScene', 'print', 'printAsBitmap', + 'printAsBitmapNum', 'PrintJob', 'printNum', 'private', 'prototype', 'public', 'push', 'quality', + 'random', 'rate', 'registerClass', 'removeListener', 'removeMovieClip', 'removeNode', 'removeTextField', + 'replaceSel', 'replaceText', 'resolutionX', 'resolutionY', 'restrict', 'reverse', 'RIGHT', + 'rightMargin', 'round', 'scaleMode', 'screenColor', 'screenDPI', 'screenResolutionX', 'screenResolutionY', + 'scroll', 'seek', 'selectable', 'Selection', 'send', 'sendAndLoad', 'separatorBefore', 'serverString', + 'set', 'setvariable', 'setBufferTime', 'setClipboard', 'setDate', 'setFocus', 'setFullYear', 'setGain', + 'setHours', 'setInterval', 'setMask', 'setMilliseconds', 'setMinutes', 'setMode', 'setMonth', + 'setMotionLevel', 'setNewTextFormat', 'setPan', 'setProperty', 'setQuality', 'setRate', 'setRGB', + 'setSeconds', 'setSelectColor', 'setSelected', 'setSelection', 'setSilenceLevel', 'setStyle', + 'setTextFormat', 'setTime', 'setTransform', 'setUseEchoSuppression', 'setUTCDate', 'setUTCFullYear', + 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setVolume', + 'setYear', 'SharedObject', 'SHIFT(Konstante)', 'shift(Methode)', 'show', 'showMenu', 'showSettings', + 'silenceLevel', 'silenceTimeout', 'sin', 'size', 'slice', 'smoothing', 'sort', 'sortOn', 'Sound', 'SPACE', + 'splice', 'split', 'sqrt', 'SQRT1_2', 'SQRT2', 'Stage', 'start', 'startDrag', 'static', 'status', 'stop', + 'stopAllSounds', 'stopDrag', 'String', 'StyleSheet(Klasse)', 'styleSheet(Eigenschaft)', 'substr', + 'substring', 'super', 'swapDepths', 'System', 'TAB', 'tabChildren', 'tabEnabled', 'tabIndex', + 'tabStops', 'tan', 'target', 'targetPath', 'tellTarget', 'text', 'textColor', 'TextField', 'TextFormat', + 'textHeight', 'TextSnapshot', 'textWidth', 'this', 'throw', 'time', 'toggleHighQuality', 'toLowerCase', + 'toString', 'toUpperCase', 'trace', 'trackAsMenu', 'try', 'type', 'typeof', 'undefined', + 'underline', 'unescape', 'uninstall', 'unloadClip', 'unloadMovie', 'unLoadMovieNum', 'unshift', 'unwatch', + 'UP', 'updateAfterEvent', 'updateProperties', 'url', 'useCodePage', 'useEchoSuppression', 'useHandCursor', + 'UTC', 'valueOf', 'variable', 'version', 'Video', 'visible', 'void', 'watch', 'width', + 'with', 'wordwrap', 'XML', 'xmlDecl', 'XMLNode', 'XMLSocket' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '@', '%', '&', '*', '|', '/', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #0066CC;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array() +); + +?> diff --git a/examples/includes/geshi/geshi/actionscript3.php b/examples/includes/geshi/geshi/actionscript3.php new file mode 100644 index 0000000..b98002f --- /dev/null +++ b/examples/includes/geshi/geshi/actionscript3.php @@ -0,0 +1,467 @@ + 'ActionScript 3', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'with', 'while', 'void', 'undefined', 'typeof', 'try', 'true', + 'throw', 'this', 'switch', 'super', 'set', 'return', 'public', 'protected', + 'private', 'null', 'new', 'is', 'internal', 'instanceof', 'in', + 'import', 'if', 'get', 'for', 'false', 'else', 'each', 'do', + 'delete', 'default', 'continue', 'catch', 'case', 'break', 'as' + ), + 2 => array( + 'var' + ), + 3 => array( + 'function' + ), + 4 => array( + 'class', 'package' + ), + 6 => array( + 'flash.xml', 'flash.utils', 'flash.ui', 'flash.text', + 'flash.system', 'flash.profiler', 'flash.printing', 'flash.net', + 'flash.media', 'flash.geom', 'flash.filters', 'flash.external', + 'flash.events', 'flash.errors', 'flash.display', + 'flash.accessibility' + ), + 7 => array( + 'zoom', 'year', 'y', 'xmlDecl', 'x', 'writeUnsignedInt', + 'writeUTFBytes', 'writeUTF', 'writeShort', 'writeObject', + 'writeMultiByte', 'writeInt', 'writeFloat', 'writeExternal', + 'writeDynamicProperty', 'writeDynamicProperties', 'writeDouble', + 'writeBytes', 'writeByte', 'writeBoolean', 'wordWrap', + 'willTrigger', 'width', 'volume', 'visible', 'videoWidth', + 'videoHeight', 'version', 'valueOf', 'value', 'usingTLS', + 'useRichTextClipboard', 'useHandCursor', 'useEchoSuppression', + 'useCodePage', 'url', 'uri', 'uploadCompleteData', 'upload', + 'updateProperties', 'updateAfterEvent', 'upState', 'unshift', + 'unlock', 'unload', 'union', 'unescapeMultiByte', 'unescape', + 'underline', 'uncompress', 'type', 'ty', 'tx', 'transparent', + 'translate', 'transformPoint', 'transform', 'trackAsMenu', 'track', + 'trace', 'totalMemory', 'totalFrames', 'topLeft', 'top', + 'togglePause', 'toXMLString', 'toUpperCase', 'toUTCString', + 'toTimeString', 'toString', 'toPrecision', 'toLowerCase', + 'toLocaleUpperCase', 'toLocaleTimeString', 'toLocaleString', + 'toLocaleLowerCase', 'toLocaleDateString', 'toFixed', + 'toExponential', 'toDateString', 'timezoneOffset', 'timerComplete', + 'timer', 'time', 'threshold', 'thickness', 'textWidth', + 'textSnapshot', 'textInput', 'textHeight', 'textColor', 'text', + 'test', 'target', 'tan', 'tabStops', 'tabIndexChange', 'tabIndex', + 'tabEnabledChange', 'tabEnabled', 'tabChildrenChange', + 'tabChildren', 'sync', 'swfVersion', 'swapChildrenAt', + 'swapChildren', 'subtract', 'substring', 'substr', 'styleSheet', + 'styleNames', 'strength', 'stopPropagation', + 'stopImmediatePropagation', 'stopDrag', 'stopAll', 'stop', 'status', + 'startDrag', 'start', 'stageY', 'stageX', 'stageWidth', + 'stageHeight', 'stageFocusRect', 'stage', 'sqrt', 'split', 'splice', + 'source', 'soundTransform', 'soundComplete', 'sortOn', 'sort', + 'songName', 'some', 'socketData', 'smoothing', 'slice', 'size', + 'sin', 'silent', 'silenceTimeout', 'silenceLevel', 'showSettings', + 'showRedrawRegions', 'showDefaultContextMenu', 'show', 'shortcut', + 'shiftKey', 'shift', 'sharpness', 'sharedEvents', 'shadowColor', + 'shadowAlpha', 'settings', 'setUseEchoSuppression', 'setUTCSeconds', + 'setUTCMonth', 'setUTCMinutes', 'setUTCMilliseconds', 'setUTCHours', + 'setUTCFullYear', 'setUTCDate', 'setTimeout', 'setTime', + 'setTextFormat', 'setStyle', 'setSilenceLevel', 'setSettings', + 'setSelection', 'setSelected', 'setSelectColor', 'setSeconds', + 'setQuality', 'setPropertyIsEnumerable', 'setProperty', 'setPixels', + 'setPixel32', 'setPixel', 'setNamespace', 'setName', + 'setMotionLevel', 'setMonth', 'setMode', 'setMinutes', + 'setMilliseconds', 'setLoopback', 'setLoopBack', 'setLocalName', + 'setKeyFrameInterval', 'setInterval', 'setHours', 'setFullYear', + 'setEmpty', 'setDirty', 'setDate', 'setCompositionString', + 'setClipboard', 'setChildren', 'setChildIndex', + 'setAdvancedAntiAliasingTable', 'serverString', 'separatorBefore', + 'sendToURL', 'send', 'selectionEndIndex', 'selectionBeginIndex', + 'selectable', 'select', 'seek', 'securityError', 'securityDomain', + 'secondsUTC', 'seconds', 'search', 'scrollV', 'scrollRect', + 'scrollH', 'scroll', 'screenResolutionY', 'screenResolutionX', + 'screenDPI', 'screenColor', 'scenes', 'scaleY', 'scaleX', + 'scaleMode', 'scale9Grid', 'scale', 'save', 'sandboxType', + 'sameDomain', 'running', 'round', 'rotation', 'rotate', 'root', + 'rollOver', 'rollOut', 'rightToRight', 'rightToLeft', 'rightPeak', + 'rightMargin', 'right', 'rewind', 'reverse', 'resume', 'restrict', + 'resize', 'reset', 'requestHeaders', 'replaceText', + 'replaceSelectedText', 'replace', 'repeatCount', 'render', + 'removedFromStage', 'removed', 'removeNode', 'removeNamespace', + 'removeEventListener', 'removeChildAt', 'removeChild', + 'relatedObject', 'registerFont', 'registerClassAlias', 'redOffset', + 'redMultiplier', 'rect', 'receiveVideo', 'receiveAudio', + 'readUnsignedShort', 'readUnsignedInt', 'readUnsignedByte', + 'readUTFBytes', 'readUTF', 'readShort', 'readObject', + 'readMultiByte', 'readInt', 'readFloat', 'readExternal', + 'readDouble', 'readBytes', 'readByte', 'readBoolean', 'ratios', + 'rate', 'random', 'quality', 'push', 'publish', 'proxyType', + 'prototype', 'propertyIsEnumerable', 'progress', + 'processingInstructions', 'printAsBitmap', 'print', + 'previousSibling', 'preventDefault', 'prevScene', 'prevFrame', + 'prettyPrinting', 'prettyIndent', 'preserveAlpha', 'prependChild', + 'prefix', 'pow', 'position', 'pop', 'polar', 'playerType', 'play', + 'pixelSnapping', 'pixelDissolve', 'pixelBounds', 'pixelAspectRatio', + 'perlinNoise', 'pause', 'parseXML', 'parseInt', 'parseFloat', + 'parseCSS', 'parse', 'parentNode', 'parentDomain', + 'parentAllowsChild', 'parent', 'parameters', 'paperWidth', + 'paperHeight', 'pan', 'paletteMap', 'pageWidth', 'pageHeight', + 'overState', 'outsideCutoff', 'os', 'orientation', 'open', + 'opaqueBackground', 'onPlayStatus', 'onMetaData', 'onCuePoint', + 'offsetPoint', 'offset', 'objectID', 'objectEncoding', 'numLock', + 'numLines', 'numFrames', 'numChildren', 'normalize', 'noise', + 'nodeValue', 'nodeType', 'nodeName', 'nodeKind', 'noAutoLabeling', + 'nextValue', 'nextSibling', 'nextScene', 'nextNameIndex', + 'nextName', 'nextFrame', 'netStatus', 'navigateToURL', + 'namespaceURI', 'namespaceDeclarations', 'namespace', 'names', + 'name', 'muted', 'multiline', 'moveTo', 'mouseY', 'mouseX', + 'mouseWheelEnabled', 'mouseWheel', 'mouseUp', 'mouseTarget', + 'mouseOver', 'mouseOut', 'mouseMove', 'mouseLeave', + 'mouseFocusChange', 'mouseEnabled', 'mouseDown', 'mouseChildren', + 'motionTimeout', 'motionLevel', 'monthUTC', 'month', + 'modificationDate', 'mode', 'minutesUTC', 'minutes', 'min', + 'millisecondsUTC', 'milliseconds', 'method', 'message', 'merge', + 'menuSelect', 'menuItemSelect', 'maxScrollV', 'maxScrollH', + 'maxLevel', 'maxChars', 'max', 'matrixY', 'matrixX', 'matrix', + 'match', 'mask', 'mapPoint', 'mapBitmap', 'map', 'manufacturer', + 'macType', 'loopback', 'loop', 'log', 'lock', 'localeCompare', + 'localY', 'localX', 'localToGlobal', 'localName', + 'localFileReadDisable', 'loaderURL', 'loaderInfo', 'loader', + 'loadPolicyFile', 'loadBytes', 'load', 'liveDelay', 'link', + 'lineTo', 'lineStyle', 'lineGradientStyle', 'level', + 'letterSpacing', 'length', 'leftToRight', 'leftToLeft', 'leftPeak', + 'leftMargin', 'left', 'leading', 'lastIndexOf', 'lastIndex', + 'lastChild', 'language', 'labels', 'knockout', 'keyUp', + 'keyLocation', 'keyFrameInterval', 'keyFocusChange', 'keyDown', + 'keyCode', 'kerning', 'join', 'italic', 'isXMLName', + 'isPrototypeOf', 'isNaN', 'isFocusInaccessible', 'isFinite', + 'isEmpty', 'isDefaultPrevented', 'isDebugger', 'isBuffering', + 'isAttribute', 'isAccessible', 'ioError', 'invert', 'invalidate', + 'intersects', 'intersection', 'interpolate', 'insideCutoff', + 'insertChildBefore', 'insertChildAfter', 'insertBefore', 'inner', + 'init', 'info', 'inflatePoint', 'inflate', 'indexOf', 'index', + 'indent', 'inScopeNamespaces', 'imeComposition', 'ime', + 'ignoreWhitespace', 'ignoreWhite', 'ignoreProcessingInstructions', + 'ignoreComments', 'ignoreCase', 'identity', 'idMap', 'id3', + 'httpStatus', 'htmlText', 'hoursUTC', 'hours', 'hitTestTextNearPos', + 'hitTestState', 'hitTestPoint', 'hitTestObject', 'hitTest', + 'hitArea', 'highlightColor', 'highlightAlpha', 'hideObject', + 'hideBuiltInItems', 'hide', 'height', 'hasVideoEncoder', 'hasTLS', + 'hasStreamingVideo', 'hasStreamingAudio', 'hasSimpleContent', + 'hasScreenPlayback', 'hasScreenBroadcast', 'hasProperty', + 'hasPrinting', 'hasOwnProperty', 'hasMP3', 'hasIME', 'hasGlyphs', + 'hasEventListener', 'hasEmbeddedVideo', 'hasDefinition', + 'hasComplexContent', 'hasChildNodes', 'hasAudioEncoder', 'hasAudio', + 'hasAccessibility', 'gridFitType', 'greenOffset', 'greenMultiplier', + 'graphics', 'gotoAndStop', 'gotoAndPlay', 'globalToLocal', 'global', + 'getUTCSeconds', 'getUTCMonth', 'getUTCMinutes', + 'getUTCMilliseconds', 'getUTCHours', 'getUTCFullYear', 'getUTCDay', + 'getUTCDate', 'getTimezoneOffset', 'getTimer', 'getTime', + 'getTextRunInfo', 'getTextFormat', 'getText', 'getStyle', + 'getStackTrace', 'getSelectedText', 'getSelected', 'getSeconds', + 'getRemote', 'getRect', 'getQualifiedSuperclassName', + 'getQualifiedClassName', 'getProperty', 'getPrefixForNamespace', + 'getPixels', 'getPixel32', 'getPixel', 'getParagraphLength', + 'getObjectsUnderPoint', 'getNamespaceForPrefix', 'getMonth', + 'getMinutes', 'getMilliseconds', 'getMicrophone', 'getLocal', + 'getLineText', 'getLineOffset', 'getLineMetrics', 'getLineLength', + 'getLineIndexOfChar', 'getLineIndexAtPoint', 'getImageReference', + 'getHours', 'getFullYear', 'getFirstCharInParagraph', + 'getDescendants', 'getDefinitionByName', 'getDefinition', 'getDay', + 'getDate', 'getColorBoundsRect', 'getClassByAlias', 'getChildIndex', + 'getChildByName', 'getChildAt', 'getCharIndexAtPoint', + 'getCharBoundaries', 'getCamera', 'getBounds', 'genre', + 'generateFilterRect', 'gain', 'fullYearUTC', 'fullYear', + 'fullScreen', 'fscommand', 'fromCharCode', 'framesLoaded', + 'frameRate', 'frame', 'fps', 'forwardAndBack', 'formatToString', + 'forceSimple', 'forEach', 'fontType', 'fontStyle', 'fontSize', + 'fontName', 'font', 'focusRect', 'focusOut', 'focusIn', 'focus', + 'flush', 'floor', 'floodFill', 'firstChild', 'findText', 'filters', + 'filter', 'fillRect', 'fileList', 'extension', 'extended', 'exp', + 'exec', 'exactSettings', 'every', 'eventPhase', 'escapeMultiByte', + 'escape', 'errorID', 'error', 'equals', 'enumerateFonts', + 'enterFrame', 'endian', 'endFill', 'encodeURIComponent', + 'encodeURI', 'enabled', 'embedFonts', 'elements', + 'dynamicPropertyWriter', 'dropTarget', 'drawRoundRect', 'drawRect', + 'drawEllipse', 'drawCircle', 'draw', 'download', 'downState', + 'doubleClickEnabled', 'doubleClick', 'dotall', 'domain', + 'docTypeDecl', 'doConversion', 'divisor', 'distance', 'dispose', + 'displayState', 'displayMode', 'displayAsPassword', 'dispatchEvent', + 'description', 'describeType', 'descent', 'descendants', + 'deltaTransformPoint', 'delta', 'deleteProperty', 'delay', + 'defaultTextFormat', 'defaultSettings', 'defaultObjectEncoding', + 'decodeURIComponent', 'decodeURI', 'decode', 'deblocking', + 'deactivate', 'dayUTC', 'day', 'dateUTC', 'date', 'dataFormat', + 'data', 'd', 'customItems', 'curveTo', 'currentTarget', + 'currentScene', 'currentLabels', 'currentLabel', 'currentFrame', + 'currentFPS', 'currentDomain', 'currentCount', 'ctrlKey', 'creator', + 'creationDate', 'createTextNode', 'createGradientBox', + 'createElement', 'createBox', 'cos', 'copyPixels', 'copyChannel', + 'copy', 'conversionMode', 'contextMenuOwner', 'contextMenu', + 'contentType', 'contentLoaderInfo', 'content', 'containsRect', + 'containsPoint', 'contains', 'constructor', 'connectedProxyType', + 'connected', 'connect', 'condenseWhite', 'concatenatedMatrix', + 'concatenatedColorTransform', 'concat', 'computeSpectrum', + 'compress', 'componentY', 'componentX', 'complete', 'compare', + 'comments', 'comment', 'colors', 'colorTransform', 'color', 'code', + 'close', 'cloneNode', 'clone', 'client', 'click', 'clearTimeout', + 'clearInterval', 'clear', 'clamp', 'children', 'childNodes', + 'childIndex', 'childAllowsParent', 'child', 'checkPolicyFile', + 'charCount', 'charCodeAt', 'charCode', 'charAt', 'changeList', + 'change', 'ceil', 'caretIndex', 'caption', 'capsLock', 'cancelable', + 'cancel', 'callee', 'callProperty', 'call', 'cacheAsBitmap', 'c', + 'bytesTotal', 'bytesLoaded', 'bytesAvailable', 'buttonMode', + 'buttonDown', 'bullet', 'builtInItems', 'bufferTime', + 'bufferLength', 'bubbles', 'browse', 'bottomScrollV', 'bottomRight', + 'bottom', 'borderColor', 'border', 'bold', 'blurY', 'blurX', + 'blueOffset', 'blueMultiplier', 'blockIndent', 'blendMode', + 'bitmapData', 'bias', 'beginGradientFill', 'beginFill', + 'beginBitmapFill', 'bandwidth', 'backgroundColor', 'background', + 'b', 'available', 'avHardwareDisable', 'autoSize', 'attributes', + 'attribute', 'attachNetStream', 'attachCamera', 'attachAudio', + 'atan2', 'atan', 'asyncError', 'asin', 'ascent', 'artist', + 'areSoundsInaccessible', 'areInaccessibleObjectsUnderPoint', + 'applyFilter', 'apply', 'applicationDomain', 'appendText', + 'appendChild', 'antiAliasType', 'angle', 'alwaysShowSelection', + 'altKey', 'alphas', 'alphaOffset', 'alphaMultiplier', 'alpha', + 'allowInsecureDomain', 'allowDomain', 'align', 'album', + 'addedToStage', 'added', 'addPage', 'addNamespace', 'addHeader', + 'addEventListener', 'addChildAt', 'addChild', 'addCallback', 'add', + 'activityLevel', 'activity', 'active', 'activating', 'activate', + 'actionScriptVersion', 'acos', 'accessibilityProperties', 'abs' + ), + 8 => array( + 'WRAP', 'VERTICAL', 'VARIABLES', + 'UTC', 'UPLOAD_COMPLETE_DATA', 'UP', 'UNLOAD', 'UNKNOWN', + 'UNIQUESORT', 'TOP_RIGHT', 'TOP_LEFT', 'TOP', 'TIMER_COMPLETE', + 'TIMER', 'TEXT_NODE', 'TEXT_INPUT', 'TEXT', 'TAB_INDEX_CHANGE', + 'TAB_ENABLED_CHANGE', 'TAB_CHILDREN_CHANGE', 'TAB', 'SYNC', + 'SUBTRACT', 'SUBPIXEL', 'STATUS', 'STANDARD', 'SQUARE', 'SQRT2', + 'SQRT1_2', 'SPACE', 'SOUND_COMPLETE', 'SOCKET_DATA', 'SHOW_ALL', + 'SHIFT', 'SETTINGS_MANAGER', 'SELECT', 'SECURITY_ERROR', 'SCROLL', + 'SCREEN', 'ROUND', 'ROLL_OVER', 'ROLL_OUT', 'RIGHT', 'RGB', + 'RETURNINDEXEDARRAY', 'RESIZE', 'REPEAT', 'RENDER', + 'REMOVED_FROM_STAGE', 'REMOVED', 'REMOTE', 'REGULAR', 'REFLECT', + 'RED', 'RADIAL', 'PROGRESS', 'PRIVACY', 'POST', 'POSITIVE_INFINITY', + 'PORTRAIT', 'PIXEL', 'PI', 'PENDING', 'PAGE_UP', 'PAGE_DOWN', 'PAD', + 'OVERLAY', 'OUTER', 'OPEN', 'NaN', 'NUM_PAD', 'NUMPAD_SUBTRACT', + 'NUMPAD_MULTIPLY', 'NUMPAD_ENTER', 'NUMPAD_DIVIDE', + 'NUMPAD_DECIMAL', 'NUMPAD_ADD', 'NUMPAD_9', 'NUMPAD_8', 'NUMPAD_7', + 'NUMPAD_6', 'NUMPAD_5', 'NUMPAD_4', 'NUMPAD_3', 'NUMPAD_2', + 'NUMPAD_1', 'NUMPAD_0', 'NUMERIC', 'NO_SCALE', 'NO_BORDER', + 'NORMAL', 'NONE', 'NEVER', 'NET_STATUS', 'NEGATIVE_INFINITY', + 'MULTIPLY', 'MOUSE_WHEEL', 'MOUSE_UP', 'MOUSE_OVER', 'MOUSE_OUT', + 'MOUSE_MOVE', 'MOUSE_LEAVE', 'MOUSE_FOCUS_CHANGE', 'MOUSE_DOWN', + 'MITER', 'MIN_VALUE', 'MICROPHONE', 'MENU_SELECT', + 'MENU_ITEM_SELECT', 'MEDIUM', 'MAX_VALUE', 'LOW', 'LOG2E', 'LOG10E', + 'LOCAL_WITH_NETWORK', 'LOCAL_WITH_FILE', 'LOCAL_TRUSTED', + 'LOCAL_STORAGE', 'LN2', 'LN10', 'LITTLE_ENDIAN', 'LINK', + 'LINEAR_RGB', 'LINEAR', 'LIGHT_COLOR', 'LIGHTEN', 'LEFT', 'LCD', + 'LAYER', 'LANDSCAPE', 'KOREAN', 'KEY_UP', 'KEY_FOCUS_CHANGE', + 'KEY_DOWN', 'JUSTIFY', 'JAPANESE_KATAKANA_HALF', + 'JAPANESE_KATAKANA_FULL', 'JAPANESE_HIRAGANA', 'Infinity', 'ITALIC', + 'IO_ERROR', 'INVERT', 'INSERT', 'INPUT', 'INNER', 'INIT', + 'IME_COMPOSITION', 'IGNORE', 'ID3', 'HTTP_STATUS', 'HORIZONTAL', + 'HOME', 'HIGH', 'HARDLIGHT', 'GREEN', 'GET', 'FULLSCREEN', 'FULL', + 'FOCUS_OUT', 'FOCUS_IN', 'FLUSHED', 'FLASH9', 'FLASH8', 'FLASH7', + 'FLASH6', 'FLASH5', 'FLASH4', 'FLASH3', 'FLASH2', 'FLASH1', 'F9', + 'F8', 'F7', 'F6', 'F5', 'F4', 'F3', 'F2', 'F15', 'F14', 'F13', + 'F12', 'F11', 'F10', 'F1', 'EXACT_FIT', 'ESCAPE', 'ERROR', 'ERASE', + 'ENTER_FRAME', 'ENTER', 'END', 'EMBEDDED', 'ELEMENT_NODE', 'E', + 'DYNAMIC', 'DOWN', 'DOUBLE_CLICK', 'DIFFERENCE', 'DEVICE', + 'DESCENDING', 'DELETE', 'DEFAULT', 'DEACTIVATE', 'DATA', + 'DARK_COLOR', 'DARKEN', 'CRT', 'CONTROL', 'CONNECT', 'COMPLETE', + 'COLOR', 'CLOSE', 'CLICK', 'CLAMP', 'CHINESE', 'CHANGE', 'CENTER', + 'CASEINSENSITIVE', 'CAPTURING_PHASE', 'CAPS_LOCK', 'CANCEL', + 'CAMERA', 'BUBBLING_PHASE', 'BOTTOM_RIGHT', 'BOTTOM_LEFT', 'BOTTOM', + 'BOLD_ITALIC', 'BOLD', 'BLUE', 'BINARY', 'BIG_ENDIAN', 'BEVEL', + 'BEST', 'BACKSPACE', 'AUTO', 'AT_TARGET', 'ASYNC_ERROR', 'AMF3', + 'AMF0', 'ALWAYS', 'ALPHANUMERIC_HALF', 'ALPHANUMERIC_FULL', 'ALPHA', + 'ADVANCED', 'ADDED_TO_STAGE', 'ADDED', 'ADD', 'ACTIVITY', + 'ACTIONSCRIPT3', 'ACTIONSCRIPT2' + ), + //FIX: Must be last in order to avoid conflicts with keywords present + //in other keyword groups, that might get highlighted as part of the URL. + //I know this is not a proper work-around, but should do just fine. + 5 => array( + 'uint', 'int', 'arguments', 'XMLSocket', 'XMLNodeType', 'XMLNode', + 'XMLList', 'XMLDocument', 'XML', 'Video', 'VerifyError', + 'URLVariables', 'URLStream', 'URLRequestMethod', 'URLRequestHeader', + 'URLRequest', 'URLLoaderDataFormat', 'URLLoader', 'URIError', + 'TypeError', 'Transform', 'TimerEvent', 'Timer', 'TextSnapshot', + 'TextRenderer', 'TextLineMetrics', 'TextFormatAlign', 'TextFormat', + 'TextFieldType', 'TextFieldAutoSize', 'TextField', 'TextEvent', + 'TextDisplayMode', 'TextColorType', 'System', 'SyntaxError', + 'SyncEvent', 'StyleSheet', 'String', 'StatusEvent', 'StaticText', + 'StageScaleMode', 'StageQuality', 'StageAlign', 'Stage', + 'StackOverflowError', 'Sprite', 'SpreadMethod', 'SoundTransform', + 'SoundMixer', 'SoundLoaderContext', 'SoundChannel', 'Sound', + 'Socket', 'SimpleButton', 'SharedObjectFlushStatus', 'SharedObject', + 'Shape', 'SecurityPanel', 'SecurityErrorEvent', 'SecurityError', + 'SecurityDomain', 'Security', 'ScriptTimeoutError', 'Scene', + 'SWFVersion', 'Responder', 'RegExp', 'ReferenceError', 'Rectangle', + 'RangeError', 'QName', 'Proxy', 'ProgressEvent', + 'PrintJobOrientation', 'PrintJobOptions', 'PrintJob', 'Point', + 'PixelSnapping', 'ObjectEncoding', 'Object', 'Number', 'NetStream', + 'NetStatusEvent', 'NetConnection', 'Namespace', 'MovieClip', + 'MouseEvent', 'Mouse', 'MorphShape', 'Microphone', 'MemoryError', + 'Matrix', 'Math', 'LocalConnection', 'LoaderInfo', 'LoaderContext', + 'Loader', 'LineScaleMode', 'KeyboardEvent', 'Keyboard', + 'KeyLocation', 'JointStyle', 'InvalidSWFError', + 'InterpolationMethod', 'InteractiveObject', 'IllegalOperationError', + 'IOErrorEvent', 'IOError', 'IMEEvent', 'IMEConversionMode', 'IME', + 'IExternalizable', 'IEventDispatcher', 'IDynamicPropertyWriter', + 'IDynamicPropertyOutput', 'IDataOutput', 'IDataInput', 'ID3Info', + 'IBitmapDrawable', 'HTTPStatusEvent', 'GridFitType', 'Graphics', + 'GradientType', 'GradientGlowFilter', 'GradientBevelFilter', + 'GlowFilter', 'Function', 'FrameLabel', 'FontType', 'FontStyle', + 'Font', 'FocusEvent', 'FileReferenceList', 'FileReference', + 'FileFilter', 'ExternalInterface', 'EventPhase', 'EventDispatcher', + 'Event', 'EvalError', 'ErrorEvent', 'Error', 'Endian', 'EOFError', + 'DropShadowFilter', 'DisplayObjectContainer', 'DisplayObject', + 'DisplacementMapFilterMode', 'DisplacementMapFilter', 'Dictionary', + 'DefinitionError', 'Date', 'DataEvent', 'ConvolutionFilter', + 'ContextMenuItem', 'ContextMenuEvent', 'ContextMenuBuiltInItems', + 'ContextMenu', 'ColorTransform', 'ColorMatrixFilter', 'Class', + 'CapsStyle', 'Capabilities', 'Camera', 'CSMSettings', 'ByteArray', + 'Boolean', 'BlurFilter', 'BlendMode', 'BitmapFilterType', + 'BitmapFilterQuality', 'BitmapFilter', 'BitmapDataChannel', + 'BitmapData', 'Bitmap', 'BevelFilter', 'AsyncErrorEvent', 'Array', + 'ArgumentError', 'ApplicationDomain', 'AntiAliasType', + 'ActivityEvent', 'ActionScriptVersion', 'AccessibilityProperties', + 'Accessibility', 'AVM1Movie' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '%', '&', '*', '|', '/', '<', '>', '^', '-', '+', '~', '?', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0033ff; font-weight: bold;', + 2 => 'color: #6699cc; font-weight: bold;', + 3 => 'color: #339966; font-weight: bold;', + 4 => 'color: #9900cc; font-weight: bold;', + 5 => 'color: #004993;', + 6 => 'color: #004993;', + 7 => 'color: #004993;', + 8 => 'color: #004993;' + ), + 'COMMENTS' => array( + 1 => 'color: #009900;', + 'MULTI' => 'color: #3f5fbf;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #990000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000; font-weight:bold;' + ), + 'METHODS' => array( + 0 => 'color: #000000;', + ), + 'SYMBOLS' => array( + 0 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => 'http://www.google.com/search?q={FNAMEL}%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:{FNAMEL}.html&filter=0&num=100&btnI=lucky', + 6 => '', + 7 => '', + 8 => '' + ), + 'OOLANG' => false,//Save some time as OO identifiers aren't used + 'OBJECT_SPLITTERS' => array( + // commented out because it's not very relevant for AS, as all properties, methods and constants are dot-accessed. + // I believe it's preferable to have package highlighting for example, which is not possible with this enabled. + // 0 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array() +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/ada.php b/examples/includes/geshi/geshi/ada.php new file mode 100644 index 0000000..1013883 --- /dev/null +++ b/examples/includes/geshi/geshi/ada.php @@ -0,0 +1,133 @@ + 'Ada', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'begin', 'declare', 'do', 'else', 'elsif', 'exception', 'for', 'if', + 'is', 'loop', 'while', 'then', 'end', 'select', 'case', 'until', + 'goto', 'return' + ), + 2 => array( + 'abs', 'and', 'mod', 'not', 'or', 'rem', 'xor' + ), + 3 => array( + 'abort', 'abstract', 'accept', 'access', 'aliased', 'all', 'array', 'at', 'body', + 'constant', 'delay', 'delta', 'digits', 'entry', 'exit', + 'function', 'generic', 'in', 'limited', 'new', 'null', 'of', 'others', 'out', 'package', 'pragma', + 'private', 'procedure', 'protected', 'raise', 'range', 'record', 'renames', 'requeue', 'reverse', + 'separate', 'subtype', 'tagged', 'task', 'terminate', 'type', 'use', 'when', 'with' + ) + ), + 'SYMBOLS' => array( + '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00007f;', + 2 => 'color: #0000ff;', + 3 => 'color: #46aa03; font-weight:bold;', + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff0000;' + ), + 'METHODS' => array( + 1 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/apache.php b/examples/includes/geshi/geshi/apache.php new file mode 100644 index 0000000..fa06afe --- /dev/null +++ b/examples/includes/geshi/geshi/apache.php @@ -0,0 +1,206 @@ + 'Apache configuration', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + /*keywords*/ + 1 => array( + 'accessconfig','accessfilename','action','addalt', + 'addaltbyencoding','addaltbytype','addcharset', + 'adddefaultcharset','adddescription', + 'addencoding','addhandler','addicon','addiconbyencoding', + 'addiconbytype','addlanguage','addmodule','addmoduleinfo', + 'addtype','agentlog','alias','aliasmatch', + 'allow','allowconnect','allowoverride','anonymous', + 'anonymous_authoritative','anonymous_logemail','anonymous_mustgiveemail', + 'anonymous_nouserid','anonymous_verifyemail','authauthoritative', + 'authdbauthoritative','authdbgroupfile','authdbmauthoritative', + 'authdbmgroupfile','authdbuserfile','authdbmuserfile', + 'authdigestfile','authgroupfile','authname','authtype', + 'authuserfile','bindaddress','browsermatch','browsermatchnocase', + 'bs2000account','cachedefaultexpire','cachedirlength','cachedirlevels', + 'cacheforcecompletion','cachegcinterval','cachelastmodifiedfactor','cachemaxexpire', + 'cachenegotiateddocs','cacheroot','cachesize','checkspelling', + 'clearmodulelist','contentdigest','cookieexpires','cookielog', + 'cookietracking','coredumpdirectory','customlog', + 'defaulticon','defaultlanguage','defaulttype','define', + 'deny','directory','directorymatch','directoryindex', + 'documentroot','errordocument','errorlog','example', + 'expiresactive','expiresbytype','expiresdefault','extendedstatus', + 'fancyindexing','files','filesmatch','forcetype', + 'group','header','headername','hostnamelookups', + 'identitycheck','ifdefine','ifmodule','imapbase', + 'imapdefault','imapmenu','include','indexignore','indexorderdefault', + 'indexoptions','keepalive','keepalivetimeout','languagepriority', + 'limit','limitexcept','limitrequestbody','limitrequestfields', + 'limitrequestfieldsize','limitrequestline','listen','listenbacklog', + 'loadfile','loadmodule','location','locationmatch', + 'lockfile','logformat','loglevel','maxclients', + 'maxkeepaliverequests','maxrequestsperchild','maxspareservers','maxsparethreads','metadir', + 'metafiles','metasuffix','mimemagicfile','minspareservers','minsparethreads', + 'mmapfile','namevirtualhost','nocache','options','order', + 'passenv','php_admin_value','php_admin_flag','php_value','pidfile','port','proxyblock','proxydomain', + 'proxypass','proxypassreverse','proxyreceivebuffersize','proxyremote', + 'proxyrequests','proxyvia','qsc','readmename', + 'redirect','redirectmatch','redirectpermanent','redirecttemp', + 'refererignore','refererlog','removehandler','require', + 'resourceconfig','rewritebase','rewritecond','rewriteengine', + 'rewritelock','rewritelog','rewriteloglevel','rewritemap', + 'rewriteoptions','rewriterule','rlimitcpu','rlimitmem', + 'rlimitnproc','satisfy','scoreboardfile','script', + 'scriptalias','scriptaliasmatch','scriptinterpretersource','scriptlog', + 'scriptlogbuffer','scriptloglength','sendbuffersize', + 'serveradmin','serveralias','servername','serverpath', + 'serverroot','serversignature','servertokens','servertype', + 'setenv','setenvif','setenvifnocase','sethandler', + 'singlelisten','startservers','threadsperchild','timeout', + 'transferlog','typesconfig','unsetenv','usecanonicalname', + 'user','userdir','virtualhost','virtualdocumentroot', + 'virtualdocumentrootip','virtualscriptalias','virtualscriptaliasip', + 'xbithack','from','all' + ), + /*keywords 2*/ + 2 => array( + 'on','off','standalone','inetd','indexes', + 'force-response-1.0','downgrade-1.0','nokeepalive', + 'ndexes','includes','followsymlinks','none', + 'x-compress','x-gzip' + ), + /*keywords 3*/ + 3 => array( + 'Directory', + 'DirectoryMatch', + 'Files', + 'FilesMatch', + 'IfDefine', + 'IfModule', + 'IfVersion', + 'Location', + 'LocationMatch', + 'Proxy', + 'ProxyMatch', + 'VirtualHost' + ) + ), + 'SYMBOLS' => array( + '+', '-' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00007f;', + 2 => 'color: #0000ff;', + 3 => 'color: #000000; font-weight:bold;', + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #339933;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff0000;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'BRACKETS' => GESHI_NEVER, + 'SYMBOLS' => GESHI_NEVER + ), + 'KEYWORDS' => array( + 3 => array( + 'DISALLOWED_BEFORE' => '(?<=<|<\/)', + 'DISALLOWED_AFTER' => '(?=\s|\/|>)', + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/applescript.php b/examples/includes/geshi/geshi/applescript.php new file mode 100644 index 0000000..395bba7 --- /dev/null +++ b/examples/includes/geshi/geshi/applescript.php @@ -0,0 +1,157 @@ + 'AppleScript', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array( '(*' => '*)'), + 'COMMENT_REGEXP' => array( + 2 => '/(?<=[a-z])\'/i', + 3 => '/(? GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'application','close','count','delete','duplicate','exists','launch','make','move','open', + 'print','quit','reopen','run','save','saving', 'idle', 'path to', 'number', 'alias', 'list', 'text', 'string', + 'integer', 'it','me','version','pi','result','space','tab','anything','case','diacriticals','expansion', + 'hyphens','punctuation','bold','condensed','expanded','hidden','italic','outline','plain', + 'shadow','strikethrough','subscript','superscript','underline','ask','no','yes','false', 'id', + 'true','weekday','monday','mon','tuesday','tue','wednesday','wed','thursday','thu','friday', + 'fri','saturday','sat','sunday','sun','month','january','jan','february','feb','march', + 'mar','april','apr','may','june','jun','july','jul','august','aug','september', 'quote', 'do JavaScript', + 'sep','october','oct','november','nov','december','dec','minutes','hours', 'name', 'default answer', + 'days','weeks', 'folder', 'folders', 'file', 'files', 'window', 'eject', 'disk', 'reveal', 'sleep', + 'shut down', 'restart', 'display dialog', 'buttons', 'invisibles', 'item', 'items', 'delimiters', 'offset of', + 'AppleScript\'s', 'choose file', 'choose folder', 'choose from list', 'beep', 'contents', 'do shell script', + 'paragraph', 'paragraphs', 'missing value', 'quoted form', 'desktop', 'POSIX path', 'POSIX file', + 'activate', 'document', 'adding', 'receiving', 'content', 'new', 'properties', 'info for', 'bounds', + 'selection', 'extension', 'into', 'onto', 'by', 'between', 'against', 'set the clipboard to', 'the clipboard' + ), + 2 => array( + 'each','some','every','whose','where','index','first','second','third','fourth', + 'fifth','sixth','seventh','eighth','ninth','tenth','last','front','back','st','nd', + 'rd','th','middle','named','through','thru','before','after','beginning','the', 'as', + 'div','mod','and','not','or','contains','equal','equals','isnt', 'less', 'greater' + ), + 3 => array( + 'script','property','prop','end','to','set','global','local','on','of', + 'in','given','with','without','return','continue','tell','if','then','else','repeat', + 'times','while','until','from','exit','try','error','considering','ignoring','timeout', + 'transaction','my','get','put','is', 'copy' + ) + ), + 'SYMBOLS' => array( + ')','+','-','^','*','/','&','<','>=','<','<=','=','�' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0066ff;', + 2 => 'color: #ff0033;', + 3 => 'color: #ff0033; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => '', + 3 => 'color: #ff0000;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000000; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #009900;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;' + ), + 'REGEXPS' => array( + 0 => 'color: #339933;', + 4 => 'color: #0066ff;', + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => ',+-=<>/?^&*' + ), + 'REGEXPS' => array( + //Variables + 0 => '[\\$%@]+[a-zA-Z_][a-zA-Z0-9_]*', + //File descriptors + 4 => '<[a-zA-Z_][a-zA-Z0-9_]*>', + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'SPACE_AS_WHITESPACE' => true + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/apt_sources.php b/examples/includes/geshi/geshi/apt_sources.php new file mode 100644 index 0000000..1321032 --- /dev/null +++ b/examples/includes/geshi/geshi/apt_sources.php @@ -0,0 +1,144 @@ + 'Apt sources', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + /*keywords*/ + 1 => array( + 'deb-src', 'deb' + ), + 2 => array( + //Generic + 'stable', 'old-stable', 'testing', 'testing-proposed-updates', + 'unstable', 'unstable-proposed-updates', 'experimental', + 'non-US', 'security', 'volatile', 'volatile-sloppy', + 'apt-build', + 'stable/updates', + //Debian + 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', 'woody', 'sarge', + 'etch', 'lenny', 'sid', + //Ubuntu + 'warty', 'warty-updates', 'warty-security', 'warty-proposed', 'warty-backports', + 'hoary', 'hoary-updates', 'hoary-security', 'hoary-proposed', 'hoary-backports', + 'breezy', 'breezy-updates', 'breezy-security', 'breezy-proposed', 'breezy-backports', + 'dapper', 'dapper-updates', 'dapper-security', 'dapper-proposed', 'dapper-backports', + 'edgy', 'edgy-updates', 'edgy-security', 'edgy-proposed', 'edgy-backports', + 'feisty', 'feisty-updates', 'feisty-security', 'feisty-proposed', 'feisty-backports', + 'gutsy', 'gutsy-updates', 'gutsy-security', 'gutsy-proposed', 'gutsy-backports', + 'hardy', 'hardy-updates', 'hardy-security', 'hardy-proposed', 'hardy-backports', + 'intrepid', 'intrepid-updates', 'intrepid-security', 'intrepid-proposed', 'intrepid-backports' + ), + 3 => array( + 'main', 'restricted', 'preview', 'contrib', 'non-free', + 'commercial', 'universe', 'multiverse' + ) + ), + 'REGEXPS' => array( + 0 => "(((http|ftp):\/\/|file:\/)[^\s]+)|(cdrom:\[[^\]]*\][^\s]*)", + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => true, + 3 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00007f;', + 2 => 'color: #b1b100;', + 3 => 'color: #b16000;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + ), + 'STRINGS' => array( + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + ), + 'REGEXPS' => array( + 0 => 'color: #009900;', + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'NUMBERS' => GESHI_NEVER, + 'METHODS' => GESHI_NEVER, + 'SCRIPT' => GESHI_NEVER, + 'SYMBOLS' => GESHI_NEVER, + 'ESCAPE_CHAR' => GESHI_NEVER, + 'BRACKETS' => GESHI_NEVER, + 'STRINGS' => GESHI_NEVER, + ), + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => '(?|^\/])', + 'DISALLOWED_AFTER' => '(?![a-zA-Z0-9_\|%\\-&\.])' + ) + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/asm.php b/examples/includes/geshi/geshi/asm.php new file mode 100644 index 0000000..af4eef7 --- /dev/null +++ b/examples/includes/geshi/geshi/asm.php @@ -0,0 +1,225 @@ + 'ASM', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + //Line address prefix suppression + 'COMMENT_REGEXP' => array(2 => "/^(?:[0-9a-f]{0,4}:)?[0-9a-f]{4}(?:[0-9a-f]{4})?/mi"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /*CPU*/ + 1 => array( + 'aaa','aad','aam','aas','adc','add','and','call','cbw','clc','cld','cli','cmc','cmp', + 'cmps','cmpsb','cmpsw','cwd','daa','das','dec','div','esc','hlt','idiv','imul','in','inc', + 'int','into','iret','ja','jae','jb','jbe','jc','jcxz','je','jg','jge','jl','jle','jmp', + 'jna','jnae','jnb','jnbe','jnc','jne','jng','jnge','jnl','jnle','jno','jnp','jns','jnz', + 'jo','jp','jpe','jpo','js','jz','lahf','lds','lea','les','lods','lodsb','lodsw','loop', + 'loope','loopew','loopne','loopnew','loopnz','loopnzw','loopw','loopz','loopzw','mov', + 'movs','movsb','movsw','mul','neg','nop','not','or','out','pop','popf','push','pushf', + 'rcl','rcr','ret','retf','retn','rol','ror','sahf','sal','sar','sbb','scas','scasb','scasw', + 'shl','shr','stc','std','sti','stos','stosb','stosw','sub','test','wait','xchg','xlat', + 'xlatb','xor','bound','enter','ins','insb','insw','leave','outs','outsb','outsw','popa','pusha','pushw', + 'arpl','lar','lsl','sgdt','sidt','sldt','smsw','str','verr','verw','clts','lgdt','lidt','lldt','lmsw','ltr', + 'bsf','bsr','bt','btc','btr','bts','cdq','cmpsd','cwde','insd','iretd','iretdf','iretf', + 'jecxz','lfs','lgs','lodsd','loopd','looped','loopned','loopnzd','loopzd','lss','movsd', + 'movsx','movzx','outsd','popad','popfd','pushad','pushd','pushfd','scasd','seta','setae', + 'setb','setbe','setc','sete','setg','setge','setl','setle','setna','setnae','setnb','setnbe', + 'setnc','setne','setng','setnge','setnl','setnle','setno','setnp','setns','setnz','seto','setp', + 'setpe','setpo','sets','setz','shld','shrd','stosd','bswap','cmpxchg','invd','invlpg','wbinvd','xadd','lock', + 'rep','repe','repne','repnz','repz' + ), + /*FPU*/ + 2 => array( + 'f2xm1','fabs','fadd','faddp','fbld','fbstp','fchs','fclex','fcom','fcomp','fcompp','fdecstp', + 'fdisi','fdiv','fdivp','fdivr','fdivrp','feni','ffree','fiadd','ficom','ficomp','fidiv', + 'fidivr','fild','fimul','fincstp','finit','fist','fistp','fisub','fisubr','fld','fld1', + 'fldcw','fldenv','fldenvw','fldl2e','fldl2t','fldlg2','fldln2','fldpi','fldz','fmul', + 'fmulp','fnclex','fndisi','fneni','fninit','fnop','fnsave','fnsavew','fnstcw','fnstenv', + 'fnstenvw','fnstsw','fpatan','fprem','fptan','frndint','frstor','frstorw','fsave', + 'fsavew','fscale','fsqrt','fst','fstcw','fstenv','fstenvw','fstp','fstsw','fsub','fsubp', + 'fsubr','fsubrp','ftst','fwait','fxam','fxch','fxtract','fyl2x','fyl2xp1', + 'fsetpm','fcos','fldenvd','fnsaved','fnstenvd','fprem1','frstord','fsaved','fsin','fsincos', + 'fstenvd','fucom','fucomp','fucompp' + ), + /*registers*/ + 3 => array( + 'ah','al','ax','bh','bl','bp','bx','ch','cl','cr0','cr2','cr3','cs','cx','dh','di','dl', + 'dr0','dr1','dr2','dr3','dr6','dr7','ds','dx','eax','ebp','ebx','ecx','edi','edx', + 'es','esi','esp','fs','gs','si','sp','ss','st','tr3','tr4','tr5','tr6','tr7' + ), + /*Directive*/ + 4 => array( + '186','286','286c','286p','287','386','386c','386p','387','486','486p', + '8086','8087','alpha','break','code','const','continue','cref','data','data?', + 'dosseg','else','elseif','endif','endw','err','err1','err2','errb', + 'errdef','errdif','errdifi','erre','erridn','erridni','errnb','errndef', + 'errnz','exit','fardata','fardata?','if','lall','lfcond','list','listall', + 'listif','listmacro','listmacroall',' model','no87','nocref','nolist', + 'nolistif','nolistmacro','radix','repeat','sall','seq','sfcond','stack', + 'startup','tfcond','type','until','untilcxz','while','xall','xcref', + 'xlist','alias','align','assume','catstr','comm','comment','db','dd','df','dq', + 'dt','dup','dw','echo','elseif1','elseif2','elseifb','elseifdef','elseifdif', + 'elseifdifi','elseife','elseifidn','elseifidni','elseifnb','elseifndef','end', + 'endm','endp','ends','eq',' equ','even','exitm','extern','externdef','extrn','for', + 'forc','ge','goto','group','high','highword','if1','if2','ifb','ifdef','ifdif', + 'ifdifi','ife',' ifidn','ifidni','ifnb','ifndef','include','includelib','instr','invoke', + 'irp','irpc','label','le','length','lengthof','local','low','lowword','lroffset', + 'macro','mask','mod','msfloat','name','ne','offset','opattr','option','org','%out', + 'page','popcontext','private','proc','proto','ptr','public','purge','pushcontext','record', + 'rept','seg','segment','short','size','sizeof','sizestr','struc','struct', + 'substr','subtitle','subttl','textequ','this','title','typedef','union','width', + '.model', '.stack', '.code', '.data' + ), + /*Operands*/ + 5 => array( + '@b','@f','addr','basic','byte','c','carry?','dword', + 'far','far16','fortran','fword','near','near16','overflow?','parity?','pascal','qword', + 'real4',' real8','real10','sbyte','sdword','sign?','stdcall','sword','syscall','tbyte', + 'vararg','word','zero?','flat','near32','far32', + 'abs','all','assumes','at','casemap','common','compact', + 'cpu','dotname','emulator','epilogue','error','export','expr16','expr32','farstack', + 'forceframe','huge','language','large','listing','ljmp','loadds','m510','medium','memory', + 'nearstack','nodotname','noemulator','nokeyword','noljmp','nom510','none','nonunique', + 'nooldmacros','nooldstructs','noreadonly','noscoped','nosignextend','nothing', + 'notpublic','oldmacros','oldstructs','os_dos','para','prologue', + 'readonly','req','scoped','setif2','smallstack','tiny','use16','use32','uses' + ) + ), + 'SYMBOLS' => array( + '[', ']', '(', ')', + '+', '-', '*', '/', '%', + '.', ',', ';', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00007f; font-weight: bold;', + 2 => 'color: #0000ff; font-weight: bold;', + 3 => 'color: #00007f;', + 4 => 'color: #000000; font-weight: bold;', + 5 => 'color: #000000; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900; font-weight: bold;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000ff;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( +// 0 => 'color: #0000ff;', +// 1 => 'color: #0000ff;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'NUMBERS' => + GESHI_NUMBER_BIN_PREFIX_PERCENT | + GESHI_NUMBER_BIN_SUFFIX | + GESHI_NUMBER_HEX_PREFIX | + GESHI_NUMBER_HEX_SUFFIX | + GESHI_NUMBER_OCT_SUFFIX | + GESHI_NUMBER_INT_BASIC | + GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_NONSCI_F | + GESHI_NUMBER_FLT_SCI_ZERO, + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Hex numbers +// 0 => /* */ "(?<=([\\s\\(\\)\\[\\],;.:+\\-\\/*]))(?:[0-9][0-9a-fA-F]{0,31}[hH]|0x[0-9a-fA-F]{1,32})(?=([\\s\\(\\)\\[\\],;.:+\\-\\/*]))", + //Binary numbers +// 1 => "(?<=([\\s\\(\\)\\[\\],;.:+\\-\\/*]))[01]{1,64}[bB](?=([\\s\\(\\)\\[\\],;.:+\\-\\/*]))" + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 8, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(?|^])", + 'DISALLOWED_AFTER' => "(?![a-zA-Z0-9_<\|%])" + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/asp.php b/examples/includes/geshi/geshi/asp.php new file mode 100644 index 0000000..d2404bb --- /dev/null +++ b/examples/includes/geshi/geshi/asp.php @@ -0,0 +1,164 @@ + 'ASP', + 'COMMENT_SINGLE' => array(1 => "'", 2 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'include', 'file', 'Const', 'Dim', 'Option', 'Explicit', 'Implicit', 'Set', 'Select', 'ReDim', 'Preserve', + 'ByVal', 'ByRef', 'End', 'Private', 'Public', 'If', 'Then', 'Else', 'ElseIf', 'Case', 'With', 'NOT', + 'While', 'Wend', 'For', 'Loop', 'Do', 'Request', 'Response', 'Server', 'ADODB', 'Session', 'Application', + 'Each', 'In', 'Get', 'Next', 'INT', 'CINT', 'CBOOL', 'CDATE', 'CBYTE', 'CCUR', 'CDBL', 'CLNG', 'CSNG', + 'CSTR', 'Fix', 'Is', 'Sgn', 'String', 'Boolean', 'Currency', 'Me', 'Single', 'Long', 'Integer', 'Byte', + 'Variant', 'Double', 'To', 'Let', 'Xor', 'Resume', 'On', 'Error', 'Imp', 'GoTo', 'Call', 'Global' + ), + 2 => array( + 'Null', 'Nothing', 'And', + 'False', + 'True', 'var', 'Or', 'BOF', 'EOF', 'xor', + 'Function', 'Class', 'New', 'Sub' + ), + 3 => array( + 'CreateObject', 'Write', 'Redirect', 'Cookies', 'BinaryRead', 'ClientCertificate', 'Form', 'QueryString', + 'ServerVariables', 'TotalBytes', 'AddHeader', 'AppendToLog', 'BinaryWrite', 'Buffer', 'CacheControl', + 'Charset', 'Clear', 'ContentType', 'End()', 'Expires', 'ExpiresAbsolute', 'Flush()', 'IsClientConnected', + 'PICS', 'Status', 'Connection', 'Recordset', 'Execute', 'Abandon', 'Lock', 'UnLock', 'Command', 'Fields', + 'Properties', 'Property', 'Send', 'Replace', 'InStr', 'TRIM', 'NOW', 'Day', 'Month', 'Hour', 'Minute', 'Second', + 'Year', 'MonthName', 'LCase', 'UCase', 'Abs', 'Array', 'As', 'LEN', 'MoveFirst', 'MoveLast', 'MovePrevious', + 'MoveNext', 'LBound', 'UBound', 'Transfer', 'Open', 'Close', 'MapPath', 'FileExists', 'OpenTextFile', 'ReadAll' + ) + ), + 'SYMBOLS' => array( + 1 => array( + '<%', '%>' + ), + 0 => array( + '(', ')', '[', ']', '!', '@', '%', '&', '*', '|', '/', '<', '>', + ';', ':', '?', '='), + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #990099; font-weight: bold;', + 2 => 'color: #0000ff; font-weight: bold;', + 3 => 'color: #330066;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000;', + 2 => 'color: #ff6600;', + 'MULTI' => 'color: #008000;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #006600; font-weight:bold;' + ), + 'STRINGS' => array( + 0 => 'color: #cc0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #800000;' + ), + 'METHODS' => array( + 1 => 'color: #9900cc;' + ), + 'SYMBOLS' => array( + 0 => 'color: #006600; font-weight: bold;', + 1 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + '<%' => '%>' + ), + 1 => array( + '' + ), + 2 => array( + '' + ), + 3 => "/(<%=?)(?:\"[^\"]*?\"|\/\*(?!\*\/).*?\*\/|.)*?(%>|\Z)/sm" + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true + ) +); + +?> diff --git a/examples/includes/geshi/geshi/autoit.php b/examples/includes/geshi/geshi/autoit.php new file mode 100644 index 0000000..259c822 --- /dev/null +++ b/examples/includes/geshi/geshi/autoit.php @@ -0,0 +1,1171 @@ + 'AutoIt', + 'COMMENT_SINGLE' => array(';'), + 'COMMENT_MULTI' => array( + '#comments-start' => '#comments-end', + '#cs' => '#ce'), + 'COMMENT_REGEXP' => array(0 => '/(? GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'And','ByRef','Case','Const','ContinueCase','ContinueLoop', + 'Default','Dim','Do','Else','ElseIf','EndFunc','EndIf','EndSelect', + 'EndSwitch','EndWith','Enum','Exit','ExitLoop','False','For','Func', + 'Global','If','In','Local','Next','Not','Or','ReDim','Return', + 'Select','Step','Switch','Then','To','True','Until','WEnd','While', + 'With' + ), + 2 => array( + '@AppDataCommonDir','@AppDataDir','@AutoItExe','@AutoItPID', + '@AutoItUnicode','@AutoItVersion','@AutoItX64','@COM_EventObj', + '@CommonFilesDir','@Compiled','@ComputerName','@ComSpec','@CR', + '@CRLF','@DesktopCommonDir','@DesktopDepth','@DesktopDir', + '@DesktopHeight','@DesktopRefresh','@DesktopWidth', + '@DocumentsCommonDir','@error','@exitCode','@exitMethod', + '@extended','@FavoritesCommonDir','@FavoritesDir','@GUI_CtrlHandle', + '@GUI_CtrlId','@GUI_DragFile','@GUI_DragId','@GUI_DropId', + '@GUI_WinHandle','@HomeDrive','@HomePath','@HomeShare', + '@HotKeyPressed','@HOUR','@InetGetActive','@InetGetBytesRead', + '@IPAddress1','@IPAddress2','@IPAddress3','@IPAddress4','@KBLayout', + '@LF','@LogonDNSDomain','@LogonDomain','@LogonServer','@MDAY', + '@MIN','@MON','@MyDocumentsDir','@NumParams','@OSBuild','@OSLang', + '@OSServicePack','@OSTYPE','@OSVersion','@ProcessorArch', + '@ProgramFilesDir','@ProgramsCommonDir','@ProgramsDir','@ScriptDir', + '@ScriptFullPath','@ScriptLineNumber','@ScriptName','@SEC', + '@StartMenuCommonDir','@StartMenuDir','@StartupCommonDir', + '@StartupDir','@SW_DISABLE','@SW_ENABLE','@SW_HIDE','@SW_LOCK', + '@SW_MAXIMIZE','@SW_MINIMIZE','@SW_RESTORE','@SW_SHOW', + '@SW_SHOWDEFAULT','@SW_SHOWMAXIMIZED','@SW_SHOWMINIMIZED', + '@SW_SHOWMINNOACTIVE','@SW_SHOWNA','@SW_SHOWNOACTIVATE', + '@SW_SHOWNORMAL','@SW_UNLOCK','@SystemDir','@TAB','@TempDir', + '@TRAY_ID','@TrayIconFlashing','@TrayIconVisible','@UserName', + '@UserProfileDir','@WDAY','@WindowsDir','@WorkingDir','@YDAY', + '@YEAR' + ), + 3 => array( + 'Abs','ACos','AdlibDisable','AdlibEnable','Asc','AscW','ASin', + 'Assign','ATan','AutoItSetOption','AutoItWinGetTitle', + 'AutoItWinSetTitle','Beep','Binary','BinaryLen','BinaryMid', + 'BinaryToString','BitAND','BitNOT','BitOR','BitRotate','BitShift', + 'BitXOR','BlockInput','Break','Call','CDTray','Ceiling','Chr', + 'ChrW','ClipGet','ClipPut','ConsoleRead','ConsoleWrite', + 'ConsoleWriteError','ControlClick','ControlCommand', + 'ControlDisable','ControlEnable','ControlFocus','ControlGetFocus', + 'ControlGetHandle','ControlGetPos','ControlGetText','ControlHide', + 'ControlListView','ControlMove','ControlSend','ControlSetText', + 'ControlShow','ControlTreeView','Cos','Dec','DirCopy','DirCreate', + 'DirGetSize','DirMove','DirRemove','DllCall','DllCallbackFree', + 'DllCallbackGetPtr','DllCallbackRegister','DllClose','DllOpen', + 'DllStructCreate','DllStructGetData','DllStructGetPtr', + 'DllStructGetSize','DllStructSetData','DriveGetDrive', + 'DriveGetFileSystem','DriveGetLabel','DriveGetSerial', + 'DriveGetType','DriveMapAdd','DriveMapDel','DriveMapGet', + 'DriveSetLabel','DriveSpaceFree','DriveSpaceTotal','DriveStatus', + 'EnvGet','EnvSet','EnvUpdate','Eval','Execute','Exp', + 'FileChangeDir','FileClose','FileCopy','FileCreateNTFSLink', + 'FileCreateShortcut','FileDelete','FileExists','FileFindFirstFile', + 'FileFindNextFile','FileGetAttrib','FileGetLongName', + 'FileGetShortcut','FileGetShortName','FileGetSize','FileGetTime', + 'FileGetVersion','FileInstall','FileMove','FileOpen', + 'FileOpenDialog','FileRead','FileReadLine','FileRecycle', + 'FileRecycleEmpty','FileSaveDialog','FileSelectFolder', + 'FileSetAttrib','FileSetTime','FileWrite','FileWriteLine','Floor', + 'FtpSetProxy','GUICreate','GUICtrlCreateAvi','GUICtrlCreateButton', + 'GUICtrlCreateCheckbox','GUICtrlCreateCombo', + 'GUICtrlCreateContextMenu','GUICtrlCreateDate','GUICtrlCreateDummy', + 'GUICtrlCreateEdit','GUICtrlCreateGraphic','GUICtrlCreateGroup', + 'GUICtrlCreateIcon','GUICtrlCreateInput','GUICtrlCreateLabel', + 'GUICtrlCreateList','GUICtrlCreateListView', + 'GUICtrlCreateListViewItem','GUICtrlCreateMenu', + 'GUICtrlCreateMenuItem','GUICtrlCreateMonthCal','GUICtrlCreateObj', + 'GUICtrlCreatePic','GUICtrlCreateProgress','GUICtrlCreateRadio', + 'GUICtrlCreateSlider','GUICtrlCreateTab','GUICtrlCreateTabItem', + 'GUICtrlCreateTreeView','GUICtrlCreateTreeViewItem', + 'GUICtrlCreateUpdown','GUICtrlDelete','GUICtrlGetHandle', + 'GUICtrlGetState','GUICtrlRead','GUICtrlRecvMsg', + 'GUICtrlRegisterListViewSort','GUICtrlSendMsg','GUICtrlSendToDummy', + 'GUICtrlSetBkColor','GUICtrlSetColor','GUICtrlSetCursor', + 'GUICtrlSetData','GUICtrlSetFont','GUICtrlSetDefColor', + 'GUICtrlSetDefBkColor','GUICtrlSetGraphic','GUICtrlSetImage', + 'GUICtrlSetLimit','GUICtrlSetOnEvent','GUICtrlSetPos', + 'GUICtrlSetResizing','GUICtrlSetState','GUICtrlSetStyle', + 'GUICtrlSetTip','GUIDelete','GUIGetCursorInfo','GUIGetMsg', + 'GUIGetStyle','GUIRegisterMsg','GUISetAccelerators()', + 'GUISetBkColor','GUISetCoord','GUISetCursor','GUISetFont', + 'GUISetHelp','GUISetIcon','GUISetOnEvent','GUISetState', + 'GUISetStyle','GUIStartGroup','GUISwitch','Hex','HotKeySet', + 'HttpSetProxy','HWnd','InetGet','InetGetSize','IniDelete','IniRead', + 'IniReadSection','IniReadSectionNames','IniRenameSection', + 'IniWrite','IniWriteSection','InputBox','Int','IsAdmin','IsArray', + 'IsBinary','IsBool','IsDeclared','IsDllStruct','IsFloat','IsHWnd', + 'IsInt','IsKeyword','IsNumber','IsObj','IsPtr','IsString','Log', + 'MemGetStats','Mod','MouseClick','MouseClickDrag','MouseDown', + 'MouseGetCursor','MouseGetPos','MouseMove','MouseUp','MouseWheel', + 'MsgBox','Number','ObjCreate','ObjEvent','ObjGet','ObjName','Opt', + 'Ping','PixelChecksum','PixelGetColor','PixelSearch','PluginClose', + 'PluginOpen','ProcessClose','ProcessExists','ProcessGetStats', + 'ProcessList','ProcessSetPriority','ProcessWait','ProcessWaitClose', + 'ProgressOff','ProgressOn','ProgressSet','Ptr','Random','RegDelete', + 'RegEnumKey','RegEnumVal','RegRead','RegWrite','Round','Run', + 'RunAs','RunAsWait','RunWait','Send','SendKeepActive','SetError', + 'SetExtended','ShellExecute','ShellExecuteWait','Shutdown','Sin', + 'Sleep','SoundPlay','SoundSetWaveVolume','SplashImageOn', + 'SplashOff','SplashTextOn','Sqrt','SRandom','StatusbarGetText', + 'StderrRead','StdinWrite','StdioClose','StdoutRead','String', + 'StringAddCR','StringCompare','StringFormat','StringInStr', + 'StringIsAlNum','StringIsAlpha','StringIsASCII','StringIsDigit', + 'StringIsFloat','StringIsInt','StringIsLower','StringIsSpace', + 'StringIsUpper','StringIsXDigit','StringLeft','StringLen', + 'StringLower','StringMid','StringRegExp','StringRegExpReplace', + 'StringReplace','StringRight','StringSplit','StringStripCR', + 'StringStripWS','StringToBinary','StringTrimLeft','StringTrimRight', + 'StringUpper','Tan','TCPAccept','TCPCloseSocket','TCPConnect', + 'TCPListen','TCPNameToIP','TCPRecv','TCPSend','TCPShutdown', + 'TCPStartup','TimerDiff','TimerInit','ToolTip','TrayCreateItem', + 'TrayCreateMenu','TrayGetMsg','TrayItemDelete','TrayItemGetHandle', + 'TrayItemGetState','TrayItemGetText','TrayItemSetOnEvent', + 'TrayItemSetState','TrayItemSetText','TraySetClick','TraySetIcon', + 'TraySetOnEvent','TraySetPauseIcon','TraySetState','TraySetToolTip', + 'TrayTip','UBound','UDPBind','UDPCloseSocket','UDPOpen','UDPRecv', + 'UDPSend','UDPShutdown','UDPStartup','VarGetType','WinActivate', + 'WinActive','WinClose','WinExists','WinFlash','WinGetCaretPos', + 'WinGetClassList','WinGetClientSize','WinGetHandle','WinGetPos', + 'WinGetProcess','WinGetState','WinGetText','WinGetTitle','WinKill', + 'WinList','WinMenuSelectItem','WinMinimizeAll','WinMinimizeAllUndo', + 'WinMove','WinSetOnTop','WinSetState','WinSetTitle','WinSetTrans', + 'WinWait','WinWaitActive','WinWaitClose','WinWaitNotActive' + ), + 4 => array( + 'ArrayAdd','ArrayBinarySearch','ArrayConcatenate','ArrayDelete', + 'ArrayDisplay','ArrayFindAll','ArrayInsert','ArrayMax', + 'ArrayMaxIndex','ArrayMin','ArrayMinIndex','ArrayPop','ArrayPush', + 'ArrayReverse','ArraySearch','ArraySort','ArraySwap','ArrayToClip', + 'ArrayToString','ArrayTrim','ChooseColor','ChooseFont', + 'ClipBoard_ChangeChain','ClipBoard_Close','ClipBoard_CountFormats', + 'ClipBoard_Empty','ClipBoard_EnumFormats','ClipBoard_FormatStr', + 'ClipBoard_GetData','ClipBoard_GetDataEx','ClipBoard_GetFormatName', + 'ClipBoard_GetOpenWindow','ClipBoard_GetOwner', + 'ClipBoard_GetPriorityFormat','ClipBoard_GetSequenceNumber', + 'ClipBoard_GetViewer','ClipBoard_IsFormatAvailable', + 'ClipBoard_Open','ClipBoard_RegisterFormat','ClipBoard_SetData', + 'ClipBoard_SetDataEx','ClipBoard_SetViewer','ClipPutFile', + 'ColorConvertHSLtoRGB','ColorConvertRGBtoHSL','ColorGetBlue', + 'ColorGetGreen','ColorGetRed','Date_Time_CompareFileTime', + 'Date_Time_DOSDateTimeToArray','Date_Time_DOSDateTimeToFileTime', + 'Date_Time_DOSDateTimeToStr','Date_Time_DOSDateToArray', + 'Date_Time_DOSDateToStr','Date_Time_DOSTimeToArray', + 'Date_Time_DOSTimeToStr','Date_Time_EncodeFileTime', + 'Date_Time_EncodeSystemTime','Date_Time_FileTimeToArray', + 'Date_Time_FileTimeToDOSDateTime', + 'Date_Time_FileTimeToLocalFileTime','Date_Time_FileTimeToStr', + 'Date_Time_FileTimeToSystemTime','Date_Time_GetFileTime', + 'Date_Time_GetLocalTime','Date_Time_GetSystemTime', + 'Date_Time_GetSystemTimeAdjustment', + 'Date_Time_GetSystemTimeAsFileTime', + 'Date_Time_GetSystemTimes','Date_Time_GetTickCount', + 'Date_Time_GetTimeZoneInformation', + 'Date_Time_LocalFileTimeToFileTime','Date_Time_SetFileTime', + 'Date_Time_SetLocalTime','Date_Time_SetSystemTime', + 'Date_Time_SetSystemTimeAdjustment', + 'Date_Time_SetTimeZoneInformation','Date_Time_SystemTimeToArray', + 'Date_Time_SystemTimeToDateStr','Date_Time_SystemTimeToDateTimeStr', + 'Date_Time_SystemTimeToFileTime','Date_Time_SystemTimeToTimeStr', + 'Date_Time_SystemTimeToTzSpecificLocalTime', + 'Date_Time_TzSpecificLocalTimeToSystemTime','DateAdd', + 'DateDayOfWeek','DateDaysInMonth','DateDiff','DateIsLeapYear', + 'DateIsValid','DateTimeFormat','DateTimeSplit','DateToDayOfWeek', + 'DateToDayOfWeekISO','DateToDayValue','DateToMonth', + 'DayValueToDate','DebugBugReportEnv','DebugOut','DebugSetup', + 'Degree','EventLog__Backup','EventLog__Clear','EventLog__Close', + 'EventLog__Count','EventLog__DeregisterSource','EventLog__Full', + 'EventLog__Notify','EventLog__Oldest','EventLog__Open', + 'EventLog__OpenBackup','EventLog__Read','EventLog__RegisterSource', + 'EventLog__Report','FileCountLines','FileCreate','FileListToArray', + 'FilePrint','FileReadToArray','FileWriteFromArray', + 'FileWriteLog','FileWriteToLine','GDIPlus_ArrowCapCreate', + 'GDIPlus_ArrowCapDispose','GDIPlus_ArrowCapGetFillState', + 'GDIPlus_ArrowCapGetHeight','GDIPlus_ArrowCapGetMiddleInset', + 'GDIPlus_ArrowCapGetWidth','GDIPlus_ArrowCapSetFillState', + 'GDIPlus_ArrowCapSetHeight','GDIPlus_ArrowCapSetMiddleInset', + 'GDIPlus_ArrowCapSetWidth','GDIPlus_BitmapCloneArea', + 'GDIPlus_BitmapCreateFromFile','GDIPlus_BitmapCreateFromGraphics', + 'GDIPlus_BitmapCreateFromHBITMAP', + 'GDIPlus_BitmapCreateHBITMAPFromBitmap','GDIPlus_BitmapDispose', + 'GDIPlus_BitmapLockBits','GDIPlus_BitmapUnlockBits', + 'GDIPlus_BrushClone','GDIPlus_BrushCreateSolid', + 'GDIPlus_BrushDispose','GDIPlus_BrushGetType', + 'GDIPlus_CustomLineCapDispose','GDIPlus_Decoders', + 'GDIPlus_DecodersGetCount','GDIPlus_DecodersGetSize', + 'GDIPlus_Encoders','GDIPlus_EncodersGetCLSID', + 'GDIPlus_EncodersGetCount','GDIPlus_EncodersGetParamList', + 'GDIPlus_EncodersGetParamListSize','GDIPlus_EncodersGetSize', + 'GDIPlus_FontCreate','GDIPlus_FontDispose', + 'GDIPlus_FontFamilyCreate','GDIPlus_FontFamilyDispose', + 'GDIPlus_GraphicsClear','GDIPlus_GraphicsCreateFromHDC', + 'GDIPlus_GraphicsCreateFromHWND','GDIPlus_GraphicsDispose', + 'GDIPlus_GraphicsDrawArc','GDIPlus_GraphicsDrawBezier', + 'GDIPlus_GraphicsDrawClosedCurve','GDIPlus_GraphicsDrawCurve', + 'GDIPlus_GraphicsDrawEllipse','GDIPlus_GraphicsDrawImage', + 'GDIPlus_GraphicsDrawImageRect','GDIPlus_GraphicsDrawImageRectRect', + 'GDIPlus_GraphicsDrawLine','GDIPlus_GraphicsDrawPie', + 'GDIPlus_GraphicsDrawPolygon','GDIPlus_GraphicsDrawRect', + 'GDIPlus_GraphicsDrawString','GDIPlus_GraphicsDrawStringEx', + 'GDIPlus_GraphicsFillClosedCurve','GDIPlus_GraphicsFillEllipse', + 'GDIPlus_GraphicsFillPie','GDIPlus_GraphicsFillRect', + 'GDIPlus_GraphicsGetDC','GDIPlus_GraphicsGetSmoothingMode', + 'GDIPlus_GraphicsMeasureString','GDIPlus_GraphicsReleaseDC', + 'GDIPlus_GraphicsSetSmoothingMode','GDIPlus_GraphicsSetTransform', + 'GDIPlus_ImageDispose','GDIPlus_ImageGetGraphicsContext', + 'GDIPlus_ImageGetHeight','GDIPlus_ImageGetWidth', + 'GDIPlus_ImageLoadFromFile','GDIPlus_ImageSaveToFile', + 'GDIPlus_ImageSaveToFileEx','GDIPlus_MatrixCreate', + 'GDIPlus_MatrixDispose','GDIPlus_MatrixRotate','GDIPlus_ParamAdd', + 'GDIPlus_ParamInit','GDIPlus_PenCreate','GDIPlus_PenDispose', + 'GDIPlus_PenGetAlignment','GDIPlus_PenGetColor', + 'GDIPlus_PenGetCustomEndCap','GDIPlus_PenGetDashCap', + 'GDIPlus_PenGetDashStyle','GDIPlus_PenGetEndCap', + 'GDIPlus_PenGetWidth','GDIPlus_PenSetAlignment', + 'GDIPlus_PenSetColor','GDIPlus_PenSetCustomEndCap', + 'GDIPlus_PenSetDashCap','GDIPlus_PenSetDashStyle', + 'GDIPlus_PenSetEndCap','GDIPlus_PenSetWidth','GDIPlus_RectFCreate', + 'GDIPlus_Shutdown','GDIPlus_Startup','GDIPlus_StringFormatCreate', + 'GDIPlus_StringFormatDispose','GetIP','GUICtrlAVI_Close', + 'GUICtrlAVI_Create','GUICtrlAVI_Destroy','GUICtrlAVI_Open', + 'GUICtrlAVI_OpenEx','GUICtrlAVI_Play','GUICtrlAVI_Seek', + 'GUICtrlAVI_Show','GUICtrlAVI_Stop','GUICtrlButton_Click', + 'GUICtrlButton_Create','GUICtrlButton_Destroy', + 'GUICtrlButton_Enable','GUICtrlButton_GetCheck', + 'GUICtrlButton_GetFocus','GUICtrlButton_GetIdealSize', + 'GUICtrlButton_GetImage','GUICtrlButton_GetImageList', + 'GUICtrlButton_GetState','GUICtrlButton_GetText', + 'GUICtrlButton_GetTextMargin','GUICtrlButton_SetCheck', + 'GUICtrlButton_SetFocus','GUICtrlButton_SetImage', + 'GUICtrlButton_SetImageList','GUICtrlButton_SetSize', + 'GUICtrlButton_SetState','GUICtrlButton_SetStyle', + 'GUICtrlButton_SetText','GUICtrlButton_SetTextMargin', + 'GUICtrlButton_Show','GUICtrlComboBox_AddDir', + 'GUICtrlComboBox_AddString','GUICtrlComboBox_AutoComplete', + 'GUICtrlComboBox_BeginUpdate','GUICtrlComboBox_Create', + 'GUICtrlComboBox_DeleteString','GUICtrlComboBox_Destroy', + 'GUICtrlComboBox_EndUpdate','GUICtrlComboBox_FindString', + 'GUICtrlComboBox_FindStringExact','GUICtrlComboBox_GetComboBoxInfo', + 'GUICtrlComboBox_GetCount','GUICtrlComboBox_GetCurSel', + 'GUICtrlComboBox_GetDroppedControlRect', + 'GUICtrlComboBox_GetDroppedControlRectEx', + 'GUICtrlComboBox_GetDroppedState','GUICtrlComboBox_GetDroppedWidth', + 'GUICtrlComboBox_GetEditSel','GUICtrlComboBox_GetEditText', + 'GUICtrlComboBox_GetExtendedUI', + 'GUICtrlComboBox_GetHorizontalExtent', + 'GUICtrlComboBox_GetItemHeight','GUICtrlComboBox_GetLBText', + 'GUICtrlComboBox_GetLBTextLen','GUICtrlComboBox_GetList', + 'GUICtrlComboBox_GetListArray','GUICtrlComboBox_GetLocale', + 'GUICtrlComboBox_GetLocaleCountry','GUICtrlComboBox_GetLocaleLang', + 'GUICtrlComboBox_GetLocalePrimLang', + 'GUICtrlComboBox_GetLocaleSubLang','GUICtrlComboBox_GetMinVisible', + 'GUICtrlComboBox_GetTopIndex','GUICtrlComboBox_InitStorage', + 'GUICtrlComboBox_InsertString','GUICtrlComboBox_LimitText', + 'GUICtrlComboBox_ReplaceEditSel','GUICtrlComboBox_ResetContent', + 'GUICtrlComboBox_SelectString','GUICtrlComboBox_SetCurSel', + 'GUICtrlComboBox_SetDroppedWidth','GUICtrlComboBox_SetEditSel', + 'GUICtrlComboBox_SetEditText','GUICtrlComboBox_SetExtendedUI', + 'GUICtrlComboBox_SetHorizontalExtent', + 'GUICtrlComboBox_SetItemHeight','GUICtrlComboBox_SetMinVisible', + 'GUICtrlComboBox_SetTopIndex','GUICtrlComboBox_ShowDropDown', + 'GUICtrlComboBoxEx_AddDir','GUICtrlComboBoxEx_AddString', + 'GUICtrlComboBoxEx_BeginUpdate','GUICtrlComboBoxEx_Create', + 'GUICtrlComboBoxEx_CreateSolidBitMap', + 'GUICtrlComboBoxEx_DeleteString','GUICtrlComboBoxEx_Destroy', + 'GUICtrlComboBoxEx_EndUpdate','GUICtrlComboBoxEx_FindStringExact', + 'GUICtrlComboBoxEx_GetComboBoxInfo', + 'GUICtrlComboBoxEx_GetComboControl','GUICtrlComboBoxEx_GetCount', + 'GUICtrlComboBoxEx_GetCurSel', + 'GUICtrlComboBoxEx_GetDroppedControlRect', + 'GUICtrlComboBoxEx_GetDroppedControlRectEx', + 'GUICtrlComboBoxEx_GetDroppedState', + 'GUICtrlComboBoxEx_GetDroppedWidth', + 'GUICtrlComboBoxEx_GetEditControl','GUICtrlComboBoxEx_GetEditSel', + 'GUICtrlComboBoxEx_GetEditText', + 'GUICtrlComboBoxEx_GetExtendedStyle', + 'GUICtrlComboBoxEx_GetExtendedUI','GUICtrlComboBoxEx_GetImageList', + 'GUICtrlComboBoxEx_GetItem','GUICtrlComboBoxEx_GetItemEx', + 'GUICtrlComboBoxEx_GetItemHeight','GUICtrlComboBoxEx_GetItemImage', + 'GUICtrlComboBoxEx_GetItemIndent', + 'GUICtrlComboBoxEx_GetItemOverlayImage', + 'GUICtrlComboBoxEx_GetItemParam', + 'GUICtrlComboBoxEx_GetItemSelectedImage', + 'GUICtrlComboBoxEx_GetItemText','GUICtrlComboBoxEx_GetItemTextLen', + 'GUICtrlComboBoxEx_GetList','GUICtrlComboBoxEx_GetListArray', + 'GUICtrlComboBoxEx_GetLocale','GUICtrlComboBoxEx_GetLocaleCountry', + 'GUICtrlComboBoxEx_GetLocaleLang', + 'GUICtrlComboBoxEx_GetLocalePrimLang', + 'GUICtrlComboBoxEx_GetLocaleSubLang', + 'GUICtrlComboBoxEx_GetMinVisible','GUICtrlComboBoxEx_GetTopIndex', + 'GUICtrlComboBoxEx_InitStorage','GUICtrlComboBoxEx_InsertString', + 'GUICtrlComboBoxEx_LimitText','GUICtrlComboBoxEx_ReplaceEditSel', + 'GUICtrlComboBoxEx_ResetContent','GUICtrlComboBoxEx_SetCurSel', + 'GUICtrlComboBoxEx_SetDroppedWidth','GUICtrlComboBoxEx_SetEditSel', + 'GUICtrlComboBoxEx_SetEditText', + 'GUICtrlComboBoxEx_SetExtendedStyle', + 'GUICtrlComboBoxEx_SetExtendedUI','GUICtrlComboBoxEx_SetImageList', + 'GUICtrlComboBoxEx_SetItem','GUICtrlComboBoxEx_SetItemEx', + 'GUICtrlComboBoxEx_SetItemHeight','GUICtrlComboBoxEx_SetItemImage', + 'GUICtrlComboBoxEx_SetItemIndent', + 'GUICtrlComboBoxEx_SetItemOverlayImage', + 'GUICtrlComboBoxEx_SetItemParam', + 'GUICtrlComboBoxEx_SetItemSelectedImage', + 'GUICtrlComboBoxEx_SetMinVisible','GUICtrlComboBoxEx_SetTopIndex', + 'GUICtrlComboBoxEx_ShowDropDown','GUICtrlDTP_Create', + 'GUICtrlDTP_Destroy','GUICtrlDTP_GetMCColor','GUICtrlDTP_GetMCFont', + 'GUICtrlDTP_GetMonthCal','GUICtrlDTP_GetRange', + 'GUICtrlDTP_GetRangeEx','GUICtrlDTP_GetSystemTime', + 'GUICtrlDTP_GetSystemTimeEx','GUICtrlDTP_SetFormat', + 'GUICtrlDTP_SetMCColor','GUICtrlDTP_SetMCFont', + 'GUICtrlDTP_SetRange','GUICtrlDTP_SetRangeEx', + 'GUICtrlDTP_SetSystemTime','GUICtrlDTP_SetSystemTimeEx', + 'GUICtrlEdit_AppendText','GUICtrlEdit_BeginUpdate', + 'GUICtrlEdit_CanUndo','GUICtrlEdit_CharFromPos', + 'GUICtrlEdit_Create','GUICtrlEdit_Destroy', + 'GUICtrlEdit_EmptyUndoBuffer','GUICtrlEdit_EndUpdate', + 'GUICtrlEdit_Find','GUICtrlEdit_FmtLines', + 'GUICtrlEdit_GetFirstVisibleLine','GUICtrlEdit_GetLimitText', + 'GUICtrlEdit_GetLine','GUICtrlEdit_GetLineCount', + 'GUICtrlEdit_GetMargins','GUICtrlEdit_GetModify', + 'GUICtrlEdit_GetPasswordChar','GUICtrlEdit_GetRECT', + 'GUICtrlEdit_GetRECTEx','GUICtrlEdit_GetSel','GUICtrlEdit_GetText', + 'GUICtrlEdit_GetTextLen','GUICtrlEdit_HideBalloonTip', + 'GUICtrlEdit_InsertText','GUICtrlEdit_LineFromChar', + 'GUICtrlEdit_LineIndex','GUICtrlEdit_LineLength', + 'GUICtrlEdit_LineScroll','GUICtrlEdit_PosFromChar', + 'GUICtrlEdit_ReplaceSel','GUICtrlEdit_Scroll', + 'GUICtrlEdit_SetLimitText','GUICtrlEdit_SetMargins', + 'GUICtrlEdit_SetModify','GUICtrlEdit_SetPasswordChar', + 'GUICtrlEdit_SetReadOnly','GUICtrlEdit_SetRECT', + 'GUICtrlEdit_SetRECTEx','GUICtrlEdit_SetRECTNP', + 'GUICtrlEdit_SetRectNPEx','GUICtrlEdit_SetSel', + 'GUICtrlEdit_SetTabStops','GUICtrlEdit_SetText', + 'GUICtrlEdit_ShowBalloonTip','GUICtrlEdit_Undo', + 'GUICtrlHeader_AddItem','GUICtrlHeader_ClearFilter', + 'GUICtrlHeader_ClearFilterAll','GUICtrlHeader_Create', + 'GUICtrlHeader_CreateDragImage','GUICtrlHeader_DeleteItem', + 'GUICtrlHeader_Destroy','GUICtrlHeader_EditFilter', + 'GUICtrlHeader_GetBitmapMargin','GUICtrlHeader_GetImageList', + 'GUICtrlHeader_GetItem','GUICtrlHeader_GetItemAlign', + 'GUICtrlHeader_GetItemBitmap','GUICtrlHeader_GetItemCount', + 'GUICtrlHeader_GetItemDisplay','GUICtrlHeader_GetItemFlags', + 'GUICtrlHeader_GetItemFormat','GUICtrlHeader_GetItemImage', + 'GUICtrlHeader_GetItemOrder','GUICtrlHeader_GetItemParam', + 'GUICtrlHeader_GetItemRect','GUICtrlHeader_GetItemRectEx', + 'GUICtrlHeader_GetItemText','GUICtrlHeader_GetItemWidth', + 'GUICtrlHeader_GetOrderArray','GUICtrlHeader_GetUnicodeFormat', + 'GUICtrlHeader_HitTest','GUICtrlHeader_InsertItem', + 'GUICtrlHeader_Layout','GUICtrlHeader_OrderToIndex', + 'GUICtrlHeader_SetBitmapMargin', + 'GUICtrlHeader_SetFilterChangeTimeout', + 'GUICtrlHeader_SetHotDivider','GUICtrlHeader_SetImageList', + 'GUICtrlHeader_SetItem','GUICtrlHeader_SetItemAlign', + 'GUICtrlHeader_SetItemBitmap','GUICtrlHeader_SetItemDisplay', + 'GUICtrlHeader_SetItemFlags','GUICtrlHeader_SetItemFormat', + 'GUICtrlHeader_SetItemImage','GUICtrlHeader_SetItemOrder', + 'GUICtrlHeader_SetItemParam','GUICtrlHeader_SetItemText', + 'GUICtrlHeader_SetItemWidth','GUICtrlHeader_SetOrderArray', + 'GUICtrlHeader_SetUnicodeFormat','GUICtrlIpAddress_ClearAddress', + 'GUICtrlIpAddress_Create','GUICtrlIpAddress_Destroy', + 'GUICtrlIpAddress_Get','GUICtrlIpAddress_GetArray', + 'GUICtrlIpAddress_GetEx','GUICtrlIpAddress_IsBlank', + 'GUICtrlIpAddress_Set','GUICtrlIpAddress_SetArray', + 'GUICtrlIpAddress_SetEx','GUICtrlIpAddress_SetFocus', + 'GUICtrlIpAddress_SetFont','GUICtrlIpAddress_SetRange', + 'GUICtrlIpAddress_ShowHide','GUICtrlListBox_AddFile', + 'GUICtrlListBox_AddString','GUICtrlListBox_BeginUpdate', + 'GUICtrlListBox_Create','GUICtrlListBox_DeleteString', + 'GUICtrlListBox_Destroy','GUICtrlListBox_Dir', + 'GUICtrlListBox_EndUpdate','GUICtrlListBox_FindInText', + 'GUICtrlListBox_FindString','GUICtrlListBox_GetAnchorIndex', + 'GUICtrlListBox_GetCaretIndex','GUICtrlListBox_GetCount', + 'GUICtrlListBox_GetCurSel','GUICtrlListBox_GetHorizontalExtent', + 'GUICtrlListBox_GetItemData','GUICtrlListBox_GetItemHeight', + 'GUICtrlListBox_GetItemRect','GUICtrlListBox_GetItemRectEx', + 'GUICtrlListBox_GetListBoxInfo','GUICtrlListBox_GetLocale', + 'GUICtrlListBox_GetLocaleCountry','GUICtrlListBox_GetLocaleLang', + 'GUICtrlListBox_GetLocalePrimLang', + 'GUICtrlListBox_GetLocaleSubLang','GUICtrlListBox_GetSel', + 'GUICtrlListBox_GetSelCount','GUICtrlListBox_GetSelItems', + 'GUICtrlListBox_GetSelItemsText','GUICtrlListBox_GetText', + 'GUICtrlListBox_GetTextLen','GUICtrlListBox_GetTopIndex', + 'GUICtrlListBox_InitStorage','GUICtrlListBox_InsertString', + 'GUICtrlListBox_ItemFromPoint','GUICtrlListBox_ReplaceString', + 'GUICtrlListBox_ResetContent','GUICtrlListBox_SelectString', + 'GUICtrlListBox_SelItemRange','GUICtrlListBox_SelItemRangeEx', + 'GUICtrlListBox_SetAnchorIndex','GUICtrlListBox_SetCaretIndex', + 'GUICtrlListBox_SetColumnWidth','GUICtrlListBox_SetCurSel', + 'GUICtrlListBox_SetHorizontalExtent','GUICtrlListBox_SetItemData', + 'GUICtrlListBox_SetItemHeight','GUICtrlListBox_SetLocale', + 'GUICtrlListBox_SetSel','GUICtrlListBox_SetTabStops', + 'GUICtrlListBox_SetTopIndex','GUICtrlListBox_Sort', + 'GUICtrlListBox_SwapString','GUICtrlListBox_UpdateHScroll', + 'GUICtrlListView_AddArray','GUICtrlListView_AddColumn', + 'GUICtrlListView_AddItem','GUICtrlListView_AddSubItem', + 'GUICtrlListView_ApproximateViewHeight', + 'GUICtrlListView_ApproximateViewRect', + 'GUICtrlListView_ApproximateViewWidth','GUICtrlListView_Arrange', + 'GUICtrlListView_BeginUpdate','GUICtrlListView_CancelEditLabel', + 'GUICtrlListView_ClickItem','GUICtrlListView_CopyItems', + 'GUICtrlListView_Create','GUICtrlListView_CreateDragImage', + 'GUICtrlListView_CreateSolidBitMap', + 'GUICtrlListView_DeleteAllItems','GUICtrlListView_DeleteColumn', + 'GUICtrlListView_DeleteItem','GUICtrlListView_DeleteItemsSelected', + 'GUICtrlListView_Destroy','GUICtrlListView_DrawDragImage', + 'GUICtrlListView_EditLabel','GUICtrlListView_EnableGroupView', + 'GUICtrlListView_EndUpdate','GUICtrlListView_EnsureVisible', + 'GUICtrlListView_FindInText','GUICtrlListView_FindItem', + 'GUICtrlListView_FindNearest','GUICtrlListView_FindParam', + 'GUICtrlListView_FindText','GUICtrlListView_GetBkColor', + 'GUICtrlListView_GetBkImage','GUICtrlListView_GetCallbackMask', + 'GUICtrlListView_GetColumn','GUICtrlListView_GetColumnCount', + 'GUICtrlListView_GetColumnOrder', + 'GUICtrlListView_GetColumnOrderArray', + 'GUICtrlListView_GetColumnWidth','GUICtrlListView_GetCounterPage', + 'GUICtrlListView_GetEditControl', + 'GUICtrlListView_GetExtendedListViewStyle', + 'GUICtrlListView_GetGroupInfo', + 'GUICtrlListView_GetGroupViewEnabled','GUICtrlListView_GetHeader', + 'GUICtrlListView_GetHotCursor','GUICtrlListView_GetHotItem', + 'GUICtrlListView_GetHoverTime','GUICtrlListView_GetImageList', + 'GUICtrlListView_GetISearchString','GUICtrlListView_GetItem', + 'GUICtrlListView_GetItemChecked','GUICtrlListView_GetItemCount', + 'GUICtrlListView_GetItemCut','GUICtrlListView_GetItemDropHilited', + 'GUICtrlListView_GetItemEx','GUICtrlListView_GetItemFocused', + 'GUICtrlListView_GetItemGroupID','GUICtrlListView_GetItemImage', + 'GUICtrlListView_GetItemIndent','GUICtrlListView_GetItemParam', + 'GUICtrlListView_GetItemPosition', + 'GUICtrlListView_GetItemPositionX', + 'GUICtrlListView_GetItemPositionY','GUICtrlListView_GetItemRect', + 'GUICtrlListView_GetItemRectEx','GUICtrlListView_GetItemSelected', + 'GUICtrlListView_GetItemSpacing','GUICtrlListView_GetItemSpacingX', + 'GUICtrlListView_GetItemSpacingY','GUICtrlListView_GetItemState', + 'GUICtrlListView_GetItemStateImage','GUICtrlListView_GetItemText', + 'GUICtrlListView_GetItemTextArray', + 'GUICtrlListView_GetItemTextString','GUICtrlListView_GetNextItem', + 'GUICtrlListView_GetNumberOfWorkAreas','GUICtrlListView_GetOrigin', + 'GUICtrlListView_GetOriginX','GUICtrlListView_GetOriginY', + 'GUICtrlListView_GetOutlineColor', + 'GUICtrlListView_GetSelectedColumn', + 'GUICtrlListView_GetSelectedCount', + 'GUICtrlListView_GetSelectedIndices', + 'GUICtrlListView_GetSelectionMark','GUICtrlListView_GetStringWidth', + 'GUICtrlListView_GetSubItemRect','GUICtrlListView_GetTextBkColor', + 'GUICtrlListView_GetTextColor','GUICtrlListView_GetToolTips', + 'GUICtrlListView_GetTopIndex','GUICtrlListView_GetUnicodeFormat', + 'GUICtrlListView_GetView','GUICtrlListView_GetViewDetails', + 'GUICtrlListView_GetViewLarge','GUICtrlListView_GetViewList', + 'GUICtrlListView_GetViewRect','GUICtrlListView_GetViewSmall', + 'GUICtrlListView_GetViewTile','GUICtrlListView_HideColumn', + 'GUICtrlListView_HitTest','GUICtrlListView_InsertColumn', + 'GUICtrlListView_InsertGroup','GUICtrlListView_InsertItem', + 'GUICtrlListView_JustifyColumn','GUICtrlListView_MapIDToIndex', + 'GUICtrlListView_MapIndexToID','GUICtrlListView_RedrawItems', + 'GUICtrlListView_RegisterSortCallBack', + 'GUICtrlListView_RemoveAllGroups','GUICtrlListView_RemoveGroup', + 'GUICtrlListView_Scroll','GUICtrlListView_SetBkColor', + 'GUICtrlListView_SetBkImage','GUICtrlListView_SetCallBackMask', + 'GUICtrlListView_SetColumn','GUICtrlListView_SetColumnOrder', + 'GUICtrlListView_SetColumnOrderArray', + 'GUICtrlListView_SetColumnWidth', + 'GUICtrlListView_SetExtendedListViewStyle', + 'GUICtrlListView_SetGroupInfo','GUICtrlListView_SetHotItem', + 'GUICtrlListView_SetHoverTime','GUICtrlListView_SetIconSpacing', + 'GUICtrlListView_SetImageList','GUICtrlListView_SetItem', + 'GUICtrlListView_SetItemChecked','GUICtrlListView_SetItemCount', + 'GUICtrlListView_SetItemCut','GUICtrlListView_SetItemDropHilited', + 'GUICtrlListView_SetItemEx','GUICtrlListView_SetItemFocused', + 'GUICtrlListView_SetItemGroupID','GUICtrlListView_SetItemImage', + 'GUICtrlListView_SetItemIndent','GUICtrlListView_SetItemParam', + 'GUICtrlListView_SetItemPosition', + 'GUICtrlListView_SetItemPosition32', + 'GUICtrlListView_SetItemSelected','GUICtrlListView_SetItemState', + 'GUICtrlListView_SetItemStateImage','GUICtrlListView_SetItemText', + 'GUICtrlListView_SetOutlineColor', + 'GUICtrlListView_SetSelectedColumn', + 'GUICtrlListView_SetSelectionMark','GUICtrlListView_SetTextBkColor', + 'GUICtrlListView_SetTextColor','GUICtrlListView_SetToolTips', + 'GUICtrlListView_SetUnicodeFormat','GUICtrlListView_SetView', + 'GUICtrlListView_SetWorkAreas','GUICtrlListView_SimpleSort', + 'GUICtrlListView_SortItems','GUICtrlListView_SubItemHitTest', + 'GUICtrlListView_UnRegisterSortCallBack', + 'GUICtrlMenu_AddMenuItem','GUICtrlMenu_AppendMenu', + 'GUICtrlMenu_CheckMenuItem','GUICtrlMenu_CheckRadioItem', + 'GUICtrlMenu_CreateMenu','GUICtrlMenu_CreatePopup', + 'GUICtrlMenu_DeleteMenu','GUICtrlMenu_DestroyMenu', + 'GUICtrlMenu_DrawMenuBar','GUICtrlMenu_EnableMenuItem', + 'GUICtrlMenu_FindItem','GUICtrlMenu_FindParent', + 'GUICtrlMenu_GetItemBmp','GUICtrlMenu_GetItemBmpChecked', + 'GUICtrlMenu_GetItemBmpUnchecked','GUICtrlMenu_GetItemChecked', + 'GUICtrlMenu_GetItemCount','GUICtrlMenu_GetItemData', + 'GUICtrlMenu_GetItemDefault','GUICtrlMenu_GetItemDisabled', + 'GUICtrlMenu_GetItemEnabled','GUICtrlMenu_GetItemGrayed', + 'GUICtrlMenu_GetItemHighlighted','GUICtrlMenu_GetItemID', + 'GUICtrlMenu_GetItemInfo','GUICtrlMenu_GetItemRect', + 'GUICtrlMenu_GetItemRectEx','GUICtrlMenu_GetItemState', + 'GUICtrlMenu_GetItemStateEx','GUICtrlMenu_GetItemSubMenu', + 'GUICtrlMenu_GetItemText','GUICtrlMenu_GetItemType', + 'GUICtrlMenu_GetMenu','GUICtrlMenu_GetMenuBackground', + 'GUICtrlMenu_GetMenuBarInfo','GUICtrlMenu_GetMenuContextHelpID', + 'GUICtrlMenu_GetMenuData','GUICtrlMenu_GetMenuDefaultItem', + 'GUICtrlMenu_GetMenuHeight','GUICtrlMenu_GetMenuInfo', + 'GUICtrlMenu_GetMenuStyle','GUICtrlMenu_GetSystemMenu', + 'GUICtrlMenu_InsertMenuItem','GUICtrlMenu_InsertMenuItemEx', + 'GUICtrlMenu_IsMenu','GUICtrlMenu_LoadMenu', + 'GUICtrlMenu_MapAccelerator','GUICtrlMenu_MenuItemFromPoint', + 'GUICtrlMenu_RemoveMenu','GUICtrlMenu_SetItemBitmaps', + 'GUICtrlMenu_SetItemBmp','GUICtrlMenu_SetItemBmpChecked', + 'GUICtrlMenu_SetItemBmpUnchecked','GUICtrlMenu_SetItemChecked', + 'GUICtrlMenu_SetItemData','GUICtrlMenu_SetItemDefault', + 'GUICtrlMenu_SetItemDisabled','GUICtrlMenu_SetItemEnabled', + 'GUICtrlMenu_SetItemGrayed','GUICtrlMenu_SetItemHighlighted', + 'GUICtrlMenu_SetItemID','GUICtrlMenu_SetItemInfo', + 'GUICtrlMenu_SetItemState','GUICtrlMenu_SetItemSubMenu', + 'GUICtrlMenu_SetItemText','GUICtrlMenu_SetItemType', + 'GUICtrlMenu_SetMenu','GUICtrlMenu_SetMenuBackground', + 'GUICtrlMenu_SetMenuContextHelpID','GUICtrlMenu_SetMenuData', + 'GUICtrlMenu_SetMenuDefaultItem','GUICtrlMenu_SetMenuHeight', + 'GUICtrlMenu_SetMenuInfo','GUICtrlMenu_SetMenuStyle', + 'GUICtrlMenu_TrackPopupMenu','GUICtrlMonthCal_Create', + 'GUICtrlMonthCal_Destroy','GUICtrlMonthCal_GetColor', + 'GUICtrlMonthCal_GetColorArray','GUICtrlMonthCal_GetCurSel', + 'GUICtrlMonthCal_GetCurSelStr','GUICtrlMonthCal_GetFirstDOW', + 'GUICtrlMonthCal_GetFirstDOWStr','GUICtrlMonthCal_GetMaxSelCount', + 'GUICtrlMonthCal_GetMaxTodayWidth', + 'GUICtrlMonthCal_GetMinReqHeight','GUICtrlMonthCal_GetMinReqRect', + 'GUICtrlMonthCal_GetMinReqRectArray', + 'GUICtrlMonthCal_GetMinReqWidth','GUICtrlMonthCal_GetMonthDelta', + 'GUICtrlMonthCal_GetMonthRange','GUICtrlMonthCal_GetMonthRangeMax', + 'GUICtrlMonthCal_GetMonthRangeMaxStr', + 'GUICtrlMonthCal_GetMonthRangeMin', + 'GUICtrlMonthCal_GetMonthRangeMinStr', + 'GUICtrlMonthCal_GetMonthRangeSpan','GUICtrlMonthCal_GetRange', + 'GUICtrlMonthCal_GetRangeMax','GUICtrlMonthCal_GetRangeMaxStr', + 'GUICtrlMonthCal_GetRangeMin','GUICtrlMonthCal_GetRangeMinStr', + 'GUICtrlMonthCal_GetSelRange','GUICtrlMonthCal_GetSelRangeMax', + 'GUICtrlMonthCal_GetSelRangeMaxStr', + 'GUICtrlMonthCal_GetSelRangeMin', + 'GUICtrlMonthCal_GetSelRangeMinStr','GUICtrlMonthCal_GetToday', + 'GUICtrlMonthCal_GetTodayStr','GUICtrlMonthCal_GetUnicodeFormat', + 'GUICtrlMonthCal_HitTest','GUICtrlMonthCal_SetColor', + 'GUICtrlMonthCal_SetCurSel','GUICtrlMonthCal_SetDayState', + 'GUICtrlMonthCal_SetFirstDOW','GUICtrlMonthCal_SetMaxSelCount', + 'GUICtrlMonthCal_SetMonthDelta','GUICtrlMonthCal_SetRange', + 'GUICtrlMonthCal_SetSelRange','GUICtrlMonthCal_SetToday', + 'GUICtrlMonthCal_SetUnicodeFormat','GUICtrlRebar_AddBand', + 'GUICtrlRebar_AddToolBarBand','GUICtrlRebar_BeginDrag', + 'GUICtrlRebar_Create','GUICtrlRebar_DeleteBand', + 'GUICtrlRebar_Destroy','GUICtrlRebar_DragMove', + 'GUICtrlRebar_EndDrag','GUICtrlRebar_GetBandBackColor', + 'GUICtrlRebar_GetBandBorders','GUICtrlRebar_GetBandBordersEx', + 'GUICtrlRebar_GetBandChildHandle','GUICtrlRebar_GetBandChildSize', + 'GUICtrlRebar_GetBandCount','GUICtrlRebar_GetBandForeColor', + 'GUICtrlRebar_GetBandHeaderSize','GUICtrlRebar_GetBandID', + 'GUICtrlRebar_GetBandIdealSize','GUICtrlRebar_GetBandLength', + 'GUICtrlRebar_GetBandLParam','GUICtrlRebar_GetBandMargins', + 'GUICtrlRebar_GetBandMarginsEx','GUICtrlRebar_GetBandRect', + 'GUICtrlRebar_GetBandRectEx','GUICtrlRebar_GetBandStyle', + 'GUICtrlRebar_GetBandStyleBreak', + 'GUICtrlRebar_GetBandStyleChildEdge', + 'GUICtrlRebar_GetBandStyleFixedBMP', + 'GUICtrlRebar_GetBandStyleFixedSize', + 'GUICtrlRebar_GetBandStyleGripperAlways', + 'GUICtrlRebar_GetBandStyleHidden', + 'GUICtrlRebar_GetBandStyleHideTitle', + 'GUICtrlRebar_GetBandStyleNoGripper', + 'GUICtrlRebar_GetBandStyleTopAlign', + 'GUICtrlRebar_GetBandStyleUseChevron', + 'GUICtrlRebar_GetBandStyleVariableHeight', + 'GUICtrlRebar_GetBandText','GUICtrlRebar_GetBarHeight', + 'GUICtrlRebar_GetBKColor','GUICtrlRebar_GetColorScheme', + 'GUICtrlRebar_GetRowCount','GUICtrlRebar_GetRowHeight', + 'GUICtrlRebar_GetTextColor','GUICtrlRebar_GetToolTips', + 'GUICtrlRebar_GetUnicodeFormat','GUICtrlRebar_HitTest', + 'GUICtrlRebar_IDToIndex','GUICtrlRebar_MaximizeBand', + 'GUICtrlRebar_MinimizeBand','GUICtrlRebar_MoveBand', + 'GUICtrlRebar_SetBandBackColor','GUICtrlRebar_SetBandForeColor', + 'GUICtrlRebar_SetBandHeaderSize','GUICtrlRebar_SetBandID', + 'GUICtrlRebar_SetBandIdealSize','GUICtrlRebar_SetBandLength', + 'GUICtrlRebar_SetBandLParam','GUICtrlRebar_SetBandStyle', + 'GUICtrlRebar_SetBandStyleBreak', + 'GUICtrlRebar_SetBandStyleChildEdge', + 'GUICtrlRebar_SetBandStyleFixedBMP', + 'GUICtrlRebar_SetBandStyleFixedSize', + 'GUICtrlRebar_SetBandStyleGripperAlways', + 'GUICtrlRebar_SetBandStyleHidden', + 'GUICtrlRebar_SetBandStyleHideTitle', + 'GUICtrlRebar_SetBandStyleNoGripper', + 'GUICtrlRebar_SetBandStyleTopAlign', + 'GUICtrlRebar_SetBandStyleUseChevron', + 'GUICtrlRebar_SetBandStyleVariableHeight', + 'GUICtrlRebar_SetBandText','GUICtrlRebar_SetBKColor', + 'GUICtrlRebar_SetColorScheme','GUICtrlRebar_SetTextColor', + 'GUICtrlRebar_SetToolTips','GUICtrlRebar_SetUnicodeFormat', + 'GUICtrlRebar_ShowBand','GUICtrlSlider_ClearSel', + 'GUICtrlSlider_ClearTics','GUICtrlSlider_Create', + 'GUICtrlSlider_Destroy','GUICtrlSlider_GetBuddy', + 'GUICtrlSlider_GetChannelRect','GUICtrlSlider_GetLineSize', + 'GUICtrlSlider_GetNumTics','GUICtrlSlider_GetPageSize', + 'GUICtrlSlider_GetPos','GUICtrlSlider_GetPTics', + 'GUICtrlSlider_GetRange','GUICtrlSlider_GetRangeMax', + 'GUICtrlSlider_GetRangeMin','GUICtrlSlider_GetSel', + 'GUICtrlSlider_GetSelEnd','GUICtrlSlider_GetSelStart', + 'GUICtrlSlider_GetThumbLength','GUICtrlSlider_GetThumbRect', + 'GUICtrlSlider_GetThumbRectEx','GUICtrlSlider_GetTic', + 'GUICtrlSlider_GetTicPos','GUICtrlSlider_GetToolTips', + 'GUICtrlSlider_GetUnicodeFormat','GUICtrlSlider_SetBuddy', + 'GUICtrlSlider_SetLineSize','GUICtrlSlider_SetPageSize', + 'GUICtrlSlider_SetPos','GUICtrlSlider_SetRange', + 'GUICtrlSlider_SetRangeMax','GUICtrlSlider_SetRangeMin', + 'GUICtrlSlider_SetSel','GUICtrlSlider_SetSelEnd', + 'GUICtrlSlider_SetSelStart','GUICtrlSlider_SetThumbLength', + 'GUICtrlSlider_SetTic','GUICtrlSlider_SetTicFreq', + 'GUICtrlSlider_SetTipSide','GUICtrlSlider_SetToolTips', + 'GUICtrlSlider_SetUnicodeFormat','GUICtrlStatusBar_Create', + 'GUICtrlStatusBar_Destroy','GUICtrlStatusBar_EmbedControl', + 'GUICtrlStatusBar_GetBorders','GUICtrlStatusBar_GetBordersHorz', + 'GUICtrlStatusBar_GetBordersRect','GUICtrlStatusBar_GetBordersVert', + 'GUICtrlStatusBar_GetCount','GUICtrlStatusBar_GetHeight', + 'GUICtrlStatusBar_GetIcon','GUICtrlStatusBar_GetParts', + 'GUICtrlStatusBar_GetRect','GUICtrlStatusBar_GetRectEx', + 'GUICtrlStatusBar_GetText','GUICtrlStatusBar_GetTextFlags', + 'GUICtrlStatusBar_GetTextLength','GUICtrlStatusBar_GetTextLengthEx', + 'GUICtrlStatusBar_GetTipText','GUICtrlStatusBar_GetUnicodeFormat', + 'GUICtrlStatusBar_GetWidth','GUICtrlStatusBar_IsSimple', + 'GUICtrlStatusBar_Resize','GUICtrlStatusBar_SetBkColor', + 'GUICtrlStatusBar_SetIcon','GUICtrlStatusBar_SetMinHeight', + 'GUICtrlStatusBar_SetParts','GUICtrlStatusBar_SetSimple', + 'GUICtrlStatusBar_SetText','GUICtrlStatusBar_SetTipText', + 'GUICtrlStatusBar_SetUnicodeFormat','GUICtrlStatusBar_ShowHide', + 'GUICtrlTab_Create','GUICtrlTab_DeleteAllItems', + 'GUICtrlTab_DeleteItem','GUICtrlTab_DeselectAll', + 'GUICtrlTab_Destroy','GUICtrlTab_FindTab','GUICtrlTab_GetCurFocus', + 'GUICtrlTab_GetCurSel','GUICtrlTab_GetDisplayRect', + 'GUICtrlTab_GetDisplayRectEx','GUICtrlTab_GetExtendedStyle', + 'GUICtrlTab_GetImageList','GUICtrlTab_GetItem', + 'GUICtrlTab_GetItemCount','GUICtrlTab_GetItemImage', + 'GUICtrlTab_GetItemParam','GUICtrlTab_GetItemRect', + 'GUICtrlTab_GetItemRectEx','GUICtrlTab_GetItemState', + 'GUICtrlTab_GetItemText','GUICtrlTab_GetRowCount', + 'GUICtrlTab_GetToolTips','GUICtrlTab_GetUnicodeFormat', + 'GUICtrlTab_HighlightItem','GUICtrlTab_HitTest', + 'GUICtrlTab_InsertItem','GUICtrlTab_RemoveImage', + 'GUICtrlTab_SetCurFocus','GUICtrlTab_SetCurSel', + 'GUICtrlTab_SetExtendedStyle','GUICtrlTab_SetImageList', + 'GUICtrlTab_SetItem','GUICtrlTab_SetItemImage', + 'GUICtrlTab_SetItemParam','GUICtrlTab_SetItemSize', + 'GUICtrlTab_SetItemState','GUICtrlTab_SetItemText', + 'GUICtrlTab_SetMinTabWidth','GUICtrlTab_SetPadding', + 'GUICtrlTab_SetToolTips','GUICtrlTab_SetUnicodeFormat', + 'GUICtrlToolbar_AddBitmap','GUICtrlToolbar_AddButton', + 'GUICtrlToolbar_AddButtonSep','GUICtrlToolbar_AddString', + 'GUICtrlToolbar_ButtonCount','GUICtrlToolbar_CheckButton', + 'GUICtrlToolbar_ClickAccel','GUICtrlToolbar_ClickButton', + 'GUICtrlToolbar_ClickIndex','GUICtrlToolbar_CommandToIndex', + 'GUICtrlToolbar_Create','GUICtrlToolbar_Customize', + 'GUICtrlToolbar_DeleteButton','GUICtrlToolbar_Destroy', + 'GUICtrlToolbar_EnableButton','GUICtrlToolbar_FindToolbar', + 'GUICtrlToolbar_GetAnchorHighlight','GUICtrlToolbar_GetBitmapFlags', + 'GUICtrlToolbar_GetButtonBitmap','GUICtrlToolbar_GetButtonInfo', + 'GUICtrlToolbar_GetButtonInfoEx','GUICtrlToolbar_GetButtonParam', + 'GUICtrlToolbar_GetButtonRect','GUICtrlToolbar_GetButtonRectEx', + 'GUICtrlToolbar_GetButtonSize','GUICtrlToolbar_GetButtonState', + 'GUICtrlToolbar_GetButtonStyle','GUICtrlToolbar_GetButtonText', + 'GUICtrlToolbar_GetColorScheme', + 'GUICtrlToolbar_GetDisabledImageList', + 'GUICtrlToolbar_GetExtendedStyle','GUICtrlToolbar_GetHotImageList', + 'GUICtrlToolbar_GetHotItem','GUICtrlToolbar_GetImageList', + 'GUICtrlToolbar_GetInsertMark','GUICtrlToolbar_GetInsertMarkColor', + 'GUICtrlToolbar_GetMaxSize','GUICtrlToolbar_GetMetrics', + 'GUICtrlToolbar_GetPadding','GUICtrlToolbar_GetRows', + 'GUICtrlToolbar_GetString','GUICtrlToolbar_GetStyle', + 'GUICtrlToolbar_GetStyleAltDrag', + 'GUICtrlToolbar_GetStyleCustomErase','GUICtrlToolbar_GetStyleFlat', + 'GUICtrlToolbar_GetStyleList','GUICtrlToolbar_GetStyleRegisterDrop', + 'GUICtrlToolbar_GetStyleToolTips', + 'GUICtrlToolbar_GetStyleTransparent', + 'GUICtrlToolbar_GetStyleWrapable','GUICtrlToolbar_GetTextRows', + 'GUICtrlToolbar_GetToolTips','GUICtrlToolbar_GetUnicodeFormat', + 'GUICtrlToolbar_HideButton','GUICtrlToolbar_HighlightButton', + 'GUICtrlToolbar_HitTest','GUICtrlToolbar_IndexToCommand', + 'GUICtrlToolbar_InsertButton','GUICtrlToolbar_InsertMarkHitTest', + 'GUICtrlToolbar_IsButtonChecked','GUICtrlToolbar_IsButtonEnabled', + 'GUICtrlToolbar_IsButtonHidden', + 'GUICtrlToolbar_IsButtonHighlighted', + 'GUICtrlToolbar_IsButtonIndeterminate', + 'GUICtrlToolbar_IsButtonPressed','GUICtrlToolbar_LoadBitmap', + 'GUICtrlToolbar_LoadImages','GUICtrlToolbar_MapAccelerator', + 'GUICtrlToolbar_MoveButton','GUICtrlToolbar_PressButton', + 'GUICtrlToolbar_SetAnchorHighlight','GUICtrlToolbar_SetBitmapSize', + 'GUICtrlToolbar_SetButtonBitMap','GUICtrlToolbar_SetButtonInfo', + 'GUICtrlToolbar_SetButtonInfoEx','GUICtrlToolbar_SetButtonParam', + 'GUICtrlToolbar_SetButtonSize','GUICtrlToolbar_SetButtonState', + 'GUICtrlToolbar_SetButtonStyle','GUICtrlToolbar_SetButtonText', + 'GUICtrlToolbar_SetButtonWidth','GUICtrlToolbar_SetCmdID', + 'GUICtrlToolbar_SetColorScheme', + 'GUICtrlToolbar_SetDisabledImageList', + 'GUICtrlToolbar_SetDrawTextFlags','GUICtrlToolbar_SetExtendedStyle', + 'GUICtrlToolbar_SetHotImageList','GUICtrlToolbar_SetHotItem', + 'GUICtrlToolbar_SetImageList','GUICtrlToolbar_SetIndent', + 'GUICtrlToolbar_SetIndeterminate','GUICtrlToolbar_SetInsertMark', + 'GUICtrlToolbar_SetInsertMarkColor','GUICtrlToolbar_SetMaxTextRows', + 'GUICtrlToolbar_SetMetrics','GUICtrlToolbar_SetPadding', + 'GUICtrlToolbar_SetParent','GUICtrlToolbar_SetRows', + 'GUICtrlToolbar_SetStyle','GUICtrlToolbar_SetStyleAltDrag', + 'GUICtrlToolbar_SetStyleCustomErase','GUICtrlToolbar_SetStyleFlat', + 'GUICtrlToolbar_SetStyleList','GUICtrlToolbar_SetStyleRegisterDrop', + 'GUICtrlToolbar_SetStyleToolTips', + 'GUICtrlToolbar_SetStyleTransparent', + 'GUICtrlToolbar_SetStyleWrapable','GUICtrlToolbar_SetToolTips', + 'GUICtrlToolbar_SetUnicodeFormat','GUICtrlToolbar_SetWindowTheme', + 'GUICtrlTreeView_Add','GUICtrlTreeView_AddChild', + 'GUICtrlTreeView_AddChildFirst','GUICtrlTreeView_AddFirst', + 'GUICtrlTreeView_BeginUpdate','GUICtrlTreeView_ClickItem', + 'GUICtrlTreeView_Create','GUICtrlTreeView_CreateDragImage', + 'GUICtrlTreeView_CreateSolidBitMap','GUICtrlTreeView_Delete', + 'GUICtrlTreeView_DeleteAll','GUICtrlTreeView_DeleteChildren', + 'GUICtrlTreeView_Destroy','GUICtrlTreeView_DisplayRect', + 'GUICtrlTreeView_DisplayRectEx','GUICtrlTreeView_EditText', + 'GUICtrlTreeView_EndEdit','GUICtrlTreeView_EndUpdate', + 'GUICtrlTreeView_EnsureVisible','GUICtrlTreeView_Expand', + 'GUICtrlTreeView_ExpandedOnce','GUICtrlTreeView_FindItem', + 'GUICtrlTreeView_FindItemEx','GUICtrlTreeView_GetBkColor', + 'GUICtrlTreeView_GetBold','GUICtrlTreeView_GetChecked', + 'GUICtrlTreeView_GetChildCount','GUICtrlTreeView_GetChildren', + 'GUICtrlTreeView_GetCount','GUICtrlTreeView_GetCut', + 'GUICtrlTreeView_GetDropTarget','GUICtrlTreeView_GetEditControl', + 'GUICtrlTreeView_GetExpanded','GUICtrlTreeView_GetFirstChild', + 'GUICtrlTreeView_GetFirstItem','GUICtrlTreeView_GetFirstVisible', + 'GUICtrlTreeView_GetFocused','GUICtrlTreeView_GetHeight', + 'GUICtrlTreeView_GetImageIndex', + 'GUICtrlTreeView_GetImageListIconHandle', + 'GUICtrlTreeView_GetIndent','GUICtrlTreeView_GetInsertMarkColor', + 'GUICtrlTreeView_GetISearchString','GUICtrlTreeView_GetItemByIndex', + 'GUICtrlTreeView_GetItemHandle','GUICtrlTreeView_GetItemParam', + 'GUICtrlTreeView_GetLastChild','GUICtrlTreeView_GetLineColor', + 'GUICtrlTreeView_GetNext','GUICtrlTreeView_GetNextChild', + 'GUICtrlTreeView_GetNextSibling','GUICtrlTreeView_GetNextVisible', + 'GUICtrlTreeView_GetNormalImageList', + 'GUICtrlTreeView_GetParentHandle','GUICtrlTreeView_GetParentParam', + 'GUICtrlTreeView_GetPrev','GUICtrlTreeView_GetPrevChild', + 'GUICtrlTreeView_GetPrevSibling','GUICtrlTreeView_GetPrevVisible', + 'GUICtrlTreeView_GetScrollTime','GUICtrlTreeView_GetSelected', + 'GUICtrlTreeView_GetSelectedImageIndex', + 'GUICtrlTreeView_GetSelection','GUICtrlTreeView_GetSiblingCount', + 'GUICtrlTreeView_GetState','GUICtrlTreeView_GetStateImageIndex', + 'GUICtrlTreeView_GetStateImageList','GUICtrlTreeView_GetText', + 'GUICtrlTreeView_GetTextColor','GUICtrlTreeView_GetToolTips', + 'GUICtrlTreeView_GetTree','GUICtrlTreeView_GetUnicodeFormat', + 'GUICtrlTreeView_GetVisible','GUICtrlTreeView_GetVisibleCount', + 'GUICtrlTreeView_HitTest','GUICtrlTreeView_HitTestEx', + 'GUICtrlTreeView_HitTestItem','GUICtrlTreeView_Index', + 'GUICtrlTreeView_InsertItem','GUICtrlTreeView_IsFirstItem', + 'GUICtrlTreeView_IsParent','GUICtrlTreeView_Level', + 'GUICtrlTreeView_SelectItem','GUICtrlTreeView_SelectItemByIndex', + 'GUICtrlTreeView_SetBkColor','GUICtrlTreeView_SetBold', + 'GUICtrlTreeView_SetChecked','GUICtrlTreeView_SetCheckedByIndex', + 'GUICtrlTreeView_SetChildren','GUICtrlTreeView_SetCut', + 'GUICtrlTreeView_SetDropTarget','GUICtrlTreeView_SetFocused', + 'GUICtrlTreeView_SetHeight','GUICtrlTreeView_SetIcon', + 'GUICtrlTreeView_SetImageIndex','GUICtrlTreeView_SetIndent', + 'GUICtrlTreeView_SetInsertMark', + 'GUICtrlTreeView_SetInsertMarkColor', + 'GUICtrlTreeView_SetItemHeight','GUICtrlTreeView_SetItemParam', + 'GUICtrlTreeView_SetLineColor','GUICtrlTreeView_SetNormalImageList', + 'GUICtrlTreeView_SetScrollTime','GUICtrlTreeView_SetSelected', + 'GUICtrlTreeView_SetSelectedImageIndex','GUICtrlTreeView_SetState', + 'GUICtrlTreeView_SetStateImageIndex', + 'GUICtrlTreeView_SetStateImageList','GUICtrlTreeView_SetText', + 'GUICtrlTreeView_SetTextColor','GUICtrlTreeView_SetToolTips', + 'GUICtrlTreeView_SetUnicodeFormat','GUICtrlTreeView_Sort', + 'GUIImageList_Add','GUIImageList_AddBitmap','GUIImageList_AddIcon', + 'GUIImageList_AddMasked','GUIImageList_BeginDrag', + 'GUIImageList_Copy','GUIImageList_Create','GUIImageList_Destroy', + 'GUIImageList_DestroyIcon','GUIImageList_DragEnter', + 'GUIImageList_DragLeave','GUIImageList_DragMove', + 'GUIImageList_Draw','GUIImageList_DrawEx','GUIImageList_Duplicate', + 'GUIImageList_EndDrag','GUIImageList_GetBkColor', + 'GUIImageList_GetIcon','GUIImageList_GetIconHeight', + 'GUIImageList_GetIconSize','GUIImageList_GetIconSizeEx', + 'GUIImageList_GetIconWidth','GUIImageList_GetImageCount', + 'GUIImageList_GetImageInfoEx','GUIImageList_Remove', + 'GUIImageList_ReplaceIcon','GUIImageList_SetBkColor', + 'GUIImageList_SetIconSize','GUIImageList_SetImageCount', + 'GUIImageList_Swap','GUIScrollBars_EnableScrollBar', + 'GUIScrollBars_GetScrollBarInfoEx','GUIScrollBars_GetScrollBarRect', + 'GUIScrollBars_GetScrollBarRGState', + 'GUIScrollBars_GetScrollBarXYLineButton', + 'GUIScrollBars_GetScrollBarXYThumbBottom', + 'GUIScrollBars_GetScrollBarXYThumbTop', + 'GUIScrollBars_GetScrollInfo','GUIScrollBars_GetScrollInfoEx', + 'GUIScrollBars_GetScrollInfoMax','GUIScrollBars_GetScrollInfoMin', + 'GUIScrollBars_GetScrollInfoPage','GUIScrollBars_GetScrollInfoPos', + 'GUIScrollBars_GetScrollInfoTrackPos','GUIScrollBars_GetScrollPos', + 'GUIScrollBars_GetScrollRange','GUIScrollBars_Init', + 'GUIScrollBars_ScrollWindow','GUIScrollBars_SetScrollInfo', + 'GUIScrollBars_SetScrollInfoMax','GUIScrollBars_SetScrollInfoMin', + 'GUIScrollBars_SetScrollInfoPage','GUIScrollBars_SetScrollInfoPos', + 'GUIScrollBars_SetScrollRange','GUIScrollBars_ShowScrollBar', + 'GUIToolTip_Activate','GUIToolTip_AddTool','GUIToolTip_AdjustRect', + 'GUIToolTip_BitsToTTF','GUIToolTip_Create','GUIToolTip_DelTool', + 'GUIToolTip_Destroy','GUIToolTip_EnumTools', + 'GUIToolTip_GetBubbleHeight','GUIToolTip_GetBubbleSize', + 'GUIToolTip_GetBubbleWidth','GUIToolTip_GetCurrentTool', + 'GUIToolTip_GetDelayTime','GUIToolTip_GetMargin', + 'GUIToolTip_GetMarginEx','GUIToolTip_GetMaxTipWidth', + 'GUIToolTip_GetText','GUIToolTip_GetTipBkColor', + 'GUIToolTip_GetTipTextColor','GUIToolTip_GetTitleBitMap', + 'GUIToolTip_GetTitleText','GUIToolTip_GetToolCount', + 'GUIToolTip_GetToolInfo','GUIToolTip_HitTest', + 'GUIToolTip_NewToolRect','GUIToolTip_Pop','GUIToolTip_PopUp', + 'GUIToolTip_SetDelayTime','GUIToolTip_SetMargin', + 'GUIToolTip_SetMaxTipWidth','GUIToolTip_SetTipBkColor', + 'GUIToolTip_SetTipTextColor','GUIToolTip_SetTitle', + 'GUIToolTip_SetToolInfo','GUIToolTip_SetWindowTheme', + 'GUIToolTip_ToolExists','GUIToolTip_ToolToArray', + 'GUIToolTip_TrackActivate','GUIToolTip_TrackPosition', + 'GUIToolTip_TTFToBits','GUIToolTip_Update', + 'GUIToolTip_UpdateTipText','HexToString','IE_Example', + 'IE_Introduction','IE_VersionInfo','IEAction','IEAttach', + 'IEBodyReadHTML','IEBodyReadText','IEBodyWriteHTML','IECreate', + 'IECreateEmbedded','IEDocGetObj','IEDocInsertHTML', + 'IEDocInsertText','IEDocReadHTML','IEDocWriteHTML', + 'IEErrorHandlerDeRegister','IEErrorHandlerRegister','IEErrorNotify', + 'IEFormElementCheckBoxSelect','IEFormElementGetCollection', + 'IEFormElementGetObjByName','IEFormElementGetValue', + 'IEFormElementOptionSelect','IEFormElementRadioSelect', + 'IEFormElementSetValue','IEFormGetCollection','IEFormGetObjByName', + 'IEFormImageClick','IEFormReset','IEFormSubmit', + 'IEFrameGetCollection','IEFrameGetObjByName','IEGetObjById', + 'IEGetObjByName','IEHeadInsertEventScript','IEImgClick', + 'IEImgGetCollection','IEIsFrameSet','IELinkClickByIndex', + 'IELinkClickByText','IELinkGetCollection','IELoadWait', + 'IELoadWaitTimeout','IENavigate','IEPropertyGet','IEPropertySet', + 'IEQuit','IETableGetCollection','IETableWriteToArray', + 'IETagNameAllGetCollection','IETagNameGetCollection','Iif', + 'INetExplorerCapable','INetGetSource','INetMail','INetSmtpMail', + 'IsPressed','MathCheckDiv','Max','MemGlobalAlloc','MemGlobalFree', + 'MemGlobalLock','MemGlobalSize','MemGlobalUnlock','MemMoveMemory', + 'MemMsgBox','MemShowError','MemVirtualAlloc','MemVirtualAllocEx', + 'MemVirtualFree','MemVirtualFreeEx','Min','MouseTrap', + 'NamedPipes_CallNamedPipe','NamedPipes_ConnectNamedPipe', + 'NamedPipes_CreateNamedPipe','NamedPipes_CreatePipe', + 'NamedPipes_DisconnectNamedPipe', + 'NamedPipes_GetNamedPipeHandleState','NamedPipes_GetNamedPipeInfo', + 'NamedPipes_PeekNamedPipe','NamedPipes_SetNamedPipeHandleState', + 'NamedPipes_TransactNamedPipe','NamedPipes_WaitNamedPipe', + 'Net_Share_ConnectionEnum','Net_Share_FileClose', + 'Net_Share_FileEnum','Net_Share_FileGetInfo','Net_Share_PermStr', + 'Net_Share_ResourceStr','Net_Share_SessionDel', + 'Net_Share_SessionEnum','Net_Share_SessionGetInfo', + 'Net_Share_ShareAdd','Net_Share_ShareCheck','Net_Share_ShareDel', + 'Net_Share_ShareEnum','Net_Share_ShareGetInfo', + 'Net_Share_ShareSetInfo','Net_Share_StatisticsGetSvr', + 'Net_Share_StatisticsGetWrk','Now','NowCalc','NowCalcDate', + 'NowDate','NowTime','PathFull','PathMake','PathSplit', + 'ProcessGetName','ProcessGetPriority','Radian', + 'ReplaceStringInFile','RunDOS','ScreenCapture_Capture', + 'ScreenCapture_CaptureWnd','ScreenCapture_SaveImage', + 'ScreenCapture_SetBMPFormat','ScreenCapture_SetJPGQuality', + 'ScreenCapture_SetTIFColorDepth','ScreenCapture_SetTIFCompression', + 'Security__AdjustTokenPrivileges','Security__GetAccountSid', + 'Security__GetLengthSid','Security__GetTokenInformation', + 'Security__ImpersonateSelf','Security__IsValidSid', + 'Security__LookupAccountName','Security__LookupAccountSid', + 'Security__LookupPrivilegeValue','Security__OpenProcessToken', + 'Security__OpenThreadToken','Security__OpenThreadTokenEx', + 'Security__SetPrivilege','Security__SidToStringSid', + 'Security__SidTypeStr','Security__StringSidToSid','SendMessage', + 'SendMessageA','SetDate','SetTime','Singleton','SoundClose', + 'SoundLength','SoundOpen','SoundPause','SoundPlay','SoundPos', + 'SoundResume','SoundSeek','SoundStatus','SoundStop', + 'SQLite_Changes','SQLite_Close','SQLite_Display2DResult', + 'SQLite_Encode','SQLite_ErrCode','SQLite_ErrMsg','SQLite_Escape', + 'SQLite_Exec','SQLite_FetchData','SQLite_FetchNames', + 'SQLite_GetTable','SQLite_GetTable2d','SQLite_LastInsertRowID', + 'SQLite_LibVersion','SQLite_Open','SQLite_Query', + 'SQLite_QueryFinalize','SQLite_QueryReset','SQLite_QuerySingleRow', + 'SQLite_SaveMode','SQLite_SetTimeout','SQLite_Shutdown', + 'SQLite_SQLiteExe','SQLite_Startup','SQLite_TotalChanges', + 'StringAddComma','StringBetween','StringEncrypt','StringInsert', + 'StringProper','StringRepeat','StringReverse','StringSplit', + 'StringToHex','TCPIpToName','TempFile','TicksToTime','Timer_Diff', + 'Timer_GetTimerID','Timer_Init','Timer_KillAllTimers', + 'Timer_KillTimer','Timer_SetTimer','TimeToTicks','VersionCompare', + 'viClose','viExecCommand','viFindGpib','viGpibBusReset','viGTL', + 'viOpen','viSetAttribute','viSetTimeout','WeekNumberISO', + 'WinAPI_AttachConsole','WinAPI_AttachThreadInput','WinAPI_Beep', + 'WinAPI_BitBlt','WinAPI_CallNextHookEx','WinAPI_Check', + 'WinAPI_ClientToScreen','WinAPI_CloseHandle', + 'WinAPI_CommDlgExtendedError','WinAPI_CopyIcon', + 'WinAPI_CreateBitmap','WinAPI_CreateCompatibleBitmap', + 'WinAPI_CreateCompatibleDC','WinAPI_CreateEvent', + 'WinAPI_CreateFile','WinAPI_CreateFont','WinAPI_CreateFontIndirect', + 'WinAPI_CreateProcess','WinAPI_CreateSolidBitmap', + 'WinAPI_CreateSolidBrush','WinAPI_CreateWindowEx', + 'WinAPI_DefWindowProc','WinAPI_DeleteDC','WinAPI_DeleteObject', + 'WinAPI_DestroyIcon','WinAPI_DestroyWindow','WinAPI_DrawEdge', + 'WinAPI_DrawFrameControl','WinAPI_DrawIcon','WinAPI_DrawIconEx', + 'WinAPI_DrawText','WinAPI_EnableWindow','WinAPI_EnumDisplayDevices', + 'WinAPI_EnumWindows','WinAPI_EnumWindowsPopup', + 'WinAPI_EnumWindowsTop','WinAPI_ExpandEnvironmentStrings', + 'WinAPI_ExtractIconEx','WinAPI_FatalAppExit','WinAPI_FillRect', + 'WinAPI_FindExecutable','WinAPI_FindWindow','WinAPI_FlashWindow', + 'WinAPI_FlashWindowEx','WinAPI_FloatToInt', + 'WinAPI_FlushFileBuffers','WinAPI_FormatMessage','WinAPI_FrameRect', + 'WinAPI_FreeLibrary','WinAPI_GetAncestor','WinAPI_GetAsyncKeyState', + 'WinAPI_GetClassName','WinAPI_GetClientHeight', + 'WinAPI_GetClientRect','WinAPI_GetClientWidth', + 'WinAPI_GetCurrentProcess','WinAPI_GetCurrentProcessID', + 'WinAPI_GetCurrentThread','WinAPI_GetCurrentThreadId', + 'WinAPI_GetCursorInfo','WinAPI_GetDC','WinAPI_GetDesktopWindow', + 'WinAPI_GetDeviceCaps','WinAPI_GetDIBits','WinAPI_GetDlgCtrlID', + 'WinAPI_GetDlgItem','WinAPI_GetFileSizeEx','WinAPI_GetFocus', + 'WinAPI_GetForegroundWindow','WinAPI_GetIconInfo', + 'WinAPI_GetLastError','WinAPI_GetLastErrorMessage', + 'WinAPI_GetModuleHandle','WinAPI_GetMousePos','WinAPI_GetMousePosX', + 'WinAPI_GetMousePosY','WinAPI_GetObject','WinAPI_GetOpenFileName', + 'WinAPI_GetOverlappedResult','WinAPI_GetParent', + 'WinAPI_GetProcessAffinityMask','WinAPI_GetSaveFileName', + 'WinAPI_GetStdHandle','WinAPI_GetStockObject','WinAPI_GetSysColor', + 'WinAPI_GetSysColorBrush','WinAPI_GetSystemMetrics', + 'WinAPI_GetTextExtentPoint32','WinAPI_GetWindow', + 'WinAPI_GetWindowDC','WinAPI_GetWindowHeight', + 'WinAPI_GetWindowLong','WinAPI_GetWindowRect', + 'WinAPI_GetWindowText','WinAPI_GetWindowThreadProcessId', + 'WinAPI_GetWindowWidth','WinAPI_GetXYFromPoint', + 'WinAPI_GlobalMemStatus','WinAPI_GUIDFromString', + 'WinAPI_GUIDFromStringEx','WinAPI_HiWord','WinAPI_InProcess', + 'WinAPI_IntToFloat','WinAPI_InvalidateRect','WinAPI_IsClassName', + 'WinAPI_IsWindow','WinAPI_IsWindowVisible','WinAPI_LoadBitmap', + 'WinAPI_LoadImage','WinAPI_LoadLibrary','WinAPI_LoadLibraryEx', + 'WinAPI_LoadShell32Icon','WinAPI_LoadString','WinAPI_LocalFree', + 'WinAPI_LoWord','WinAPI_MakeDWord','WinAPI_MAKELANGID', + 'WinAPI_MAKELCID','WinAPI_MakeLong','WinAPI_MessageBeep', + 'WinAPI_Mouse_Event','WinAPI_MoveWindow','WinAPI_MsgBox', + 'WinAPI_MulDiv','WinAPI_MultiByteToWideChar', + 'WinAPI_MultiByteToWideCharEx','WinAPI_OpenProcess', + 'WinAPI_PointFromRect','WinAPI_PostMessage','WinAPI_PrimaryLangId', + 'WinAPI_PtInRect','WinAPI_ReadFile','WinAPI_ReadProcessMemory', + 'WinAPI_RectIsEmpty','WinAPI_RedrawWindow', + 'WinAPI_RegisterWindowMessage','WinAPI_ReleaseCapture', + 'WinAPI_ReleaseDC','WinAPI_ScreenToClient','WinAPI_SelectObject', + 'WinAPI_SetBkColor','WinAPI_SetCapture','WinAPI_SetCursor', + 'WinAPI_SetDefaultPrinter','WinAPI_SetDIBits','WinAPI_SetEvent', + 'WinAPI_SetFocus','WinAPI_SetFont','WinAPI_SetHandleInformation', + 'WinAPI_SetLastError','WinAPI_SetParent', + 'WinAPI_SetProcessAffinityMask','WinAPI_SetSysColors', + 'WinAPI_SetTextColor','WinAPI_SetWindowLong','WinAPI_SetWindowPos', + 'WinAPI_SetWindowsHookEx','WinAPI_SetWindowText', + 'WinAPI_ShowCursor','WinAPI_ShowError','WinAPI_ShowMsg', + 'WinAPI_ShowWindow','WinAPI_StringFromGUID','WinAPI_SubLangId', + 'WinAPI_SystemParametersInfo','WinAPI_TwipsPerPixelX', + 'WinAPI_TwipsPerPixelY','WinAPI_UnhookWindowsHookEx', + 'WinAPI_UpdateLayeredWindow','WinAPI_UpdateWindow', + 'WinAPI_ValidateClassName','WinAPI_WaitForInputIdle', + 'WinAPI_WaitForMultipleObjects','WinAPI_WaitForSingleObject', + 'WinAPI_WideCharToMultiByte','WinAPI_WindowFromPoint', + 'WinAPI_WriteConsole','WinAPI_WriteFile', + 'WinAPI_WriteProcessMemory','WinNet_AddConnection', + 'WinNet_AddConnection2','WinNet_AddConnection3', + 'WinNet_CancelConnection','WinNet_CancelConnection2', + 'WinNet_CloseEnum','WinNet_ConnectionDialog', + 'WinNet_ConnectionDialog1','WinNet_DisconnectDialog', + 'WinNet_DisconnectDialog1','WinNet_EnumResource', + 'WinNet_GetConnection','WinNet_GetConnectionPerformance', + 'WinNet_GetLastError','WinNet_GetNetworkInformation', + 'WinNet_GetProviderName','WinNet_GetResourceInformation', + 'WinNet_GetResourceParent','WinNet_GetUniversalName', + 'WinNet_GetUser','WinNet_OpenEnum','WinNet_RestoreConnection', + 'WinNet_UseConnection','Word_VersionInfo','WordAttach','WordCreate', + 'WordDocAdd','WordDocAddLink','WordDocAddPicture','WordDocClose', + 'WordDocFindReplace','WordDocGetCollection', + 'WordDocLinkGetCollection','WordDocOpen','WordDocPrint', + 'WordDocPropertyGet','WordDocPropertySet','WordDocSave', + 'WordDocSaveAs','WordErrorHandlerDeRegister', + 'WordErrorHandlerRegister','WordErrorNotify','WordMacroRun', + 'WordPropertyGet','WordPropertySet','WordQuit' + ), + 5 => array( + 'ce','comments-end','comments-start','cs','include','include-once', + 'NoTrayIcon','RequireAdmin' + ), + 6 => array( + 'AutoIt3Wrapper_Au3Check_Parameters', + 'AutoIt3Wrapper_Au3Check_Stop_OnWarning', + 'AutoIt3Wrapper_Change2CUI','AutoIt3Wrapper_Compression', + 'AutoIt3Wrapper_cvsWrapper_Parameters','AutoIt3Wrapper_Icon', + 'AutoIt3Wrapper_Outfile','AutoIt3Wrapper_Outfile_Type', + 'AutoIt3Wrapper_Plugin_Funcs','AutoIt3Wrapper_Res_Comment', + 'AutoIt3Wrapper_Res_Description','AutoIt3Wrapper_Res_Field', + 'AutoIt3Wrapper_Res_File_Add','AutoIt3Wrapper_Res_Fileversion', + 'AutoIt3Wrapper_Res_FileVersion_AutoIncrement', + 'AutoIt3Wrapper_Res_Icon_Add','AutoIt3Wrapper_Res_Language', + 'AutoIt3Wrapper_Res_LegalCopyright', + 'AutoIt3Wrapper_res_requestedExecutionLevel', + 'AutoIt3Wrapper_Res_SaveSource','AutoIt3Wrapper_Run_After', + 'AutoIt3Wrapper_Run_Au3check','AutoIt3Wrapper_Run_Before', + 'AutoIt3Wrapper_Run_cvsWrapper','AutoIt3Wrapper_Run_Debug_Mode', + 'AutoIt3Wrapper_Run_Obfuscator','AutoIt3Wrapper_Run_Tidy', + 'AutoIt3Wrapper_Tidy_Stop_OnError','AutoIt3Wrapper_UseAnsi', + 'AutoIt3Wrapper_UseUpx','AutoIt3Wrapper_UseX64', + 'AutoIt3Wrapper_Version','EndRegion','forceref', + 'Obfuscator_Ignore_Funcs','Obfuscator_Ignore_Variables', + 'Obfuscator_Parameters','Region','Tidy_Parameters' + ) + ), + 'SYMBOLS' => array( + '(',')','[',']', + '+','-','*','/','&','^', + '=','+=','-=','*=','/=','&=', + '==','<','<=','>','>=', + ',','.' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000FF; font-weight: bold;', + 2 => 'color: #800000; font-weight: bold;', + 3 => 'color: #000080; font-style: italic; font-weight: bold;', + 4 => 'color: #0080FF; font-style: italic; font-weight: bold;', + 5 => 'color: #F000FF; font-style: italic;', + 6 => 'color: #A00FF0; font-style: italic;' + ), + 'COMMENTS' => array( + 0 => 'font-style: italic; color: #009933;', + 'MULTI' => 'font-style: italic; color: #669900;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => 'color: #FF0000; font-weight: bold;' + ), + 'STRINGS' => array( + 0 => 'font-weight: bold; color: #008080;' + ), + 'NUMBERS' => array( + 0 => 'color: #AC00A9; font-style: italic; font-weight: bold;' + ), + 'METHODS' => array( + 1 => 'color: #0000FF; font-style: italic; font-weight: bold;' + ), + 'SYMBOLS' => array( + 0 => 'color: #FF0000; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'font-weight: bold; color: #AA0000;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://www.autoitscript.com/autoit3/docs/keywords.htm', + 2 => 'http://www.autoitscript.com/autoit3/docs/macros.htm', + 3 => 'http://www.autoitscript.com/autoit3/docs/functions/{FNAME}.htm', + 4 => '', + 5 => '', + 6 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + //Variables + 0 => '[\\$%@]+[a-zA-Z_][a-zA-Z0-9_]*' + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 4 => array( + 'DISALLOWED_BEFORE' => '(? array( + 'DISALLOWED_BEFORE' => '(? array( + 'DISALLOWED_BEFORE' => '(? \ No newline at end of file diff --git a/examples/includes/geshi/geshi/avisynth.php b/examples/includes/geshi/geshi/avisynth.php new file mode 100644 index 0000000..a3f60d0 --- /dev/null +++ b/examples/includes/geshi/geshi/avisynth.php @@ -0,0 +1,194 @@ + 'AviSynth', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/', '[*' => '*]'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + // Reserved words. + 1 => array( + 'try', 'cache', 'function', 'global', 'return' + ), + // Constants / special variables. + 2 => array( + 'true', 'yes', 'false', 'no', '__END__' + ), + // Internal Filters. + 3 => array( + 'AviSource', 'AviFileSource', 'AddBorders', 'AlignedSplice', 'AssumeFPS', 'AssumeScaledFPS', + 'AssumeFrameBased', 'AssumeFieldBased', 'AssumeBFF', 'AssumeTFF', 'Amplify', 'AmplifydB', + 'AssumeSampleRate', 'AudioDub', 'AudioDubEx', 'Animate', 'ApplyRange', + 'BicubicResize', 'BilinearResize', 'BlackmanResize', 'Blur', 'Bob', 'BlankClip', 'Blackness', + 'ColorYUV', 'ConvertBackToYUY2', 'ConvertToRGB', 'ConvertToRGB24', 'ConvertToRGB32', + 'ConvertToYUY2', 'ConvertToY8', 'ConvertToYV411', 'ConvertToYV12', 'ConvertToYV16', 'ConvertToYV24', + 'ColorKeyMask', 'Crop', 'CropBottom', 'ChangeFPS', 'ConvertFPS', 'ComplementParity', 'ConvertAudioTo8bit', + 'ConvertAudioTo16bit', 'ConvertAudioTo24bit', 'ConvertAudioTo32bit', 'ConvertAudioToFloat', 'ConvertToMono', + 'ConditionalFilter', 'ConditionalReader', 'ColorBars', 'Compare', + 'DirectShowSource', 'DeleteFrame', 'Dissolve', 'DuplicateFrame', 'DoubleWeave', 'DelayAudio', + 'EnsureVBRMP3Sync', + 'FixLuminance', 'FlipHorizontal', 'FlipVertical', 'FixBrokenChromaUpsampling', 'FadeIn0', 'FadeIn', + 'FadeIn2', 'FadeOut0', 'FadeOut', 'FadeOut2', 'FadeIO0', 'FadeIO', 'FadeIO2', 'FreezeFrame', 'FrameEvaluate', + 'GreyScale', 'GaussResize', 'GeneralConvolution', 'GetChannel', 'GetLeftChannel', 'GetRightChannel', + 'HorizontalReduceBy2', 'Histogram', + 'ImageReader', 'ImageSource', 'ImageWriter', 'Invert', 'Interleave', 'Info', + 'KillAudio', 'KillVideo', + 'Levels', 'Limiter', 'Layer', 'Letterbox', 'LanczosResize', 'Lanczos4Resize', 'Loop', + 'MergeARGB', 'MergeRGB', 'MergeChroma', 'MergeLuma', 'Merge', 'Mask', 'MaskHS', 'MergeChannels', 'MixAudio', + 'MonoToStereo', 'MessageClip', + 'Normalize', + 'OpenDMLSource', 'Overlay', + 'PointResize', 'PeculiarBlend', 'Pulldown', + 'RGBAdjust', 'ResetMask', 'Reverse', 'ResampleAudio', 'ReduceBy2', + 'SegmentedAviSource', 'SegmentedDirectShowSource', 'SoundOut', 'ShowAlpha', 'ShowRed', 'ShowGreen', + 'ShowBlue', 'SwapUV', 'Subtract', 'SincResize', 'Spline16Resize', 'Spline36Resize', 'Spline64Resize', + 'SelectEven', 'SelectOdd', 'SelectEvery', 'SelectRangeEvery', 'Sharpen', 'SpatialSoften', 'SeparateFields', + 'ShowFiveVersions', 'ShowFrameNumber', 'ShowSMPTE', 'ShowTime', 'StackHorizontal', 'StackVertical', 'Subtitle', + 'SwapFields', 'SuperEQ', 'SSRC', 'ScriptClip', + 'Tweak', 'TurnLeft', 'TurnRight', 'Turn180', 'TemporalSoften', 'TimeStretch', 'TCPServer', 'TCPSource', 'Trim', + 'Tone', + 'UToY', 'UToY8', 'UnalignedSplice', + 'VToY', 'VToY8', 'VerticalReduceBy2', 'Version', + 'WavSource', 'Weave', 'WriteFile', 'WriteFileIf', 'WriteFileStart', 'WriteFileEnd', + 'YToUV' + ), + // Internal functions. + 4 => array( + 'Abs', 'Apply', 'Assert', 'AverageLuma', 'AverageChromaU', 'AverageChromaV', + 'Ceil', 'Cos', 'Chr', 'ChromaUDifference', 'ChromaVDifference', + 'Defined', 'Default', + 'Exp', 'Exist', 'Eval', + 'Floor', 'Frac', 'Float', 'Findstr', 'GetMTMode', + 'HexValue', + 'Int', 'IsBool', 'IsClip', 'IsFloat', 'IsInt', 'IsString', 'Import', + 'LoadPlugin', 'Log', 'LCase', 'LeftStr', 'LumaDifference', 'LoadVirtualDubPlugin', 'LoadVFAPIPlugin', + 'LoadCPlugin', 'Load_Stdcall_Plugin', + 'Max', 'MulDiv', 'MidStr', + 'NOP', + 'OPT_AllowFloatAudio', 'OPT_UseWaveExtensible', + 'Pi', 'Pow', + 'Round', 'Rand', 'RevStr', 'RightStr', 'RGBDifference', 'RGBDifferenceFromPrevious', 'RGBDifferenceToNext', + 'Sin', 'Sqrt', 'Sign', 'Spline', 'StrLen', 'String', 'Select', 'SetMemoryMax', 'SetWorkingDir', 'SetMTMode', + 'SetPlanarLegacyAlignment', + 'Time', + 'UCase', 'UDifferenceFromPrevious', 'UDifferenceToNext', 'UPlaneMax', 'UPlaneMin', 'UPlaneMedian', + 'UPlaneMinMaxDifference', + 'Value', 'VersionNumber', 'VersionString', 'VDifferenceFromPrevious', 'VDifferenceToNext', 'VPlaneMax', + 'VPlaneMin', 'VPlaneMedian', 'VPlaneMinMaxDifference', + 'YDifferenceFromPrevious', 'YDifferenceToNext', 'YPlaneMax', 'YPlaneMin', 'YPlaneMedian', + 'YPlaneMinMaxDifference' + ) + ), + 'SYMBOLS' => array( + '+', '++', '-', '--', '/', '*', '%', + '=', '==', '<', '<=', '>', '>=', '<>', '!=', + '!', '?', ':', + '|', '||', '&&', + '\\', + '(', ')', '{', '}', + '.', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color:#9966CC; font-weight:bold;', + 2 => 'color:#0000FF; font-weight:bold;', + 3 => 'color:#CC3300; font-weight:bold;', + 4 => 'color:#660000; font-weight:bold;' + ), + 'COMMENTS' => array( + 1 => 'color:#008000; font-style:italic;', + 'MULTI' => 'color:#000080; font-style:italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color:#000099;' + ), + 'BRACKETS' => array( + 0 => 'color:#006600; font-weight:bold;' + ), + 'STRINGS' => array( + 0 => 'color:#996600;' + ), + 'NUMBERS' => array( + 0 => 'color:#006666;' + ), + 'METHODS' => array( + 1 => 'color:#9900CC;' + ), + 'SYMBOLS' => array( + 0 => 'color:#006600; font-weight:bold;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://avisynth.org/mediawiki/{FNAME}', + 4 => '' + ), + 'REGEXPS' => array( + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); +?> diff --git a/examples/includes/geshi/geshi/bash.php b/examples/includes/geshi/geshi/bash.php new file mode 100644 index 0000000..b41f895 --- /dev/null +++ b/examples/includes/geshi/geshi/bash.php @@ -0,0 +1,282 @@ + 'Bash', + // Bash DOES have single line comments with # markers. But bash also has + // the $# variable, so comments need special handling (see sf.net + // 1564839) + 'COMMENT_SINGLE' => array('#'), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + //Variables + 1 => "/\\$\\{[^\\n\\}]*?\\}/i", + //BASH-style Heredoc + 2 => '/<<-?\s*?(\'?)([a-zA-Z0-9]+)\1\\n.*\\n\\2(?![a-zA-Z0-9])/siU', + //Escaped String Starters + 3 => "/\\\\['\"]/siU" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array("\'"), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[nfrtv\\$\\\"\n]#i", + // $var + 2 => "#\\$[a-z_][a-z0-9_]*#i", + // ${...} + 3 => "/\\$\\{[^\\n\\}]*?\\}/i", + // $(...) + 4 => "/\\$\\([^\\n\\)]*?\\)/i", + // `...` + 5 => "/`[^`]*`/" + ), + 'KEYWORDS' => array( + 1 => array( + 'case', 'do', 'done', 'elif', 'else', 'esac', 'fi', 'for', 'function', + 'if', 'in', 'select', 'set', 'then', 'until', 'while', 'time' + ), + 2 => array( + 'aclocal', 'aconnect', 'aplay', 'apm', 'apmsleep', 'apropos', + 'apt-cache', 'apt-get', 'apt-key', 'aptitude', + 'ar', 'arch', 'arecord', 'as', 'as86', 'ash', 'autoconf', + 'autoheader', 'automake', 'awk', + + 'basename', 'bash', 'bc', 'bison', 'bunzip2', 'bzcat', + 'bzcmp', 'bzdiff', 'bzegrep', 'bzfgrep', 'bzgrep', + 'bzip2', 'bzip2recover', 'bzless', 'bzmore', + + 'c++', 'cal', 'cat', 'chattr', 'cc', 'cdda2wav', 'cdparanoia', + 'cdrdao', 'cd-read', 'cdrecord', 'chfn', 'chgrp', 'chmod', + 'chown', 'chroot', 'chsh', 'chvt', 'clear', 'cmp', 'comm', 'co', + 'col', 'cp', 'cpio', 'cpp', 'csh', 'cut', 'cvs', 'cvs-pserver', + + 'dash', 'date', 'dd', 'dc', 'dcop', 'deallocvt', 'df', 'dialog', + 'diff', 'diff3', 'dir', 'dircolors', 'directomatic', 'dirname', + 'dmesg', 'dnsdomainname', 'domainname', 'dpkg', 'dselect', 'du', + 'dumpkeys', + + 'ed', 'egrep', 'env', 'expr', + + 'false', 'fbset', 'ffmpeg', 'fgconsole','fgrep', 'file', 'find', + 'flex', 'flex++', 'fmt', 'free', 'ftp', 'funzip', 'fuser', + + 'g++', 'gawk', 'gc','gcc', 'gdb', 'getent', 'getkeycodes', + 'getopt', 'gettext', 'gettextize', 'gimp', 'gimp-remote', + 'gimptool', 'gmake', 'gocr', 'grep', 'groups', 'gs', 'gunzip', + 'gzexe', 'gzip', + + 'head', 'hexdump', 'hostname', + + 'id', 'ifconfig', 'igawk', 'install', + + 'join', + + 'kbd_mode','kbdrate', 'kdialog', 'kfile', 'kill', 'killall', + + 'lame', 'last', 'lastb', 'ld', 'ld86', 'ldd', 'less', 'lex', 'link', + 'ln', 'loadkeys', 'loadunimap', 'locate', 'lockfile', 'login', + 'logname', 'lp', 'lpr', 'ls', 'lsattr', 'lsmod', 'lsmod.old', + 'lspci', 'ltrace', 'lynx', + + 'm4', 'make', 'man', 'mapscrn', 'mesg', 'mkdir', 'mkfifo', + 'mknod', 'mktemp', 'more', 'mount', 'mplayer', 'msgfmt', 'mv', + + 'namei', 'nano', 'nasm', 'nawk', 'netstat', 'nice', + 'nisdomainname', 'nl', 'nm', 'nm86', 'nmap', 'nohup', 'nop', + + 'od', 'openvt', + + 'passwd', 'patch', 'pcregrep', 'pcretest', 'perl', 'perror', + 'pgawk', 'pidof', 'ping', 'pr', 'procmail', 'prune', 'ps', 'pstree', + 'ps2ascii', 'ps2epsi', 'ps2frag', 'ps2pdf', 'ps2ps', 'psbook', + 'psmerge', 'psnup', 'psresize', 'psselect', 'pstops', + + 'rbash', 'rcs', 'rcs2log', 'read', 'readlink', 'red', 'resizecons', + 'rev', 'rm', 'rmdir', 'rsh', 'run-parts', + + 'sash', 'scp', 'screen', 'sed', 'seq', 'sendmail', 'setfont', + 'setkeycodes', 'setleds', 'setmetamode', 'setserial', 'setterm', + 'sh', 'showkey', 'shred', 'size', 'size86', 'skill', 'sleep', + 'slogin', 'snice', 'sort', 'sox', 'split', 'ssed', 'ssh', 'ssh-add', + 'ssh-agent', 'ssh-keygen', 'ssh-keyscan', 'stat', 'strace', + 'strings', 'strip', 'stty', 'su', 'sudo', 'suidperl', 'sum', 'svn', + 'svnadmin', 'svndumpfilter', 'svnlook', 'svnmerge', 'svnmucc', + 'svnserve', 'svnshell', 'svnsync', 'svnversion', 'svnwrap', 'sync', + + 'tac', 'tail', 'tar', 'tee', 'tempfile', 'touch', 'tr', 'tree', + 'true', + + 'umount', 'uname', 'unicode_start', 'unicode_stop', 'uniq', + 'unlink', 'unzip', 'updatedb', 'updmap', 'uptime', 'users', + 'utmpdump', 'uuidgen', + + 'valgrind', 'vdir', 'vi', 'vim', 'vmstat', + + 'w', 'wall', 'wc', 'wget', 'whatis', 'whereis', 'which', 'whiptail', + 'who', 'whoami', 'write', + + 'xargs', 'xhost', 'xmodmap', 'xset', + + 'yacc', 'yes', 'ypdomainname', + + 'zcat', 'zcmp', 'zdiff', 'zdump', 'zegrep', 'zfgrep', 'zforce', + 'zgrep', 'zip', 'zipgrep', 'zipinfo', 'zless', 'zmore', 'znew', + 'zsh', 'zsoelim' + ), + 3 => array( + 'alias', 'bg', 'bind', 'break', 'builtin', 'cd', 'command', + 'compgen', 'complete', 'continue', 'declare', 'dirs', 'disown', + 'echo', 'enable', 'eval', 'exec', 'exit', 'export', 'fc', + 'fg', 'getopts', 'hash', 'help', 'history', 'jobs', 'let', + 'local', 'logout', 'popd', 'printf', 'pushd', 'pwd', 'readonly', + 'return', 'shift', 'shopt', 'source', 'suspend', 'test', 'times', + 'trap', 'type', 'typeset', 'ulimit', 'umask', 'unalias', 'unset', + 'wait' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '!', '@', '%', '&', '*', '|', '/', '<', '>', ';;', '`' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #c20cb9; font-weight: bold;', + 3 => 'color: #7a0874; font-weight: bold;' + ), + 'COMMENTS' => array( + 0 => 'color: #666666; font-style: italic;', + 1 => 'color: #800000;', + 2 => 'color: #cc0000; font-style: italic;', + 3 => 'color: #000000; font-weight: bold;' + ), + 'ESCAPE_CHAR' => array( + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #007800;', + 3 => 'color: #007800;', + 4 => 'color: #007800;', + 5 => 'color: #780078;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #7a0874; font-weight: bold;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;', + 'HARD' => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #007800;', + 1 => 'color: #007800;', + 2 => 'color: #007800;', + 4 => 'color: #007800;', + 5 => 'color: #660033;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Variables (will be handled by comment_regexps) + 0 => "\\$\\{[a-zA-Z_][a-zA-Z0-9_]*?\\}", + //Variables without braces + 1 => "\\$[a-zA-Z_][a-zA-Z0-9_]*", + //Variable assignment + 2 => "(? "\\$[*#\$\\-\\?!]", + //Parameters of commands + 5 => "(?<=\s)--?[0-9a-zA-Z\-]+(?=[\s=]|$)" + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'COMMENTS' => array( + 'DISALLOWED_BEFORE' => '$' + ), + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(? "(?![\.\-a-zA-Z0-9_%\\/])" + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/basic4gl.php b/examples/includes/geshi/geshi/basic4gl.php new file mode 100644 index 0000000..a7b00b9 --- /dev/null +++ b/examples/includes/geshi/geshi/basic4gl.php @@ -0,0 +1,341 @@ + 'Basic4GL', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + + // Navy Blue Bold Keywords + + 'true','rnd_max','m_pi','m_e','false','VK_ZOOM','VK_UP','VK_TAB','VK_SUBTRACT','VK_SPACE','VK_SNAPSHOT', + 'VK_SHIFT','VK_SEPARATOR','VK_SELECT','VK_SCROLL','VK_RWIN','VK_RSHIFT','VK_RMENU','VK_RIGHT','VK_RETURN', + 'VK_RCONTROL','VK_RBUTTON','VK_PROCESSKEY','VK_PRIOR','VK_PRINT','VK_PLAY','VK_PAUSE','VK_NUMPAD9','VK_NUMPAD8', + 'VK_NUMPAD7','VK_NUMPAD6','VK_NUMPAD5','VK_NUMPAD4','VK_NUMPAD3','VK_NUMPAD2','VK_NUMPAD1','VK_NUMPAD0', + 'VK_NUMLOCK','VK_NONCONVERT','VK_NEXT','VK_MULTIPLY','VK_MODECHANGE','VK_MENU','VK_MBUTTON','VK_LWIN', + 'VK_LSHIFT','VK_LMENU','VK_LEFT','VK_LCONTROL','VK_LBUTTON','VK_KANJI','VK_KANA','VK_JUNJA','VK_INSERT', + 'VK_HOME','VK_HELP','VK_HANJA','VK_HANGUL','VK_HANGEUL','VK_FINAL','VK_F9','VK_F8','VK_F7','VK_F6','VK_F5', + 'VK_F4','VK_F3','VK_F24','VK_F23','VK_F22','VK_F21','VK_F20','VK_F2','VK_F19','VK_F18','VK_F17','VK_F16', + 'VK_F15','VK_F14','VK_F13','VK_F12','VK_F11','VK_F10','VK_F1','VK_EXSEL','VK_EXECUTE','VK_ESCAPE','VK_EREOF', + 'VK_END','VK_DOWN','VK_DIVIDE','VK_DELETE','VK_DECIMAL','VK_CRSEL','VK_CONVERT','VK_CONTROL','VK_CLEAR', + 'VK_CAPITAL','VK_CANCEL','VK_BACK','VK_ATTN','VK_APPS','VK_ADD','VK_ACCEPT','TEXT_SIMPLE','TEXT_OVERLAID', + 'TEXT_BUFFERED','SPR_TILEMAP','SPR_SPRITE','SPR_INVALID','MOUSE_RBUTTON','MOUSE_MBUTTON','MOUSE_LBUTTON', + 'GL_ZOOM_Y','GL_ZOOM_X','GL_ZERO','GL_XOR','GL_WIN_swap_hint','GL_WIN_draw_range_elements','GL_VIEWPORT_BIT', + 'GL_VIEWPORT','GL_VERTEX_ARRAY_TYPE_EXT','GL_VERTEX_ARRAY_TYPE','GL_VERTEX_ARRAY_STRIDE_EXT','GL_VERTEX_ARRAY_STRIDE', + 'GL_VERTEX_ARRAY_SIZE_EXT','GL_VERTEX_ARRAY_SIZE','GL_VERTEX_ARRAY_POINTER_EXT','GL_VERTEX_ARRAY_POINTER', + 'GL_VERTEX_ARRAY_EXT','GL_VERTEX_ARRAY_COUNT_EXT','GL_VERTEX_ARRAY','GL_VERSION_1_1','GL_VERSION','GL_VENDOR', + 'GL_V3F','GL_V2F','GL_UNSIGNED_SHORT','GL_UNSIGNED_INT','GL_UNSIGNED_BYTE','GL_UNPACK_SWAP_BYTES','GL_UNPACK_SKIP_ROWS', + 'GL_UNPACK_SKIP_PIXELS','GL_UNPACK_ROW_LENGTH','GL_UNPACK_LSB_FIRST','GL_UNPACK_ALIGNMENT','GL_TRUE','GL_TRIANGLE_STRIP', + 'GL_TRIANGLE_FAN','GL_TRIANGLES','GL_TRANSFORM_BIT','GL_TEXTURE_WRAP_T','GL_TEXTURE_WRAP_S','GL_TEXTURE_WIDTH', + 'GL_TEXTURE_STACK_DEPTH','GL_TEXTURE_RESIDENT','GL_TEXTURE_RED_SIZE','GL_TEXTURE_PRIORITY','GL_TEXTURE_MIN_FILTER', + 'GL_TEXTURE_MATRIX','GL_TEXTURE_MAG_FILTER','GL_TEXTURE_LUMINANCE_SIZE','GL_TEXTURE_INTERNAL_FORMAT','GL_TEXTURE_INTENSITY_SIZE', + 'GL_TEXTURE_HEIGHT','GL_TEXTURE_GREEN_SIZE','GL_TEXTURE_GEN_T','GL_TEXTURE_GEN_S','GL_TEXTURE_GEN_R','GL_TEXTURE_GEN_Q', + 'GL_TEXTURE_GEN_MODE','GL_TEXTURE_ENV_MODE','GL_TEXTURE_ENV_COLOR','GL_TEXTURE_ENV','GL_TEXTURE_COORD_ARRAY_TYPE_EXT', + 'GL_TEXTURE_COORD_ARRAY_TYPE','GL_TEXTURE_COORD_ARRAY_STRIDE_EXT','GL_TEXTURE_COORD_ARRAY_STRIDE','GL_TEXTURE_COORD_ARRAY_SIZE_EXT', + 'GL_TEXTURE_COORD_ARRAY_SIZE','GL_TEXTURE_COORD_ARRAY_POINTER_EXT','GL_TEXTURE_COORD_ARRAY_POINTER','GL_TEXTURE_COORD_ARRAY_EXT', + 'GL_TEXTURE_COORD_ARRAY_COUNT_EXT','GL_TEXTURE_COORD_ARRAY','GL_TEXTURE_COMPONENTS','GL_TEXTURE_BORDER_COLOR','GL_TEXTURE_BORDER', + 'GL_TEXTURE_BLUE_SIZE','GL_TEXTURE_BIT','GL_TEXTURE_BINDING_2D','GL_TEXTURE_BINDING_1D','GL_TEXTURE_ALPHA_SIZE', + 'GL_TEXTURE_2D','GL_TEXTURE_1D','GL_TEXTURE9_ARB','GL_TEXTURE9','GL_TEXTURE8_ARB','GL_TEXTURE8','GL_TEXTURE7_ARB', + 'GL_TEXTURE7','GL_TEXTURE6_ARB','GL_TEXTURE6','GL_TEXTURE5_ARB','GL_TEXTURE5','GL_TEXTURE4_ARB','GL_TEXTURE4', + 'GL_TEXTURE3_ARB','GL_TEXTURE31_ARB','GL_TEXTURE31','GL_TEXTURE30_ARB','GL_TEXTURE30','GL_TEXTURE3','GL_TEXTURE2_ARB', + 'GL_TEXTURE29_ARB','GL_TEXTURE29','GL_TEXTURE28_ARB','GL_TEXTURE28','GL_TEXTURE27_ARB','GL_TEXTURE27','GL_TEXTURE26_ARB', + 'GL_TEXTURE26','GL_TEXTURE25_ARB','GL_TEXTURE25','GL_TEXTURE24_ARB','GL_TEXTURE24','GL_TEXTURE23_ARB','GL_TEXTURE23', + 'GL_TEXTURE22_ARB','GL_TEXTURE22','GL_TEXTURE21_ARB','GL_TEXTURE21','GL_TEXTURE20_ARB','GL_TEXTURE20','GL_TEXTURE2', + 'GL_TEXTURE1_ARB','GL_TEXTURE19_ARB','GL_TEXTURE19','GL_TEXTURE18_ARB','GL_TEXTURE18','GL_TEXTURE17_ARB', + 'GL_TEXTURE17','GL_TEXTURE16_ARB','GL_TEXTURE16','GL_TEXTURE15_ARB','GL_TEXTURE15','GL_TEXTURE14_ARB','GL_TEXTURE14', + 'GL_TEXTURE13_ARB','GL_TEXTURE13','GL_TEXTURE12_ARB','GL_TEXTURE12','GL_TEXTURE11_ARB','GL_TEXTURE11','GL_TEXTURE10_ARB', + 'GL_TEXTURE10','GL_TEXTURE1','GL_TEXTURE0_ARB','GL_TEXTURE0','GL_TEXTURE','GL_T4F_V4F','GL_T4F_C4F_N3F_V4F','GL_T2F_V3F', + 'GL_T2F_N3F_V3F','GL_T2F_C4UB_V3F','GL_T2F_C4F_N3F_V3F','GL_T2F_C3F_V3F','GL_T','GL_SUBPIXEL_BITS','GL_STEREO', + 'GL_STENCIL_WRITEMASK','GL_STENCIL_VALUE_MASK','GL_STENCIL_TEST','GL_STENCIL_REF','GL_STENCIL_PASS_DEPTH_PASS', + 'GL_STENCIL_PASS_DEPTH_FAIL','GL_STENCIL_INDEX','GL_STENCIL_FUNC','GL_STENCIL_FAIL','GL_STENCIL_CLEAR_VALUE', + 'GL_STENCIL_BUFFER_BIT','GL_STENCIL_BITS','GL_STENCIL','GL_STACK_UNDERFLOW','GL_STACK_OVERFLOW','GL_SRC_COLOR', + 'GL_SRC_ALPHA_SATURATE','GL_SRC_ALPHA','GL_SPOT_EXPONENT','GL_SPOT_DIRECTION','GL_SPOT_CUTOFF','GL_SPHERE_MAP', + 'GL_SPECULAR','GL_SOURCE2_RGB_EXT','GL_SOURCE2_RGB','GL_SOURCE2_ALPHA_EXT','GL_SOURCE2_ALPHA','GL_SOURCE1_RGB_EXT', + 'GL_SOURCE1_RGB','GL_SOURCE1_ALPHA_EXT','GL_SOURCE1_ALPHA','GL_SOURCE0_RGB_EXT','GL_SOURCE0_RGB','GL_SOURCE0_ALPHA_EXT', + 'GL_SOURCE0_ALPHA','GL_SMOOTH','GL_SHORT','GL_SHININESS','GL_SHADE_MODEL','GL_SET','GL_SELECTION_BUFFER_SIZE', + 'GL_SELECTION_BUFFER_POINTER','GL_SELECT','GL_SCISSOR_TEST','GL_SCISSOR_BOX','GL_SCISSOR_BIT','GL_S','GL_RIGHT', + 'GL_RGB_SCALE_EXT','GL_RGB_SCALE','GL_RGBA_MODE','GL_RGBA8','GL_RGBA4','GL_RGBA2','GL_RGBA16','GL_RGBA12','GL_RGBA', + 'GL_RGB8','GL_RGB5_A1','GL_RGB5','GL_RGB4','GL_RGB16','GL_RGB12','GL_RGB10_A2','GL_RGB10','GL_RGB','GL_RETURN', + 'GL_REPLACE','GL_REPEAT','GL_RENDER_MODE','GL_RENDERER','GL_RENDER','GL_RED_SCALE','GL_RED_BITS','GL_RED_BIAS', + 'GL_RED','GL_READ_BUFFER','GL_R3_G3_B2','GL_R','GL_QUAD_STRIP','GL_QUADS','GL_QUADRATIC_ATTENUATION','GL_Q', + 'GL_PROXY_TEXTURE_2D','GL_PROXY_TEXTURE_1D','GL_PROJECTION_STACK_DEPTH','GL_PROJECTION_MATRIX','GL_PROJECTION', + 'GL_PRIMARY_COLOR_EXT','GL_PRIMARY_COLOR','GL_PREVIOUS_EXT','GL_PREVIOUS','GL_POSITION','GL_POLYGON_TOKEN', + 'GL_POLYGON_STIPPLE_BIT','GL_POLYGON_STIPPLE','GL_POLYGON_SMOOTH_HINT','GL_POLYGON_SMOOTH','GL_POLYGON_OFFSET_UNITS', + 'GL_POLYGON_OFFSET_POINT','GL_POLYGON_OFFSET_LINE','GL_POLYGON_OFFSET_FILL','GL_POLYGON_OFFSET_FACTOR','GL_POLYGON_MODE', + 'GL_POLYGON_BIT','GL_POLYGON','GL_POINT_TOKEN','GL_POINT_SMOOTH_HINT','GL_POINT_SMOOTH','GL_POINT_SIZE_RANGE', + 'GL_POINT_SIZE_GRANULARITY','GL_POINT_SIZE','GL_POINT_BIT','GL_POINTS','GL_POINT','GL_PIXEL_MODE_BIT', + 'GL_PIXEL_MAP_S_TO_S_SIZE','GL_PIXEL_MAP_S_TO_S','GL_PIXEL_MAP_R_TO_R_SIZE','GL_PIXEL_MAP_R_TO_R','GL_PIXEL_MAP_I_TO_R_SIZE', + 'GL_PIXEL_MAP_I_TO_R','GL_PIXEL_MAP_I_TO_I_SIZE','GL_PIXEL_MAP_I_TO_I','GL_PIXEL_MAP_I_TO_G_SIZE','GL_PIXEL_MAP_I_TO_G', + 'GL_PIXEL_MAP_I_TO_B_SIZE','GL_PIXEL_MAP_I_TO_B','GL_PIXEL_MAP_I_TO_A_SIZE','GL_PIXEL_MAP_I_TO_A','GL_PIXEL_MAP_G_TO_G_SIZE', + 'GL_PIXEL_MAP_G_TO_G','GL_PIXEL_MAP_B_TO_B_SIZE','GL_PIXEL_MAP_B_TO_B','GL_PIXEL_MAP_A_TO_A_SIZE','GL_PIXEL_MAP_A_TO_A', + 'GL_PHONG_WIN','GL_PHONG_HINT_WIN','GL_PERSPECTIVE_CORRECTION_HINT','GL_PASS_THROUGH_TOKEN','GL_PACK_SWAP_BYTES', + 'GL_PACK_SKIP_ROWS','GL_PACK_SKIP_PIXELS','GL_PACK_ROW_LENGTH','GL_PACK_LSB_FIRST','GL_PACK_ALIGNMENT','GL_OUT_OF_MEMORY', + 'GL_OR_REVERSE','GL_OR_INVERTED','GL_ORDER','GL_OR','GL_OPERAND2_RGB_EXT','GL_OPERAND2_RGB','GL_OPERAND2_ALPHA_EXT', + 'GL_OPERAND2_ALPHA','GL_OPERAND1_RGB_EXT','GL_OPERAND1_RGB','GL_OPERAND1_ALPHA_EXT','GL_OPERAND1_ALPHA','GL_OPERAND0_RGB_EXT', + 'GL_OPERAND0_RGB','GL_OPERAND0_ALPHA_EXT','GL_OPERAND0_ALPHA','GL_ONE_MINUS_SRC_COLOR','GL_ONE_MINUS_SRC_ALPHA', + 'GL_ONE_MINUS_DST_COLOR','GL_ONE_MINUS_DST_ALPHA','GL_ONE','GL_OBJECT_PLANE','GL_OBJECT_LINEAR','GL_NO_ERROR', + 'GL_NOTEQUAL','GL_NORMAL_ARRAY_TYPE_EXT','GL_NORMAL_ARRAY_TYPE','GL_NORMAL_ARRAY_STRIDE_EXT','GL_NORMAL_ARRAY_STRIDE', + 'GL_NORMAL_ARRAY_POINTER_EXT','GL_NORMAL_ARRAY_POINTER','GL_NORMAL_ARRAY_EXT','GL_NORMAL_ARRAY_COUNT_EXT', + 'GL_NORMAL_ARRAY','GL_NORMALIZE','GL_NOR','GL_NOOP','GL_NONE','GL_NICEST','GL_NEVER','GL_NEAREST_MIPMAP_NEAREST','GL_NEAREST_MIPMAP_LINEAR', + 'GL_NEAREST','GL_NAND','GL_NAME_STACK_DEPTH','GL_N3F_V3F','GL_MULT','GL_MODULATE','GL_MODELVIEW_STACK_DEPTH','GL_MODELVIEW_MATRIX', + 'GL_MODELVIEW','GL_MAX_VIEWPORT_DIMS','GL_MAX_TEXTURE_UNITS_ARB','GL_MAX_TEXTURE_UNITS','GL_MAX_TEXTURE_STACK_DEPTH', + 'GL_MAX_TEXTURE_SIZE','GL_MAX_PROJECTION_STACK_DEPTH','GL_MAX_PIXEL_MAP_TABLE','GL_MAX_NAME_STACK_DEPTH','GL_MAX_MODELVIEW_STACK_DEPTH', + 'GL_MAX_LIST_NESTING','GL_MAX_LIGHTS','GL_MAX_EVAL_ORDER','GL_MAX_ELEMENTS_VERTICES_WIN','GL_MAX_ELEMENTS_INDICES_WIN', + 'GL_MAX_CLIP_PLANES','GL_MAX_CLIENT_ATTRIB_STACK_DEPTH','GL_MAX_ATTRIB_STACK_DEPTH','GL_MATRIX_MODE','GL_MAP_STENCIL', + 'GL_MAP_COLOR','GL_MAP2_VERTEX_4','GL_MAP2_VERTEX_3','GL_MAP2_TEXTURE_COORD_4','GL_MAP2_TEXTURE_COORD_3','GL_MAP2_TEXTURE_COORD_2', + 'GL_MAP2_TEXTURE_COORD_1','GL_MAP2_NORMAL','GL_MAP2_INDEX','GL_MAP2_GRID_SEGMENTS','GL_MAP2_GRID_DOMAIN','GL_MAP2_COLOR_4', + 'GL_MAP1_VERTEX_4','GL_MAP1_VERTEX_3','GL_MAP1_TEXTURE_COORD_4','GL_MAP1_TEXTURE_COORD_3','GL_MAP1_TEXTURE_COORD_2', + 'GL_MAP1_TEXTURE_COORD_1','GL_MAP1_NORMAL','GL_MAP1_INDEX','GL_MAP1_GRID_SEGMENTS','GL_MAP1_GRID_DOMAIN', + 'GL_MAP1_COLOR_4','GL_LUMINANCE_ALPHA','GL_LUMINANCE8_ALPHA8','GL_LUMINANCE8','GL_LUMINANCE6_ALPHA2','GL_LUMINANCE4_ALPHA4', + 'GL_LUMINANCE4','GL_LUMINANCE16_ALPHA16','GL_LUMINANCE16','GL_LUMINANCE12_ALPHA4','GL_LUMINANCE12_ALPHA12','GL_LUMINANCE12', + 'GL_LUMINANCE','GL_LOGIC_OP_MODE','GL_LOGIC_OP','GL_LOAD','GL_LIST_MODE','GL_LIST_INDEX','GL_LIST_BIT', + 'GL_LIST_BASE','GL_LINE_WIDTH_RANGE','GL_LINE_WIDTH_GRANULARITY','GL_LINE_WIDTH','GL_LINE_TOKEN','GL_LINE_STRIP','GL_LINE_STIPPLE_REPEAT', + 'GL_LINE_STIPPLE_PATTERN','GL_LINE_STIPPLE','GL_LINE_SMOOTH_HINT','GL_LINE_SMOOTH','GL_LINE_RESET_TOKEN','GL_LINE_LOOP', + 'GL_LINE_BIT','GL_LINES','GL_LINEAR_MIPMAP_NEAREST','GL_LINEAR_MIPMAP_LINEAR','GL_LINEAR_ATTENUATION','GL_LINEAR', + 'GL_LINE','GL_LIGHT_MODEL_TWO_SIDE','GL_LIGHT_MODEL_LOCAL_VIEWER','GL_LIGHT_MODEL_AMBIENT','GL_LIGHTING_BIT', + 'GL_LIGHTING','GL_LIGHT7','GL_LIGHT6','GL_LIGHT5','GL_LIGHT4','GL_LIGHT3','GL_LIGHT2','GL_LIGHT1','GL_LIGHT0', + 'GL_LESS','GL_LEQUAL','GL_LEFT','GL_KEEP','GL_INVERT','GL_INVALID_VALUE','GL_INVALID_OPERATION','GL_INVALID_ENUM','GL_INTERPOLATE_EXT', + 'GL_INTERPOLATE','GL_INTENSITY8','GL_INTENSITY4','GL_INTENSITY16','GL_INTENSITY12','GL_INTENSITY','GL_INT', + 'GL_INDEX_WRITEMASK','GL_INDEX_SHIFT','GL_INDEX_OFFSET','GL_INDEX_MODE','GL_INDEX_LOGIC_OP','GL_INDEX_CLEAR_VALUE','GL_INDEX_BITS', + 'GL_INDEX_ARRAY_TYPE_EXT','GL_INDEX_ARRAY_TYPE','GL_INDEX_ARRAY_STRIDE_EXT','GL_INDEX_ARRAY_STRIDE','GL_INDEX_ARRAY_POINTER_EXT', + 'GL_INDEX_ARRAY_POINTER','GL_INDEX_ARRAY_EXT','GL_INDEX_ARRAY_COUNT_EXT','GL_INDEX_ARRAY','GL_INCR','GL_HINT_BIT', + 'GL_GREEN_SCALE','GL_GREEN_BITS','GL_GREEN_BIAS','GL_GREEN','GL_GREATER','GL_GEQUAL','GL_FRONT_RIGHT','GL_FRONT_LEFT', + 'GL_FRONT_FACE','GL_FRONT_AND_BACK','GL_FRONT','GL_FOG_START','GL_FOG_SPECULAR_TEXTURE_WIN','GL_FOG_MODE','GL_FOG_INDEX', + 'GL_FOG_HINT','GL_FOG_END','GL_FOG_DENSITY','GL_FOG_COLOR','GL_FOG_BIT','GL_FOG','GL_FLOAT','GL_FLAT','GL_FILL', + 'GL_FEEDBACK_BUFFER_TYPE','GL_FEEDBACK_BUFFER_SIZE','GL_FEEDBACK_BUFFER_POINTER','GL_FEEDBACK','GL_FASTEST','GL_FALSE', + 'GL_EYE_PLANE','GL_EYE_LINEAR','GL_EXT_vertex_array','GL_EXT_paletted_texture','GL_EXT_bgra','GL_EXTENSIONS','GL_EXP2', + 'GL_EXP','GL_EVAL_BIT','GL_EQUIV','GL_EQUAL','GL_ENABLE_BIT','GL_EMISSION','GL_EDGE_FLAG_ARRAY_STRIDE_EXT','GL_EDGE_FLAG_ARRAY_STRIDE', + 'GL_EDGE_FLAG_ARRAY_POINTER_EXT','GL_EDGE_FLAG_ARRAY_POINTER','GL_EDGE_FLAG_ARRAY_EXT','GL_EDGE_FLAG_ARRAY_COUNT_EXT','GL_EDGE_FLAG_ARRAY', + 'GL_EDGE_FLAG','GL_DST_COLOR','GL_DST_ALPHA','GL_DRAW_PIXEL_TOKEN','GL_DRAW_BUFFER','GL_DOUBLE_EXT','GL_DOUBLEBUFFER', + 'GL_DOUBLE','GL_DONT_CARE','GL_DOMAIN','GL_DITHER','GL_DIFFUSE','GL_DEPTH_WRITEMASK','GL_DEPTH_TEST','GL_DEPTH_SCALE', + 'GL_DEPTH_RANGE','GL_DEPTH_FUNC','GL_DEPTH_COMPONENT','GL_DEPTH_CLEAR_VALUE','GL_DEPTH_BUFFER_BIT','GL_DEPTH_BITS', + 'GL_DEPTH_BIAS','GL_DEPTH','GL_DECR','GL_DECAL','GL_CW','GL_CURRENT_TEXTURE_COORDS','GL_CURRENT_RASTER_TEXTURE_COORDS','GL_CURRENT_RASTER_POSITION_VALID', + 'GL_CURRENT_RASTER_POSITION','GL_CURRENT_RASTER_INDEX','GL_CURRENT_RASTER_DISTANCE','GL_CURRENT_RASTER_COLOR','GL_CURRENT_NORMAL', + 'GL_CURRENT_INDEX','GL_CURRENT_COLOR','GL_CURRENT_BIT','GL_CULL_FACE_MODE','GL_CULL_FACE','GL_COPY_PIXEL_TOKEN', + 'GL_COPY_INVERTED','GL_COPY','GL_CONSTANT_EXT','GL_CONSTANT_ATTENUATION','GL_CONSTANT','GL_COMPILE_AND_EXECUTE','GL_COMPILE','GL_COMBINE_RGB_EXT', + 'GL_COMBINE_RGB','GL_COMBINE_EXT','GL_COMBINE_ALPHA_EXT','GL_COMBINE_ALPHA','GL_COMBINE','GL_COLOR_WRITEMASK', + 'GL_COLOR_TABLE_WIDTH_EXT','GL_COLOR_TABLE_RED_SIZE_EXT','GL_COLOR_TABLE_LUMINANCE_SIZE_EXT','GL_COLOR_TABLE_INTENSITY_SIZE_EXT', + 'GL_COLOR_TABLE_GREEN_SIZE_EXT','GL_COLOR_TABLE_FORMAT_EXT','GL_COLOR_TABLE_BLUE_SIZE_EXT','GL_COLOR_TABLE_ALPHA_SIZE_EXT', + 'GL_COLOR_MATERIAL_PARAMETER','GL_COLOR_MATERIAL_FACE','GL_COLOR_MATERIAL','GL_COLOR_LOGIC_OP','GL_COLOR_INDEXES', + 'GL_COLOR_INDEX8_EXT','GL_COLOR_INDEX4_EXT','GL_COLOR_INDEX2_EXT','GL_COLOR_INDEX1_EXT','GL_COLOR_INDEX16_EXT', + 'GL_COLOR_INDEX12_EXT','GL_COLOR_INDEX','GL_COLOR_CLEAR_VALUE','GL_COLOR_BUFFER_BIT','GL_COLOR_ARRAY_TYPE_EXT', + 'GL_COLOR_ARRAY_TYPE','GL_COLOR_ARRAY_STRIDE_EXT','GL_COLOR_ARRAY_STRIDE','GL_COLOR_ARRAY_SIZE_EXT','GL_COLOR_ARRAY_SIZE', + 'GL_COLOR_ARRAY_POINTER_EXT','GL_COLOR_ARRAY_POINTER','GL_COLOR_ARRAY_EXT','GL_COLOR_ARRAY_COUNT_EXT','GL_COLOR_ARRAY', + 'GL_COLOR','GL_COEFF','GL_CLIP_PLANE5','GL_CLIP_PLANE4','GL_CLIP_PLANE3','GL_CLIP_PLANE2','GL_CLIP_PLANE1','GL_CLIP_PLANE0', + 'GL_CLIENT_VERTEX_ARRAY_BIT','GL_CLIENT_PIXEL_STORE_BIT','GL_CLIENT_ATTRIB_STACK_DEPTH','GL_CLIENT_ALL_ATTRIB_BITS', + 'GL_CLIENT_ACTIVE_TEXTURE_ARB','GL_CLIENT_ACTIVE_TEXTURE','GL_CLEAR','GL_CLAMP','GL_CCW','GL_C4UB_V3F','GL_C4UB_V2F', + 'GL_C4F_N3F_V3F','GL_C3F_V3F','GL_BYTE','GL_BLUE_SCALE','GL_BLUE_BITS','GL_BLUE_BIAS','GL_BLUE','GL_BLEND_SRC','GL_BLEND_DST', + 'GL_BLEND','GL_BITMAP_TOKEN','GL_BITMAP','GL_BGR_EXT','GL_BGRA_EXT','GL_BACK_RIGHT','GL_BACK_LEFT','GL_BACK', + 'GL_AUX_BUFFERS','GL_AUX3','GL_AUX2','GL_AUX1','GL_AUX0','GL_AUTO_NORMAL','GL_ATTRIB_STACK_DEPTH','GL_AND_REVERSE', + 'GL_AND_INVERTED','GL_AND','GL_AMBIENT_AND_DIFFUSE','GL_AMBIENT','GL_ALWAYS','GL_ALPHA_TEST_REF','GL_ALPHA_TEST_FUNC', + 'GL_ALPHA_TEST','GL_ALPHA_SCALE','GL_ALPHA_BITS','GL_ALPHA_BIAS','GL_ALPHA8','GL_ALPHA4','GL_ALPHA16','GL_ALPHA12', + 'GL_ALPHA','GL_ALL_ATTRIB_BITS','GL_ADD_SIGNED_EXT','GL_ADD_SIGNED','GL_ADD','GL_ACTIVE_TEXTURE_ARB','GL_ACTIVE_TEXTURE', + 'GL_ACCUM_RED_BITS','GL_ACCUM_GREEN_BITS','GL_ACCUM_CLEAR_VALUE','GL_ACCUM_BUFFER_BIT','GL_ACCUM_BLUE_BITS','GL_ACCUM_ALPHA_BITS', + 'GL_ACCUM','GL_4_BYTES','GL_4D_COLOR_TEXTURE','GL_3_BYTES','GL_3D_COLOR_TEXTURE','GL_3D_COLOR','GL_3D','GL_2_BYTES', + 'GL_2D','GLU_V_STEP','GLU_VERTEX','GLU_VERSION_1_2','GLU_VERSION_1_1','GLU_VERSION','GLU_U_STEP','GLU_UNKNOWN','GLU_TRUE', + 'GLU_TESS_WINDING_RULE','GLU_TESS_WINDING_POSITIVE','GLU_TESS_WINDING_ODD','GLU_TESS_WINDING_NONZERO','GLU_TESS_WINDING_NEGATIVE', + 'GLU_TESS_WINDING_ABS_GEQ_TWO','GLU_TESS_VERTEX_DATA','GLU_TESS_VERTEX','GLU_TESS_TOLERANCE','GLU_TESS_NEED_COMBINE_CALLBACK','GLU_TESS_MISSING_END_POLYGON', + 'GLU_TESS_MISSING_END_CONTOUR','GLU_TESS_MISSING_BEGIN_POLYGON','GLU_TESS_MISSING_BEGIN_CONTOUR','GLU_TESS_ERROR_DATA', + 'GLU_TESS_ERROR8','GLU_TESS_ERROR7','GLU_TESS_ERROR6','GLU_TESS_ERROR5','GLU_TESS_ERROR4','GLU_TESS_ERROR3','GLU_TESS_ERROR2', + 'GLU_TESS_ERROR1','GLU_TESS_ERROR','GLU_TESS_END_DATA','GLU_TESS_END','GLU_TESS_EDGE_FLAG_DATA','GLU_TESS_EDGE_FLAG', + 'GLU_TESS_COORD_TOO_LARGE','GLU_TESS_COMBINE_DATA','GLU_TESS_COMBINE','GLU_TESS_BOUNDARY_ONLY','GLU_TESS_BEGIN_DATA', + 'GLU_TESS_BEGIN','GLU_SMOOTH','GLU_SILHOUETTE','GLU_SAMPLING_TOLERANCE','GLU_SAMPLING_METHOD','GLU_POINT','GLU_PATH_LENGTH', + 'GLU_PARAMETRIC_TOLERANCE','GLU_PARAMETRIC_ERROR','GLU_OUT_OF_MEMORY','GLU_OUTSIDE','GLU_OUTLINE_POLYGON','GLU_OUTLINE_PATCH', + 'GLU_NURBS_ERROR9','GLU_NURBS_ERROR8','GLU_NURBS_ERROR7','GLU_NURBS_ERROR6','GLU_NURBS_ERROR5','GLU_NURBS_ERROR4', + 'GLU_NURBS_ERROR37','GLU_NURBS_ERROR36','GLU_NURBS_ERROR35','GLU_NURBS_ERROR34','GLU_NURBS_ERROR33','GLU_NURBS_ERROR32', + 'GLU_NURBS_ERROR31','GLU_NURBS_ERROR30','GLU_NURBS_ERROR3','GLU_NURBS_ERROR29','GLU_NURBS_ERROR28','GLU_NURBS_ERROR27','GLU_NURBS_ERROR26', + 'GLU_NURBS_ERROR25','GLU_NURBS_ERROR24','GLU_NURBS_ERROR23','GLU_NURBS_ERROR22','GLU_NURBS_ERROR21','GLU_NURBS_ERROR20', + 'GLU_NURBS_ERROR2','GLU_NURBS_ERROR19','GLU_NURBS_ERROR18','GLU_NURBS_ERROR17','GLU_NURBS_ERROR16','GLU_NURBS_ERROR15','GLU_NURBS_ERROR14', + 'GLU_NURBS_ERROR13','GLU_NURBS_ERROR12','GLU_NURBS_ERROR11','GLU_NURBS_ERROR10','GLU_NURBS_ERROR1','GLU_NONE', + 'GLU_MAP1_TRIM_3','GLU_MAP1_TRIM_2','GLU_LINE','GLU_INVALID_VALUE','GLU_INVALID_ENUM','GLU_INTERIOR','GLU_INSIDE','GLU_INCOMPATIBLE_GL_VERSION', + 'GLU_FLAT','GLU_FILL','GLU_FALSE','GLU_EXTERIOR','GLU_EXTENSIONS','GLU_ERROR','GLU_END','GLU_EDGE_FLAG','GLU_DOMAIN_DISTANCE', + 'GLU_DISPLAY_MODE','GLU_CW','GLU_CULLING','GLU_CCW','GLU_BEGIN','GLU_AUTO_LOAD_MATRIX','CHANNEL_UNORDERED','CHANNEL_ORDERED', + 'CHANNEL_MAX' + ), + 2 => array( + + // Red Lowercase Keywords + + 'WriteWord','WriteString','WriteReal','WriteLine','WriteInt','WriteFloat','WriteDouble','WriteChar','WriteByte', + 'windowwidth','windowheight','waittimer','Vec4','Vec3','Vec2','val','UpdateJoystick','ucase$','Transpose','tickcount', + 'textscroll','textrows','textmode','textcols','tanh','tand','tan','synctimercatchup','synctimer','swapbuffers', + 'str$','stopsoundvoice','stopsounds','stopmusic','sqrt','sqr','sprzorder','spryvel','sprytiles','sprysize','spryrepeat', + 'spryflip','sprycentre','spry','sprxvel','sprxtiles','sprxsize','sprxrepeat','sprxflip','sprxcentre','sprx', + 'sprvisible','sprvel','sprtype','sprtop','sprspin','sprsolid','sprsetzorder','sprsetyvel','sprsetysize','sprsetyrepeat', + 'sprsetyflip','sprsetycentre','sprsety','sprsetxvel','sprsetxsize','sprsetxrepeat','sprsetxflip','sprsetxcentre', + 'sprsetx','sprsetvisible','sprsetvel','sprsettiles','sprsettextures','sprsettexture','sprsetspin','sprsetsolid', + 'sprsetsize','sprsetscale','sprsetpos','sprsetparallax','sprsetframe','sprsetcolor','sprsetanimspeed','sprsetanimloop', + 'sprsetangle','sprsetalpha','sprscale','sprright','sprpos','sprparallax','sprleft','spriteareawidth','spriteareaheight', + 'sprframe','sprcolor','sprcameraz','sprcameray','sprcamerax','sprcamerasetz','sprcamerasety','sprcamerasetx', + 'sprcamerasetpos','sprcamerasetfov','sprcamerasetangle','sprcamerapos','sprcamerafov','sprcameraangle', + 'sprbottom','spranimspeed','spranimloop','spranimdone','sprangle','spralpha','spraddtextures','spraddtexture', + 'sounderror','sleep','sind','sin','showcursor','sgn','settextscroll','setmusicvolume','SendMessage','Seek', + 'scankeydown','RTInvert','rnd','right$','resizetext','resizespritearea','RejectConnection','ReceiveMessage','ReadWord', + 'ReadText','ReadReal','ReadLine','ReadInt','ReadFloat','ReadDouble','ReadChar','ReadByte','randomize','printr', + 'print','pow','playsound','playmusic','performancecounter','Orthonormalize','OpenFileWrite','OpenFileRead','Normalize', + 'newtilemap','newsprite','NewServer','NewConnection','musicplaying','mouse_yd','mouse_y','mouse_xd','mouse_x', + 'mouse_wheel','mouse_button','mid$','MessageSmoothed','MessageReliable','MessagePending','MessageChannel','maxtextureunits', + 'MatrixZero','MatrixTranslate','MatrixScale','MatrixRotateZ','MatrixRotateY','MatrixRotateX','MatrixRotate','MatrixIdentity', + 'MatrixCrossProduct','MatrixBasis','log','locate','loadtexture','loadsound','loadmipmaptexture','loadmipmapimagestrip', + 'loadimagestrip','loadimage','Length','len','left$','lcase$','keydown','Joy_Y','Joy_X','Joy_Up','Joy_Right','Joy_Left', + 'Joy_Keys','Joy_Down','Joy_Button','Joy_3','Joy_2','Joy_1','Joy_0','int','inscankey','input$','inkey$','inittimer', + 'imagewidth','imagestripframes','imageheight','imageformat','imagedatatype','hidecursor','glViewport','glVertex4sv', + 'glVertex4s','glVertex4iv','glVertex4i','glVertex4fv','glVertex4f','glVertex4dv','glVertex4d','glVertex3sv','glVertex3s', + 'glVertex3iv','glVertex3i','glVertex3fv','glVertex3f','glVertex3dv','glVertex3d','glVertex2sv','glVertex2s','glVertex2iv', + 'glVertex2i','glVertex2fv','glVertex2f','glVertex2dv','glVertex2d','gluPerspective','gluOrtho2D','gluLookAt', + 'glubuild2dmipmaps','glTranslatef','glTranslated','gltexsubimage2d','glTexParameteriv','glTexParameteri', + 'glTexParameterfv','glTexParameterf','glteximage2d','glTexGeniv','glTexGeni','glTexGenfv','glTexGenf','glTexGendv', + 'glTexGend','glTexEnviv','glTexEnvi','glTexEnvfv','glTexEnvf','glTexCoord4sv','glTexCoord4s','glTexCoord4iv','glTexCoord4i', + 'glTexCoord4fv','glTexCoord4f','glTexCoord4dv','glTexCoord4d','glTexCoord3sv','glTexCoord3s','glTexCoord3iv','glTexCoord3i', + 'glTexCoord3fv','glTexCoord3f','glTexCoord3dv','glTexCoord3d','glTexCoord2sv','glTexCoord2s','glTexCoord2iv','glTexCoord2i', + 'glTexCoord2fv','glTexCoord2f','glTexCoord2dv','glTexCoord2d','glTexCoord1sv','glTexCoord1s','glTexCoord1iv','glTexCoord1i','glTexCoord1fv', + 'glTexCoord1f','glTexCoord1dv','glTexCoord1d','glStencilOp','glStencilMask','glStencilFunc','glShadeModel','glSelectBuffer', + 'glScissor','glScalef','glScaled','glRotatef','glRotated','glRenderMode','glRectsv','glRects','glRectiv','glRecti', + 'glRectfv','glRectf','glRectdv','glRectd','glReadBuffer','glRasterPos4sv','glRasterPos4s','glRasterPos4iv', + 'glRasterPos4i','glRasterPos4fv','glRasterPos4f','glRasterPos4dv','glRasterPos4d','glRasterPos3sv','glRasterPos3s', + 'glRasterPos3iv','glRasterPos3i','glRasterPos3fv','glRasterPos3f','glRasterPos3dv','glRasterPos3d','glRasterPos2sv', + 'glRasterPos2s','glRasterPos2iv','glRasterPos2i','glRasterPos2fv','glRasterPos2f','glRasterPos2dv','glRasterPos2d', + 'glPushName','glPushMatrix','glPushClientAttrib','glPushAttrib','glPrioritizeTextures','glPopName','glPopMatrix', + 'glPopClientAttrib','glPopAttrib','glpolygonstipple','glPolygonOffset','glPolygonMode','glPointSize','glPixelZoom', + 'glPixelTransferi','glPixelTransferf','glPixelStorei','glPixelStoref','glPassThrough','glOrtho','glNormal3sv','glNormal3s', + 'glNormal3iv','glNormal3i','glNormal3fv','glNormal3f','glNormal3dv','glNormal3d','glNormal3bv','glNormal3b','glNewList', + 'glMultMatrixf','glMultMatrixd','glmultitexcoord2f','glmultitexcoord2d','glMatrixMode','glMaterialiv','glMateriali', + 'glMaterialfv','glMaterialf','glMapGrid2f','glMapGrid2d','glMapGrid1f','glMapGrid1d','glLogicOp','glLoadName','glLoadMatrixf', + 'glLoadMatrixd','glLoadIdentity','glListBase','glLineWidth','glLineStipple','glLightModeliv','glLightModeli','glLightModelfv', + 'glLightModelf','glLightiv','glLighti','glLightfv','glLightf','glIsTexture','glIsList','glIsEnabled','glInitNames', + 'glIndexubv','glIndexub','glIndexsv','glIndexs','glIndexMask','glIndexiv','glIndexi','glIndexfv','glIndexf','glIndexdv', + 'glIndexd','glHint','glGetTexParameteriv','glGetTexParameterfv','glGetTexLevelParameteriv','glGetTexLevelParameterfv', + 'glGetTexGeniv','glGetTexGenfv','glGetTexGendv','glGetTexEnviv','glGetTexEnvfv','glgetstring','glgetpolygonstipple','glGetPixelMapuiv', + 'glGetMaterialiv','glGetMaterialfv','glGetLightiv','glGetLightfv','glGetIntegerv','glGetFloatv', + 'glGetError','glGetDoublev','glGetClipPlane','glGetBooleanv','glgentextures','glgentexture', + 'glgenlists','glFrustum','glFrontFace','glFogiv','glFogi','glFogfv','glFogf','glFlush','glFinish','glFeedbackBuffer', + 'glEvalPoint2','glEvalPoint1','glEvalMesh2','glEvalMesh1','glEvalCoord2fv','glEvalCoord2f','glEvalCoord2dv','glEvalCoord2d', + 'glEvalCoord1fv','glEvalCoord1f','glEvalCoord1dv','glEvalCoord1d','glEndList','glEnd','glEnableClientState','glEnable', + 'glEdgeFlagv','glEdgeFlag','glDrawBuffer','glDrawArrays','glDisableClientState','glDisable','glDepthRange','glDepthMask', + 'glDepthFunc','gldeletetextures','gldeletetexture','gldeletelists','glCullFace','glCopyTexSubImage2D','glCopyTexSubImage1D', + 'glCopyTexImage2D','glCopyTexImage1D','glColorMaterial','glColorMask','glColor4usv','glColor4us','glColor4uiv','glColor4ui', + 'glColor4ubv','glColor4ub','glColor4sv','glColor4s','glColor4iv','glColor4i','glColor4fv','glColor4f','glColor4dv', + 'glColor4d','glColor4bv','glColor4b','glColor3usv','glColor3us','glColor3uiv','glColor3ui','glColor3ubv','glColor3ub', + 'glColor3sv','glColor3s','glColor3iv','glColor3i','glColor3fv','glColor3f','glColor3dv','glColor3d','glColor3bv', + 'glColor3b','glClipPlane','glClearStencil','glClearIndex','glClearDepth','glClearColor','glClearAccum','glClear', + 'glcalllists','glCallList','glBlendFunc','glBindTexture','glBegin','glArrayElement','glAreTexturesResident', + 'glAlphaFunc','glactivetexture','glAccum','font','FindNextFile','FindFirstFile','FindClose','FileError', + 'extensionsupported','exp','execute','EndOfFile','drawtext','divbyzero','Determinant','deletesprite','deletesound', + 'DeleteServer','deleteimage','DeleteConnection','defaultfont','CrossProduct','cosd','cos','copysprite','ConnectionPending', + 'ConnectionHandShaking','ConnectionConnected','ConnectionAddress','compilererrorline','compilererrorcol','compilererror', + 'compilefile','compile','color','cls','CloseFile','clearregion','clearline','clearkeys','chr$','charat$','bindsprite', + 'beep','atnd','atn2d','atn2','atn','atand','asc','argcount','arg','animatesprites','AcceptConnection','abs' + ), + 3 => array( + + // Blue Lowercase Keywords + + 'xor','while','wend','until','type','traditional_print','traditional','to','then','struc','string','step','single', + 'run','return','reset','read','or','null','not','next','lor','loop','language','land','integer','input','if', + 'goto','gosub','for','endstruc','endif','end','elseif','else','double','do','dim','data','const','basic4gl','as', + 'and','alloc' + ) + + ), + 'SYMBOLS' => array( + '=', '<', '>', '>=', '<=', '+', '-', '*', '/', '%', '(', ')', '{', '}', '[', ']', '&', ';', ':', '$' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000080; font-weight: bold;', + 2 => 'color: #FF0000;', + 3 => 'color: #0000FF;' + ), + 'COMMENTS' => array( + 1 => 'color: #657CC4; font-style: italic;' + ), + 'BRACKETS' => array( + 0 => 'color: #000080;' + ), + 'STRINGS' => array( + 0 => 'color: #008000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000080; font-weight: bold;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #0000FF;' + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/bf.php b/examples/includes/geshi/geshi/bf.php new file mode 100644 index 0000000..e5dcc42 --- /dev/null +++ b/examples/includes/geshi/geshi/bf.php @@ -0,0 +1,114 @@ + 'Brainfuck', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array(1 => '/[^\n+\-<>\[\]\.\,Y]+/s'), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + ), + 'SYMBOLS' => array( + 0 => array('+', '-'), + 1 => array('[', ']'), + 2 => array('<', '>'), + 3 => array('.', ','), + 4 => array('Y') //Brainfork Extension ;-) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #006600;', + 1 => 'color: #660000;', + 2 => 'color: #000066;', + 3 => 'color: #660066;', + 4 => 'color: #666600;' + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'STRINGS' => GESHI_NEVER, + 'NUMBERS' => GESHI_NEVER + ), + 'KEYWORDS' => array( + 'DISALLOW_BEFORE' => '', + 'DISALLOW_AFTER' => '' + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/blitzbasic.php b/examples/includes/geshi/geshi/blitzbasic.php new file mode 100644 index 0000000..a8c3259 --- /dev/null +++ b/examples/includes/geshi/geshi/blitzbasic.php @@ -0,0 +1,185 @@ + 'BlitzBasic', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'If','EndIf','ElseIf','Else If','Else','While','Wend','Return','Next','Include','End Type','End Select','End If','End Function','End','Select', + 'Type','Forever','For','Or','And','AppTitle','Case','Goto','Gosub','Step','Stop','Int','Last','False','Then','To','True','Until','Float', + 'String','Before','Not' + ), + 2 => array( + // All Functions - 2D BB and 3D BB + 'Xor','WriteString','WriteShort','WritePixelFast','WritePixel','WriteLine','WriteInt','WriteFloat','WriteFile','WriteBytes', + 'WriteByte','Write','WaitTimer','WaitMouse','WaitKey','WaitJoy','VWait','Viewport', + 'Upper','UpdateGamma','UnlockBuffer','UDPTimeouts','UDPStreamPort','UDPStreamIP','UDPMsgPort','UDPMsgIP', + 'Trim','TotalVidMem','TileImage','TileBlock','TFormImage','TFormFilter','Text', + 'TCPTimeouts','TCPStreamPort','TCPStreamIP','Tan','SystemProperty','StringWidth','StringHeight','Str','StopNetGame', + 'StopChannel','StartNetGame','Sqr','SoundVolume','SoundPitch','SoundPan','Sin','Shr', + 'ShowPointer','Shl','Sgn','SetGfxDriver','SetGamma','SetFont','SetEnv','SetBuffer','SendUDPMsg','SendNetMsg', + 'SeekFile','SeedRnd','ScanLine','ScaleImage','SaveImage','SaveBuffer','Sar','RuntimeError','RSet', + 'RotateImage','RndSeed','Rnd','Right','ResumeChannel','Restore','ResizeImage','ResizeBank','Replace', + 'Repeat','RecvUDPMsg','RecvNetMsg','RectsOverlap','Rect','ReadString','ReadShort','ReadPixelFast','ReadPixel','ReadLine', + 'ReadInt','ReadFloat','ReadFile','ReadDir','ReadBytes','ReadByte','ReadAvail','Read','Rand','Print', + 'PokeShort','PokeInt','PokeFloat','PokeByte','Plot','PlaySound','PlayMusic','PlayCDTrack','Pi','PeekShort', + 'PeekInt','PeekFloat','PeekByte','PauseChannel','Oval','Origin','OpenTCPStream','OpenMovie','OpenFile', + 'Null','NextFile','New','NetPlayerName','NetPlayerLocal','NetMsgType','NetMsgTo','NetMsgFrom', + 'NetMsgData','MovieWidth','MoviePlaying','MovieHeight','MoveMouse','MouseZSpeed','MouseZ','MouseYSpeed','MouseY','MouseXSpeed', + 'MouseX','MouseHit','MouseDown','Mod','Millisecs','MidHandle','Mid','MaskImage','LSet','Lower', + 'LoopSound','Log10','Log','LockBuffer','Locate','Local','LoadSound','LoadImage','LoadFont','LoadBuffer', + 'LoadAnimImage','Line','Len','Left','KeyHit','KeyDown','JoyZDir','JoyZ','JoyYDir', + 'JoyYaw','JoyY','JoyXDir','JoyX','JoyVDir','JoyV','JoyUDir','JoyU','JoyType','JoyRoll', + 'JoyPitch','JoyHit','JoyHat','JoyDown','JoinNetGame','Instr','Insert','Input', + 'ImageYHandle','ImageXHandle','ImageWidth','ImagesOverlap','ImagesCollide','ImageRectOverlap','ImageRectCollide','ImageHeight','ImageBuffer', + 'HostNetGame','HostIP','HidePointer','Hex','HandleImage','GraphicsWidth','GraphicsHeight','GraphicsDepth','GraphicsBuffer','Graphics', + 'GrabImage','Global','GFXModeWidth','GFXModeHeight','GfxModeExists','GFXModeDepth','GfxDriverName','GetMouse', + 'GetKey','GetJoy','GetEnv','GetColor','GammaRed','GammaGreen','GammaBlue','Function','FrontBuffer','FreeTimer', + 'FreeSound','FreeImage','FreeFont','FreeBank','FontWidth','FontHeight','FlushMouse','FlushKeys', + 'FlushJoy','Floor','Flip','First','FileType','FileSize','FilePos','Field', + 'Exp','Exit','ExecFile','Eof','EndGraphics','Each','DrawMovie','DrawImageRect','DrawImage','DrawBlockRect','DrawBlock', + 'DottedIP','Dim','DeleteNetPlayer','DeleteFile','DeleteDir','Delete','Delay','Default','DebugLog','Data', + 'CurrentTime','CurrentDir','CurrentDate','CreateUDPStream','CreateTimer','CreateTCPServer','CreateNetPlayer','CreateImage','CreateDir','CreateBank', + 'CountHostIPs','CountGFXModes','CountGfxDrivers','Cos','CopyStream','CopyRect','CopyPixelFast','CopyPixel','CopyImage','CopyFile', + 'CopyBank','Const','CommandLine','ColorRed','ColorGreen','ColorBlue','Color','ClsColor','Cls','CloseUDPStream', + 'CloseTCPStream','CloseTCPServer','CloseMovie','CloseFile','CloseDir','Chr','ChannelVolume','ChannelPlaying','ChannelPitch','ChannelPan', + 'ChangeDir','Ceil','CallDLL','Bin','BankSize','BackBuffer','AvailVidMem','AutoMidHandle', + 'ATan2','ATan','ASin','Asc','After','ACos','AcceptTCPStream','Abs', + // 3D Commands + 'Wireframe','Windowed3D','WBuffer','VertexZ','VertexY', + 'VertexX','VertexW','VertexV','VertexU','VertexTexCoords','VertexRed','VertexNZ','VertexNY','VertexNX','VertexNormal', + 'VertexGreen','VertexCoords','VertexColor','VertexBlue','VertexAlpha','VectorYaw','VectorPitch','UpdateWorld','UpdateNormals','TurnEntity', + 'TrisRendered','TriangleVertex','TranslateEntity','TFormVector','TFormPoint','TFormNormal','TFormedZ','TFormedY','TFormedX','TextureWidth', + 'TextureName','TextureHeight','TextureFilter','TextureCoords','TextureBuffer','TextureBlend','TerrainZ','TerrainY','TerrainX','TerrainSize', + 'TerrainShading','TerrainHeight','TerrainDetail','SpriteViewMode','ShowEntity','SetCubeFace','SetAnimTime','SetAnimKey','ScaleTexture','ScaleSprite', + 'ScaleMesh','ScaleEntity','RotateTexture','RotateSprite','RotateMesh','RotateEntity','ResetEntity','RenderWorld','ProjectedZ','ProjectedY', + 'ProjectedX','PositionTexture','PositionMesh','PositionEntity','PointEntity','PickedZ','PickedY','PickedX','PickedTriangle','PickedTime', + 'PickedSurface','PickedNZ','PickedNY','PickedNX','PickedEntity','PaintSurface','PaintMesh','PaintEntity','NameEntity','MoveEntity', + 'ModifyTerrain','MeshWidth','MeshHeight','MeshesIntersect','MeshDepth','MD2AnimTime','MD2AnimLength','MD2Animating','LoadTexture','LoadTerrain', + 'LoadSprite','LoadMesh','LoadMD2','LoaderMatrix','LoadBSP','LoadBrush','LoadAnimTexture','LoadAnimSeq','LoadAnimMesh','Load3DSound', + 'LinePick','LightRange','LightMesh','LightConeAngles','LightColor','HWMultiTex','HideEntity','HandleSprite','Graphics3D','GfxMode3DExists', + 'GfxMode3D','GfxDriverCaps3D','GfxDriver3D','GetSurfaceBrush','GetSurface','GetParent','GetMatElement','GetEntityType','GetEntityBrush','GetChild', + 'GetBrushTexture','FreeTexture','FreeEntity','FreeBrush','FlipMesh','FitMesh','FindSurface','FindChild','ExtractAnimSeq','EntityZ', + 'EntityYaw','EntityY','EntityX','EntityVisible','EntityType','EntityTexture','EntityShininess','EntityRoll','EntityRadius','EntityPitch', + 'EntityPickMode','EntityPick','EntityParent','EntityOrder','EntityName','EntityInView','EntityFX','EntityDistance','EntityColor','EntityCollided', + 'EntityBox','EntityBlend','EntityAutoFade','EntityAlpha','EmitSound','Dither','DeltaYaw','DeltaPitch','CreateTexture','CreateTerrain', + 'CreateSurface','CreateSprite','CreateSphere','CreatePlane','CreatePivot','CreateMirror','CreateMesh','CreateListener','CreateLight','CreateCylinder', + 'CreateCube','CreateCone','CreateCamera','CreateBrush','CountVertices','CountTriangles','CountSurfaces','CountGfxModes3D','CountCollisions','CountChildren', + 'CopyMesh','CopyEntity','CollisionZ','CollisionY','CollisionX','CollisionTriangle','CollisionTime','CollisionSurface','Collisions','CollisionNZ', + 'CollisionNY','CollisionNX','CollisionEntity','ClearWorld','ClearTextureFilters','ClearSurface','ClearCollisions','CaptureWorld','CameraZoom','CameraViewport', + 'CameraRange','CameraProjMode','CameraProject','CameraPick','CameraFogRange','CameraFogMode','CameraFogColor','CameraClsMode','CameraClsColor','BSPLighting', + 'BSPAmbientLight','BrushTexture','BrushShininess','BrushFX','BrushColor','BrushBlend','BrushAlpha','AntiAlias','AnimTime','AnimSeq', + 'AnimLength','Animating','AnimateMD2','Animate','AmbientLight','AlignToVector','AddVertex','AddTriangle','AddMesh','AddAnimSeq', + ) + ), + 'SYMBOLS' => array( + '(',')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000066; font-weight: bold;', + 2 => 'color: #0000ff;' + ), + 'COMMENTS' => array( + 1 => 'color: #D9D100; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000066;' + ), + 'STRINGS' => array( + 0 => 'color: #009900;' + ), + 'NUMBERS' => array( + 0 => 'color: #CC0000;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + 1 => '\\' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => false, + 1 => false + ) +); + +?> diff --git a/examples/includes/geshi/geshi/bnf.php b/examples/includes/geshi/geshi/bnf.php new file mode 100644 index 0000000..c9b3aae --- /dev/null +++ b/examples/includes/geshi/geshi/bnf.php @@ -0,0 +1,110 @@ + 'bnf', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', "'"), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array(), + 'SYMBOLS' => array( + '(', ')', '<', '>', '::=', '|' + ), + 'CASE_SENSITIVE' => array( + //GESHI_COMMENTS => false + ), + 'STYLES' => array( + 'KEYWORDS' => array(), + 'COMMENTS' => array( + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => '' + ), + 'STRINGS' => array( + 0 => 'color: #a00;', + 1 => 'color: #a00;' + ), + 'NUMBERS' => array( + 0 => '' + ), + 'METHODS' => array( + 0 => '' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066; font-weight: bold;', // Unused + ), + 'REGEXPS' => array( + 0 => 'color: #007;', + ), + 'SCRIPT' => array( + 0 => '' + ) + ), + 'URLS' => array(), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + //terminal symbols + 0 => array( + GESHI_SEARCH => '(<)([^&]+?)(>)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/boo.php b/examples/includes/geshi/geshi/boo.php new file mode 100644 index 0000000..1741d2c --- /dev/null +++ b/examples/includes/geshi/geshi/boo.php @@ -0,0 +1,217 @@ + 'Boo', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'''", "'", '"""', '"'), + 'HARDQUOTE' => array('"""', '"""'), + 'HARDESCAPE' => array('\"""'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array(//Namespace + 'namespace', 'import', 'from' + ), + 2 => array(//Jump + 'yield', 'return', 'goto', 'continue', 'break' + ), + 3 => array(//Conditional + 'while', 'unless', 'then', 'in', 'if', 'for', 'else', 'elif' + ), + 4 => array(//Property + 'set', 'get' + ), + 5 => array(//Exception + 'try', 'raise', 'failure', 'except', 'ensure' + ), + 6 => array(//Visibility + 'public', 'private', 'protected', 'internal' + ), + 7 => array(//Define + 'struct', 'ref', 'of', 'interface', 'event', 'enum', 'do', 'destructor', 'def', 'constructor', 'class' + ), + 8 => array(//Cast + 'typeof', 'cast', 'as' + ), + 9 => array(//BiMacro + 'yieldAll', 'using', 'unchecked', 'rawArayIndexing', 'print', 'normalArrayIndexing', 'lock', + 'debug', 'checked', 'assert' + ), + 10 => array(//BiAttr + 'required', 'property', 'meta', 'getter', 'default' + ), + 11 => array(//BiFunc + 'zip', 'shellp', 'shellm', 'shell', 'reversed', 'range', 'prompt', + 'matrix', 'map', 'len', 'join', 'iterator', 'gets', 'enumerate', 'cat', 'array' + ), + 12 => array(//HiFunc + '__switch__', '__initobj__', '__eval__', '__addressof__', 'quack' + ), + 13 => array(//Primitive + 'void', 'ushort', 'ulong', 'uint', 'true', 'timespan', 'string', 'single', + 'short', 'sbyte', 'regex', 'object', 'null', 'long', 'int', 'false', 'duck', + 'double', 'decimal', 'date', 'char', 'callable', 'byte', 'bool' + ), + 14 => array(//Operator + 'not', 'or', 'and', 'is', 'isa', + ), + 15 => array(//Modifier + 'virtual', 'transient', 'static', 'partial', 'override', 'final', 'abstract' + ), + 16 => array(//Access + 'super', 'self' + ), + 17 => array(//Pass + 'pass' + ) + ), + 'SYMBOLS' => array( + '[|', '|]', '${', '(', ')', '[', ']', '{', '}', '!', '@', '%', '&', '*', '|', '/', '<', '>', '+', '-', ';' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true, + 10 => true, + 11 => true, + 12 => true, + 13 => true, + 14 => true, + 15 => true, + 16 => true, + 17 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color:green;font-weight:bold;', + 2 => 'color:navy;', + 3 => 'color:blue;font-weight:bold;', + 4 => 'color:#8B4513;', + 5 => 'color:teal;font-weight:bold;', + 6 => 'color:blue;font-weight:bold;', + 7 => 'color:blue;font-weight:bold;', + 8 => 'color:blue;font-weight:bold;', + 9 => 'color:maroon;', + 10 => 'color:maroon;', + 11 => 'color:purple;', + 12 => 'color:#4B0082;', + 13 => 'color:purple;font-weight:bold;', + 14 => 'color:#008B8B;font-weight:bold;', + 15 => 'color:brown;', + 16 => 'color:black;font-weight:bold;', + 17 => 'color:gray;' + ), + 'COMMENTS' => array( + 1 => 'color: #999999; font-style: italic;', + 2 => 'color: #999999; font-style: italic;', + 'MULTI' => 'color: #008000; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #0000FF; font-weight: bold;', + 'HARD' => 'color: #0000FF; font-weight: bold;', + ), + 'BRACKETS' => array( + 0 => 'color: #006400;' + ), + 'STRINGS' => array( + 0 => 'color: #008000;', + 'HARD' => 'color: #008000;' + ), + 'NUMBERS' => array( + 0 => 'color: #00008B;' + ), + 'METHODS' => array( + 0 => 'color: 000000;', + 1 => 'color: 000000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #006400;' + ), + 'REGEXPS' => array( + #0 => 'color: #0066ff;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '', + 8 => '', + 9 => '', + 10 => '', + 11 => '', + 12 => '', + 13 => '', + 14 => '', + 15 => '', + 16 => '', + 17 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 0 => '.', + 1 => '::' + ), + 'REGEXPS' => array( + #0 => '%(@)?\/(?:(?(1)[^\/\\\\\r\n]+|[^\/\\\\\r\n \t]+)|\\\\[\/\\\\\w+()|.*?$^[\]{}\d])+\/%' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/c.php b/examples/includes/geshi/geshi/c.php new file mode 100644 index 0000000..272885a --- /dev/null +++ b/examples/includes/geshi/geshi/c.php @@ -0,0 +1,188 @@ + 'C', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Multiline-continued single-line comments + 1 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m', + //Multiline-continued preprocessor define + 2 => '/#(?:\\\\\\\\|\\\\\\n|.)*$/m' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[abfnrtv\\'\"?\n]#i", + //Hexadecimal Char Specs + 2 => "#\\\\x[\da-fA-F]{2}#", + //Hexadecimal Char Specs + 3 => "#\\\\u[\da-fA-F]{4}#", + //Hexadecimal Char Specs + 4 => "#\\\\U[\da-fA-F]{8}#", + //Octal Char Specs + 5 => "#\\\\[0-7]{1,3}#" + ), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE | GESHI_NUMBER_BIN_PREFIX_0B | + GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'if', 'return', 'while', 'case', 'continue', 'default', + 'do', 'else', 'for', 'switch', 'goto' + ), + 2 => array( + 'null', 'false', 'break', 'true', 'function', 'enum', 'extern', 'inline' + ), + 3 => array( + 'printf', 'cout' + ), + 4 => array( + 'auto', 'char', 'const', 'double', 'float', 'int', 'long', + 'register', 'short', 'signed', 'sizeof', 'static', 'string', 'struct', + 'typedef', 'union', 'unsigned', 'void', 'volatile', 'wchar_t' + ), + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', + '+', '-', '*', '/', '%', + '=', '<', '>', + '!', '^', '&', '|', + '?', ':', + ';', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;', + 4 => 'color: #993333;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #339933;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #660099; font-weight: bold;', + 3 => 'color: #660099; font-weight: bold;', + 4 => 'color: #660099; font-weight: bold;', + 5 => 'color: #006699; font-weight: bold;', + 'HARD' => '', + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000dd;', + GESHI_NUMBER_BIN_PREFIX_0B => 'color: #208080;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_SHORT => 'color:#800080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI_F => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI => 'color:#800080;' + ), + 'METHODS' => array( + 1 => 'color: #202020;', + 2 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.opengroup.org/onlinepubs/009695399/functions/{FNAMEL}.html', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/c_mac.php b/examples/includes/geshi/geshi/c_mac.php new file mode 100644 index 0000000..3478fba --- /dev/null +++ b/examples/includes/geshi/geshi/c_mac.php @@ -0,0 +1,212 @@ + 'C (Mac)', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Multiline-continued single-line comments + 1 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m', + //Multiline-continued preprocessor define + 2 => '/#(?:\\\\\\\\|\\\\\\n|.)*$/m' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[abfnrtv\\'\"?\n]#i", + //Hexadecimal Char Specs + 2 => "#\\\\x[\da-fA-F]{2}#", + //Hexadecimal Char Specs + 3 => "#\\\\u[\da-fA-F]{4}#", + //Hexadecimal Char Specs + 4 => "#\\\\U[\da-fA-F]{8}#", + //Octal Char Specs + 5 => "#\\\\[0-7]{1,3}#" + ), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE | GESHI_NUMBER_BIN_PREFIX_0B | + GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'if', 'return', 'while', 'case', 'continue', 'default', + 'do', 'else', 'for', 'switch', 'goto' + ), + 2 => array( + 'NULL', 'false', 'break', 'true', 'enum', 'errno', 'EDOM', + 'ERANGE', 'FLT_RADIX', 'FLT_ROUNDS', 'FLT_DIG', 'DBL_DIG', 'LDBL_DIG', + 'FLT_EPSILON', 'DBL_EPSILON', 'LDBL_EPSILON', 'FLT_MANT_DIG', 'DBL_MANT_DIG', + 'LDBL_MANT_DIG', 'FLT_MAX', 'DBL_MAX', 'LDBL_MAX', 'FLT_MAX_EXP', 'DBL_MAX_EXP', + 'LDBL_MAX_EXP', 'FLT_MIN', 'DBL_MIN', 'LDBL_MIN', 'FLT_MIN_EXP', 'DBL_MIN_EXP', + 'LDBL_MIN_EXP', 'CHAR_BIT', 'CHAR_MAX', 'CHAR_MIN', 'SCHAR_MAX', 'SCHAR_MIN', + 'UCHAR_MAX', 'SHRT_MAX', 'SHRT_MIN', 'USHRT_MAX', 'INT_MAX', 'INT_MIN', + 'UINT_MAX', 'LONG_MAX', 'LONG_MIN', 'ULONG_MAX', 'HUGE_VAL', 'SIGABRT', + 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', 'SIG_DFL', 'SIG_ERR', + 'SIG_IGN', 'BUFSIZ', 'EOF', 'FILENAME_MAX', 'FOPEN_MAX', 'L_tmpnam', + 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'stdin', 'stdout', 'stderr', + 'EXIT_FAILURE', 'EXIT_SUCCESS', 'RAND_MAX', 'CLOCKS_PER_SEC', + // Mac-specific constants: + 'kCFAllocatorDefault' + ), + 3 => array( + 'printf', 'fprintf', 'snprintf', 'sprintf', 'assert', + 'isalnum', 'isalpha', 'isdigit', 'iscntrl', 'isgraph', 'islower', 'isprint', + 'ispunct', 'isspace', 'isupper', 'isxdigit', 'tolower', 'toupper', + 'exp', 'log', 'log10', 'pow', 'sqrt', 'ceil', 'floor', 'fabs', 'ldexp', + 'frexp', 'modf', 'fmod', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', + 'sinh', 'cosh', 'tanh', 'setjmp', 'longjmp', + 'va_start', 'va_arg', 'va_end', 'offsetof', 'sizeof', 'fopen', 'freopen', + 'fflush', 'fclose', 'remove', 'rename', 'tmpfile', 'tmpname', 'setvbuf', + 'setbuf', 'vfprintf', 'vprintf', 'vsprintf', 'fscanf', 'scanf', 'sscanf', + 'fgetc', 'fgets', 'fputc', 'fputs', 'getc', 'getchar', 'gets', 'putc', + 'putchar', 'puts', 'ungetc', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', + 'fgetpos', 'fsetpos', 'clearerr', 'feof', 'ferror', 'perror', 'abs', 'labs', + 'div', 'ldiv', 'atof', 'atoi', 'atol', 'strtod', 'strtol', 'strtoul', 'calloc', + 'malloc', 'realloc', 'free', 'abort', 'exit', 'atexit', 'system', 'getenv', + 'bsearch', 'qsort', 'rand', 'srand', 'strcpy', 'strncpy', 'strcat', 'strncat', + 'strcmp', 'strncmp', 'strcoll', 'strchr', 'strrchr', 'strspn', 'strcspn', + 'strpbrk', 'strstr', 'strlen', 'strerror', 'strtok', 'strxfrm', 'memcpy', + 'memmove', 'memcmp', 'memchr', 'memset', 'clock', 'time', 'difftime', 'mktime', + 'asctime', 'ctime', 'gmtime', 'localtime', 'strftime' + ), + 4 => array( + 'auto', 'char', 'const', 'double', 'float', 'int', 'long', + 'register', 'short', 'signed', 'static', 'string', 'struct', + 'typedef', 'union', 'unsigned', 'void', 'volatile', 'extern', 'jmp_buf', + 'signal', 'raise', 'va_list', 'ptrdiff_t', 'size_t', 'FILE', 'fpos_t', + 'div_t', 'ldiv_t', 'clock_t', 'time_t', 'tm', + // Mac-specific types: + 'CFArrayRef', 'CFDictionaryRef', 'CFMutableDictionaryRef', 'CFBundleRef', 'CFSetRef', 'CFStringRef', + 'CFURLRef', 'CFLocaleRef', 'CFDateFormatterRef', 'CFNumberFormatterRef', 'CFPropertyListRef', + 'CFTreeRef', 'CFWriteStreamRef', 'CFCharacterSetRef', 'CFMutableStringRef', 'CFNotificationRef', + 'CFReadStreamRef', 'CFNull', 'CFAllocatorRef', 'CFBagRef', 'CFBinaryHeapRef', + 'CFBitVectorRef', 'CFBooleanRef', 'CFDataRef', 'CFDateRef', 'CFMachPortRef', 'CFMessagePortRef', + 'CFMutableArrayRef', 'CFMutableBagRef', 'CFMutableBitVectorRef', 'CFMutableCharacterSetRef', + 'CFMutableDataRef', 'CFMutableSetRef', 'CFNumberRef', 'CFPlugInRef', 'CFPlugInInstanceRef', + 'CFRunLoopRef', 'CFRunLoopObserverRef', 'CFRunLoopSourceRef', 'CFRunLoopTimerRef', 'CFSocketRef', + 'CFTimeZoneRef', 'CFTypeRef', 'CFUserNotificationRef', 'CFUUIDRef', 'CFXMLNodeRef', 'CFXMLParserRef', + 'CFXMLTreeRef' + ), + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', '&', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff;', + 2 => 'color: #0000ff;', + 3 => 'color: #0000dd;', + 4 => 'color: #0000ff;' + ), + 'COMMENTS' => array( + 1 => 'color: #ff0000;', + 2 => 'color: #339900;', + 'MULTI' => 'color: #ff0000; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #660099; font-weight: bold;', + 3 => 'color: #660099; font-weight: bold;', + 4 => 'color: #660099; font-weight: bold;', + 5 => 'color: #006699; font-weight: bold;', + 'HARD' => '', + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #666666;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000dd;', + GESHI_NUMBER_BIN_PREFIX_0B => 'color: #208080;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_SHORT => 'color:#800080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI_F => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI => 'color:#800080;' + ), + 'METHODS' => array( + 1 => 'color: #00eeff;', + 2 => 'color: #00eeff;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.opengroup.org/onlinepubs/009695399/functions/{FNAMEL}.html', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/caddcl.php b/examples/includes/geshi/geshi/caddcl.php new file mode 100644 index 0000000..69d19dc --- /dev/null +++ b/examples/includes/geshi/geshi/caddcl.php @@ -0,0 +1,126 @@ + 'CAD DCL', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'boxed_column','boxed_radio_column','boxed_radio_row','boxed_row', + 'column','concatenation','button','dialog','edit_box','image','image_button', + 'errtile','list_box','ok_cancel','ok_cancel_help','ok_cancel_help_errtile', + 'ok_cancel_help_info','ok_only','paragraph','popup_list','radio_button', + 'radio_column','radio_row','row','slider','spacer','spacer_0','spacer_1','text', + 'text_part','toggle', + 'action','alignment','allow_accept','aspect_ratio','big_increment', + 'children_alignment','children_fixed_height', + 'children_fixed_width','color', + 'edit_limit','edit_width','fixed_height','fixed_width', + 'height','initial_focus','is_cancel','is_default', + 'is_enabled','is_tab_stop','is-bold','key','label','layout','list', + 'max_value','min_value','mnemonic','multiple_select','password_char', + 'small_increment','tabs','tab_truncate','value','width', + 'false','true','left','right','centered','top','bottom', + 'dialog_line','dialog_foreground','dialog_background', + 'graphics_background','black','red','yellow','green','cyan', + 'blue','magenta','whitegraphics_foreground', + 'horizontal','vertical' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', '&', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/cadlisp.php b/examples/includes/geshi/geshi/cadlisp.php new file mode 100644 index 0000000..9865840 --- /dev/null +++ b/examples/includes/geshi/geshi/cadlisp.php @@ -0,0 +1,186 @@ + 'CAD Lisp', + 'COMMENT_SINGLE' => array(1 => ";"), + 'COMMENT_MULTI' => array(";|" => "|;"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'abs','acad_colordlg','acad_helpdlg','acad_strlsort','action_tile', + 'add_list','alert','alloc','and','angle','angtof','angtos','append','apply', + 'arx','arxload','arxunload','ascii','assoc','atan','atof','atoi','atom', + 'atoms-family','autoarxload','autoload','Boole','boundp','caddr', + 'cadr','car','cdr','chr','client_data_tile','close','command','cond', + 'cons','cos','cvunit','defun','defun-q','defun-q-list-ref', + 'defun-q-list-set','dictadd','dictnext','dictremove','dictrename', + 'dictsearch','dimx_tile','dimy_tile','distance','distof','done_dialog', + 'end_image','end_list','entdel','entget','entlast','entmake', + 'entmakex','entmod','entnext','entsel','entupd','eq','equal','eval','exit', + 'exp','expand','expt','fill_image','findfile','fix','float','foreach','function', + 'gc','gcd','get_attr','get_tile','getangle','getcfg','getcname','getcorner', + 'getdist','getenv','getfiled','getint','getkword','getorient','getpoint', + 'getreal','getstring','getvar','graphscr','grclear','grdraw','grread','grtext', + 'grvecs','handent','help','if','initdia','initget','inters','itoa','lambda','last', + 'layoutlist','length','list','listp','load','load_dialog','log','logand','logior', + 'lsh','mapcar','max','mem','member','menucmd','menugroup','min','minusp','mode_tile', + 'namedobjdict','nentsel','nentselp','new_dialog','nil','not','nth','null', + 'numberp','open','or','osnap','polar','prin1','princ','print','progn','prompt', + 'quit','quote','read','read-char','read-line','redraw','regapp','rem','repeat', + 'reverse','rtos','set','set_tile','setcfg','setenv','setfunhelp','setq','setvar', + 'setview','sin','slide_image','snvalid','sqrt','ssadd','ssdel','ssget','ssgetfirst', + 'sslength','ssmemb','ssname','ssnamex','sssetfirst','start_dialog','start_image', + 'start_list','startapp','strcase','strcat','strlen','subst','substr','t','tablet', + 'tblnext','tblobjname','tblsearch','term_dialog','terpri','textbox','textpage', + 'textscr','trace','trans','type','unload_dialog','untrace','vector_image','ver', + 'vports','wcmatch','while','write-char','write-line','xdroom','xdsize','zerop', + 'vl-acad-defun','vl-acad-undefun','vl-arx-import','vlax-3D-point', + 'vlax-add-cmd','vlax-create-object','vlax-curve-getArea', + 'vlax-curve-getClosestPointTo','vlax-curve-getClosestPointToProjection', + 'vlax-curve-getDistAtParam','vlax-curve-getDistAtPoint', + 'vlax-curve-getEndParam','vlax-curve-getEndPoint', + 'vlax-curve-getFirstDeriv','vlax-curve-getParamAtDist', + 'vlax-curve-getParamAtPoint','vlax-curve-getPointAtDist', + 'vlax-curve-getPointAtParam','vlax-curve-getSecondDeriv', + 'vlax-curve-getStartParam','vlax-curve-getStartPoint', + 'vlax-curve-isClosed','vlax-curve-isPeriodic','vlax-curve-isPlanar', + 'vlax-dump-object','vlax-erased-p','vlax-for','vlax-get-acad-object', + 'vlax-get-object','vlax-get-or-create-object','vlax-get-property', + 'vlax-import-type-library','vlax-invoke-method','vlax-ldata-delete', + 'vlax-ldata-get','vlax-ldata-list','vlax-ldata-put','vlax-ldata-test', + 'vlax-make-safearray','vlax-make-variant','vlax-map-collection', + 'vlax-method-applicable-p','vlax-object-released-p','vlax-product-key', + 'vlax-property-available-p','vlax-put-property','vlax-read-enabled-p', + 'vlax-release-object','vlax-remove-cmd','vlax-safearray-fill', + 'vlax-safearray-get-dim','vlax-safearray-get-element', + 'vlax-safearray-get-l-bound','vlax-safearray-get-u-bound', + 'vlax-safearray-put-element','vlax-safearray-type','vlax-tmatrix', + 'vlax-typeinfo-available-p','vlax-variant-change-type', + 'vlax-variant-type','vlax-variant-value','vlax-write-enabled-p', + 'vl-bb-ref','vl-bb-set','vl-catch-all-apply','vl-catch-all-error-message', + 'vl-catch-all-error-p','vl-cmdf','vl-consp','vl-directory-files','vl-doc-export', + 'vl-doc-import','vl-doc-ref','vl-doc-set','vl-every','vl-exit-with-error', + 'vl-exit-with-value','vl-file-copy','vl-file-delete','vl-file-directory-p', + 'vl-filename-base','vl-filename-directory','vl-filename-extension', + 'vl-filename-mktemp','vl-file-rename','vl-file-size','vl-file-systime', + 'vl-get-resource','vlisp-compile','vl-list-exported-functions', + 'vl-list-length','vl-list-loaded-vlx','vl-load-all','vl-load-com', + 'vl-load-reactors','vl-member-if','vl-member-if-not','vl-position', + 'vl-prin1-to-string','vl-princ-to-string','vl-propagate','vlr-acdb-reactor', + 'vlr-add','vlr-added-p','vlr-beep-reaction','vlr-command-reactor', + 'vlr-current-reaction-name','vlr-data','vlr-data-set', + 'vlr-deepclone-reactor','vlr-docmanager-reactor','vlr-dwg-reactor', + 'vlr-dxf-reactor','vlr-editor-reactor','vl-registry-delete', + 'vl-registry-descendents','vl-registry-read','vl-registry-write', + 'vl-remove','vl-remove-if','vl-remove-if-not','vlr-insert-reactor', + 'vlr-linker-reactor','vlr-lisp-reactor','vlr-miscellaneous-reactor', + 'vlr-mouse-reactor','vlr-notification','vlr-object-reactor', + 'vlr-owner-add','vlr-owner-remove','vlr-owners','vlr-pers','vlr-pers-list', + 'vlr-pers-p','vlr-pers-release','vlr-reaction-names','vlr-reactions', + 'vlr-reaction-set','vlr-reactors','vlr-remove','vlr-remove-all', + 'vlr-set-notification','vlr-sysvar-reactor','vlr-toolbar-reactor', + 'vlr-trace-reaction','vlr-type','vlr-types','vlr-undo-reactor', + 'vlr-wblock-reactor','vlr-window-reactor','vlr-xref-reactor', + 'vl-some','vl-sort','vl-sort-i','vl-string-elt','vl-string-left-trim', + 'vl-string-mismatch','vl-string-position','vl-string-right-trim', + 'vl-string-search','vl-string-subst','vl-string-translate','vl-string-trim', + 'vl-symbol-name','vl-symbolp','vl-symbol-value','vl-unload-vlx','vl-vbaload', + 'vl-vbarun','vl-vlx-loaded-p' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '!', '%', '^', '&', '/','+','-','*','=','<','>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/cfdg.php b/examples/includes/geshi/geshi/cfdg.php new file mode 100644 index 0000000..fc097ca --- /dev/null +++ b/examples/includes/geshi/geshi/cfdg.php @@ -0,0 +1,124 @@ + + * Copyright: (c) 2006 John Horigan http://www.ozonehouse.com/john/ + * Release Version: 1.0.8.3 + * Date Started: 2006/03/11 + * + * CFDG language file for GeSHi. + * + * CHANGES + * ------- + * 2006/03/11 (1.0.0) + * - First Release + * + * TODO (updated 2006/03/11) + * ------------------------- + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'CFDG', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'include', 'startshape', 'rule', 'background' + ), + 2 => array( + 'SQUARE', 'CIRCLE', 'TRIANGLE', + ), + 3 => array( + 'b','brightness','h','hue','sat','saturation', + 'a','alpha','x','y','z','s','size', + 'r','rotate','f','flip','skew','xml_set_object' + ) + ), + 'SYMBOLS' => array( + '[', ']', '{', '}', '*', '|' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #717100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #006666;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/cfm.php b/examples/includes/geshi/geshi/cfm.php new file mode 100644 index 0000000..e900f46 --- /dev/null +++ b/examples/includes/geshi/geshi/cfm.php @@ -0,0 +1,299 @@ + 'ColdFusion', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + /* CFM Tags */ + 1 => array( + 'cfabort', 'cfapplet', 'cfapplication', 'cfargument', 'cfassociate', + 'cfbreak', 'cfcache', 'cfcase', 'cfcatch', 'cfchart', 'cfchartdata', + 'cfchartseries', 'cfcol', 'cfcollection', 'cfcomponent', + 'cfcontent', 'cfcookie', 'cfdefaultcase', 'cfdirectory', + 'cfdocument', 'cfdocumentitem', 'cfdocumentsection', 'cfdump', + 'cfelse', 'cfelseif', 'cferror', 'cfexecute', 'cfexit', 'cffile', + 'cfflush', 'cfform', 'cfformgroup', 'cfformitem', 'cfftp', + 'cffunction', 'cfgrid', 'cfgridcolumn', 'cfgridrow', 'cfgridupdate', + 'cfheader', 'cfhtmlhead', 'cfhttp', 'cfhttpparam', 'cfif', + 'cfimport', 'cfinclude', 'cfindex', 'cfinput', 'cfinsert', + 'cfinvoke', 'cfinvokeargument', 'cfldap', 'cflocation', 'cflock', + 'cflog', 'cflogin', 'cfloginuser', 'cflogout', 'cfloop', 'cfmail', + 'cfmailparam', 'cfmailpart', 'cfmodule', 'cfNTauthenticate', + 'cfobject', 'cfobjectcache', 'cfoutput', 'cfparam', 'cfpop', + 'cfprocessingdirective', 'cfprocparam', + 'cfprocresult', 'cfproperty', 'cfquery', 'cfqueryparam', + 'cfregistry', 'cfreport', 'cfreportparam', 'cfrethrow', 'cfreturn', + 'cfsavecontent', 'cfschedule', 'cfscript', 'cfsearch', 'cfselect', + 'cfset', 'cfsetting', 'cfsilent', 'cfstoredproc', + 'cfswitch', 'cftable', 'cftextarea', 'cfthrow', 'cftimer', + 'cftrace', 'cftransaction', 'cftree', 'cftreeitem', 'cftry', + 'cfupdate', 'cfwddx' + ), + /* HTML Tags */ + 2 => array( + 'a', 'abbr', 'acronym', 'address', 'applet', + + 'base', 'basefont', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'b', + + 'caption', 'center', 'cite', 'code', 'colgroup', 'col', + + 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', + + 'em', + + 'fieldset', 'font', 'form', 'frame', 'frameset', + + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', + + 'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'i', + + 'kbd', + + 'label', 'legend', 'link', 'li', + + 'map', 'meta', + + 'noframes', 'noscript', + + 'object', 'ol', 'optgroup', 'option', + + 'param', 'pre', 'p', + + 'q', + + 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'style', 'sub', 'sup', 's', + + 'table', 'tbody', 'td', 'textarea', 'text', 'tfoot', 'thead', 'th', 'title', 'tr', 'tt', + + 'ul', 'u', + + 'var', + ), + /* HTML attributes */ + 3 => array( + 'abbr', 'accept-charset', 'accept', 'accesskey', 'action', 'align', 'alink', 'alt', 'archive', 'axis', + 'background', 'bgcolor', 'border', + 'cellpadding', 'cellspacing', 'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'classid', 'clear', 'code', 'codebase', 'codetype', 'color', 'cols', 'colspan', 'compact', 'content', 'coords', + 'data', 'datetime', 'declare', 'defer', 'dir', 'disabled', + 'enctype', + 'face', 'for', 'frame', 'frameborder', + 'headers', 'height', 'href', 'hreflang', 'hspace', 'http-equiv', + 'id', 'ismap', + 'label', 'lang', 'language', 'link', 'longdesc', + 'marginheight', 'marginwidth', 'maxlength', 'media', 'method', 'multiple', + 'name', 'nohref', 'noresize', 'noshade', 'nowrap', + 'object', 'onblur', 'onchange', 'onclick', 'ondblclick', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onselect', 'onsubmit', 'onunload', + 'profile', 'prompt', + 'readonly', 'rel', 'rev', 'rowspan', 'rows', 'rules', + 'scheme', 'scope', 'scrolling', 'selected', 'shape', 'size', 'span', 'src', 'standby', 'start', 'style', 'summary', + 'tabindex', 'target', 'text', 'title', 'type', + 'usemap', + 'valign', 'value', 'valuetype', 'version', 'vlink', 'vspace', + 'width' + ), + /* CFM Script delimeters */ + 4 => array( + 'var', 'function', 'while', 'if','else' + ), + /* CFM Functions */ + 5 => array( + 'Abs', 'GetFunctionList', 'LSTimeFormat','ACos','GetGatewayHelper','LTrim','AddSOAPRequestHeader','GetHttpRequestData', + 'Max','AddSOAPResponseHeader','GetHttpTimeString','Mid','ArrayAppend','GetLocale','Min','ArrayAvg','GetLocaleDisplayName', + 'Minute','ArrayClear','GetMetaData','Month','ArrayDeleteAt','GetMetricData','MonthAsString','ArrayInsertAt','GetPageContext', + 'Now','ArrayIsEmpty','GetProfileSections','NumberFormat','ArrayLen','GetProfileString','ParagraphFormat','ArrayMax', + 'GetLocalHostIP','ParseDateTime','ArrayMin','GetSOAPRequest','Pi','ArrayNew','GetSOAPRequestHeader','PreserveSingleQuotes', + 'ArrayPrepend','GetSOAPResponse','Quarter','ArrayResize','GetSOAPResponseHeader','QueryAddColumn','ArraySet', + 'GetTempDirectory','QueryAddRow','ArraySort','QueryNew','ArraySum','GetTempFile','QuerySetCell', + 'ArraySwap','GetTickCount','QuotedValueList','ArrayToList','GetTimeZoneInfo','Rand','Asc','GetToken','Randomize', + 'ASin','Hash','RandRange','Atn','Hour','REFind','BinaryDecode','HTMLCodeFormat','REFindNoCase','BinaryEncode', + 'HTMLEditFormat','ReleaseComObject','BitAnd','IIf','RemoveChars','BitMaskClear','IncrementValue','RepeatString', + 'BitMaskRead','InputBaseN','Replace','BitMaskSet','Insert','ReplaceList','BitNot','Int','ReplaceNoCase','BitOr', + 'IsArray','REReplace','BitSHLN','IsBinary','REReplaceNoCase','BitSHRN','IsBoolean','Reverse','BitXor','IsCustomFunction', + 'Right','Ceiling','IsDate','RJustify','CharsetDecode','IsDebugMode','Round','CharsetEncode','IsDefined','RTrim', + 'Chr','IsLeapYear','Second','CJustify','IsLocalHost','SendGatewayMessage','Compare','IsNumeric','SetEncoding', + 'CompareNoCase','IsNumericDate','SetLocale','Cos','IsObject','SetProfileString','CreateDate','IsQuery','SetVariable', + 'CreateDateTime','IsSimpleValue','Sgn','CreateObject','IsSOAPRequest','Sin','CreateODBCDate','IsStruct','SpanExcluding', + 'CreateODBCDateTime','IsUserInRole','SpanIncluding','CreateODBCTime','IsValid','Sqr','CreateTime','IsWDDX','StripCR', + 'CreateTimeSpan','IsXML','StructAppend','CreateUUID','IsXmlAttribute','StructClear','DateAdd','IsXmlDoc','StructCopy', + 'DateCompare','IsXmlElem','StructCount','DateConvert','IsXmlNode','StructDelete','DateDiff','IsXmlRoot','StructFind', + 'DateFormat','JavaCast','StructFindKey','DatePart','JSStringFormat','StructFindValue','Day','LCase','StructGet', + 'DayOfWeek','Left','StructInsert','DayOfWeekAsString','Len','StructIsEmpty','DayOfYear','ListAppend','StructKeyArray', + 'DaysInMonth','ListChangeDelims','StructKeyExists','DaysInYear','ListContains','StructKeyList','DE','ListContainsNoCase', + 'StructNew','DecimalFormat','ListDeleteAt','StructSort','DecrementValue','ListFind','StructUpdate','Decrypt','ListFindNoCase', + 'Tan','DecryptBinary','ListFirst','TimeFormat','DeleteClientVariable','ListGetAt','ToBase64','DirectoryExists', + 'ListInsertAt','ToBinary','DollarFormat','ListLast','ToScript','Duplicate','ListLen','ToString','Encrypt','ListPrepend', + 'Trim','EncryptBinary','ListQualify','UCase','Evaluate','ListRest','URLDecode','Exp','ListSetAt','URLEncodedFormat', + 'ExpandPath','ListSort','URLSessionFormat','FileExists','ListToArray','Val','Find','ListValueCount','ValueList', + 'FindNoCase','ListValueCountNoCase','Week','FindOneOf','LJustify','Wrap','FirstDayOfMonth','Log','WriteOutput', + 'Fix','Log10','XmlChildPos','FormatBaseN','LSCurrencyFormat','XmlElemNew','GetAuthUser','LSDateFormat','XmlFormat', + 'GetBaseTagData','LSEuroCurrencyFormat','XmlGetNodeType','GetBaseTagList','LSIsCurrency','XmlNew','GetBaseTemplatePath', + 'LSIsDate','XmlParse','GetClientVariablesList','LSIsNumeric','XmlSearch','GetCurrentTemplatePath','LSNumberFormat', + 'XmlTransform','GetDirectoryFromPath','LSParseCurrency','XmlValidate','GetEncoding','LSParseDateTime','Year', + 'GetException','LSParseEuroCurrency','YesNoFormat','GetFileFromPath','LSParseNumber' + ), + /* CFM Attributes */ + 6 => array( + 'dbtype','connectstring','datasource','username','password','query','delimeter','description','required','hint','default','access','from','to','list','index' + ), + 7 => array( + 'EQ', 'GT', 'LT', 'GTE', 'LTE', 'IS', 'LIKE', 'NEQ' + ) + ), + 'SYMBOLS' => array( + '/', '=', '{', '}', '(', ')', '[', ']', '<', '>', '&' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #990000; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #0000FF;', + 4 => 'color: #000000; font-weight: bold;', + 5 => 'color: #0000FF;', + 6 => 'color: #0000FF;', + 7 => 'color: #0000FF;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #0000FF;' + ), + 'STRINGS' => array( + 0 => 'color: #009900;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF0000;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #0000FF;' + ), + 'SCRIPT' => array( + 0 => 'color: #808080; font-style: italic;', + 1 => 'color: #00bbdd;', + 2 => 'color: #0000FF;', + 3 => 'color: #000099;', + 4 => 'color: #333333;', + 5 => 'color: #333333;' + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => 'http://december.com/html/4/element/{FNAMEL}.html', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + '' + ), + 1 => array( + ' '>' + ), + 2 => "/(?!<#)(?:(?:##)*)(#)[a-zA-Z0-9_\.\(\)]+(#)/", + 3 => array( + '' => '' + ), + 4 => array( + '<' => '>' + ), + 5 => '/((?!])+?(>)/si' + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => false, + 1 => false, + 2 => true, + 3 => true, + 4 => true, + 5 => true + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 1 => array( + 'DISALLOWED_BEFORE' => '(?<=<|<\/)', + 'DISALLOWED_AFTER' => '(?=\s|\/|>)', + ), + 2 => array( + 'DISALLOWED_BEFORE' => '(?<=<|<\/)', + 'DISALLOWED_AFTER' => '(?=\s|\/|>)', + ), + 3 => array( + 'DISALLOWED_BEFORE' => '(?|^])', // allow ; before keywords + 'DISALLOWED_AFTER' => '(?![a-zA-Z0-9_\|%\\-])', // allow & after keywords + ), + 7 => array( + 'DISALLOWED_BEFORE' => '(?&|^])', // allow ; before keywords + 'DISALLOWED_AFTER' => '(?![a-zA-Z0-9_\|%\\-])', // allow & after keywords + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/cil.php b/examples/includes/geshi/geshi/cil.php new file mode 100644 index 0000000..41777d6 --- /dev/null +++ b/examples/includes/geshi/geshi/cil.php @@ -0,0 +1,196 @@ + 'CIL', + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'COMMENT_SINGLE' => array('//'), + 'COMMENT_MULTI' => array(), + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array(//Dotted + '.zeroinit', '.vtfixup', '.vtentry', '.vtable', '.ver', '.try', '.subsystem', '.size', '.set', '.removeon', + '.publickeytoken', '.publickey', '.property', '.permissionset', '.permission', '.pdirect', '.param', '.pack', + '.override', '.other', '.namespace', '.mresource', '.module', '.method', '.maxstack', '.manifestres', '.locals', + '.localized', '.locale', '.line', '.language', '.import', '.imagebase', '.hash', '.get', '.fire', '.file', '.field', + '.export', '.event', '.entrypoint', '.emitbyte', '.data', '.custom', '.culture', '.ctor', '.corflags', '.class', + '.cctor', '.assembly', '.addon' + ), + 2 => array(//Attributes + 'wrapper', 'with', 'winapi', 'virtual', 'vector', 'vararg', 'value', 'userdefined', 'unused', 'unmanagedexp', + 'unmanaged', 'unicode', 'to', 'tls', 'thiscall', 'synchronized', 'struct', 'strict', 'storage', 'stdcall', + 'static', 'specialname', 'special', 'serializable', 'sequential', 'sealed', 'runtime', 'rtspecialname', 'request', + 'reqsecobj', 'reqrefuse', 'reqopt', 'reqmin', 'record', 'public', 'privatescope', 'private', 'preservesig', + 'prejitgrant', 'prejitdeny', 'platformapi', 'pinvokeimpl', 'pinned', 'permitonly', 'out', 'optil', 'opt', + 'notserialized', 'notremotable', 'not_in_gc_heap', 'noprocess', 'noncaslinkdemand', 'noncasinheritance', + 'noncasdemand', 'nometadata', 'nomangle', 'nomachine', 'noinlining', 'noappdomain', 'newslot', 'nested', 'native', + 'modreq', 'modopt', 'marshal', 'managed', 'literal', 'linkcheck', 'lcid', 'lasterr', 'internalcall', 'interface', + 'instance', 'initonly', 'init', 'inheritcheck', 'in', 'import', 'implicitres', 'implicitcom', 'implements', + 'illegal', 'il', 'hidebysig', 'handler', 'fromunmanaged', 'forwardref', 'fixed', 'finally', 'final', 'filter', + 'filetime', 'field', 'fault', 'fastcall', 'famorassem', 'family', 'famandassem', 'extern', 'extends', 'explicit', + 'error', 'enum', 'endmac', 'deny', 'demand', 'default', 'custom', 'compilercontrolled', 'clsid', 'class', 'cil', + 'cf', 'cdecl', 'catch', 'beforefieldinit', 'autochar', 'auto', 'at', 'assert', 'assembly', 'as', 'any', 'ansi', + 'alignment', 'algorithm', 'abstract' + ), + 3 => array(//Types + 'wchar', 'void', 'variant', 'unsigned', 'valuetype', 'typedref', 'tbstr', 'sysstring', 'syschar', 'string', + 'streamed_object', 'stream', 'stored_object', 'safearray', 'objectref', 'object', 'nullref', 'method', 'lpwstr', + 'lpvoid', 'lptstr', 'lpstruct', 'lpstr', 'iunknown', 'int64', 'int32', 'int16', 'int8', 'int', 'idispatch', + 'hresult', 'float64', 'float32', 'float', 'decimal', 'date', 'currency', 'char', 'carray', 'byvalstr', + 'bytearray', 'boxed', 'bool', 'blob_object', 'blob', 'array' + ), + 4 => array(//Prefix + 'volatile', 'unaligned', 'tail', 'readonly', 'no', 'constrained' + ), + 5 => array(//Suffix + 'un', 'u8', 'u4', 'u2', 'u1', 'u', 's', 'ref', 'r8', 'r4', 'm1', 'i8', 'i4', 'i2', 'i1', 'i'#, '.8', '.7', '.6', '.5', '.4', '.3', '.2', '.1', '.0' + ), + 6 => array(//Base + 'xor', 'switch', 'sub', 'stloc', + 'stind', 'starg', + 'shr', 'shl', 'ret', 'rem', 'pop', 'or', 'not', 'nop', 'neg', 'mul', + 'localloc', 'leave', 'ldnull', 'ldloca', + 'ldloc', 'ldind', 'ldftn', 'ldc', 'ldarga', + 'ldarg', 'jmp', 'initblk', 'endfinally', 'endfilter', + 'endfault', 'dup', 'div', 'cpblk', 'conv', 'clt', 'ckfinite', 'cgt', 'ceq', 'calli', + 'call', 'brzero', 'brtrue', 'brnull', 'brinst', + 'brfalse', 'break', 'br', 'bne', 'blt', 'ble', 'bgt', 'bge', 'beq', 'arglist', + 'and', 'add' + ), + 7 => array(//Object + 'unbox.any', 'unbox', 'throw', 'stsfld', 'stobj', 'stfld', 'stelem', 'sizeof', 'rethrow', 'refanyval', 'refanytype', 'newobj', + 'newarr', 'mkrefany', 'ldvirtftn', 'ldtoken', 'ldstr', 'ldsflda', 'ldsfld', 'ldobj', 'ldlen', 'ldflda', 'ldfld', + 'ldelema', 'ldelem', 'isinst', 'initobj', 'cpobj', 'castclass', + 'callvirt', 'callmostderived', 'box' + ), + 8 => array(//Other + 'prefixref', 'prefix7', 'prefix6', 'prefix5', 'prefix4', 'prefix3', 'prefix2', 'prefix1', 'prefix0' + ), + 9 => array(//Literal + 'true', 'null', 'false' + ), + 10 => array(//Comment-like + '#line', '^THE_END^' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '!!' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true, + 10 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color:maroon;font-weight:bold;', + 2 => 'color:blue;font-weight:bold;', + 3 => 'color:purple;font-weight:bold;', + 4 => 'color:teal;', + 5 => 'color:blue;', + 6 => 'color:blue;', + 7 => 'color:blue;', + 8 => 'color:blue;', + 9 => 'color:00008B', + 10 => 'color:gray' + ), + 'COMMENTS' => array( + 0 => 'color:gray;font-style:italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008000; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #006400;' + ), + 'STRINGS' => array( + 0 => 'color: #008000;' + ), + 'NUMBERS' => array( + 0 => 'color: #00008B;' + ), + 'METHODS' => array( + 1 => 'color: #000033;' + ), + 'SYMBOLS' => array( + 0 => 'color: #006400;' + ), + 'REGEXPS' => array( + 0 => 'color:blue;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '', + 8 => '', + 9 => '', + 10 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '::' + ), + 'REGEXPS' => array( + 0 => '(?<=ldc\\.i4\\.)[0-8]|(?<=(?:ldarg|ldloc|stloc)\\.)[0-3]' # Pickup the opcodes that end with integers + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/cobol.php b/examples/includes/geshi/geshi/cobol.php new file mode 100644 index 0000000..71f9828 --- /dev/null +++ b/examples/includes/geshi/geshi/cobol.php @@ -0,0 +1,244 @@ + 'COBOL', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array(1 => '/^\*.*?$/m'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', "'"), + 'ESCAPE_CHAR' => '\\', + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | + GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_SCI_SHORT | + GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( //Compiler Directives + 'ANSI', 'BLANK', 'NOBLANK', 'CALL-SHARED', 'CANCEL', 'NOCANCEL', + 'CHECK', 'CODE', 'NOCODE', 'COLUMNS', 'COMPACT', 'NOCOMPACT', + 'COMPILE', 'CONSULT', 'NOCONSULT', 'CROSSREF', 'NOCROSSREF', + 'DIAGNOSE-74', 'NODIAGNOSE-74', 'DIAGNOSE-85', 'NODIAGNOSE-85', + 'DIAGNOSEALL', 'NODIAGNOSEALL', 'ENDIF', 'ENDUNIT', 'ENV', + 'ERRORFILE', 'ERRORS', 'FIPS', 'NOFIPS', 'FMAP', 'HEADING', 'HEAP', + 'HIGHPIN', 'HIGHREQUESTERS', 'ICODE', 'NOICODE', 'IF', 'IFNOT', + 'INNERLIST', 'NOINNERLIST', 'INSPECT', 'NOINSPECT', 'LARGEDATA', + 'LD', 'LESS-CODE', 'LIBRARY', 'LINES', 'LIST', 'NOLIST', 'LMAP', + 'NOLMAP', 'MAIN', 'MAP', 'NOMAP', 'NLD', 'NONSTOP', 'NON-SHARED', + 'OPTIMIZE', 'PERFORM-TRACE', 'PORT', 'NOPORT', 'RESETTOG', + 'RUNNABLE', 'RUNNAMED', 'SAVE', 'SAVEABEND', 'NOSAVEABEND', + 'SEARCH', 'NOSEARCH', 'SECTION', 'SETTOG', 'SHARED', 'SHOWCOPY', + 'NOSHOWCOPY', 'SHOWFILE', 'NOSHOWFILE', 'SOURCE', 'SQL', 'NOSQL', + 'SQLMEM', 'SUBSET', 'SUBTYPE', 'SUPPRESS', 'NOSUPPRESS', 'SYMBOLS', + 'NOSYMBOLS', 'SYNTAX', 'TANDEM', 'TRAP2', 'NOTRAP2', 'TRAP2-74', + 'NOTRAP2-74', 'UL', 'WARN', 'NOWARN' + ), + 2 => array( //Statement Keywords + 'ACCEPT', 'ADD', 'TO', 'GIVING', 'CORRESPONDING', 'ALTER', 'CALL', + 'CHECKPOINT', 'CLOSE', 'COMPUTE', 'CONTINUE', 'COPY', + 'DELETE', 'DISPLAY', 'DIVIDE', 'INTO', 'REMAINDER', 'ENTER', + 'COBOL', 'EVALUATE', 'EXIT', 'GO', 'INITIALIZE', + 'TALLYING', 'REPLACING', 'CONVERTING', 'LOCKFILE', 'MERGE', 'MOVE', + 'MULTIPLY', 'OPEN', 'PERFORM', 'TIMES', + 'UNTIL', 'VARYING', 'RETURN', + ), + 3 => array( //Reserved in some contexts + 'ACCESS', 'ADDRESS', 'ADVANCING', 'AFTER', 'ALL', + 'ALPHABET', 'ALPHABETIC', 'ALPHABETIC-LOWER', 'ALPHABETIC-UPPER', + 'ALPHANUMERIC', 'ALPHANUMERIC-EDITED', 'ALSO', 'ALTERNATE', + 'AND', 'ANY', 'APPROXIMATE', 'AREA', 'AREAS', 'ASCENDING', 'ASSIGN', + 'AT', 'AUTHOR', 'BEFORE', 'BINARY', 'BLOCK', 'BOTTOM', 'BY', + 'CD', 'CF', 'CH', 'CHARACTER', 'CHARACTERS', + 'CHARACTER-SET', 'CLASS', 'CLOCK-UNITS', + 'CODE-SET', 'COLLATING', 'COLUMN', 'COMMA', + 'COMMON', 'COMMUNICATION', 'COMP', 'COMP-3', 'COMP-5', + 'COMPUTATIONAL', 'COMPUTATIONAL-3', 'COMPUTATIONAL-5', + 'CONFIGURATION', 'CONTAINS', 'CONTENT', 'CONTROL', + 'CONTROLS', 'CORR', 'COUNT', + 'CURRENCY', 'DATA', 'DATE', 'DATE-COMPILED', 'DATE-WRITTEN', 'DAY', + 'DAY-OF-WEEK', 'DE', 'DEBUG-CONTENTS', 'DEBUG-ITEM', 'DEBUG-LINE', + 'DEBUG-SUB-2', 'DEBUG-SUB-3', 'DEBUGGING', 'DECIMAL-POINT', + 'DECLARATIVES', 'DEBUG-NAME', 'DEBUG-SUB-1', 'DELIMITED', + 'DELIMITER', 'DEPENDING', 'DESCENDING', 'DESTINATION', 'DETAIL', + 'DISABLE', 'DIVISION', 'DOWN', 'DUPLICATES', + 'DYNAMIC', 'EGI', 'ELSE', 'EMI', 'ENABLE', 'END', 'END-ADD', + 'END-COMPUTE', 'END-DELETE', 'END-DIVIDE', 'END-EVALUATE', 'END-IF', + 'END-MULTIPLY', 'END-OF-PAGE', 'END-PERFORM', 'END-READ', + 'END-RECEIVE', 'END-RETURN', 'END-REWRITE', 'END-SEARCH', + 'END-START', 'END-STRING', 'END-SUBTRACT', 'END-UNSTRING', + 'END-WRITE', 'EOP', 'EQUAL', 'ERROR', 'ESI', + 'EVERY', 'EXCEPTION', 'EXCLUSIVE', 'EXTEND', + 'EXTENDED-STORAGE', 'EXTERNAL', 'FALSE', 'FD', 'FILE', + 'FILE-CONTROL', 'FILLER', 'FINAL', 'FIRST', 'FOOTING', 'FOR', + 'FROM', 'FUNCTION', 'GENERATE', 'GENERIC', 'GLOBAL', + 'GREATER', 'GROUP', 'GUARDIAN-ERR', 'HIGH-VALUE', + 'HIGH-VALUES', 'I-O', 'I-O-CONTROL', 'IDENTIFICATION', 'IN', + 'INDEX', 'INDEXED', 'INDICATE', 'INITIAL', 'INITIATE', + 'INPUT', 'INPUT-OUTPUT', 'INSTALLATION', + 'INVALID', 'IS', 'JUST', 'JUSTIFIED', 'KEY', 'LABEL', 'LAST', + 'LEADING', 'LEFT', 'LESS', 'LIMIT', 'LIMITS', 'LINAGE', + 'LINAGE-COUNTER', 'LINE', 'LINE-COUNTER', 'LINKAGE', 'LOCK', + 'LOW-VALUE', 'LOW-VALUES', 'MEMORY', 'MESSAGE', + 'MODE', 'MODULES', 'MULTIPLE', 'NATIVE', + 'NEGATIVE', 'NEXT', 'NO', 'NOT', 'NULL', 'NULLS', 'NUMBER', + 'NUMERIC', 'NUMERIC-EDITED', 'OBJECT-COMPUTER', 'OCCURS', 'OF', + 'OFF', 'OMITTED', 'ON', 'OPTIONAL', 'OR', 'ORDER', + 'ORGANIZATION', 'OTHER', 'OUTPUT', 'OVERFLOW', 'PACKED-DECIMAL', + 'PADDING', 'PAGE', 'PAGE-COUNTER', 'PF', 'PH', 'PIC', + 'PICTURE', 'PLUS', 'POINTER', 'POSITION', 'POSITIVE', 'PRINTING', + 'PROCEDURE', 'PROCEDURES', 'PROCEED', 'PROGRAM', 'PROGRAM-ID', + 'PROGRAM-STATUS', 'PROGRAM-STATUS-1', 'PROGRAM-STATUS-2', 'PROMPT', + 'PROTECTED', 'PURGE', 'QUEUE', 'QUOTE', 'QUOTES', 'RD', + 'RECEIVE', 'RECEIVE-CONTROL', 'RECORD', 'RECORDS', + 'REDEFINES', 'REEL', 'REFERENCE', 'REFERENCES', 'RELATIVE', + 'REMOVAL', 'RENAMES', 'REPLACE', + 'REPLY', 'REPORT', 'REPORTING', 'REPORTS', 'RERUN', + 'RESERVE', 'RESET', 'REVERSED', 'REWIND', 'REWRITE', 'RF', + 'RH', 'RIGHT', 'ROUNDED', 'RUN', 'SAME', 'SD', + 'SECURITY', 'SEGMENT', 'SEGMENT-LIMIT', 'SELECT', 'SEND', + 'SENTENCE', 'SEPARATE', 'SEQUENCE', 'SEQUENTIAL', 'SET', + 'SIGN', 'SIZE', 'SORT', 'SORT-MERGE', 'SOURCE-COMPUTER', + 'SPACE', 'SPACES', 'SPECIAL-NAMES', 'STANDARD', 'STANDARD-1', + 'STANDARD-2', 'START', 'STARTBACKUP', 'STATUS', 'STOP', 'STRING', + 'SUB-QUEUE-1', 'SUB-QUEUE-2', 'SUB-QUEUE-3', 'SUBTRACT', + 'SYMBOLIC', 'SYNC', 'SYNCDEPTH', 'SYNCHRONIZED', + 'TABLE', 'TAL', 'TAPE', 'TERMINAL', 'TERMINATE', 'TEST', + 'TEXT', 'THAN', 'THEN', 'THROUGH', 'THRU', 'TIME', + 'TOP', 'TRAILING', 'TRUE', 'TYPE', 'UNIT', 'UNLOCK', 'UNLOCKFILE', + 'UNLOCKRECORD', 'UNSTRING', 'UP', 'UPON', 'USAGE', 'USE', + 'USING', 'VALUE', 'VALUES', 'WHEN', 'WITH', 'WORDS', + 'WORKING-STORAGE', 'WRITE', 'ZERO', 'ZEROES' + ), + 4 => array( //Standard functions + 'ACOS', 'ANNUITY', 'ASIN', 'ATAN', 'CHAR', 'COS', 'CURRENT-DATE', + 'DATE-OF-INTEGER', 'DAY-OF-INTEGER', 'FACTORIAL', 'INTEGER', + 'INTEGER-OF-DATE', 'INTEGER-OF-DAY', 'INTEGER-PART', 'LENGTH', + 'LOG', 'LOG10', 'LOWER-CASE', 'MAX', 'MEAN', 'MEDIAN', 'MIDRANGE', + 'MIN', 'MOD', 'NUMVAL', 'NUMVAL-C', 'ORD', 'ORD-MAX', 'ORD-MIN', + 'PRESENT-VALUE', 'RANDOM', 'RANGE', 'REM', 'REVERSE', 'SIN', 'SQRT', + 'STANDARD-DEVIATION', 'SUM', 'TAN', 'UPPER-CASE', 'VARIANCE', + 'WHEN-COMPILED' + ), + 5 => array( //Privileged Built-in Functions + '#IN', '#OUT', '#TERM', '#TEMP', '#DYNAMIC', 'COBOL85^ARMTRAP', + 'COBOL85^COMPLETION', 'COBOL_COMPLETION_', 'COBOL_CONTROL_', + 'COBOL_GETENV_', 'COBOL_PUTENV_', 'COBOL85^RETURN^SORT^ERRORS', + 'COBOL_RETURN_SORT_ERRORS_', 'COBOL85^REWIND^SEQUENTIAL', + 'COBOL_REWIND_SEQUENTIAL_', 'COBOL85^SET^SORT^PARAM^TEXT', + 'COBOL_SET_SORT_PARAM_TEXT_', 'COBOL85^SET^SORT^PARAM^VALUE', + 'COBOL_SET_SORT_PARAM_VALUE_', 'COBOL_SET_MAX_RECORD_', + 'COBOL_SETMODE_', 'COBOL85^SPECIAL^OPEN', 'COBOL_SPECIAL_OPEN_', + 'COBOLASSIGN', 'COBOL_ASSIGN_', 'COBOLFILEINFO', 'COBOL_FILE_INFO_', + 'COBOLSPOOLOPEN', 'CREATEPROCESS', 'ALTERPARAMTEXT', + 'CHECKLOGICALNAME', 'CHECKMESSAGE', 'DELETEASSIGN', 'DELETEPARAM', + 'DELETESTARTUP', 'GETASSIGNTEXT', 'GETASSIGNVALUE', 'GETBACKUPCPU', + 'GETPARAMTEXT', 'GETSTARTUPTEXT', 'PUTASSIGNTEXT', 'PUTASSIGNVALUE', + 'PUTPARAMTEXT', 'PUTSTARTUPTEXT' + ) + ), + 'SYMBOLS' => array( + //Avoid having - in identifiers marked as symbols + ' + ', ' - ', ' * ', ' / ', ' ** ', + '.', ',', + '=', + '(', ')', '[', ']' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000080; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #008000; font-weight: bold;', + 4 => 'color: #000080;', + 5 => 'color: #008000;', + ), + 'COMMENTS' => array( + 1 => 'color: #a0a0a0; font-style: italic;', + 'MULTI' => 'color: #a0a0a0; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #339933;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #993399;' + ), + 'METHODS' => array( + 1 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 + ); + +?> diff --git a/examples/includes/geshi/geshi/cpp-qt.php b/examples/includes/geshi/geshi/cpp-qt.php new file mode 100644 index 0000000..79ec3c6 --- /dev/null +++ b/examples/includes/geshi/geshi/cpp-qt.php @@ -0,0 +1,315 @@ + 'C++ (QT)', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Multiline-continued single-line comments + 1 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m', + //Multiline-continued preprocessor define + 2 => '/#(?:\\\\\\\\|\\\\\\n|.)*$/m' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[abfnrtv\\'\"?\n]#i", + //Hexadecimal Char Specs + 2 => "#\\\\x[\da-fA-F]{2}#", + //Hexadecimal Char Specs + 3 => "#\\\\u[\da-fA-F]{4}#", + //Hexadecimal Char Specs + 4 => "#\\\\U[\da-fA-F]{8}#", + //Octal Char Specs + 5 => "#\\\\[0-7]{1,3}#" + ), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE | GESHI_NUMBER_BIN_PREFIX_0B | + GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'case', 'continue', 'default', 'do', 'else', 'for', 'goto', 'if', 'return', + 'switch', 'while', 'delete', 'new', 'this' + ), + 2 => array( + 'NULL', 'false', 'break', 'true', 'enum', 'errno', 'EDOM', + 'ERANGE', 'FLT_RADIX', 'FLT_ROUNDS', 'FLT_DIG', 'DBL_DIG', 'LDBL_DIG', + 'FLT_EPSILON', 'DBL_EPSILON', 'LDBL_EPSILON', 'FLT_MANT_DIG', 'DBL_MANT_DIG', + 'LDBL_MANT_DIG', 'FLT_MAX', 'DBL_MAX', 'LDBL_MAX', 'FLT_MAX_EXP', 'DBL_MAX_EXP', + 'LDBL_MAX_EXP', 'FLT_MIN', 'DBL_MIN', 'LDBL_MIN', 'FLT_MIN_EXP', 'DBL_MIN_EXP', + 'LDBL_MIN_EXP', 'CHAR_BIT', 'CHAR_MAX', 'CHAR_MIN', 'SCHAR_MAX', 'SCHAR_MIN', + 'UCHAR_MAX', 'SHRT_MAX', 'SHRT_MIN', 'USHRT_MAX', 'INT_MAX', 'INT_MIN', + 'UINT_MAX', 'LONG_MAX', 'LONG_MIN', 'ULONG_MAX', 'HUGE_VAL', 'SIGABRT', + 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', 'SIG_DFL', 'SIG_ERR', + 'SIG_IGN', 'BUFSIZ', 'EOF', 'FILENAME_MAX', 'FOPEN_MAX', 'L_tmpnam', + 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'stdin', 'stdout', 'stderr', + 'EXIT_FAILURE', 'EXIT_SUCCESS', 'RAND_MAX', 'CLOCKS_PER_SEC', + 'virtual', 'public', 'private', 'protected', 'template', 'using', 'namespace', + 'try', 'catch', 'inline', 'dynamic_cast', 'const_cast', 'reinterpret_cast', + 'static_cast', 'explicit', 'friend', 'wchar_t', 'typename', 'typeid', 'class' , + 'foreach','connect', 'Q_OBJECT' , 'slots' , 'signals' + ), + 3 => array( + 'cin', 'cerr', 'clog', 'cout', + 'printf', 'fprintf', 'snprintf', 'sprintf', 'assert', + 'isalnum', 'isalpha', 'isdigit', 'iscntrl', 'isgraph', 'islower', 'isprint', + 'ispunct', 'isspace', 'isupper', 'isxdigit', 'tolower', 'toupper', + 'exp', 'log', 'log10', 'pow', 'sqrt', 'ceil', 'floor', 'fabs', 'ldexp', + 'frexp', 'modf', 'fmod', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', + 'sinh', 'cosh', 'tanh', 'setjmp', 'longjmp', + 'va_start', 'va_arg', 'va_end', 'offsetof', 'sizeof', 'fopen', 'freopen', + 'fflush', 'fclose', 'remove', 'rename', 'tmpfile', 'tmpname', 'setvbuf', + 'setbuf', 'vfprintf', 'vprintf', 'vsprintf', 'fscanf', 'scanf', 'sscanf', + 'fgetc', 'fgets', 'fputc', 'fputs', 'getc', 'getchar', 'gets', 'putc', + 'putchar', 'puts', 'ungetc', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', + 'fgetpos', 'fsetpos', 'clearerr', 'feof', 'ferror', 'perror', 'abs', 'labs', + 'div', 'ldiv', 'atof', 'atoi', 'atol', 'strtod', 'strtol', 'strtoul', 'calloc', + 'malloc', 'realloc', 'free', 'abort', 'exit', 'atexit', 'system', 'getenv', + 'bsearch', 'qsort', 'rand', 'srand', 'strcpy', 'strncpy', 'strcat', 'strncat', + 'strcmp', 'strncmp', 'strcoll', 'strchr', 'strrchr', 'strspn', 'strcspn', + 'strpbrk', 'strstr', 'strlen', 'strerror', 'strtok', 'strxfrm', 'memcpy', + 'memmove', 'memcmp', 'memchr', 'memset', 'clock', 'time', 'difftime', 'mktime', + 'asctime', 'ctime', 'gmtime', 'localtime', 'strftime' + ), + 4 => array( + 'auto', 'bool', 'char', 'const', 'double', 'float', 'int', 'long', 'longint', + 'register', 'short', 'shortint', 'signed', 'static', 'struct', + 'typedef', 'union', 'unsigned', 'void', 'volatile', 'extern', 'jmp_buf', + 'signal', 'raise', 'va_list', 'ptrdiff_t', 'size_t', 'FILE', 'fpos_t', + 'div_t', 'ldiv_t', 'clock_t', 'time_t', 'tm', + ), + 5 => array( + 'QAbstractButton','QDir','QIntValidator','QRegExpValidator','QTabWidget','QAbstractEventDispatcher', + 'QDirectPainter','QIODevice','QRegion','QTcpServer','QAbstractExtensionFactory','QDirModel', + 'QItemDelegate','QResizeEvent','QTcpSocket','QAbstractExtensionManager','QDockWidget', + 'QItemEditorCreatorBase','QResource','QTemporaryFile','QAbstractFileEngine','QDomAttr', + 'QItemEditorFactory','QRubberBand','QTestEventList','QAbstractFileEngineHandler','QDomCDATASection', + 'QItemSelection','QScreen','QTextBlock','QAbstractFormBuilder','QDomCharacterData','QItemSelectionModel', + 'QScreenCursor','QTextBlockFormat','QAbstractGraphicsShapeItem','QDomComment','QItemSelectionRange', + 'QScreenDriverFactory','QTextBlockGroup','QAbstractItemDelegate','QDomDocument','QKbdDriverFactory', + 'QScreenDriverPlugin','QTextBlockUserData','QAbstractItemModel','QDomDocumentFragment','QKbdDriverPlugin', + 'QScrollArea','QTextBrowser','QAbstractItemView','QDomDocumentType','QKeyEvent','QScrollBar', + 'QTextCharFormat','QAbstractListModel','QDomElement','QKeySequence','QSemaphore','QTextCodec', + 'QAbstractPrintDialog','QDomEntity','QLabel','QSessionManager','QTextCodecPlugin','QAbstractProxyModel', + 'QDomEntityReference','QLatin1Char','QSet','QTextCursor','QAbstractScrollArea','QDomImplementation', + 'QLatin1String','QSetIterator','QTextDecoder','QAbstractSlider','QDomNamedNodeMap','QLayout','QSettings', + 'QTextDocument','QAbstractSocket','QDomNode','QLayoutItem','QSharedData','QTextDocumentFragment', + 'QAbstractSpinBox','QDomNodeList','QLCDNumber','QSharedDataPointer','QTextEdit','QAbstractTableModel', + 'QDomNotation','QLibrary','QShortcut','QTextEncoder','QAbstractTextDocumentLayout', + 'QDomProcessingInstruction','QLibraryInfo','QShortcutEvent','QTextFormat','QAccessible','QDomText', + 'QLine','QShowEvent','QTextFragment','QAccessibleBridge','QDoubleSpinBox','QLinearGradient', + 'QSignalMapper','QTextFrame','QAccessibleBridgePlugin','QDoubleValidator','QLineEdit','QSignalSpy', + 'QTextFrameFormat','QAccessibleEvent','QDrag','QLineF','QSize','QTextImageFormat','QAccessibleInterface', + 'QDragEnterEvent','QLinkedList','QSizeF','QTextInlineObject','QAccessibleObject','QDragLeaveEvent', + 'QLinkedListIterator','QSizeGrip','QTextLayout','QAccessiblePlugin','QDragMoveEvent','QLinuxFbScreen', + 'QSizePolicy','QTextLength','QAccessibleWidget','QDropEvent','QList','QSlider','QTextLine','QAction', + 'QDynamicPropertyChangeEvent','QListIterator','QSocketNotifier','QTextList','QActionEvent','QErrorMessage', + 'QListView','QSortFilterProxyModel','QTextListFormat','QActionGroup','QEvent','QListWidget','QSound', + 'QTextObject','QApplication','QEventLoop','QListWidgetItem','QSpacerItem','QTextOption','QAssistantClient', + 'QExtensionFactory','QLocale','QSpinBox','QTextStream','QAxAggregated','QExtensionManager', + 'QMacPasteboardMime','QSplashScreen','QTextTable','QAxBase','QFile','QMacStyle','QSplitter', + 'QTextTableCell','QAxBindable','QFileDialog','QMainWindow','QSplitterHandle','QTextTableFormat', + 'QAxFactory','QFileIconProvider','QMap','QSqlDatabase','QThread','QAxObject','QFileInfo','QMapIterator', + 'QSqlDriver','QThreadStorage','QAxScript','QFileOpenEvent','QMatrix','QSqlDriverCreator','QTime', + 'QAxScriptEngine','QFileSystemWatcher','QMenu','QSqlDriverCreatorBase','QTimeEdit','QAxScriptManager', + 'QFlag','QMenuBar','QSqlDriverPlugin','QTimeLine','QAxWidget','QFlags','QMessageBox','QSqlError','QTimer', + 'QBasicTimer','QFocusEvent','QMetaClassInfo','QSqlField','QTimerEvent','QBitArray','QFocusFrame', + 'QMetaEnum','QSqlIndex','QToolBar','QBitmap','QFont','QMetaMethod','QSqlQuery','QToolBox','QBoxLayout', + 'QFontComboBox','QMetaObject','QSqlQueryModel','QToolButton','QBrush','QFontDatabase','QMetaProperty', + 'QSqlRecord','QToolTip','QBuffer','QFontDialog','QMetaType','QSqlRelation','QTransformedScreen', + 'QButtonGroup','QFontInfo','QMimeData','QSqlRelationalDelegate','QTranslator','QByteArray','QFontMetrics', + 'QMimeSource','QSqlRelationalTableModel','QTreeView','QByteArrayMatcher','QFontMetricsF','QModelIndex', + 'QSqlResult','QTreeWidget','QCache','QFormBuilder','QMotifStyle','QSqlTableModel','QTreeWidgetItem', + 'QCalendarWidget','QFrame','QMouseDriverFactory','QStack','QTreeWidgetItemIterator','QCDEStyle', + 'QFSFileEngine','QMouseDriverPlugin','QStackedLayout','QUdpSocket','QChar','QFtp','QMouseEvent', + 'QStackedWidget','QUiLoader','QCheckBox','QGenericArgument','QMoveEvent','QStandardItem','QUndoCommand', + 'QChildEvent','QGenericReturnArgument','QMovie','QStandardItemEditorCreator','QUndoGroup', + 'QCleanlooksStyle','QGLColormap','QMultiHash','QStandardItemModel','QUndoStack','QClipboard', + 'QGLContext','QMultiMap','QStatusBar','QUndoView','QCloseEvent','QGLFormat','QMutableHashIterator', + 'QStatusTipEvent','QUrl','QColor','QGLFramebufferObject','QMutableLinkedListIterator','QString', + 'QUrlInfo','QColorDialog','QGLPixelBuffer','QMutableListIterator','QStringList','QUuid','QColormap', + 'QGLWidget','QMutableMapIterator','QStringListModel','QValidator','QComboBox','QGradient', + 'QMutableSetIterator','QStringMatcher','QVariant','QCommonStyle','QGraphicsEllipseItem', + 'QMutableVectorIterator','QStyle','QVarLengthArray','QCompleter','QGraphicsItem','QMutex', + 'QStyleFactory','QVBoxLayout','QConicalGradient','QGraphicsItemAnimation','QMutexLocker', + 'QStyleHintReturn','QVector','QContextMenuEvent','QGraphicsItemGroup','QNetworkAddressEntry', + 'QStyleHintReturnMask','QVectorIterator','QCopChannel','QGraphicsLineItem','QNetworkInterface', + 'QStyleOption','QVFbScreen','QCoreApplication','QGraphicsPathItem','QNetworkProxy','QStyleOptionButton', + 'QVNCScreen','QCursor','QGraphicsPixmapItem','QObject','QStyleOptionComboBox','QWaitCondition', + 'QCustomRasterPaintDevice','QGraphicsPolygonItem','QObjectCleanupHandler','QStyleOptionComplex', + 'QWhatsThis','QDataStream','QGraphicsRectItem','QPageSetupDialog','QStyleOptionDockWidget', + 'QWhatsThisClickedEvent','QDataWidgetMapper','QGraphicsScene','QPaintDevice','QStyleOptionFocusRect', + 'QWheelEvent','QDate','QGraphicsSceneContextMenuEvent','QPaintEngine','QStyleOptionFrame','QWidget', + 'QDateEdit','QGraphicsSceneEvent','QPaintEngineState','QStyleOptionFrameV2','QWidgetAction','QDateTime', + 'QGraphicsSceneHoverEvent','QPainter','QStyleOptionGraphicsItem','QWidgetItem','QDateTimeEdit', + 'QGraphicsSceneMouseEvent','QPainterPath','QStyleOptionGroupBox','QWindowsMime','QDBusAbstractAdaptor', + 'QGraphicsSceneWheelEvent','QPainterPathStroker','QStyleOptionHeader','QWindowsStyle', + 'QDBusAbstractInterface','QGraphicsSimpleTextItem','QPaintEvent','QStyleOptionMenuItem', + 'QWindowStateChangeEvent','QDBusArgument','QGraphicsSvgItem','QPair','QStyleOptionProgressBar', + 'QWindowsXPStyle','QDBusConnection','QGraphicsTextItem','QPalette','QStyleOptionProgressBarV2', + 'QWorkspace','QDBusConnectionInterface','QGraphicsView','QPen','QStyleOptionQ3DockWindow','QWriteLocker', + 'QDBusError','QGridLayout','QPersistentModelIndex','QStyleOptionQ3ListView','QWSCalibratedMouseHandler', + 'QDBusInterface','QGroupBox','QPicture','QStyleOptionQ3ListViewItem','QWSClient','QDBusMessage','QHash', + 'QPictureFormatPlugin','QStyleOptionRubberBand','QWSEmbedWidget','QDBusObjectPath','QHashIterator', + 'QPictureIO','QStyleOptionSizeGrip','QWSEvent','QDBusReply','QHBoxLayout','QPixmap','QStyleOptionSlider', + 'QWSInputMethod','QDBusServer','QHeaderView','QPixmapCache','QStyleOptionSpinBox','QWSKeyboardHandler', + 'QDBusSignature','QHelpEvent','QPlastiqueStyle','QStyleOptionTab','QWSMouseHandler','QDBusVariant', + 'QHideEvent','QPluginLoader','QStyleOptionTabBarBase','QWSPointerCalibrationData','QDecoration', + 'QHostAddress','QPoint','QStyleOptionTabV2','QWSScreenSaver','QDecorationFactory','QHostInfo','QPointer', + 'QStyleOptionTabWidgetFrame','QWSServer','QDecorationPlugin','QHoverEvent','QPointF','QStyleOptionTitleBar', + 'QWSTslibMouseHandler','QDesignerActionEditorInterface','QHttp','QPolygon','QStyleOptionToolBar','QWSWindow', + 'QDesignerContainerExtension','QHttpHeader','QPolygonF','QStyleOptionToolBox','QWSWindowSurface', + 'QDesignerCustomWidgetCollectionInterface','QHttpRequestHeader','QPrintDialog','QStyleOptionToolButton', + 'QX11EmbedContainer','QDesignerCustomWidgetInterface','QHttpResponseHeader','QPrintEngine', + 'QStyleOptionViewItem','QX11EmbedWidget','QDesignerFormEditorInterface','QIcon','QPrinter', + 'QStyleOptionViewItemV2','QX11Info','QDesignerFormWindowCursorInterface','QIconDragEvent','QProcess', + 'QStylePainter','QXmlAttributes','QDesignerFormWindowInterface','QIconEngine','QProgressBar', + 'QStylePlugin','QXmlContentHandler','QDesignerFormWindowManagerInterface','QIconEnginePlugin', + 'QProgressDialog','QSvgRenderer','QXmlDeclHandler','QDesignerMemberSheetExtension','QImage', + 'QProxyModel','QSvgWidget','QXmlDefaultHandler','QDesignerObjectInspectorInterface','QImageIOHandler', + 'QPushButton','QSyntaxHighlighter','QXmlDTDHandler','QDesignerPropertyEditorInterface','QImageIOPlugin', + 'QQueue','QSysInfo','QXmlEntityResolver','QDesignerPropertySheetExtension','QImageReader','QRadialGradient', + 'QSystemLocale','QXmlErrorHandler','QDesignerTaskMenuExtension','QImageWriter','QRadioButton', + 'QSystemTrayIcon','QXmlInputSource','QDesignerWidgetBoxInterface','QInputContext','QRasterPaintEngine', + 'QTabBar','QXmlLexicalHandler','QDesktopServices','QInputContextFactory','QReadLocker','QTabletEvent', + 'QXmlLocator','QDesktopWidget','QInputContextPlugin','QReadWriteLock','QTableView','QXmlNamespaceSupport', + 'QDial','QInputDialog','QRect','QTableWidget','QXmlParseException','QDialog','QInputEvent','QRectF', + 'QTableWidgetItem','QXmlReader','QDialogButtonBox','QInputMethodEvent','QRegExp', + 'QTableWidgetSelectionRange','QXmlSimpleReader' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', '&', ':', ',', ';', '|', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight:bold;', + 2 => 'color: #0057AE;', + 3 => 'color: #2B74C7;', + 4 => 'color: #0057AE;', + 5 => 'color: #22aadd;' + ), + 'COMMENTS' => array( + 1 => 'color: #888888;', + 2 => 'color: #006E28;', + 'MULTI' => 'color: #888888; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #660099; font-weight: bold;', + 3 => 'color: #660099; font-weight: bold;', + 4 => 'color: #660099; font-weight: bold;', + 5 => 'color: #006699; font-weight: bold;', + 'HARD' => '', + ), + 'BRACKETS' => array( + 0 => 'color: #006E28;' + ), + 'STRINGS' => array( + 0 => 'color: #BF0303;' + ), + 'NUMBERS' => array( + 0 => 'color: #B08000;', + GESHI_NUMBER_BIN_PREFIX_0B => 'color: #208080;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_SHORT => 'color:#800080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI_F => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI => 'color:#800080;' + ), + 'METHODS' => array( + 1 => 'color: #2B74C7;', + 2 => 'color: #2B74C7;', + 3 => 'color: #2B74C7;' + ), + 'SYMBOLS' => array( + 0 => 'color: #006E28;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => 'http://doc.trolltech.com/latest/{FNAMEL}.html' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::', + 3 => '->', + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(?|^])", + 'DISALLOWED_AFTER' => "(?![a-zA-Z0-9_<\|%\\-])" + ), + 'OOLANG' => array( + 'MATCH_AFTER' => '~?[a-zA-Z][a-zA-Z0-9_]*', + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/cpp.php b/examples/includes/geshi/geshi/cpp.php new file mode 100644 index 0000000..28b585d --- /dev/null +++ b/examples/includes/geshi/geshi/cpp.php @@ -0,0 +1,226 @@ + 'C++', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Multiline-continued single-line comments + 1 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m', + //Multiline-continued preprocessor define + 2 => '/#(?:\\\\\\\\|\\\\\\n|.)*$/m' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[abfnrtv\\'\"?\n]#i", + //Hexadecimal Char Specs + 2 => "#\\\\x[\da-fA-F]{2}#", + //Hexadecimal Char Specs + 3 => "#\\\\u[\da-fA-F]{4}#", + //Hexadecimal Char Specs + 4 => "#\\\\U[\da-fA-F]{8}#", + //Octal Char Specs + 5 => "#\\\\[0-7]{1,3}#" + ), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE | GESHI_NUMBER_BIN_PREFIX_0B | + GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'break', 'case', 'continue', 'default', 'do', 'else', 'for', 'goto', 'if', 'return', + 'switch', 'throw', 'while' + ), + 2 => array( + 'NULL', 'false', 'true', 'enum', 'errno', 'EDOM', + 'ERANGE', 'FLT_RADIX', 'FLT_ROUNDS', 'FLT_DIG', 'DBL_DIG', 'LDBL_DIG', + 'FLT_EPSILON', 'DBL_EPSILON', 'LDBL_EPSILON', 'FLT_MANT_DIG', 'DBL_MANT_DIG', + 'LDBL_MANT_DIG', 'FLT_MAX', 'DBL_MAX', 'LDBL_MAX', 'FLT_MAX_EXP', 'DBL_MAX_EXP', + 'LDBL_MAX_EXP', 'FLT_MIN', 'DBL_MIN', 'LDBL_MIN', 'FLT_MIN_EXP', 'DBL_MIN_EXP', + 'LDBL_MIN_EXP', 'CHAR_BIT', 'CHAR_MAX', 'CHAR_MIN', 'SCHAR_MAX', 'SCHAR_MIN', + 'UCHAR_MAX', 'SHRT_MAX', 'SHRT_MIN', 'USHRT_MAX', 'INT_MAX', 'INT_MIN', + 'UINT_MAX', 'LONG_MAX', 'LONG_MIN', 'ULONG_MAX', 'HUGE_VAL', 'SIGABRT', + 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', 'SIG_DFL', 'SIG_ERR', + 'SIG_IGN', 'BUFSIZ', 'EOF', 'FILENAME_MAX', 'FOPEN_MAX', 'L_tmpnam', + 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'stdin', 'stdout', 'stderr', + 'EXIT_FAILURE', 'EXIT_SUCCESS', 'RAND_MAX', 'CLOCKS_PER_SEC', + 'virtual', 'public', 'private', 'protected', 'template', 'using', 'namespace', + 'try', 'catch', 'inline', 'dynamic_cast', 'const_cast', 'reinterpret_cast', + 'static_cast', 'explicit', 'friend', 'wchar_t', 'typename', 'typeid', 'class' + ), + 3 => array( + 'cin', 'cerr', 'clog', 'cout', 'delete', 'new', 'this', + 'printf', 'fprintf', 'snprintf', 'sprintf', 'assert', + 'isalnum', 'isalpha', 'isdigit', 'iscntrl', 'isgraph', 'islower', 'isprint', + 'ispunct', 'isspace', 'isupper', 'isxdigit', 'tolower', 'toupper', + 'exp', 'log', 'log10', 'pow', 'sqrt', 'ceil', 'floor', 'fabs', 'ldexp', + 'frexp', 'modf', 'fmod', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', + 'sinh', 'cosh', 'tanh', 'setjmp', 'longjmp', + 'va_start', 'va_arg', 'va_end', 'offsetof', 'sizeof', 'fopen', 'freopen', + 'fflush', 'fclose', 'remove', 'rename', 'tmpfile', 'tmpname', 'setvbuf', + 'setbuf', 'vfprintf', 'vprintf', 'vsprintf', 'fscanf', 'scanf', 'sscanf', + 'fgetc', 'fgets', 'fputc', 'fputs', 'getc', 'getchar', 'gets', 'putc', + 'putchar', 'puts', 'ungetc', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', + 'fgetpos', 'fsetpos', 'clearerr', 'feof', 'ferror', 'perror', 'abs', 'labs', + 'div', 'ldiv', 'atof', 'atoi', 'atol', 'strtod', 'strtol', 'strtoul', 'calloc', + 'malloc', 'realloc', 'free', 'abort', 'exit', 'atexit', 'system', 'getenv', + 'bsearch', 'qsort', 'rand', 'srand', 'strcpy', 'strncpy', 'strcat', 'strncat', + 'strcmp', 'strncmp', 'strcoll', 'strchr', 'strrchr', 'strspn', 'strcspn', + 'strpbrk', 'strstr', 'strlen', 'strerror', 'strtok', 'strxfrm', 'memcpy', + 'memmove', 'memcmp', 'memchr', 'memset', 'clock', 'time', 'difftime', 'mktime', + 'asctime', 'ctime', 'gmtime', 'localtime', 'strftime' + ), + 4 => array( + 'auto', 'bool', 'char', 'const', 'double', 'float', 'int', 'long', 'longint', + 'register', 'short', 'shortint', 'signed', 'static', 'struct', + 'typedef', 'union', 'unsigned', 'void', 'volatile', 'extern', 'jmp_buf', + 'signal', 'raise', 'va_list', 'ptrdiff_t', 'size_t', 'FILE', 'fpos_t', + 'div_t', 'ldiv_t', 'clock_t', 'time_t', 'tm', + ), + ), + 'SYMBOLS' => array( + 0 => array('(', ')', '{', '}', '[', ']'), + 1 => array('<', '>','='), + 2 => array('+', '-', '*', '/', '%'), + 3 => array('!', '^', '&', '|'), + 4 => array('?', ':', ';') + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff;', + 2 => 'color: #0000ff;', + 3 => 'color: #0000dd;', + 4 => 'color: #0000ff;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666;', + 2 => 'color: #339900;', + 'MULTI' => 'color: #ff0000; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #660099; font-weight: bold;', + 3 => 'color: #660099; font-weight: bold;', + 4 => 'color: #660099; font-weight: bold;', + 5 => 'color: #006699; font-weight: bold;', + 'HARD' => '', + ), + 'BRACKETS' => array( + 0 => 'color: #008000;' + ), + 'STRINGS' => array( + 0 => 'color: #FF0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000dd;', + GESHI_NUMBER_BIN_PREFIX_0B => 'color: #208080;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_SHORT => 'color:#800080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI_F => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI => 'color:#800080;' + ), + 'METHODS' => array( + 1 => 'color: #007788;', + 2 => 'color: #007788;' + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;', + 1 => 'color: #000080;', + 2 => 'color: #000040;', + 3 => 'color: #000040;', + 4 => 'color: #008080;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(? "(?![a-zA-Z0-9_\|%\\-])" + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/csharp.php b/examples/includes/geshi/geshi/csharp.php new file mode 100644 index 0000000..2d79ee2 --- /dev/null +++ b/examples/includes/geshi/geshi/csharp.php @@ -0,0 +1,249 @@ + 'C#', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Using and Namespace directives (basic support) + //Please note that the alias syntax for using is not supported + 3 => '/(?:(?<=using[\\n\\s])|(?<=namespace[\\n\\s]))[\\n\\s]*([a-zA-Z0-9_]+\\.)*[a-zA-Z0-9_]+[\n\s]*(?=[;=])/i'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'HARDQUOTE' => array('@"', '"'), + 'HARDESCAPE' => array('""'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'as', 'auto', 'base', 'break', 'case', 'catch', 'const', 'continue', + 'default', 'do', 'else', 'event', 'explicit', 'extern', 'false', + 'finally', 'fixed', 'for', 'foreach', 'goto', 'if', 'implicit', + 'in', 'internal', 'lock', 'namespace', 'null', 'operator', 'out', + 'override', 'params', 'partial', 'private', 'protected', 'public', + 'readonly', 'ref', 'return', 'sealed', 'stackalloc', 'static', + 'switch', 'this', 'throw', 'true', 'try', 'unsafe', 'using', + 'virtual', 'void', 'while' + ), + 2 => array( + '#elif', '#endif', '#endregion', '#else', '#error', '#define', '#if', + '#line', '#region', '#undef', '#warning' + ), + 3 => array( + 'checked', 'is', 'new', 'sizeof', 'typeof', 'unchecked' + ), + 4 => array( + 'bool', 'byte', 'char', 'class', 'decimal', 'delegate', 'double', + 'enum', 'float', 'int', 'interface', 'long', 'object', 'sbyte', + 'short', 'string', 'struct', 'uint', 'ulong', 'ushort' + ), + 5 => array( + 'Microsoft.Win32', + 'System', + 'System.CodeDOM', + 'System.CodeDOM.Compiler', + 'System.Collections', + 'System.Collections.Bases', + 'System.ComponentModel', + 'System.ComponentModel.Design', + 'System.ComponentModel.Design.CodeModel', + 'System.Configuration', + 'System.Configuration.Assemblies', + 'System.Configuration.Core', + 'System.Configuration.Install', + 'System.Configuration.Interceptors', + 'System.Configuration.Schema', + 'System.Configuration.Web', + 'System.Core', + 'System.Data', + 'System.Data.ADO', + 'System.Data.Design', + 'System.Data.Internal', + 'System.Data.SQL', + 'System.Data.SQLTypes', + 'System.Data.XML', + 'System.Data.XML.DOM', + 'System.Data.XML.XPath', + 'System.Data.XML.XSLT', + 'System.Diagnostics', + 'System.Diagnostics.SymbolStore', + 'System.DirectoryServices', + 'System.Drawing', + 'System.Drawing.Design', + 'System.Drawing.Drawing2D', + 'System.Drawing.Imaging', + 'System.Drawing.Printing', + 'System.Drawing.Text', + 'System.Globalization', + 'System.IO', + 'System.IO.IsolatedStorage', + 'System.Messaging', + 'System.Net', + 'System.Net.Sockets', + 'System.NewXml', + 'System.NewXml.XPath', + 'System.NewXml.Xsl', + 'System.Reflection', + 'System.Reflection.Emit', + 'System.Resources', + 'System.Runtime.InteropServices', + 'System.Runtime.InteropServices.Expando', + 'System.Runtime.Remoting', + 'System.Runtime.Serialization', + 'System.Runtime.Serialization.Formatters', + 'System.Runtime.Serialization.Formatters.Binary', + 'System.Security', + 'System.Security.Cryptography', + 'System.Security.Cryptography.X509Certificates', + 'System.Security.Permissions', + 'System.Security.Policy', + 'System.Security.Principal', + 'System.ServiceProcess', + 'System.Text', + 'System.Text.RegularExpressions', + 'System.Threading', + 'System.Timers', + 'System.Web', + 'System.Web.Caching', + 'System.Web.Configuration', + 'System.Web.Security', + 'System.Web.Services', + 'System.Web.Services.Description', + 'System.Web.Services.Discovery', + 'System.Web.Services.Protocols', + 'System.Web.UI', + 'System.Web.UI.Design', + 'System.Web.UI.Design.WebControls', + 'System.Web.UI.Design.WebControls.ListControls', + 'System.Web.UI.HtmlControls', + 'System.Web.UI.WebControls', + 'System.WinForms', + 'System.WinForms.ComponentModel', + 'System.WinForms.Design', + 'System.Xml', + 'System.Xml.Serialization', + 'System.Xml.Serialization.Code', + 'System.Xml.Serialization.Schema' + ), + ), + 'SYMBOLS' => array( + '+', '-', '*', '?', '=', '/', '%', '&', '>', '<', '^', '!', ':', ';', + '(', ')', '{', '}', '[', ']', '|' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0600FF;', + 2 => 'color: #FF8000; font-weight: bold;', + 3 => 'color: #008000;', + 4 => 'color: #FF0000;', + 5 => 'color: #000000;' + ), + 'COMMENTS' => array( + 1 => 'color: #008080; font-style: italic;', + 2 => 'color: #008080;', + 3 => 'color: #008080;', + 'MULTI' => 'color: #008080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008080; font-weight: bold;', + 'HARD' => 'color: #008080; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #666666;', + 'HARD' => 'color: #666666;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF0000;' + ), + 'METHODS' => array( + 1 => 'color: #0000FF;', + 2 => 'color: #0000FF;' + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.google.com/search?q={FNAMEL}+msdn.microsoft.com', + 4 => '', + 5 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(?|^])", + 'DISALLOWED_AFTER' => "(?![a-zA-Z0-9_<\|%\\-])" + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/css.php b/examples/includes/geshi/geshi/css.php new file mode 100644 index 0000000..0080325 --- /dev/null +++ b/examples/includes/geshi/geshi/css.php @@ -0,0 +1,212 @@ + 'CSS', + 'COMMENT_SINGLE' => array(1 => '@'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + 2 => "/(?<=\\()\\s*(?:(?:[a-z0-9]+?:\\/\\/)?[a-z0-9_\\-\\.\\/:]+?)?[a-z]+?\\.[a-z]+?(\\?[^\)]+?)?\\s*?(?=\\))/i" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', "'"), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'aqua', 'azimuth', 'background-attachment', 'background-color', + 'background-image', 'background-position', 'background-repeat', + 'background', 'black', 'blue', 'border-bottom-color', + 'border-bottom-style', 'border-bottom-width', 'border-left-color', + 'border-left-style', 'border-left-width', 'border-right', + 'border-right-color', 'border-right-style', 'border-right-width', + 'border-top-color', 'border-top-style', + 'border-top-width','border-bottom', 'border-collapse', + 'border-left', 'border-width', 'border-color', 'border-spacing', + 'border-style', 'border-top', 'border', 'caption-side', 'clear', + 'clip', 'color', 'content', 'counter-increment', 'counter-reset', + 'cue-after', 'cue-before', 'cue', 'cursor', 'direction', 'display', + 'elevation', 'empty-cells', 'float', 'font-family', 'font-size', + 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', + 'font-weight', 'font', 'line-height', 'letter-spacing', + 'list-style', 'list-style-image', 'list-style-position', + 'list-style-type', 'margin-bottom', 'margin-left', 'margin-right', + 'margin-top', 'margin', 'marker-offset', 'marks', 'max-height', + 'max-width', 'min-height', 'min-width', 'orphans', 'outline', + 'outline-color', 'outline-style', 'outline-width', 'overflow', + 'padding-bottom', 'padding-left', 'padding-right', 'padding-top', + 'padding', 'page', 'page-break-after', 'page-break-before', + 'page-break-inside', 'pause-after', 'pause-before', 'pause', + 'pitch', 'pitch-range', 'play-during', 'position', 'quotes', + 'richness', 'right', 'size', 'speak-header', 'speak-numeral', + 'speak-punctuation', 'speak', 'speech-rate', 'stress', + 'table-layout', 'text-align', 'text-decoration', 'text-indent', + 'text-shadow', 'text-transform', 'top', 'unicode-bidi', + 'vertical-align', 'visibility', 'voice-family', 'volume', + 'white-space', 'widows', 'width', 'word-spacing', 'z-index', + 'bottom', 'left', 'height' + ), + 2 => array( + 'above', 'absolute', 'always', 'armenian', 'aural', 'auto', + 'avoid', 'baseline', 'behind', 'below', 'bidi-override', 'blink', + 'block', 'bold', 'bolder', 'both', 'capitalize', 'center-left', + 'center-right', 'center', 'circle', 'cjk-ideographic', + 'close-quote', 'collapse', 'condensed', 'continuous', 'crop', + 'crosshair', 'cross', 'cursive', 'dashed', 'decimal-leading-zero', + 'decimal', 'default', 'digits', 'disc', 'dotted', 'double', + 'e-resize', 'embed', 'extra-condensed', 'extra-expanded', + 'expanded', 'fantasy', 'far-left', 'far-right', 'faster', 'fast', + 'fixed', 'fuchsia', 'georgian', 'gray', 'green', 'groove', + 'hebrew', 'help', 'hidden', 'hide', 'higher', 'high', + 'hiragana-iroha', 'hiragana', 'icon', 'inherit', 'inline-table', + 'inline', 'inset', 'inside', 'invert', 'italic', 'justify', + 'katakana-iroha', 'katakana', 'landscape', 'larger', 'large', + 'left-side', 'leftwards', 'level', 'lighter', 'lime', + 'line-through', 'list-item', 'loud', 'lower-alpha', 'lower-greek', + 'lower-roman', 'lowercase', 'ltr', 'lower', 'low', 'maroon', + 'medium', 'message-box', 'middle', 'mix', 'monospace', 'n-resize', + 'narrower', 'navy', 'ne-resize', 'no-close-quote', + 'no-open-quote', 'no-repeat', 'none', 'normal', 'nowrap', + 'nw-resize', 'oblique', 'olive', 'once', 'open-quote', 'outset', + 'outside', 'overline', 'pointer', 'portrait', 'purple', 'px', + 'red', 'relative', 'repeat-x', 'repeat-y', 'repeat', 'rgb', + 'ridge', 'right-side', 'rightwards', 's-resize', 'sans-serif', + 'scroll', 'se-resize', 'semi-condensed', 'semi-expanded', + 'separate', 'serif', 'show', 'silent', 'silver', 'slow', 'slower', + 'small-caps', 'small-caption', 'smaller', 'soft', 'solid', + 'spell-out', 'square', 'static', 'status-bar', 'super', + 'sw-resize', 'table-caption', 'table-cell', 'table-column', + 'table-column-group', 'table-footer-group', 'table-header-group', + 'table-row', 'table-row-group', 'teal', 'text', 'text-bottom', + 'text-top', 'thick', 'thin', 'transparent', 'ultra-condensed', + 'ultra-expanded', 'underline', 'upper-alpha', 'upper-latin', + 'upper-roman', 'uppercase', 'url', 'visible', 'w-resize', 'wait', + 'white', 'wider', 'x-fast', 'x-high', 'x-large', 'x-loud', + 'x-low', 'x-small', 'x-soft', 'xx-large', 'xx-small', 'yellow', + 'yes' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', ':', ';', + '>', '+', '*', ',', '^', '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #993333;' + ), + 'COMMENTS' => array( + 1 => 'color: #a1a100;', + 2 => 'color: #ff0000; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #00AA00;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #00AA00;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 0 => 'color: #cc00cc;', + 1 => 'color: #6666ff;', + 2 => 'color: #3333ff;', + 3 => 'color: #933;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //DOM Node ID + 0 => '\#[a-zA-Z0-9\-_]+(?:\\\\:[a-zA-Z0-9\-_]+)*', + //CSS classname + 1 => '\.(?!\d)[a-zA-Z0-9\-_]+(?:\\\\:[a-zA-Z0-9\-_]+)*\b(?=[\{\.#\s,:].|<\|)', + //CSS Pseudo classes + //note: & is needed for > (i.e. > ) + 2 => '(? '[+\-]?(\d+|(\d*\.\d+))(em|ex|pt|px|cm|in|%)', + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_AFTER' => '(?![a-zA-Z0-9_\|%\\-&\.])' + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/d.php b/examples/includes/geshi/geshi/d.php new file mode 100644 index 0000000..9711a6e --- /dev/null +++ b/examples/includes/geshi/geshi/d.php @@ -0,0 +1,272 @@ + 'D', + 'COMMENT_SINGLE' => array(2 => '///', 1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + // doxygen comments + 3 => '#/\*\*(?![\*\/]).*\*/#sU', + // raw strings + 4 => '#r"[^"]*"#s', + // Script Style interpreter comment + 5 => "/\A#!(?=\\/).*?$/m" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', "'"), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[abfnrtv\\'\"?\n\\\\]#i", + //Hexadecimal Char Specs + 2 => "#\\\\x[\da-fA-F]{2}#", + //Hexadecimal Char Specs + 3 => "#\\\\u[\da-fA-F]{4}#", + //Hexadecimal Char Specs + 4 => "#\\\\U[\da-fA-F]{8}#", + //Octal Char Specs + 5 => "#\\\\[0-7]{1,3}#", + //Named entity escapes + /*6 => "#\\\\&(?:quot|amp|lt|gt|OElig|oelig|Scaron|scaron|Yuml|circ|tilde|". + "ensp|emsp|thinsp|zwnj|zwj|lrm|rlm|ndash|mdash|lsquo|rsquo|sbquo|". + "ldquo|rdquo|bdquo|dagger|Dagger|permil|lsaquo|rsaquo|euro|nbsp|". + "iexcl|cent|pound|curren|yen|brvbar|sect|uml|copy|ordf|laquo|not|". + "shy|reg|macr|deg|plusmn|sup2|sup3|acute|micro|para|middot|cedil|". + "sup1|ordm|raquo|frac14|frac12|frac34|iquest|Agrave|Aacute|Acirc|". + "Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml|Igrave|". + "Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|Ouml|". + "times|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|szlig|agrave|". + "aacute|acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|". + "euml|igrave|iacute|icirc|iuml|eth|ntilde|ograve|oacute|ocirc|". + "otilde|ouml|divide|oslash|ugrave|uacute|ucirc|uuml|yacute|thorn|". + "yuml|fnof|Alpha|Beta|Gamma|Delta|Epsilon|Zeta|Eta|Theta|Iota|". + "Kappa|Lambda|Mu|Nu|Xi|Omicron|Pi|Rho|Sigma|Tau|Upsilon|Phi|Chi|". + "Psi|Omega|alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|". + "kappa|lambda|mu|nu|xi|omicron|pi|rho|sigmaf|sigma|tau|upsilon|". + "phi|chi|psi|omega|thetasym|upsih|piv|bull|hellip|prime|Prime|". + "oline|frasl|weierp|image|real|trade|alefsym|larr|uarr|rarr|darr|". + "harr|crarr|lArr|uArr|rArr|dArr|hArr|forall|part|exist|empty|". + "nabla|isin|notin|ni|prod|sum|minus|lowast|radic|prop|infin|ang|". + "and|or|cap|cup|int|there4|sim|cong|asymp|ne|equiv|le|ge|sub|sup|". + "nsub|sube|supe|oplus|otimes|perp|sdot|lceil|rceil|lfloor|rfloor|". + "lang|rang|loz|spades|clubs|hearts|diams);#",*/ + // optimized: + 6 => "#\\\\&(?:A(?:Elig|acute|circ|grave|lpha|ring|tilde|uml)|Beta|". + "C(?:cedil|hi)|D(?:agger|elta)|E(?:TH|acute|circ|grave|psilon|ta|uml)|". + "Gamma|I(?:acute|circ|grave|ota|uml)|Kappa|Lambda|Mu|N(?:tilde|u)|". + "O(?:Elig|acute|circ|grave|m(?:ega|icron)|slash|tilde|uml)|". + "P(?:hi|i|rime|si)|Rho|S(?:caron|igma)|T(?:HORN|au|heta)|". + "U(?:acute|circ|grave|psilon|uml)|Xi|Y(?:acute|uml)|Zeta|". + "a(?:acute|c(?:irc|ute)|elig|grave|l(?:efsym|pha)|mp|n[dg]|ring|". + "symp|tilde|uml)|b(?:dquo|eta|rvbar|ull)|c(?:ap|cedil|e(?:dil|nt)|". + "hi|irc|lubs|o(?:ng|py)|rarr|u(?:p|rren))|d(?:Arr|a(?:gger|rr)|". + "e(?:g|lta)|i(?:ams|vide))|e(?:acute|circ|grave|m(?:pty|sp)|nsp|". + "psilon|quiv|t[ah]|u(?:ml|ro)|xist)|f(?:nof|orall|ra(?:c(?:1[24]|34)|sl))|". + "g(?:amma|e|t)|h(?:Arr|arr|e(?:arts|llip))|i(?:acute|circ|excl|grave|mage|". + "n(?:fin|t)|ota|quest|sin|uml)|kappa|l(?:Arr|a(?:mbda|ng|quo|rr)|ceil|". + "dquo|e|floor|o(?:wast|z)|rm|s(?:aquo|quo)|t)|m(?:acr|dash|". + "i(?:cro|ddot|nus)|u)|n(?:abla|bsp|dash|e|i|ot(?:in)?|sub|tilde|u)|". + "o(?:acute|circ|elig|grave|line|m(?:ega|icron)|plus|r(?:d[fm])?|". + "slash|ti(?:lde|mes)|uml)|p(?:ar[at]|er(?:mil|p)|hi|iv?|lusmn|ound|". + "r(?:ime|o[dp])|si)|quot|r(?:Arr|a(?:dic|ng|quo|rr)|ceil|dquo|e(?:al|g)|". + "floor|ho|lm|s(?:aquo|quo))|s(?:bquo|caron|dot|ect|hy|i(?:gmaf?|m)|". + "pades|u(?:be?|m|p[123e]?)|zlig)|t(?:au|h(?:e(?:re4|ta(?:sym)?)|insp|". + "orn)|i(?:lde|mes)|rade)|u(?:Arr|a(?:cute|rr)|circ|grave|ml|". + "psi(?:h|lon)|uml)|weierp|xi|y(?:acute|en|uml)|z(?:eta|w(?:j|nj)));#", + ), + 'HARDQUOTE' => array('`', '`'), + 'HARDESCAPE' => array(), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_INT_CSTYLE | GESHI_NUMBER_BIN_PREFIX_0B | + GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_NONSCI_F | GESHI_NUMBER_FLT_SCI_SHORT | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'break', 'case', 'continue', 'do', 'else', + 'for', 'foreach', 'goto', 'if', 'return', + 'switch', 'while' + ), + 2 => array( + 'alias', 'asm', 'assert', 'body', 'cast', + 'catch', 'default', 'delegate', 'delete', + 'extern', 'false', 'finally', 'function', + 'import', 'in', 'inout', 'interface', + 'invariant', 'is', 'mixin', 'module', 'new', + 'null', 'out', 'pragma', 'ref', 'super', 'this', + 'throw', 'true', 'try', 'typedef', 'typeid', + 'typeof', 'union', 'with' + ), + 3 => array( + 'ArrayBoundsError', 'AssertError', + 'ClassInfo', 'Error', 'Exception', + 'Interface', 'ModuleInfo', 'Object', + 'OutOfMemoryException', 'SwitchError', + 'TypeInfo', '_d_arrayappend', + '_d_arrayappendb', '_d_arrayappendc', + '_d_arrayappendcb', '_d_arraycast', + '_d_arraycast_frombit', '_d_arraycat', + '_d_arraycatb', '_d_arraycatn', + '_d_arraycopy', '_d_arraycopybit', + '_d_arraysetbit', '_d_arraysetbit2', + '_d_arraysetlength', '_d_arraysetlengthb', + '_d_callfinalizer', + '_d_create_exception_object', + '_d_criticalenter', '_d_criticalexit', + '_d_delarray', '_d_delclass', + '_d_delinterface', '_d_delmemory', + '_d_dynamic_cast', '_d_exception', + '_d_exception_filter', '_d_framehandler', + '_d_interface_cast', '_d_interface_vtbl', + '_d_invariant', '_d_isbaseof', + '_d_isbaseof2', '_d_local_unwind', + '_d_monitorenter', '_d_monitorexit', + '_d_monitorrelease', '_d_monitor_epilog', + '_d_monitor_handler', '_d_monitor_prolog', + '_d_new', '_d_newarrayi', '_d_newbitarray', + '_d_newclass', '_d_obj_cmp', '_d_obj_eq', + '_d_OutOfMemory', '_d_switch_dstring', + '_d_switch_string', '_d_switch_ustring', + '_d_throw', + ), + 4 => array( + 'abstract', 'align', 'auto', 'bit', 'bool', + 'byte', 'cdouble', 'cent', 'cfloat', 'char', + 'class', 'const', 'creal', 'dchar', 'debug', + 'deprecated', 'double', 'enum', 'export', + 'final', 'float', 'idouble', 'ifloat', 'int', + 'ireal', 'long', 'override', 'package', + 'private', 'protected', 'ptrdiff_t', + 'public', 'real', 'short', 'size_t', + 'static', 'struct', 'synchronized', + 'template', 'ubyte', 'ucent', 'uint', + 'ulong', 'unittest', 'ushort', 'version', + 'void', 'volatile', 'wchar' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '?', '!', ';', ':', ',', '...', '..', + '+', '-', '*', '/', '%', '&', '|', '^', '<', '>', '=', '~', + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #aaaadd; font-weight: bold;', + 4 => 'color: #993333;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #009933; font-style: italic;', + 3 => 'color: #009933; font-style: italic;', + 4 => 'color: #ff0000;', + 5 => 'color: #0040ff;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #660099; font-weight: bold;', + 3 => 'color: #660099; font-weight: bold;', + 4 => 'color: #660099; font-weight: bold;', + 5 => 'color: #006699; font-weight: bold;', + 6 => 'color: #666699; font-weight: bold; font-style: italic;', + 'HARD' => '', + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;', + 'HARD' => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000dd;', + GESHI_NUMBER_BIN_PREFIX_0B => 'color: #208080;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_SHORT => 'color:#800080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI_F => 'color:#800080;', + GESHI_NUMBER_FLT_NONSCI => 'color:#800080;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/dcs.php b/examples/includes/geshi/geshi/dcs.php new file mode 100644 index 0000000..b9fe581 --- /dev/null +++ b/examples/includes/geshi/geshi/dcs.php @@ -0,0 +1,185 @@ + 'DCS', + 'COMMENT_SINGLE' => array( + 1 => ';' + ), + 'COMMENT_MULTI' => array( + ), + 'HARDQUOTE' => array( + ), + 'HARDESCAPE' => '', + 'COMMENT_REGEXP' => array( + // Highlight embedded C code in a separate color: + 2 => '/\bINSERT_C_CODE\b.*?\bEND_C_CODE\b/ims' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array( + '"' + ), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => '', + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'abs', 'ascii_value', 'bit_value', 'blank_date', 'calc_unit_values', 'cm', + 'complete_months', 'complete_years', 'correct', 'create_input_file', 'cy', + 'date_convert', 'day', 'del_output_separator', + 'delete_existing_output_files', 'div', 'ex', 'exact_years', 'exp', + 'extract_date', 'failed_validation', 'file_number', 'first_record', + 'fract', 'fund_fac_a', 'fund_fac_b', 'fund_fac_c', 'fund_fac_d', + 'fund_fac_e', 'fund_fac_f', 'fund_fac_g', 'fund_fac_h', 'fund_fac_i', + 'fund_fac_j', 'fund_fac_k', 'fund_fac_l', 'fund_fac_m', 'fund_fac_n', + 'fund_fac_o', 'fund_fac_p', 'fund_fac_q', 'fund_fac_r', 'fund_fac_s', + 'fund_fac_t', 'fund_fac_u', 'fund_fac_v', 'fund_fac_w', 'fund_fac_x', + 'fund_fac_y', 'fund_fac_z', 'group', 'group_record', + 'input_file_date_time', 'input_file_extension', 'input_file_location', + 'input_file_name', 'int', 'invalid', 'last_record', 'leap_year', 'len', + 'ln', 'log', 'main_format_name', 'max', 'max_num_subrecords', 'message', + 'min', 'mod', 'month', 'months_add', 'months_sub', 'nearest_months', + 'nearest_years', 'next_record', 'nm', 'no_of_current_records', + 'no_of_records', 'numval', 'ny', 'output', 'output_array_as_constants', + 'output_file_path', 'output_record', 'pmdf_output', 'previous', 'rand', + 're_start', 'read_generic_table', 'read_generic_table_text', + 'read_input_footer', 'read_input_footer_text', 'read_input_header', + 'read_input_header_text', 'record_count', 'record_suppressed', 'round', + 'round_down', 'round_near', 'round_up', 'run_dcs_program', 'run_parameter', + 'run_parameter_text', 'set_main_record', 'set_num_subrecords', + 'sort_array', 'sort_current_records', 'sort_input', 'strval', 'substr', + 'summarise', 'summarise_record', 'summarise_units', + 'summarise_units_record', 'suppress_record', 'table_correct', + 'table_validate', 'terminate', 'time', 'today', 'trim', 'ubound', 'year', + 'years_add', 'years_sub' + ), + 2 => array( + 'and', 'as', 'begin', 'boolean', 'byref', 'byval', 'call', 'case', 'date', + 'default', 'do', 'else', 'elseif', 'end_c_code', 'endfor', 'endfunction', + 'endif', 'endproc', 'endswitch', 'endwhile', 'eq', + 'explicit_declarations', 'false', 'for', 'from', 'function', 'ge', 'gt', + 'if', 'insert_c_code', 'integer', 'le', 'loop', 'lt', 'ne', 'not', + 'number', 'or', 'private', 'proc', 'public', 'quitloop', 'return', + 'short', 'step', 'switch', 'text', 'then', 'to', 'true', 'while' + ), + 3 => array( + // These keywords are not highlighted by the DCS IDE but we may as well + // keep track of them anyway: + 'mp_file', 'odbc_file' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', + '=', '<', '>', + '+', '-', '*', '/', '^', + ':', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: red;', + 2 => 'color: blue;', + 3 => 'color: black;' + ), + 'COMMENTS' => array( + 1 => 'color: black; background-color: silver;', + // Colors for highlighting embedded C code: + 2 => 'color: maroon; background-color: pink;' + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + 0 => 'color: black;' + ), + 'STRINGS' => array( + 0 => 'color: green;' + ), + 'NUMBERS' => array( + 0 => 'color: green;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: black;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ), + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/delphi.php b/examples/includes/geshi/geshi/delphi.php new file mode 100644 index 0000000..7de1f8c --- /dev/null +++ b/examples/includes/geshi/geshi/delphi.php @@ -0,0 +1,289 @@ + 'Delphi', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('(*' => '*)', '{' => '}'), + //Compiler directives + 'COMMENT_REGEXP' => array(2 => '/{\\$.*?}|\\(\\*\\$.*?\\*\\)/U'), + 'CASE_KEYWORDS' => 0, + 'QUOTEMARKS' => array("'"), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'Abstract', 'And', 'Array', 'As', 'Asm', 'At', 'Begin', 'Case', + 'Class', 'Const', 'Constructor', 'Contains', 'Destructor', + 'DispInterface', 'Div', 'Do', 'DownTo', 'Else', 'End', 'Except', + 'Export', 'Exports', 'External', 'File', 'Finalization', 'Finally', + 'For', 'Function', 'Goto', 'If', 'Implementation', 'In', 'Inherited', + 'Initialization', 'Inline', 'Interface', 'Is', 'Label', 'Library', + 'Mod', 'Not', 'Object', 'Of', 'On', 'Or', 'Overload', 'Override', + 'Package', 'Packed', 'Private', 'Procedure', 'Program', 'Property', + 'Protected', 'Public', 'Published', 'Raise', 'Record', 'Register', + 'Repeat', 'Requires', 'Resourcestring', 'Set', 'Shl', 'Shr', 'Then', + 'ThreadVar', 'To', 'Try', 'Type', 'Unit', 'Until', 'Uses', 'Var', + 'Virtual', 'While', 'With', 'Xor', 'assembler', 'far', + 'near', 'pascal', 'register', 'cdecl', 'safecall', 'stdcall', 'varargs' + ), + 2 => array( + 'nil', 'false', 'self', 'true', 'var', 'type', 'const' + ), + 3 => array( + 'Abs', 'AcquireExceptionObject', 'Addr', 'AnsiToUtf8', 'Append', 'ArcTan', + 'Assert', 'AssignFile', 'Assigned', 'BeginThread', 'BlockRead', + 'BlockWrite', 'Break', 'ChDir', 'Chr', 'Close', 'CloseFile', + 'CompToCurrency', 'CompToDouble', 'Concat', 'Continue', 'Copy', 'Cos', + 'Dec', 'Delete', 'Dispose', 'DoubleToComp', 'EndThread', 'EnumModules', + 'EnumResourceModules', 'Eof', 'Eoln', 'Erase', 'ExceptAddr', + 'ExceptObject', 'Exclude', 'Exit', 'Exp', 'FilePos', 'FileSize', + 'FillChar', 'Finalize', 'FindClassHInstance', 'FindHInstance', + 'FindResourceHInstance', 'Flush', 'Frac', 'FreeMem', 'Get8087CW', + 'GetDir', 'GetLastError', 'GetMem', 'GetMemoryManager', + 'GetModuleFileName', 'GetVariantManager', 'Halt', 'Hi', 'High', + 'IOResult', 'Inc', 'Include', 'Initialize', 'Insert', 'Int', + 'IsMemoryManagerSet', 'IsVariantManagerSet', 'Length', 'Ln', 'Lo', 'Low', + 'MkDir', 'Move', 'New', 'Odd', 'OleStrToStrVar', 'OleStrToString', 'Ord', + 'PUCS4Chars', 'ParamCount', 'ParamStr', 'Pi', 'Pos', 'Pred', 'Ptr', + 'Random', 'Randomize', 'Read', 'ReadLn', 'ReallocMem', + 'ReleaseExceptionObject', 'Rename', 'Reset', 'Rewrite', 'RmDir', 'Round', + 'RunError', 'Seek', 'SeekEof', 'SeekEoln', 'Set8087CW', 'SetLength', + 'SetLineBreakStyle', 'SetMemoryManager', 'SetString', 'SetTextBuf', + 'SetVariantManager', 'Sin', 'SizeOf', 'Slice', 'Sqr', 'Sqrt', 'Str', + 'StringOfChar', 'StringToOleStr', 'StringToWideChar', 'Succ', 'Swap', + 'Trunc', 'Truncate', 'TypeInfo', 'UCS4StringToWideString', 'UTF8Decode', + 'UTF8Encode', 'UnicodeToUtf8', 'UniqueString', 'UpCase', 'Utf8ToAnsi', + 'Utf8ToUnicode', 'Val', 'VarArrayRedim', 'VarClear', + 'WideCharLenToStrVar', 'WideCharLenToString', 'WideCharToStrVar', + 'WideCharToString', 'WideStringToUCS4String', 'Write', 'WriteLn', + + 'Abort', 'AddExitProc', 'AddTerminateProc', 'AdjustLineBreaks', 'AllocMem', + 'AnsiCompareFileName', 'AnsiCompareStr', 'AnsiCompareText', + 'AnsiDequotedStr', 'AnsiExtractQuotedStr', 'AnsiLastChar', + 'AnsiLowerCase', 'AnsiLowerCaseFileName', 'AnsiPos', 'AnsiQuotedStr', + 'AnsiSameStr', 'AnsiSameText', 'AnsiStrComp', 'AnsiStrIComp', + 'AnsiStrLComp', 'AnsiStrLIComp', 'AnsiStrLastChar', 'AnsiStrLower', + 'AnsiStrPos', 'AnsiStrRScan', 'AnsiStrScan', 'AnsiStrUpper', + 'AnsiUpperCase', 'AnsiUpperCaseFileName', 'AppendStr', 'AssignStr', + 'Beep', 'BoolToStr', 'ByteToCharIndex', 'ByteToCharLen', 'ByteType', + 'CallTerminateProcs', 'ChangeFileExt', 'CharLength', 'CharToByteIndex', + 'CharToByteLen', 'CompareMem', 'CompareStr', 'CompareText', 'CreateDir', + 'CreateGUID', 'CurrToStr', 'CurrToStrF', 'CurrentYear', 'Date', + 'DateTimeToFileDate', 'DateTimeToStr', 'DateTimeToString', + 'DateTimeToSystemTime', 'DateTimeToTimeStamp', 'DateToStr', 'DayOfWeek', + 'DecodeDate', 'DecodeDateFully', 'DecodeTime', 'DeleteFile', + 'DirectoryExists', 'DiskFree', 'DiskSize', 'DisposeStr', 'EncodeDate', + 'EncodeTime', 'ExceptionErrorMessage', 'ExcludeTrailingBackslash', + 'ExcludeTrailingPathDelimiter', 'ExpandFileName', 'ExpandFileNameCase', + 'ExpandUNCFileName', 'ExtractFileDir', 'ExtractFileDrive', + 'ExtractFileExt', 'ExtractFileName', 'ExtractFilePath', + 'ExtractRelativePath', 'ExtractShortPathName', 'FileAge', 'FileClose', + 'FileCreate', 'FileDateToDateTime', 'FileExists', 'FileGetAttr', + 'FileGetDate', 'FileIsReadOnly', 'FileOpen', 'FileRead', 'FileSearch', + 'FileSeek', 'FileSetAttr', 'FileSetDate', 'FileSetReadOnly', 'FileWrite', + 'FinalizePackage', 'FindClose', 'FindCmdLineSwitch', 'FindFirst', + 'FindNext', 'FloatToCurr', 'FloatToDateTime', 'FloatToDecimal', + 'FloatToStr', 'FloatToStrF', 'FloatToText', 'FloatToTextFmt', + 'FmtLoadStr', 'FmtStr', 'ForceDirectories', 'Format', 'FormatBuf', + 'FormatCurr', 'FormatDateTime', 'FormatFloat', 'FreeAndNil', + 'GUIDToString', 'GetCurrentDir', 'GetEnvironmentVariable', + 'GetFileVersion', 'GetFormatSettings', 'GetLocaleFormatSettings', + 'GetModuleName', 'GetPackageDescription', 'GetPackageInfo', 'GetTime', + 'IncAMonth', 'IncMonth', 'IncludeTrailingBackslash', + 'IncludeTrailingPathDelimiter', 'InitializePackage', 'IntToHex', + 'IntToStr', 'InterlockedDecrement', 'InterlockedExchange', + 'InterlockedExchangeAdd', 'InterlockedIncrement', 'IsDelimiter', + 'IsEqualGUID', 'IsLeapYear', 'IsPathDelimiter', 'IsValidIdent', + 'Languages', 'LastDelimiter', 'LoadPackage', 'LoadStr', 'LowerCase', + 'MSecsToTimeStamp', 'NewStr', 'NextCharIndex', 'Now', 'OutOfMemoryError', + 'QuotedStr', 'RaiseLastOSError', 'RaiseLastWin32Error', 'RemoveDir', + 'RenameFile', 'ReplaceDate', 'ReplaceTime', 'SafeLoadLibrary', + 'SameFileName', 'SameText', 'SetCurrentDir', 'ShowException', 'Sleep', + 'StrAlloc', 'StrBufSize', 'StrByteType', 'StrCat', 'StrCharLength', + 'StrComp', 'StrCopy', 'StrDispose', 'StrECopy', 'StrEnd', 'StrFmt', + 'StrIComp', 'StrLCat', 'StrLComp', 'StrLCopy', 'StrLFmt', 'StrLIComp', + 'StrLen', 'StrLower', 'StrMove', 'StrNew', 'StrNextChar', 'StrPCopy', + 'StrPLCopy', 'StrPas', 'StrPos', 'StrRScan', 'StrScan', 'StrToBool', + 'StrToBoolDef', 'StrToCurr', 'StrToCurrDef', 'StrToDate', 'StrToDateDef', + 'StrToDateTime', 'StrToDateTimeDef', 'StrToFloat', 'StrToFloatDef', + 'StrToInt', 'StrToInt64', 'StrToInt64Def', 'StrToIntDef', 'StrToTime', + 'StrToTimeDef', 'StrUpper', 'StringReplace', 'StringToGUID', 'Supports', + 'SysErrorMessage', 'SystemTimeToDateTime', 'TextToFloat', 'Time', + 'TimeStampToDateTime', 'TimeStampToMSecs', 'TimeToStr', 'Trim', + 'TrimLeft', 'TrimRight', 'TryEncodeDate', 'TryEncodeTime', + 'TryFloatToCurr', 'TryFloatToDateTime', 'TryStrToBool', 'TryStrToCurr', + 'TryStrToDate', 'TryStrToDateTime', 'TryStrToFloat', 'TryStrToInt', + 'TryStrToInt64', 'TryStrToTime', 'UnloadPackage', 'UpperCase', + 'WideCompareStr', 'WideCompareText', 'WideFmtStr', 'WideFormat', + 'WideFormatBuf', 'WideLowerCase', 'WideSameStr', 'WideSameText', + 'WideUpperCase', 'Win32Check', 'WrapText', + + 'ActivateClassGroup', 'AllocateHwnd', 'BinToHex', 'CheckSynchronize', + 'CollectionsEqual', 'CountGenerations', 'DeallocateHwnd', 'EqualRect', + 'ExtractStrings', 'FindClass', 'FindGlobalComponent', 'GetClass', + 'GroupDescendantsWith', 'HexToBin', 'IdentToInt', + 'InitInheritedComponent', 'IntToIdent', 'InvalidPoint', + 'IsUniqueGlobalComponentName', 'LineStart', 'ObjectBinaryToText', + 'ObjectResourceToText', 'ObjectTextToBinary', 'ObjectTextToResource', + 'PointsEqual', 'ReadComponentRes', 'ReadComponentResEx', + 'ReadComponentResFile', 'Rect', 'RegisterClass', 'RegisterClassAlias', + 'RegisterClasses', 'RegisterComponents', 'RegisterIntegerConsts', + 'RegisterNoIcon', 'RegisterNonActiveX', 'SmallPoint', 'StartClassGroup', + 'TestStreamFormat', 'UnregisterClass', 'UnregisterClasses', + 'UnregisterIntegerConsts', 'UnregisterModuleClasses', + 'WriteComponentResFile', + + 'ArcCos', 'ArcCosh', 'ArcCot', 'ArcCotH', 'ArcCsc', 'ArcCscH', 'ArcSec', + 'ArcSecH', 'ArcSin', 'ArcSinh', 'ArcTan2', 'ArcTanh', 'Ceil', + 'CompareValue', 'Cosecant', 'Cosh', 'Cot', 'CotH', 'Cotan', 'Csc', 'CscH', + 'CycleToDeg', 'CycleToGrad', 'CycleToRad', 'DegToCycle', 'DegToGrad', + 'DegToRad', 'DivMod', 'DoubleDecliningBalance', 'EnsureRange', 'Floor', + 'Frexp', 'FutureValue', 'GetExceptionMask', 'GetPrecisionMode', + 'GetRoundMode', 'GradToCycle', 'GradToDeg', 'GradToRad', 'Hypot', + 'InRange', 'IntPower', 'InterestPayment', 'InterestRate', + 'InternalRateOfReturn', 'IsInfinite', 'IsNan', 'IsZero', 'Ldexp', 'LnXP1', + 'Log10', 'Log2', 'LogN', 'Max', 'MaxIntValue', 'MaxValue', 'Mean', + 'MeanAndStdDev', 'Min', 'MinIntValue', 'MinValue', 'MomentSkewKurtosis', + 'NetPresentValue', 'Norm', 'NumberOfPeriods', 'Payment', 'PeriodPayment', + 'Poly', 'PopnStdDev', 'PopnVariance', 'Power', 'PresentValue', + 'RadToCycle', 'RadToDeg', 'RadToGrad', 'RandG', 'RandomRange', 'RoundTo', + 'SLNDepreciation', 'SYDDepreciation', 'SameValue', 'Sec', 'SecH', + 'Secant', 'SetExceptionMask', 'SetPrecisionMode', 'SetRoundMode', 'Sign', + 'SimpleRoundTo', 'SinCos', 'Sinh', 'StdDev', 'Sum', 'SumInt', + 'SumOfSquares', 'SumsAndSquares', 'Tan', 'Tanh', 'TotalVariance', + 'Variance' + ), + 4 => array( + 'AnsiChar', 'AnsiString', 'Bool', 'Boolean', 'Byte', 'ByteBool', 'Cardinal', 'Char', + 'Comp', 'Currency', 'DWORD', 'Double', 'Extended', 'Int64', 'Integer', 'IUnknown', + 'LongBool', 'LongInt', 'LongWord', 'PAnsiChar', 'PAnsiString', 'PBool', 'PBoolean', 'PByte', + 'PByteArray', 'PCardinal', 'PChar', 'PComp', 'PCurrency', 'PDWORD', 'PDate', 'PDateTime', + 'PDouble', 'PExtended', 'PInt64', 'PInteger', 'PLongInt', 'PLongWord', 'Pointer', 'PPointer', + 'PShortInt', 'PShortString', 'PSingle', 'PSmallInt', 'PString', 'PHandle', 'PVariant', 'PWord', + 'PWordArray', 'PWordBool', 'PWideChar', 'PWideString', 'Real', 'Real48', 'ShortInt', 'ShortString', + 'Single', 'SmallInt', 'String', 'TClass', 'TDate', 'TDateTime', 'TextFile', 'THandle', + 'TObject', 'TTime', 'Variant', 'WideChar', 'WideString', 'Word', 'WordBool' + ), + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'SYMBOLS' => array( + 0 => array('(', ')', '[', ']'), + 1 => array('.', ',', ':', ';'), + 2 => array('@', '^'), + 3 => array('=', '+', '-', '*', '/') + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;', + 4 => 'color: #000066; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #008000; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #ff0000; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000066;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000ff;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'REGEXPS' => array( + 0 => 'color: #9ac;', + 1 => 'color: #ff0000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066;', + 1 => 'color: #000066;', + 2 => 'color: #000066;', + 3 => 'color: #000066;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + //Hex numbers + 0 => '\$[0-9a-fA-F]+', + //Characters + 1 => '\#\$?[0-9]{1,3}' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 2 +); + +?> diff --git a/examples/includes/geshi/geshi/diff.php b/examples/includes/geshi/geshi/diff.php new file mode 100644 index 0000000..c82e65c --- /dev/null +++ b/examples/includes/geshi/geshi/diff.php @@ -0,0 +1,196 @@ + 'Diff', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => ' ', + 'KEYWORDS' => array( + 1 => array( + '\ No newline at end of file' + ), +// 2 => array( +// '***************' /* This only seems to works in some cases? */ +// ), + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + 1 => false, +// 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #aaaaaa; font-style: italic;', +// 2 => 'color: #dd6611;', + ), + 'COMMENTS' => array( + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => '' + ), + 'STRINGS' => array( + 0 => '' + ), + 'NUMBERS' => array( + 0 => '' + ), + 'METHODS' => array( + 0 => '' + ), + 'SYMBOLS' => array( + 0 => '' + ), + 'SCRIPT' => array( + 0 => '' + ), + 'REGEXPS' => array( + 0 => 'color: #440088;', + 1 => 'color: #991111;', + 2 => 'color: #00b000;', + 3 => 'color: #888822;', + 4 => 'color: #888822;', + 5 => 'color: #0011dd;', + 6 => 'color: #440088;', + 7 => 'color: #991111;', + 8 => 'color: #00b000;', + 9 => 'color: #888822;', + ), + ), + 'URLS' => array( + 1 => '', +// 2 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + 0 => "[0-9,]+[acd][0-9,]+", + //Removed lines + 1 => array( + GESHI_SEARCH => '^\\<.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //Inserted lines + 2 => array( + GESHI_SEARCH => '^\\>.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //Location line + 3 => array( + GESHI_SEARCH => '^[\\-]{3}\\s.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //Inserted line + 4 => array( + GESHI_SEARCH => '^(\\+){3}\\s.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //Modified line + 5 => array( + GESHI_SEARCH => '^\\!.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //File specification + 6 => array( + GESHI_SEARCH => '^[\\@]{2}.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //Removed line + 7 => array( + GESHI_SEARCH => '^\\-.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //Inserted line + 8 => array( + GESHI_SEARCH => '^\\+.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + //File specification + 9 => array( + GESHI_SEARCH => '^(\\*){3}\\s.*$', + GESHI_REPLACE => '\\0', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/div.php b/examples/includes/geshi/geshi/div.php new file mode 100644 index 0000000..d3d506d --- /dev/null +++ b/examples/includes/geshi/geshi/div.php @@ -0,0 +1,126 @@ + 'DIV', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'while','until','to','switch','step','return','repeat','loop','if','from','frame','for','end','elseif', + 'else','default','debug','continue','clone','case','break','begin' + ), + 2 => array( + 'xor','whoami','type','sizeof','pointer','or','offset','not','neg','mod','id','dup','and','_ne','_lt', + '_le','_gt','_ge','_eq' + ), + 3 => array( + 'setup_program','program','process','private','local','import','global','function','const', + 'compiler_options' + ), + 4 => array( + 'word','struct','string','int','byte' + ), + ), + 'SYMBOLS' => array( + '(',')','[',']','=','+','-','*','/','!','%','^','&',':',';',',','<','>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0040b1;', + 2 => 'color: #000000;', + 3 => 'color: #000066; font-weight: bold;', + 4 => 'color: #993333;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => 'color: #44aa44;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #202020;', + ), + 'SYMBOLS' => array( + 0 => 'color: #44aa44;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/dos.php b/examples/includes/geshi/geshi/dos.php new file mode 100644 index 0000000..af8fdae --- /dev/null +++ b/examples/includes/geshi/geshi/dos.php @@ -0,0 +1,198 @@ + 'DOS', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + //DOS comment lines + 'COMMENT_REGEXP' => array(1 => "/^\s*@?REM.*$/mi"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /* Flow control keywords */ + 1 => array( + 'if', 'else', 'goto', 'shift', + 'for', 'in', 'do', + 'call', 'exit' + ), + /* IF statement keywords */ + 2 => array( + 'not', 'exist', 'errorlevel', + 'defined', + 'equ', 'neq', 'lss', 'leq', 'gtr', 'geq' + ), + /* Internal commands */ + 3 => array( + 'cd', 'md', 'rd', 'chdir', 'mkdir', 'rmdir', 'dir', + 'del', 'copy', 'move', 'ren', 'rename', + 'echo', + 'setlocal', 'endlocal', 'set', + 'pause', + 'pushd', 'popd', 'title', 'verify' + ), + /* Special files */ + 4 => array( + 'prn', 'nul', 'lpt3', 'lpt2', 'lpt1', 'con', + 'com4', 'com3', 'com2', 'com1', 'aux' + ) + ), + 'SYMBOLS' => array( + '(', ')', '@', '%' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00b100; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #b1b100; font-weight: bold;', + 4 => 'color: #0000ff; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #ff0000; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #33cc33;', + 1 => 'color: #33cc33;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 0 => 'color: #b100b1; font-weight: bold;', + 1 => 'color: #448844;', + 2 => 'color: #448888;' + ) + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'URLS' => array( + 1 => 'http://www.ss64.com/nt/{FNAMEL}.html', + 2 => 'http://www.ss64.com/nt/{FNAMEL}.html', + 3 => 'http://www.ss64.com/nt/{FNAMEL}.html', + 4 => 'http://www.ss64.com/nt/{FNAMEL}.html' + ), + 'REGEXPS' => array( + /* Label */ + 0 => array( +/* GESHI_SEARCH => '((?si:[@\s]+GOTO\s+|\s+:)[\s]*)((? '((?si:[@\s]+GOTO\s+|\s+:)[\s]*)((? '\\2', + GESHI_MODIFIERS => 'si', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + /* Variable assignement */ + 1 => array( +/* GESHI_SEARCH => '(SET[\s]+(?si:\/A[\s]+|\/P[\s]+|))([^=\s\n]+)([\s]*=)',*/ + GESHI_SEARCH => '(SET[\s]+(?si:\/A[\s]+|\/P[\s]+|))([^=\n]+)([\s]*=)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'si', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + /* Arguments or variable evaluation */ + 2 => array( +/* GESHI_SEARCH => '(%)([\d*]|[^%\s]*(?=%))((? '(%(?:%(?=[a-z0-9]))?)([\d*]|(?:~[adfnpstxz]*(?:$\w+:)?)?[a-z0-9](?!\w)|[^%\n]*(?=%))((? '\\2', + GESHI_MODIFIERS => 'si', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 4 => array( + 'DISALLOWED_BEFORE' => '(? diff --git a/examples/includes/geshi/geshi/dot.php b/examples/includes/geshi/geshi/dot.php new file mode 100644 index 0000000..35d3d9b --- /dev/null +++ b/examples/includes/geshi/geshi/dot.php @@ -0,0 +1,164 @@ + 'dot', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'URL', 'arrowhead', 'arrowsize', 'arrowtail', 'bb', 'bgcolor', 'bottomlabel', + 'center', 'clusterrank', 'color', 'comment', 'constraint', 'decorate', + 'dir', 'distortion', 'fillcolor', 'fixedsize', 'fontcolor', + 'fontname', 'fontsize', 'group', 'headclip', 'headlabel', 'headport', + 'height', 'id', 'label', 'labelangle', 'labeldistance', 'labelfontcolor', + 'labelfontname', 'labelfontsize', 'layer', 'layers', 'margin', 'mclimit', + 'minlen', 'nodesep', 'nslimit', 'ordering', 'orientation', 'page', + 'pagedir', 'peripheries', 'port_label_distance', 'quantum', 'rank', 'rankdir', + 'ranksep', 'ratio', 'regular', 'rotate', 'samehead', 'sametail', 'searchsize', + 'shape', 'shapefile', 'showboxes', 'sides', 'size', 'skew', 'style', + 'tailclip', 'taillabel', 'tailport', 'toplabel', 'weight', 'width' + ), + 2 => array( + 'node', 'graph', 'digraph', 'strict', 'edge', 'subgraph' + ), + 3 => array( + 'Mcircle', 'Mdiamond', 'Mrecord', 'Msquare', 'TRUE', 'auto', 'back', + 'bold', 'both', 'box', 'circle', 'compress', 'dashed', 'diamond', 'dot', + 'dotted', 'doublecircle', 'doubleoctagon', 'egg', 'ellipse', 'epsf', 'false', + 'fill', 'filled', 'forward', 'global', 'hexagon', 'house', 'inv', 'invdot', + 'invhouse', 'invis', 'invodot', 'invtrapezium', 'invtriangle', 'local', 'max', + 'min', 'none', 'normal', 'octagon', 'odot', 'out', 'parallelogram', 'plaintext', + 'polygon', 'record', 'same', 'solid', 'trapezium', 'triangle', 'tripleoctagon', + 'true' + ), + 4 => array( + 'aliceblue', 'antiquewhite', 'aquamarine', 'azure', 'beige', 'bisque', 'black', + 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', + 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', + 'cyan', 'darkgoldenrod', 'darkgreen', 'darkkhaki', 'darkolivegreen', + 'darkorange', 'darkorchid', 'darksalmon', 'darkseagreen', 'darkslateblue', + 'darkslategray', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', + 'dimgray', 'dodgerblue', 'firebrick', 'forestgreen', 'gainsboro', 'ghostwhite', + 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'honeydew', 'hotpink', + 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', + 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcyan', 'lightgoldenrod', + 'lightgoldenrodyellow', 'lightgray', 'lightpink', 'lightsalmon', + 'lightseagreen', 'lightskyblue', 'lightslateblue', 'lightslategray', + 'lightyellow', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', + 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', + 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', + 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'navy', + 'navyblue', 'oldlace', 'olivedrab', 'oralwhite', 'orange', 'orangered', + 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', + 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', + 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'salmon2', 'sandybrown', + 'seagreen', 'seashell', 'sienna', 'skyblue', 'slateblue', 'slategray', 'snow', + 'springgreen', 'steelblue', 'tan', 'thistle', 'tomato', 'turquoise', 'violet', + 'violetred', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen' + ) + ), + 'SYMBOLS' => array( + '[', ']', '{', '}', '-', '+', '*', '/', '<', '>', '!', '~', '%', '&', '|', '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000066;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #993333;', + 4 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #339933;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #af624d; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'METHODS' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ), + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array(), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true + ) +); + +?> diff --git a/examples/includes/geshi/geshi/eiffel.php b/examples/includes/geshi/geshi/eiffel.php new file mode 100644 index 0000000..7a9a61e --- /dev/null +++ b/examples/includes/geshi/geshi/eiffel.php @@ -0,0 +1,395 @@ + 'Eiffel', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '%', + 'KEYWORDS' => array( + 1 => array( + 'separate', + 'invariant', + 'inherit', + 'indexing', + 'feature', + 'expanded', + 'deferred', + 'class' + ), + 2 => array( + 'xor', + 'when', + 'variant', + 'until', + 'unique', + 'undefine', + 'then', + 'strip', + 'select', + 'retry', + 'rescue', + 'require', + 'rename', + 'reference', + 'redefine', + 'prefix', + 'or', + 'once', + 'old', + 'obsolete', + 'not', + 'loop', + 'local', + 'like', + 'is', + 'inspect', + 'infix', + 'include', + 'implies', + 'if', + 'frozen', + 'from', + 'external', + 'export', + 'ensure', + 'end', + 'elseif', + 'else', + 'do', + 'creation', + 'create', + 'check', + 'as', + 'and', + 'alias', + 'agent' + ), + 3 => array( + 'Void', + 'True', + 'Result', + 'Precursor', + 'False', + 'Current' + ), + 4 => array( + 'UNIX_SIGNALS', + 'UNIX_FILE_INFO', + 'UNBOUNDED', + 'TWO_WAY_TREE_CURSOR', + 'TWO_WAY_TREE', + 'TWO_WAY_SORTED_SET', + 'TWO_WAY_LIST', + 'TWO_WAY_CURSOR_TREE', + 'TWO_WAY_CIRCULAR', + 'TWO_WAY_CHAIN_ITERATOR', + 'TUPLE', + 'TREE', + 'TRAVERSABLE', + 'TO_SPECIAL', + 'THREAD_CONTROL', + 'THREAD_ATTRIBUTES', + 'THREAD', + 'TABLE', + 'SUBSET', + 'STRING_HANDLER', + 'STRING', + 'STREAM', + 'STORABLE', + 'STD_FILES', + 'STACK', + 'SPECIAL', + 'SORTED_TWO_WAY_LIST', + 'SORTED_STRUCT', + 'SORTED_LIST', + 'SINGLE_MATH', + 'SET', + 'SEQUENCE', + 'SEQ_STRING', + 'SEMAPHORE', + 'ROUTINE', + 'RESIZABLE', + 'RECURSIVE_TREE_CURSOR', + 'RECURSIVE_CURSOR_TREE', + 'REAL_REF', + 'REAL', + 'RAW_FILE', + 'RANDOM', + 'QUEUE', + 'PROXY', + 'PROFILING_SETTING', + 'PROCEDURE', + 'PRIORITY_QUEUE', + 'PRIMES', + 'PRECOMP', + 'POINTER_REF', + 'POINTER', + 'PLATFORM', + 'PLAIN_TEXT_FILE', + 'PATH_NAME', + 'PART_SORTED_TWO_WAY_LIST', + 'PART_SORTED_SET', + 'PART_SORTED_LIST', + 'PART_COMPARABLE', + 'OPERATING_ENVIRONMENT', + 'ONCE_CONTROL', + 'OBJECT_OWNER', + 'OBJECT_CONTROL', + 'NUMERIC', + 'NONE', + 'MUTEX', + 'MULTI_ARRAY_LIST', + 'MULTAR_LIST_CURSOR', + 'MEMORY', + 'MEM_INFO', + 'MEM_CONST', + 'MATH_CONST', + 'LIST', + 'LINKED_TREE_CURSOR', + 'LINKED_TREE', + 'LINKED_STACK', + 'LINKED_SET', + 'LINKED_QUEUE', + 'LINKED_PRIORITY_QUEUE', + 'LINKED_LIST_CURSOR', + 'LINKED_LIST', + 'LINKED_CURSOR_TREE', + 'LINKED_CIRCULAR', + 'LINKABLE', + 'LINEAR_ITERATOR', + 'LINEAR', + 'ITERATOR', + 'IO_MEDIUM', + 'INTERNAL', + 'INTEGER_REF', + 'INTEGER_INTERVAL', + 'INTEGER', + 'INFINITE', + 'INDEXABLE', + 'IDENTIFIED_CONTROLLER', + 'IDENTIFIED', + 'HIERARCHICAL', + 'HEAP_PRIORITY_QUEUE', + 'HASHABLE', + 'HASH_TABLE_CURSOR', + 'HASH_TABLE', + 'GENERAL', + 'GC_INFO', + 'FUNCTION', + 'FORMAT_INTEGER', + 'FORMAT_DOUBLE', + 'FIXED_TREE', + 'FIXED_LIST', + 'FIXED', + 'FINITE', + 'FILE_NAME', + 'FILE', + 'FIBONACCI', + 'EXECUTION_ENVIRONMENT', + 'EXCEPTIONS', + 'EXCEP_CONST', + 'DYNAMIC_TREE', + 'DYNAMIC_LIST', + 'DYNAMIC_CIRCULAR', + 'DYNAMIC_CHAIN', + 'DOUBLE_REF', + 'DOUBLE_MATH', + 'DOUBLE', + 'DISPENSER', + 'DIRECTORY_NAME', + 'DIRECTORY', + 'DECLARATOR', + 'DEBUG_OUTPUT', + 'CURSOR_TREE_ITERATOR', + 'CURSOR_TREE', + 'CURSOR_STRUCTURE', + 'CURSOR', + 'COUNTABLE_SEQUENCE', + 'COUNTABLE', + 'CONTAINER', + 'CONSOLE', + 'CONDITION_VARIABLE', + 'COMPARABLE_STRUCT', + 'COMPARABLE_SET', + 'COMPARABLE', + 'COMPACT_TREE_CURSOR', + 'COMPACT_CURSOR_TREE', + 'COLLECTION', + 'CIRCULAR_CURSOR', + 'CIRCULAR', + 'CHARACTER_REF', + 'CHARACTER', + 'CHAIN', + 'CELL', + 'BOX', + 'BOUNDED_STACK', + 'BOUNDED_QUEUE', + 'BOUNDED', + 'BOOLEAN_REF', + 'BOOLEAN', + 'BOOL_STRING', + 'BIT_REF', + 'BINARY_TREE', + 'BINARY_SEARCH_TREE_SET', + 'BINARY_SEARCH_TREE', + 'BILINEAR', + 'BI_LINKABLE', + 'BASIC_ROUTINES', + 'BAG', + 'ASCII', + 'ARRAYED_TREE', + 'ARRAYED_STACK', + 'ARRAYED_QUEUE', + 'ARRAYED_LIST_CURSOR', + 'ARRAYED_LIST', + 'ARRAYED_CIRCULAR', + 'ARRAY2', + 'ARRAY', + 'ARGUMENTS', + 'ANY', + 'ACTIVE' + ), + 5 => array( + 'yes', + 'visible', + 'trace', + 'system', + 'root', + 'profile', + 'override_cluster', + 'object', + 'no', + 'multithreaded', + 'msil_generation_type', + 'line_generation', + 'library', + 'inlining_size', + 'inlining', + 'include_path', + 'il_verifiable', + 'exclude', + 'exception_trace', + 'dynamic_runtime', + 'dotnet_naming_convention', + 'disabled_debug', + 'default', + 'debug', + 'dead_code_removal', + 'console_application', + 'cluster', + 'cls_compliant', + 'check_vape', + 'assertion', + 'array_optimization', + 'all', + 'address_expression' + ), + ), + 'SYMBOLS' => array( + '+', '-', '*', '?', '=', '/', '%', '&', '>', '<', '^', '!', '|', ':', + '(', ')', '{', '}', '[', ']', '#' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => true, + 5 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0600FF; font-weight: bold;', + 2 => 'color: #0600FF; font-weight: bold;', + 3 => 'color: #800080;', + 4 => 'color: #800000', + 5 => 'color: #603000;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000; font-style: italic;', + 'MULTI' => '' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #005070; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #FF0000;' + ), + 'STRINGS' => array( + 0 => 'color: #0080A0;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF0000;' + ), + 'METHODS' => array( + 1 => 'color: #000060;', + 2 => 'color: #000050;' + ), + 'SYMBOLS' => array( + 0 => 'color: #600000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => 'http://www.google.com/search?q=site%3Ahttp%3A%2F%2Fdocs.eiffel.com%2Feiffelstudio%2Flibraries+{FNAMEL}&btnI=I%27m+Feeling+Lucky', + 5 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/email.php b/examples/includes/geshi/geshi/email.php new file mode 100644 index 0000000..26466dc --- /dev/null +++ b/examples/includes/geshi/geshi/email.php @@ -0,0 +1,209 @@ + 'eMail (mbox)', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'HTTP', 'SMTP', 'ASMTP', 'ESMTP' + ), + 2 => array( + 'Content-Type','Content-Transfer-Encoding','Content-Disposition', + 'Delivered-To','Dkim-Signature','Domainkey-Signature','In-Reply-To', + 'Message-Id','MIME-Version','Received','Received-SPF','References', + 'Resend-From','Resend-To','Return-Path' + ), + 3 => array( + 'Date','From','Subject','To', + ), + 4 => array( + 'by', 'for', 'from', 'id', 'with' + ) + ), + 'SYMBOLS' => array( + ':', ';', '<', '>', '[', ']' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => false, + 3 => false, + 4 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000FF; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #800000; font-weight: bold;', + 4 => 'font-weight: bold;', + ), + 'COMMENTS' => array( + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + 0 => 'color: #000040;', + ), + 'REGEXPS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #0000FF;', + 3 => 'color: #008000;', + 4 => 'color: #0000FF; font-weight: bold;', + 5 => 'font-weight: bold;', + 6 => 'color: #400080;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + // Non-Standard-Header + 1 => array( + GESHI_SEARCH => "(?<=\A\x20|\n)x-[a-z0-9\-]*(?=\s*:|\s*<)", + GESHI_REPLACE => "\\0", + GESHI_MODIFIERS => "smi", + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + //Email-Adresses or Mail-IDs + 2 => array( + GESHI_SEARCH => "\b[\w\.]+@\w+(?:(?:\.\w+)*\.\w{2,4})?", + GESHI_REPLACE => "\\0", + GESHI_MODIFIERS => "mi", + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + //Date values in RFC format + 3 => array( + GESHI_SEARCH => "\b(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s+\d\d?\s+" . + "(?:Jan|Feb|Mar|apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+" . + "\d{4}\s+\d\d?:\d\d:\d\d\s+[+\-]\d{4}(?:\s+\(\w+\))?", + GESHI_REPLACE => "\\0", + GESHI_MODIFIERS => "mi", + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + //IP addresses + 4 => array( + GESHI_SEARCH => "(?<=\s)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?=\s)|". + "(?<=\[)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?=\])|". + "(?<==)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?=<)", + GESHI_REPLACE => "\\0", + GESHI_MODIFIERS => "i", + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + //Field-Assignments + 5 => array( + GESHI_SEARCH => "(?<=\s)[A-Z0-9\-]+(?==(?!\s|$))", + GESHI_REPLACE => "\\0", + GESHI_MODIFIERS => "mi", + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + //MIME type + 6 => array( + GESHI_SEARCH => "(?<=\s)(?:audio|application|image|multipart|text|". + "video|x-[a-z0-9\-]+)\/[a-z0-9][a-z0-9\-]*(?=\s|<|$)", + GESHI_REPLACE => "\\0", + GESHI_MODIFIERS => "m", + GESHI_BEFORE => "", + GESHI_AFTER => "" + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + 0 => "/(^)[A-Z][a-zA-Z0-9\-]*\s*:\s*(?:.|(?=\n\s)\n)*($)/m" + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 2 => array( + 'DISALLOWED_BEFORE' => '(?<=\A\x20|\n)', + 'DISALLOWED_AFTER' => '(?=\s*:)', + ), + 3 => array( + 'DISALLOWED_BEFORE' => '(?<=\A\x20|\n)', + 'DISALLOWED_AFTER' => '(?=\s*:)', + ), + 4 => array( + 'DISALLOWED_BEFORE' => '(?<=\s)', + 'DISALLOWED_AFTER' => '(?=\s|\b)', + ) + ), + 'ENABLE_FLAGS' => array( + 'BRACKETS' => GESHI_NEVER, + 'COMMENTS' => GESHI_NEVER, + 'NUMBERS' => GESHI_NEVER + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/fortran.php b/examples/includes/geshi/geshi/fortran.php new file mode 100644 index 0000000..1caf09d --- /dev/null +++ b/examples/includes/geshi/geshi/fortran.php @@ -0,0 +1,160 @@ +'Fortran', + 'COMMENT_SINGLE'=> array(1 =>'!',2=>'Cf2py'), + 'COMMENT_MULTI'=> array(), + //Fortran Comments + 'COMMENT_REGEXP' => array(1 => '/^C.*?$/mi'), + 'CASE_KEYWORDS'=> GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS'=> array("'",'"'), + 'ESCAPE_CHAR'=>'\\', + 'KEYWORDS'=> array( + 1 => array( + 'allocate','block','call','case','contains','continue','cycle','deallocate', + 'default','do','else','elseif','elsewhere','end','enddo','endif','endwhere', + 'entry','exit','function','go','goto','if','interface','module','nullify','only', + 'operator','procedure','program','recursive','return','select','stop', + 'subroutine','then','to','where','while', + 'access','action','advance','blank','blocksize','carriagecontrol', + 'delim','direct','eor','err','exist','file','flen','fmt','form','formatted', + 'iostat','name','named','nextrec','nml','number','opened','pad','position', + 'readwrite','recl','sequential','status','unformatted','unit' + ), + 2 => array( + '.AND.','.EQ.','.EQV.','.GE.','.GT.','.LE.','.LT.','.NE.','.NEQV.','.NOT.', + '.OR.','.TRUE.','.FALSE.' + ), + 3 => array( + 'allocatable','character','common','complex','data','dimension','double', + 'equivalence','external','implicit','in','inout','integer','intent','intrinsic', + 'kind','logical','namelist','none','optional','out','parameter','pointer', + 'private','public','real','result','save','sequence','target','type','use' + ), + 4 => array( + 'abs','achar','acos','adjustl','adjustr','aimag','aint','all','allocated', + 'anint','any','asin','atan','atan2','bit_size','break','btest','carg', + 'ceiling','char','cmplx','conjg','cos','cosh','cpu_time','count','cshift', + 'date_and_time','dble','digits','dim','dot_product','dprod dvchk', + 'eoshift','epsilon','error','exp','exponent','floor','flush','fraction', + 'getcl','huge','iachar','iand','ibclr','ibits','ibset','ichar','ieor','index', + 'int','intrup','invalop','ior','iostat_msg','ishft','ishftc','lbound', + 'len','len_trim','lge','lgt','lle','llt','log','log10','matmul','max','maxexponent', + 'maxloc','maxval','merge','min','minexponent','minloc','minval','mod','modulo', + 'mvbits','nbreak','ndperr','ndpexc','nearest','nint','not','offset','ovefl', + 'pack','precfill','precision','present','product','prompt','radix', + 'random_number','random_seed','range','repeat','reshape','rrspacing', + 'scale','scan','segment','selected_int_kind','selected_real_kind', + 'set_exponent','shape','sign','sin','sinh','size','spacing','spread','sqrt', + 'sum system','system_clock','tan','tanh','timer','tiny','transfer','transpose', + 'trim','ubound','undfl','unpack','val','verify' + ), + ), + 'SYMBOLS'=> array( + '(',')','{','}','[',']','=','+','-','*','/','!','%','^','&',':' + ), + 'CASE_SENSITIVE'=> array( + GESHI_COMMENTS => true, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES'=> array( + 'KEYWORDS'=> array( + 1 =>'color: #b1b100;', + 2 =>'color: #000000; font-weight: bold;', + 3 =>'color: #000066;', + 4 =>'color: #993333;' + ), + 'COMMENTS'=> array( + 1 =>'color: #666666; font-style: italic;', + 2 =>'color: #339933;', + 'MULTI'=>'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR'=> array( + 0 =>'color: #000099; font-weight: bold;' + ), + 'BRACKETS'=> array( + 0 =>'color: #009900;' + ), + 'STRINGS'=> array( + 0 =>'color: #ff0000;' + ), + 'NUMBERS'=> array( + 0 =>'color: #cc66cc;' + ), + 'METHODS'=> array( + 1 =>'color: #202020;', + 2 =>'color: #202020;' + ), + 'SYMBOLS'=> array( + 0 =>'color: #339933;' + ), + 'REGEXPS'=> array( + ), + 'SCRIPT'=> array( + ) + ), + 'URLS'=> array( + 1 =>'', + 2 =>'', + 3 =>'', + 4 =>'' + ), + 'OOLANG'=> true, + 'OBJECT_SPLITTERS'=> array( + 1 =>'.', + 2 =>'::' + ), + 'REGEXPS'=> array( + ), + 'STRICT_MODE_APPLIES'=> GESHI_NEVER, + 'SCRIPT_DELIMITERS'=> array( + ), + 'HIGHLIGHT_STRICT_BLOCK'=> array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/freebasic.php b/examples/includes/geshi/geshi/freebasic.php new file mode 100644 index 0000000..0ddc46c --- /dev/null +++ b/examples/includes/geshi/geshi/freebasic.php @@ -0,0 +1,141 @@ + 'FreeBasic', + 'COMMENT_SINGLE' => array(1 => "'", 2 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + "append", "as", "asc", "asin", "asm", "atan2", "atn", "beep", "bin", "binary", "bit", + "bitreset", "bitset", "bload", "bsave", "byref", "byte", "byval", "call", + "callocate", "case", "cbyte", "cdbl", "cdecl", "chain", "chdir", "chr", "cint", + "circle", "clear", "clng", "clngint", "close", "cls", "color", "command", + "common", "cons", "const", "continue", "cos", "cshort", "csign", "csng", + "csrlin", "cubyte", "cuint", "culngint", "cunsg", "curdir", "cushort", "custom", + "cvd", "cvi", "cvl", "cvlongint", "cvs", "cvshort", "data", "date", + "deallocate", "declare", "defbyte", "defdbl", "defined", "defint", "deflng", + "deflngint", "defshort", "defsng", "defstr", "defubyte", "defuint", + "defulngint", "defushort", "dim", "dir", "do", "double", "draw", "dylibload", + "dylibsymbol", "else", "elseif", "end", "enum", "environ", 'environ$', "eof", + "eqv", "erase", "err", "error", "exec", "exepath", "exit", "exp", "export", + "extern", "field", "fix", "flip", "for", "fre", "freefile", "function", "get", + "getjoystick", "getkey", "getmouse", "gosub", "goto", "hex", "hibyte", "hiword", + "if", "iif", "imagecreate", "imagedestroy", "imp", "inkey", "inp", "input", + "instr", "int", "integer", "is", "kill", "lbound", "lcase", "left", "len", + "let", "lib", "line", "lobyte", "loc", "local", "locate", "lock", "lof", "log", + "long", "longint", "loop", "loword", "lset", "ltrim", "mid", "mkd", "mkdir", + "mki", "mkl", "mklongint", "mks", "mkshort", "mod", "multikey", "mutexcreate", + "mutexdestroy", "mutexlock", "mutexunlock", "name", "next", "not", "oct", "on", + "once", "open", "option", "or", "out", "output", "overload", "paint", "palette", + "pascal", "pcopy", "peek", "peeki", "peeks", "pipe", "pmap", "point", "pointer", + "poke", "pokei", "pokes", "pos", "preserve", "preset", "print", "private", + "procptr", "pset", "ptr", "public", "put", "random", "randomize", "read", + "reallocate", "redim", "rem", "reset", "restore", "resume", + "return", "rgb", "rgba", "right", "rmdir", "rnd", "rset", "rtrim", "run", + "sadd", "screen", "screencopy", "screeninfo", "screenlock", "screenptr", + "screenres", "screenset", "screensync", "screenunlock", "seek", "statement", + "selectcase", "setdate", "setenviron", "setmouse", + "settime", "sgn", "shared", "shell", "shl", "short", "shr", "sin", "single", + "sizeof", "sleep", "space", "spc", "sqr", "static", "stdcall", "step", "stop", + "str", "string", "strptr", "sub", "swap", "system", "tab", "tan", + "then", "threadcreate", "threadwait", "time", "timer", "to", "trans", + "trim", "type", "ubound", "ubyte", "ucase", "uinteger", "ulongint", "union", + "unlock", "unsigned", "until", "ushort", "using", "va_arg", "va_first", + "va_next", "val", "val64", "valint", "varptr", "view", "viewprint", "wait", + "wend", "while", "width", "window", "windowtitle", "with", "write", "xor", + "zstring", "explicit", "escape", "true", "false" + ) + ), + 'SYMBOLS' => array( + '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080;', + 2 => 'color: #339933;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #66cc66;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/genero.php b/examples/includes/geshi/geshi/genero.php new file mode 100644 index 0000000..997e21f --- /dev/null +++ b/examples/includes/geshi/geshi/genero.php @@ -0,0 +1,463 @@ + 'genero', + 'COMMENT_SINGLE' => array(1 => '--', 2 => '#'), + 'COMMENT_MULTI' => array('{' => '}'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + "ABSOLUTE", + "ACCEPT", + "ACTION", + "ADD", + "AFTER", + "ALL", + "ALTER", + "AND", + "ANY", + "APPEND", + "APPLICATION", + "AS", + "AT", + "ATTRIBUTE", + "ATTRIBUTES", + "AUDIT", + "AVG", + "BEFORE", + "BEGIN", + "BETWEEN", + "BORDER", + "BOTTOM", + "BREAKPOINT", + "BUFFER", + "BUFFERED", + "BY", + "CALL", + "CANCEL", + "CASE", + "CENTURY", + "CHANGE", + "CHECK", + "CLEAR", + "CLIPPED", + "CLOSE", + "CLUSTER", + "COLUMN", + "COLUMNS", + "COMMAND", + "COMMENT", + "COMMIT", + "COMMITTED", + "CONCURRENT ", + "CONNECT", + "CONNECTION", + "CONSTANT", + "CONSTRAINED", + "CONSTRAINT", + "CONSTRUCT", + "CONTINUE", + "CONTROL", + "COUNT", + "CREATE", + "CROSS", + "CURRENT", + "DATABASE", + "DBA", + "DEC", + "DECLARE", + "DEFAULT", + "DEFAULTS", + "DEFER", + "DEFINE", + "DELETE", + "DELIMITER", + "DESCRIBE", + "DESTINATION", + "DIM", + "DIALOG", + "DIMENSION", + "DIRTY", + "DISCONNECT", + "DISPLAY", + "DISTINCT", + "DORMANT", + "DOWN", + "DROP", + "DYNAMIC", + "ELSE", + "END", + "ERROR", + "ESCAPE", + "EVERY", + "EXCLUSIVE", + "EXECUTE", + "EXISTS", + "EXIT", + "EXPLAIN", + "EXTEND", + "EXTENT", + "EXTERNAL", + "FETCH", + "FGL_DRAWBOX", + "FIELD", + "FIELD_TOUCHED", + "FILE", + "FILL", + "FINISH", + "FIRST", + "FLOAT", + "FLUSH", + "FOR", + "FOREACH", + "FORM", + "FORMAT", + "FOUND", + "FRACTION", + "FREE", + "FROM", + "FULL", + "FUNCTION", + "GET_FLDBUF", + "GLOBALS", + "GO", + "GOTO", + "GRANT", + "GROUP", + "HAVING", + "HEADER", + "HELP", + "HIDE", + "HOLD", + "HOUR", + "IDLE", + "IF", + "IMAGE", + "IMMEDIATE", + "IN", + "INDEX", + "INFIELD", + "INITIALIZE", + "INNER", + "INPUT", + "INSERT", + "INTERRUPT", + "INTERVAL", + "INTO", + "INVISIBLE", + "IS", + "ISOLATION", + "JOIN", + "KEEP", + "KEY", + "LABEL", + "LAST", + "LEFT", + "LENGTH", + "LET", + "LIKE", + "LINE", + "LINENO", + "LINES", + "LOAD", + "LOCATE", + "LOCK", + "LOG", + "LSTR", + "MAIN", + "MARGIN", + "MATCHES", + "MAX", + "MAXCOUNT", + "MDY", + "MEMORY", + "MENU", + "MESSAGE", + "MIN", + "MINUTE", + "MOD", + "MODE", + "MODIFY", + "MONEY", + "NAME", + "NEED", + "NEXT", + "NO", + "NORMAL", + "NOT", + "NOTFOUND", + "NULL", + "NUMERIC", + "OF", + "ON", + "OPEN", + "OPTION", + "OPTIONS", + "OR", + "ORDER", + "OTHERWISE", + "OUTER", + "OUTPUT", + "PAGE", + "PAGENO", + "PAUSE", + "PERCENT", + "PICTURE", + "PIPE", + "PRECISION", + "PREPARE", + "PREVIOUS", + "PRINT", + "PRINTER", + "PRINTX", + "PRIOR", + "PRIVILEGES", + "PROCEDURE", + "PROGRAM", + "PROMPT", + "PUBLIC", + "PUT", + "QUIT", + "READ", + "REAL", + "RECORD", + "RECOVER", + "RED ", + "RELATIVE", + "RENAME", + "REOPTIMIZATION", + "REPEATABLE", + "REPORT", + "RESOURCE", + "RETURN", + "RETURNING", + "REVERSE", + "REVOKE", + "RIGHT", + "ROLLBACK", + "ROLLFORWARD", + "ROW", + "ROWS", + "RUN", + "SCHEMA", + "SCREEN", + "SCROLL", + "SECOND", + "SELECT", + "SERIAL", + "SET", + "SFMT", + "SHARE", + "SHIFT", + "SHOW", + "SIGNAL ", + "SIZE", + "SKIP", + "SLEEP", + "SOME", + "SPACE", + "SPACES", + "SQL", + "SQLERRMESSAGE", + "SQLERROR", + "SQLSTATE", + "STABILITY", + "START", + "STATISTICS", + "STEP", + "STOP", + "STYLE", + "SUM", + "SYNONYM", + "TABLE", + "TEMP", + "TERMINATE", + "TEXT", + "THEN", + "THROUGH", + "THRU", + "TO", + "TODAY", + "TOP", + "TRAILER", + "TRANSACTION ", + "UNBUFFERED", + "UNCONSTRAINED", + "UNDERLINE", + "UNION", + "UNIQUE", + "UNITS", + "UNLOAD", + "UNLOCK", + "UP", + "UPDATE", + "USE", + "USER", + "USING", + "VALIDATE", + "VALUE", + "VALUES", + "VARCHAR", + "VIEW", + "WAIT", + "WAITING", + "WARNING", + "WHEN", + "WHENEVER", + "WHERE", + "WHILE", + "WINDOW", + "WITH", + "WITHOUT", + "WORDWRAP", + "WORK", + "WRAP" + ), + 2 => array( + '&IFDEF', '&ENDIF' + ), + 3 => array( + "ARRAY", + "BYTE", + "CHAR", + "CHARACTER", + "CURSOR", + "DATE", + "DATETIME", + "DECIMAL", + "DOUBLE", + "FALSE", + "INT", + "INTEGER", + "SMALLFLOAT", + "SMALLINT", + "STRING", + "TIME", + "TRUE" + ), + 4 => array( + "BLACK", + "BLINK", + "BLUE", + "BOLD", + "ANSI", + "ASC", + "ASCENDING", + "ASCII", + "CYAN", + "DESC", + "DESCENDING", + "GREEN", + "MAGENTA", + "OFF", + "WHITE", + "YELLOW", + "YEAR", + "DAY", + "MONTH", + "WEEKDAY" + ), + ), + 'SYMBOLS' => array( + '+', '-', '*', '?', '=', '/', '%', '>', '<', '^', '!', '|', ':', + '(', ')', '[', ']' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0600FF;', + 2 => 'color: #0000FF; font-weight: bold;', + 3 => 'color: #008000;', + 4 => 'color: #FF0000;', + ), + 'COMMENTS' => array( + 1 => 'color: #008080; font-style: italic;', + 2 => 'color: #008080;', + 'MULTI' => 'color: #008080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008080; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #808080;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF0000;' + ), + 'METHODS' => array( + 1 => 'color: #0000FF;', + 2 => 'color: #0000FF;' + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/gettext.php b/examples/includes/geshi/geshi/gettext.php new file mode 100644 index 0000000..78e8bff --- /dev/null +++ b/examples/includes/geshi/geshi/gettext.php @@ -0,0 +1,97 @@ + 'GNU Gettext', + 'COMMENT_SINGLE' => array('#:', '#.', '#,', '#|', '#'), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array('msgctxt', 'msgid_plural', 'msgid', 'msgstr'), + ), + 'SYMBOLS' => array(), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;' + ), + 'COMMENTS' => array( + 0 => 'color: #000099;', + 1 => 'color: #000099;', + 2 => 'color: #000099;', + 3 => 'color: #006666;', + 4 => 'color: #666666; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'REGEXPS' => array(), + 'SYMBOLS' => array(), + 'NUMBERS' => array( + 0 => 'color: #000099;' + ), + 'METHODS' => array(), + 'SCRIPT' => array(), + 'BRACKETS' => array( + 0 => 'color: #000099;' + ), + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array(), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, +); + +?> diff --git a/examples/includes/geshi/geshi/glsl.php b/examples/includes/geshi/geshi/glsl.php new file mode 100644 index 0000000..1f10cf8 --- /dev/null +++ b/examples/includes/geshi/geshi/glsl.php @@ -0,0 +1,205 @@ + 'glSlang', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Multiline-continued single-line comments + 1 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m', + //Multiline-continued preprocessor define + 2 => '/#(?:\\\\\\\\|\\\\\\n|.)*$/m' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'if', 'else', 'for', 'while', 'do', 'break', 'continue', 'asm', + 'switch', 'case', 'default', 'return', 'discard', + 'namespace', 'using', 'sizeof', 'cast' + ), + 2 => array( + 'const', 'uniform', 'attribute', 'centroid', 'varying', 'invariant', + 'in', 'out', 'inout', 'input', 'output', 'typedef', 'volatile', + 'public', 'static', 'extern', 'external', 'packed', + 'inline', 'noinline', 'noperspective', 'flat' + ), + 3 => array( + 'void', 'bool', 'int', 'long', 'short', 'float', 'half', 'fixed', + 'unsigned', 'lowp', 'mediump', 'highp', 'precision', + 'vec2', 'vec3', 'vec4', 'bvec2', 'bvec3', 'bvec4', + 'dvec2', 'dvec3', 'dvec4', 'fvec2', 'fvec3', 'fvec4', + 'hvec2', 'hvec3', 'hvec4', 'ivec2', 'ivec3', 'ivec4', + 'mat2', 'mat3', 'mat4', 'mat2x2', 'mat3x2', 'mat4x2', + 'mat2x3', 'mat3x3', 'mat4x3', 'mat2x4', 'mat3x4', 'mat4x4', + 'sampler1D', 'sampler2D', 'sampler3D', 'samplerCube', + 'sampler1DShadow', 'sampler2DShadow', + 'struct', 'class', 'union', 'enum', 'interface', 'template' + ), + 4 => array( + 'this', 'false', 'true' + ), + 5 => array( + 'radians', 'degrees', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', + 'pow', 'exp2', 'log2', 'sqrt', 'inversesqrt', 'abs', 'sign', 'ceil', + 'floor', 'fract', 'mod', 'min', 'max', 'clamp', 'mix', 'step', + 'smoothstep', 'length', 'distance', 'dot', 'cross', 'normalize', + 'ftransform', 'faceforward', 'reflect', 'matrixCompMult', 'equal', + 'lessThan', 'lessThanEqual', 'greaterThan', 'greaterThanEqual', + 'notEqual', 'any', 'all', 'not', 'texture1D', 'texture1DProj', + 'texture1DLod', 'texture1DProjLod', 'texture2D', 'texture2DProj', + 'texture2DLod', 'texture2DProjLod', 'texture3D', 'texture3DProj', + 'texture3DLod', 'texture3DProjLod', 'textureCube', 'textureCubeLod', + 'shadow1D', 'shadow1DProj', 'shadow1DLod', 'shadow1DProjLod', + 'shadow2D', 'shadow2DProj', 'shadow2DLod', 'shadow2DProjLod', + 'noise1', 'noise2', 'noise3', 'noise4' + ), + 6 => array( + 'gl_Position', 'gl_PointSize', 'gl_ClipVertex', 'gl_FragColor', + 'gl_FragData', 'gl_FragDepth', 'gl_FragCoord', 'gl_FrontFacing', + 'gl_Color', 'gl_SecondaryColor', 'gl_Normal', 'gl_Vertex', + 'gl_MultiTexCoord0', 'gl_MultiTexCoord1', 'gl_MultiTexCoord2', + 'gl_MultiTexCoord3', 'gl_MultiTexCoord4', 'gl_MultiTexCoord5', + 'gl_MultiTexCoord6', 'gl_MultiTexCoord7', 'gl_FogCoord', + 'gl_MaxLights', 'gl_MaxClipPlanes', 'gl_MaxTextureUnits', + 'gl_MaxTextureCoords', 'gl_MaxVertexAttribs', 'gl_MaxVaryingFloats', + 'gl_MaxVertexUniformComponents', 'gl_MaxVertexTextureImageUnits', + 'gl_MaxCombinedTextureImageUnits', 'gl_MaxTextureImageUnits', + 'gl_MaxFragmentUniformComponents', 'gl_MaxDrawBuffers', 'gl_Point', + 'gl_ModelViewMatrix', 'gl_ProjectionMatrix', 'gl_FrontMaterial', + 'gl_ModelViewProjectionMatrix', 'gl_TextureMatrix', 'gl_ClipPlane', + 'gl_NormalMatrix', 'gl_ModelViewMatrixInverse', 'gl_BackMaterial', + 'gl_ProjectionMatrixInverse', 'gl_ModelViewProjectionMatrixInverse', + 'gl_TextureMatrixInverse', 'gl_ModelViewMatrixTranspose', 'gl_Fog', + 'gl_ProjectionMatrixTranspose', 'gl_NormalScale', 'gl_DepthRange', + 'gl_odelViewProjectionMatrixTranspose', 'gl_TextureMatrixTranspose', + 'gl_ModelViewMatrixInverseTranspose', 'gl_LightSource', + 'gl_ProjectionMatrixInverseTranspose', 'gl_LightModel', + 'gl_ModelViewProjectionMatrixInverseTranspose', 'gl_TexCoord', + 'gl_TextureMatrixInverseTranspose', 'gl_TextureEnvColor', + 'gl_FrontLightModelProduct', 'gl_BackLightModelProduct', + 'gl_FrontLightProduct', 'gl_BackLightProduct', 'gl_ObjectPlaneS', + 'gl_ObjectPlaneT', 'gl_ObjectPlaneR', 'gl_ObjectPlaneQ', + 'gl_EyePlaneS', 'gl_EyePlaneT', 'gl_EyePlaneR', 'gl_EyePlaneQ', + 'gl_FrontColor', 'gl_BackColor', 'gl_FrontSecondaryColor', + 'gl_BackSecondaryColor', 'gl_FogFragCoord', 'gl_PointCoord' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', + '&', '?', ':', '.', '|', ';', ',', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #333399; font-weight: bold;', + 3 => 'color: #000066; font-weight: bold;', + 4 => 'color: #333399; font-weight: bold;', + 5 => 'color: #993333; font-weight: bold;', + 6 => 'color: #551111;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #009900;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000066;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000ff;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'OOLANG' => array( + 'MATCH_BEFORE' => '', + 'MATCH_AFTER' => '[a-zA-Z_][a-zA-Z0-9_]*', + 'MATCH_SPACES' => '[\s]*' + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/gml.php b/examples/includes/geshi/geshi/gml.php new file mode 100644 index 0000000..77966bc --- /dev/null +++ b/examples/includes/geshi/geshi/gml.php @@ -0,0 +1,506 @@ +5 and KEYWORDS=>6 sections (actually, they were empty). + * I was planning of using those for the GML functions available only in the + * registered version of the program, but not anymore. + * + * 2005/06/26 (1.0.3) + * - First Release. + * + * TODO (updated 2005/11/11) + * ------------------------- + * - Test it for a while and make the appropiate corrections. + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'GML', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'"), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + // language keywords + 1 => array( + 'break', 'continue', 'do', 'until', 'if', 'else', + 'exit', 'for', 'repeat', 'return', 'switch', + 'case', 'default', 'var', 'while', 'with', 'div', 'mod', + // GML Language overview + 'self', 'other', 'all', 'noone', 'global', + ), + // modifiers and built-in variables + 2 => array( + // Game play + 'x','y','xprevious','yprevious','xstart','ystart','hspeed','vspeed','direction','speed', + 'friction','gravity','gravity_direction', + 'path_index','path_position','path_positionprevious','path_speed','path_orientation', + 'path_endaction', + 'object_index','id','mask_index','solid','persistent','instance_count','instance_id', + 'room_speed','fps','current_time','current_year','current_month','current_day','current_weekday', + 'current_hour','current_minute','current_second','alarm','timeline_index','timeline_position', + 'timeline_speed', + 'room','room_first','room_last','room_width','room_height','room_caption','room_persistent', + 'score','lives','health','show_score','show_lives','show_health','caption_score','caption_lives', + 'caption_health', + 'event_type','event_number','event_object','event_action', + 'error_occurred','error_last', + // User interaction + 'keyboard_lastkey','keyboard_key','keyboard_lastchar','keyboard_string', + 'mouse_x','mouse_y','mouse_button','mouse_lastbutton', + // Game Graphics + 'sprite_index','sprite_width','sprite_height','sprite_xoffset','sprite_yoffset', + 'image_number','image_index','image_speed','image_xscale','image_yscale','image_angle', + 'image_alpha','image_blend','bbox_left','bbox_right','bbox_top','bbox_bottom', + 'background_color','background_showcolor','background_visible','background_foreground', + 'background_index','background_x','background_y','background_width','background_height', + 'background_htiled','background_vtiled','background_xscale','background_yscale', + 'background_hspeed','background_vspeed','background_blend','background_alpha', + 'background','left, top, width, height','depth','visible','xscale','yscale','blend','alpha', + 'view_enabled','view_current','view_visible','view_yview','view_wview','view_hview','view_xport', + 'view_yport','view_wport','view_hport','view_angle','view_hborder','view_vborder','view_hspeed', + 'view_vspeed','view_object', + 'transition_kind', + // Files, registry and executing programs + 'game_id','working_directory','temp_directory', + 'secure_mode', + // Creating particles + 'xmin', 'xmax', 'ymin', 'ymax','shape','distribution','particle type','number', + 'force','dist','kind','additive', 'parttype1', 'parttype2' + ), + // functions + 3 => array( + // Computing things + 'random','choose','abs','sign','round','floor','ceil','frac','sqrt','sqr','power','exp','ln', + 'log2','log10','logn','sin','cos','tan','arcsin','arccos','arctan','arctan2','degtorad', + 'radtodeg','min','max','mean','median','point_distance','point_direction','lengthdir_x', + 'lengthdir_y','is_real','is_string', + 'chr','ord','real','string','string_format','string_length','string_pos','string_copy', + 'string_char_at','string_delete','string_insert','string_replace','string_replace_all', + 'string_count','string_lower','string_upper','string_repeat','string_letters','string_digits', + 'string_lettersdigits','clipboard_has_text','clipboard_get_text','clipboard_set_text', + 'date_current_datetime','date_current_date','date_current_time','date_create_datetime', + 'date_create_date','date_create_time','date_valid_datetime','date_valid_date','date_valid_time', + 'date_inc_year','date_inc_month','date_inc_week','date_inc_day','date_inc_hour', + 'date_inc_minute','date_inc_second','date_get_year','date_get_month','date_get_week', + 'date_get_day','date_get_hour', 'date_get_minute','date_get_second','date_get_weekday', + 'date_get_day_of_year','date_get_hour_of_year','date_get_minute_of_year', + 'date_get_second_of_year','date_year_span','date_month_span','date_week_span','date_day_span', + 'date_hour_span','date_minute_span','date_second_span','date_compare_datetime', + 'date_compare_date','date_compare_time','date_date_of','date_time_of','date_datetime_string', + 'date_date_string','date_time_string','date_days_in_month','date_days_in_year','date_leap_year', + 'date_is_today', + // Game play + 'motion_set','motion_add','place_free','place_empty','place_meeting','place_snapped', + 'move_random','move_snap','move_wrap','move_towards_point','move_bounce_solid','move_bounce_all', + 'move_contact_solid','move_contact_all','move_outside_solid','move_outside_all', + 'distance_to_point','distance_to_object','position_empty','position_meeting', + 'path_start','path_end', + 'mp_linear_step','mp_linear_step_object','mp_potential_step','mp_potential_step_object', + 'mp_potential_settings','mp_linear_path','mp_linear_path_object', 'mp_potential_path', + 'mp_potential_path_object','mp_grid_create','mp_grid_destroy','mp_grid_clear_all', + 'mp_grid_clear_cell','mp_grid_clear_rectangle','mp_grid_add_cell','mp_grid_add_rectangle', + 'mp_grid_add_instances','mp_grid_path','mp_grid_draw', + 'collision_point','collision_rectangle','collision_circle','collision_ellipse','collision_line', + 'instance_find','instance_exists','instance_number','instance_position','instance_nearest', + 'instance_furthest','instance_place','instance_create','instance_copy','instance_destroy', + 'instance_change','position_destroy','position_change', + 'instance_deactivate_all','instance_deactivate_object','instance_deactivate_region', + 'instance_activate_all','instance_activate_object','instance_activate_region', + 'sleep', + 'room_goto','room_goto_previous','room_goto_next','room_restart','room_previous','room_next', + 'game_end','game_restart','game_save','game_load', + 'event_perform', 'event_perform_object','event_user','event_inherited', + 'show_debug_message','variable_global_exists','variable_local_exists','variable_global_get', + 'variable_global_array_get','variable_global_array2_get','variable_local_get', + 'variable_local_array_get','variable_local_array2_get','variable_global_set', + 'variable_global_array_set','variable_global_array2_set','variable_local_set', + 'variable_local_array_set','variable_local_array2_set','set_program_priority', + // User interaction + 'keyboard_set_map','keyboard_get_map','keyboard_unset_map','keyboard_check', + 'keyboard_check_pressed','keyboard_check_released','keyboard_check_direct', + 'keyboard_get_numlock','keyboard_set_numlock','keyboard_key_press','keyboard_key_release', + 'keyboard_clear','io_clear','io_handle','keyboard_wait', + 'mouse_check_button','mouse_check_button_pressed','mouse_check_button_released','mouse_clear', + 'mouse_wait', + 'joystick_exists','joystick_name','joystick_axes','joystick_buttons','joystick_has_pov', + 'joystick_direction','joystick_check_button','joystick_xpos','joystick_ypos','joystick_zpos', + 'joystick_rpos','joystick_upos','joystick_vpos','joystick_pov', + // Game Graphics + 'draw_sprite','draw_sprite_stretched','draw_sprite_tiled','draw_sprite_part','draw_background', + 'draw_background_stretched','draw_background_tiled','draw_background_part','draw_sprite_ext', + 'draw_sprite_stretched_ext','draw_sprite_tiled_ext','draw_sprite_part_ext','draw_sprite_general', + 'draw_background_ext','draw_background_stretched_ext','draw_background_tiled_ext', + 'draw_background_part_ext','draw_background_general', + 'draw_clear','draw_clear_alpha','draw_point','draw_line','draw_rectangle','draw_roundrect', + 'draw_triangle','draw_circle','draw_ellipse','draw_arrow','draw_button','draw_path', + 'draw_healthbar','draw_set_color','draw_set_alpha','draw_get_color','draw_get_alpha', + 'make_color_rgb','make_color_hsv','color_get_red','color_get_green','color_get_blue', + 'color_get_hue','color_get_saturation','color_get_value','merge_color','draw_getpixel', + 'screen_save','screen_save_part', + 'draw_set_font','draw_set_halign','draw_set_valign','draw_text','draw_text_ext','string_width', + 'string_height','string_width_ext','string_height_ext','draw_text_transformed', + 'draw_text_ext_transformed','draw_text_color','draw_text_ext_color', + 'draw_text_transformed_color','draw_text_ext_transformed_color', + 'draw_point_color','draw_line_color','draw_rectangle_color','draw_roundrect_color', + 'draw_triangle_color','draw_circle_color','draw_ellipse_color','draw_primitive_begin', + 'draw_vertex','draw_vertex_color','draw_primitive_end','sprite_get_texture', + 'background_get_texture','texture_preload','texture_set_priority', + 'texture_get_width','texture_get_height','draw_primitive_begin_texture','draw_vertex_texture', + 'draw_vertex_texture_color','texture_set_interpolation', + 'texture_set_blending','texture_set_repeat','draw_set_blend_mode','draw_set_blend_mode_ext', + 'surface_create','surface_free','surface_exists','surface_get_width','surface_get_height', + 'surface_get_texture','surface_set_target','surface_reset_target','surface_getpixel', + 'surface_save','surface_save_part','draw_surface','draw_surface_stretched','draw_surface_tiled', + 'draw_surface_part','draw_surface_ext','draw_surface_stretched_ext','draw_surface_tiled_ext', + 'draw_surface_part_ext','draw_surface_general','surface_copy','surface_copy_part', + 'tile_add','tile_delete','tile_exists','tile_get_x','tile_get_y','tile_get_left','tile_get_top', + 'tile_get_width','tile_get_height','tile_get_depth','tile_get_visible','tile_get_xscale', + 'tile_get_yscale','tile_get_background','tile_get_blend','tile_get_alpha','tile_set_position', + 'tile_set_region','tile_set_background','tile_set_visible','tile_set_depth','tile_set_scale', + 'tile_set_blend','tile_set_alpha','tile_layer_hide','tile_layer_show','tile_layer_delete', + 'tile_layer_shift','tile_layer_find','tile_layer_delete_at','tile_layer_depth', + 'display_get_width','display_get_height','display_get_colordepth','display_get_frequency', + 'display_set_size','display_set_colordepth','display_set_frequency','display_set_all', + 'display_test_all','display_reset','display_mouse_get_x','display_mouse_get_y','display_mouse_set', + 'window_set_visible','window_get_visible','window_set_fullscreen','window_get_fullscreen', + 'window_set_showborder','window_get_showborder','window_set_showicons','window_get_showicons', + 'window_set_stayontop','window_get_stayontop','window_set_sizeable','window_get_sizeable', + 'window_set_caption','window_get_caption','window_set_cursor', 'window_get_cursor', + 'window_set_color','window_get_color','window_set_region_scale','window_get_region_scale', + 'window_set_position','window_set_size','window_set_rectangle','window_center','window_default', + 'window_get_x','window_get_y','window_get_width','window_get_height','window_mouse_get_x', + 'window_mouse_get_y','window_mouse_set', + 'window_set_region_size','window_get_region_width','window_get_region_height', + 'window_view_mouse_get_x','window_view_mouse_get_y','window_view_mouse_set', + 'window_views_mouse_get_x','window_views_mouse_get_y','window_views_mouse_set', + 'screen_redraw','screen_refresh','set_automatic_draw','set_synchronization','screen_wait_vsync', + // Sound and music) + 'sound_play','sound_loop','sound_stop','sound_stop_all','sound_isplaying','sound_volume', + 'sound_global_volume','sound_fade','sound_pan','sound_background_tempo','sound_set_search_directory', + 'sound_effect_set','sound_effect_chorus','sound_effect_echo', 'sound_effect_flanger', + 'sound_effect_gargle','sound_effect_reverb','sound_effect_compressor','sound_effect_equalizer', + 'sound_3d_set_sound_position','sound_3d_set_sound_velocity','sound_3d_set_sound_distance', + 'sound_3d_set_sound_cone', + 'cd_init','cd_present','cd_number','cd_playing','cd_paused','cd_track','cd_length', + 'cd_track_length','cd_position','cd_track_position','cd_play','cd_stop','cd_pause','cd_resume', + 'cd_set_position','cd_set_track_position','cd_open_door','cd_close_door','MCI_command', + // Splash screens, highscores, and other pop-ups + 'show_text','show_image','show_video','show_info','load_info', + 'show_message','show_message_ext','show_question','get_integer','get_string', + 'message_background','message_alpha','message_button','message_text_font','message_button_font', + 'message_input_font','message_mouse_color','message_input_color','message_caption', + 'message_position','message_size','show_menu','show_menu_pos','get_color','get_open_filename', + 'get_save_filename','get_directory','get_directory_alt','show_error', + 'highscore_show','highscore_set_background','highscore_set_border','highscore_set_font', + 'highscore_set_colors','highscore_set_strings','highscore_show_ext','highscore_clear', + 'highscore_add','highscore_add_current','highscore_value','highscore_name','draw_highscore', + // Resources + 'sprite_exists','sprite_get_name','sprite_get_number','sprite_get_width','sprite_get_height', + 'sprite_get_transparent','sprite_get_smooth','sprite_get_preload','sprite_get_xoffset', + 'sprite_get_yoffset','sprite_get_bbox_left','sprite_get_bbox_right','sprite_get_bbox_top', + 'sprite_get_bbox_bottom','sprite_get_bbox_mode','sprite_get_precise', + 'sound_exists','sound_get_name','sound_get_kind','sound_get_preload','sound_discard', + 'sound_restore', + 'background_exists','background_get_name','background_get_width','background_get_height', + 'background_get_transparent','background_get_smooth','background_get_preload', + 'font_exists','font_get_name','font_get_fontname','font_get_bold','font_get_italic', + 'font_get_first','font_get_last', + 'path_exists','path_get_name','path_get_length','path_get_kind','path_get_closed', + 'path_get_precision','path_get_number','path_get_point_x','path_get_point_y', + 'path_get_point_speed','path_get_x','path_get_y','path_get_speed', + 'script_exists','script_get_name','script_get_text', + 'timeline_exists','timeline_get_name', + 'object_exists','object_get_name','object_get_sprite','object_get_solid','object_get_visible', + 'object_get_depth','object_get_persistent','object_get_mask','object_get_parent', + 'object_is_ancestor', + 'room_exists','room_get_name', + // Changing resources + 'sprite_set_offset','sprite_set_bbox_mode','sprite_set_bbox','sprite_set_precise', + 'sprite_duplicate','sprite_assign','sprite_merge','sprite_add','sprite_replace', + 'sprite_create_from_screen','sprite_add_from_screen','sprite_create_from_surface', + 'sprite_add_from_surface','sprite_delete','sprite_set_alpha_from_sprite', + 'sound_add','sound_replace','sound_delete', + 'background_duplicate','background_assign','background_add','background_replace', + 'background_create_color','background_create_gradient','background_create_from_screen', + 'background_create_from_surface','background_delete','background_set_alpha_from_background', + 'font_add','font_add_sprite','font_replace_sprite','font_delete', + 'path_set_kind','path_set_closed','path_set_precision','path_add','path_delete','path_duplicate', + 'path_assign','path_append','path_add_point','path_insert_point','path_change_point', + 'path_delete_point','path_clear_points','path_reverse','path_mirror','path_flip','path_rotate', + 'path_scale','path_shift', + 'execute_string','execute_file','script_execute', + 'timeline_add','timeline_delete','timeline_moment_add','timeline_moment_clear', + 'object_set_sprite','object_set_solid','object_set_visible','object_set_depth', + 'object_set_persistent','object_set_mask','object_set_parent','object_add','object_delete', + 'object_event_add','object_event_clear', + 'room_set_width','room_set_height','room_set_caption','room_set_persistent','room_set_code', + 'room_set_background_color','room_set_background','room_set_view','room_set_view_enabled', + 'room_add','room_duplicate','room_assign','room_instance_add','room_instance_clear', + 'room_tile_add','room_tile_add_ext','room_tile_clear', + // Files, registry and executing programs + 'file_text_open_read','file_text_open_write','file_text_open_append','file_text_close', + 'file_text_write_string','file_text_write_real','file_text_writeln','file_text_read_string', + 'file_text_read_real','file_text_readln','file_text_eof','file_exists','file_delete', + 'file_rename','file_copy','directory_exists','directory_create','file_find_first', + 'file_find_next','file_find_close','file_attributes', 'filename_name','filename_path', + 'filename_dir','filename_drive','filename_ext','filename_change_ext','file_bin_open', + 'file_bin_rewrite','file_bin_close','file_bin_size','file_bin_position','file_bin_seek', + 'file_bin_write_byte','file_bin_read_byte','parameter_count','parameter_string', + 'environment_get_variable', + 'registry_write_string','registry_write_real','registry_read_string','registry_read_real', + 'registry_exists','registry_write_string_ext','registry_write_real_ext', + 'registry_read_string_ext','registry_read_real_ext','registry_exists_ext','registry_set_root', + 'ini_open','ini_close','ini_read_string','ini_read_real','ini_write_string','ini_write_real', + 'ini_key_exists','ini_section_exists','ini_key_delete','ini_section_delete', + 'execute_program','execute_shell', + // Data structures + 'ds_stack_create','ds_stack_destroy','ds_stack_clear','ds_stack_size','ds_stack_empty', + 'ds_stack_push','ds_stack_pop','ds_stack_top', + 'ds_queue_create','ds_queue_destroy','ds_queue_clear','ds_queue_size','ds_queue_empty', + 'ds_queue_enqueue','ds_queue_dequeue','ds_queue_head','ds_queue_tail', + 'ds_list_create','ds_list_destroy','ds_list_clear','ds_list_size','ds_list_empty','ds_list_add', + 'ds_list_insert','ds_list_replace','ds_list_delete','ds_list_find_index','ds_list_find_value', + 'ds_list_sort', + 'ds_map_create','ds_map_destroy','ds_map_clear','ds_map_size','ds_map_empty','ds_map_add', + 'ds_map_replace','ds_map_delete','ds_map_exists','ds_map_find_value','ds_map_find_previous', + 'ds_map_find_next','ds_map_find_first','ds_map_find_last', + 'ds_priority_create','ds_priority_destroy','ds_priority_clear','ds_priority_size', + 'ds_priority_empty','ds_priority_add','ds_priority_change_priority','ds_priority_find_priority', + 'ds_priority_delete_value','ds_priority_delete_min','ds_priority_find_min', + 'ds_priority_delete_max','ds_priority_find_max', + 'ds_grid_create','ds_grid_destroy','ds_grid_resize','ds_grid_width','ds_grid_height', + 'ds_grid_clear','ds_grid_set','ds_grid_add','ds_grid_multiply','ds_grid_set_region', + 'ds_grid_add_region','ds_grid_multiply_region','ds_grid_set_disk','ds_grid_add_disk', + 'ds_grid_multiply_disk','ds_grid_get','ds_grid_get_sum','ds_grid_get_max','ds_grid_get_min', + 'ds_grid_get_mean','ds_grid_get_disk_sum','ds_grid_get_disk_min','ds_grid_get_disk_max', + 'ds_grid_get_disk_mean','ds_grid_value_exists','ds_grid_value_x','ds_grid_value_y', + 'ds_grid_value_disk_exists','ds_grid_value_disk_x','ds_grid_value_disk_y', + // Creating particles + 'effect_create_below','effect_create_above','effect_clear', + 'part_type_create','part_type_destroy','part_type_exists','part_type_clear','part_type_shape', + 'part_type_sprite','part_type_size','part_type_scale', + 'part_type_orientation','part_type_color1','part_type_color2','part_type_color3', + 'part_type_color_mix','part_type_color_rgb','part_type_color_hsv', + 'part_type_alpha1','part_type_alpha2','part_type_alpha3','part_type_blend','part_type_life', + 'part_type_step','part_type_death','part_type_speed','part_type_direction','part_type_gravity', + 'part_system_create','part_system_destroy','part_system_exists','part_system_clear', + 'part_system_draw_order','part_system_depth','part_system_position', + 'part_system_automatic_update','part_system_automatic_draw','part_system_update', + 'part_system_drawit','part_particles_create','part_particles_create_color', + 'part_particles_clear','part_particles_count', + 'part_emitter_create','part_emitter_destroy','part_emitter_destroy_all','part_emitter_exists', + 'part_emitter_clear','part_emitter_region','part_emitter_burst','part_emitter_stream', + 'part_attractor_create','part_attractor_destroy','part_attractor_destroy_all', + 'part_attractor_exists','part_attractor_clear','part_attractor_position','part_attractor_force', + 'part_destroyer_create','part_destroyer_destroy','part_destroyer_destroy_all', + 'part_destroyer_exists','part_destroyer_clear','part_destroyer_region', + 'part_deflector_create','part_deflector_destroy','part_deflector_destroy_all', + 'part_deflector_exists','part_deflector_clear','part_deflector_region','part_deflector_kind', + 'part_deflector_friction', + 'part_changer_create','part_changer_destroy','part_changer_destroy_all','part_changer_exists', + 'part_changer_clear','part_changer_region','part_changer_types','part_changer_kind', + // Multiplayer games + 'mplay_init_ipx','mplay_init_tcpip','mplay_init_modem','mplay_init_serial', + 'mplay_connect_status','mplay_end','mplay_ipaddress', + 'mplay_session_create','mplay_session_find','mplay_session_name','mplay_session_join', + 'mplay_session_mode','mplay_session_status','mplay_session_end', + 'mplay_player_find','mplay_player_name','mplay_player_id', + 'mplay_data_write','mplay_data_read','mplay_data_mode', + 'mplay_message_send','mplay_message_send_guaranteed','mplay_message_receive','mplay_message_id', + 'mplay_message_value','mplay_message_player','mplay_message_name','mplay_message_count', + 'mplay_message_clear', + // Using DLL's + 'external_define','external_call','external_free','window_handle', + // 3D Graphics + 'd3d_start','d3d_end','d3d_set_hidden','d3d_set_perspective', + 'd3d_set_depth', + 'd3d_primitive_begin','d3d_vertex','d3d_vertex_color','d3d_primitive_end', + 'd3d_primitive_begin_texture','d3d_vertex_texture','d3d_vertex_texture_color','d3d_set_culling', + 'd3d_draw_block','d3d_draw_cylinder','d3d_draw_cone','d3d_draw_ellipsoid','d3d_draw_wall', + 'd3d_draw_floor', + 'd3d_set_projection','d3d_set_projection_ext','d3d_set_projection_ortho', + 'd3d_set_projection_perspective', + 'd3d_transform_set_identity','d3d_transform_set_translation','d3d_transform_set_scaling', + 'd3d_transform_set_rotation_x','d3d_transform_set_rotation_y','d3d_transform_set_rotation_z', + 'd3d_transform_set_rotation_axis','d3d_transform_add_translation','d3d_transform_add_scaling', + 'd3d_transform_add_rotation_x','d3d_transform_add_rotation_y','d3d_transform_add_rotation_z', + 'd3d_transform_add_rotation_axis','d3d_transform_stack_clear','d3d_transform_stack_empty', + 'd3d_transform_stack_push','d3d_transform_stack_pop','d3d_transform_stack_top', + 'd3d_transform_stack_discard', + 'd3d_set_fog', + 'd3d_set_lighting','d3d_set_shading','d3d_light_define_direction','d3d_light_define_point', + 'd3d_light_enable','d3d_vertex_normal','d3d_vertex_normal_color','d3d_vertex_normal_texture', + 'd3d_vertex_normal_texture_color', + 'd3d_model_create','d3d_model_destroy','d3d_model_clear','d3d_model_save','d3d_model_load', + 'd3d_model_draw','d3d_model_primitive_begin','d3d_model_vertex','d3d_model_vertex_color', + 'd3d_model_vertex_texture','d3d_model_vertex_texture_color','d3d_model_vertex_normal', + 'd3d_model_vertex_normal_color','d3d_model_vertex_normal_texture', + 'd3d_model_vertex_normal_texture_color','d3d_model_primitive_end','d3d_model_block', + 'd3d_model_cylinder','d3d_model_cone','d3d_model_ellipsoid','d3d_model_wall','d3d_model_floor' + ), + // constants + 4 => array( + 'true', 'false', 'pi', + 'ev_destroy','ev_step','ev_alarm','ev_keyboard','ev_mouse','ev_collision','ev_other','ev_draw', + 'ev_keypress','ev_keyrelease','ev_left_button','ev_right_button','ev_middle_button', + 'ev_no_button','ev_left_press','ev_right_press','ev_middle_press','ev_left_release', + 'ev_right_release','ev_middle_release','ev_mouse_enter','ev_mouse_leave','ev_mouse_wheel_up', + 'ev_mouse_wheel_down','ev_global_left_button','ev_global_right_button','ev_global_middle_button', + 'ev_global_left_press','ev_global_right_press','ev_global_middle_press','ev_global_left_release', + 'ev_global_right_release','ev_global_middle_release','ev_joystick1_left','ev_joystick1_right', + 'ev_joystick1_up','ev_joystick1_down','ev_joystick1_button1','ev_joystick1_button2', + 'ev_joystick1_button3','ev_joystick1_button4','ev_joystick1_button5','ev_joystick1_button6', + 'ev_joystick1_button7','ev_joystick1_button8','ev_joystick2_left','ev_joystick2_right', + 'ev_joystick2_up','ev_joystick2_down','ev_joystick2_button1','ev_joystick2_button2', + 'ev_joystick2_button3','ev_joystick2_button4','ev_joystick2_button5','ev_joystick2_button6', + 'ev_joystick2_button7','ev_joystick2_button8', + 'ev_outside','ev_boundary','ev_game_start','ev_game_end','ev_room_start','ev_room_end', + 'ev_no_more_lives','ev_no_more_health','ev_animation_end','ev_end_of_path','ev_user0','ev_user1', + 'ev_user2','ev_user3','ev_user4','ev_user5','ev_user6','ev_user7','ev_user8','ev_user9', + 'ev_user10','ev_user11','ev_user12','ev_user13','ev_user14','ev_user15','ev_step_normal', + 'ev_step_begin','ev_step_end', + 'vk_nokey','vk_anykey','vk_left','vk_right','vk_up','vk_down','vk_enter','vk_escape','vk_space', + 'vk_shift','vk_control','vk_alt','vk_backspace','vk_tab','vk_home','vk_end','vk_delete', + 'vk_insert','vk_pageup','vk_pagedown','vk_pause','vk_printscreen', + 'vk_f1','vk_f2','vk_f3','vk_f4','vk_f5','vk_f6','vk_f7','vk_f8','vk_f9','vk_f10','vk_f11','vk_f12', + 'vk_numpad0','vk_numpad1','vk_numpad2','vk_numpad3','vk_numpad4','vk_numpad5','vk_numpad6', + 'vk_numpad7','vk_numpad8','vk_numpad9', 'vk_multiply','vk_divide','vk_add','vk_subtract', + 'vk_decimal','vk_lshift','vk_lcontrol','vk_lalt','vk_rshift','vk_rcontrol','vk_ralt', + 'c_aqua','c_black','c_blue','c_dkgray','c_fuchsia','c_gray','c_green','c_lime','c_ltgray', + 'c_maroon','c_navy','c_olive','c_purple','c_red','c_silver','c_teal','c_white','c_yellow', + 'fa_left', 'fa_center','fa_right','fa_top','fa_middle','fa_bottom', + 'pr_pointlist','pr_linelist','pr_linestrip','pr_trianglelist','pr_trianglestrip', + 'pr_trianglefan', + 'cr_none','cr_arrow','cr_cross','cr_beam','cr_size_nesw','cr_size_ns','cr_size_nwse', + 'cr_size_we','cr_uparrow','cr_hourglass','cr_drag','cr_nodrop','cr_hsplit','cr_vsplit', + 'cr_multidrag','cr_sqlwait','cr_no','cr_appstart','cr_help','cr_handpoint','cr_size_all', + 'se_chorus','se_echo','se_flanger','se_gargle','se_reverb','se_compressor','se_equalizer', + 'fa_readonly','fa_hidden','fa_sysfile','fa_volumeid','fa_directory','fa_archive', + 'pt_shape_pixel','pt_shape_disk','pt_shape_square','pt_shape_line','pt_shape_star', + 'pt_shape_circle','pt_shape_ring','pt_shape_sphere','pt_shape_flare','pt_shape_spark', + 'pt_shape_explosion','pt_shape_cloud','pt_shape_smoke','pt_shape_snow', + 'ps_shape_rectangle','ps_shape_ellipse ','ps_shape_diamond','ps_shape_line', + 'ps_distr_linear','ps_distr_gaussian','ps_force_constant','ps_force_linear','ps_force_quadratic', + 'ps_deflect_horizontal', 'ps_deflect_vertical', + 'ps_change_motion','ps_change_shape','ps_change_all' + ), + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', + '&&', '||', '^^', '&', '|', '^', + '<', '<=', '==', '!=', '>', '>=', '=', + '<<', '>>', + '+=', '-=', '*=', '/=', + '+', '-', '*', '/', + '!', '~', ',', ';' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'font-weight: bold; color: #000000;', + 2 => 'font-weight: bold; color: #000000;', + 3 => 'color: navy;', + 4 => 'color: #663300;', + ), + 'COMMENTS' => array( + 1 => 'font-style: italic; color: green;', + 'MULTI' => 'font-style: italic; color: green;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' //'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66; font-weight: bold;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/gnuplot.php b/examples/includes/geshi/geshi/gnuplot.php new file mode 100644 index 0000000..3b67fb6 --- /dev/null +++ b/examples/includes/geshi/geshi/gnuplot.php @@ -0,0 +1,296 @@ + 'Gnuplot', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('`', '"', "'"), + 'ESCAPE_CHAR' => '\\', + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | + GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_SCI_SHORT | + GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + // copy output of help command, indent properly and use this replace regexp: + // ([a-z0-9_\-]+)(( )+|$) => '\1',\3 + + // commands as found in `help commands` + 1 => array( + 'bind', 'call', 'cd', 'clear', + 'exit', 'fit', 'help', 'history', + 'if', 'load', 'lower', 'pause', + 'plot', 'print', 'pwd', 'quit', + 'raise', 'replot', 'reread', 'reset', + 'save', 'set', 'shell', 'show', + 'splot', 'system', 'test', 'unset', + 'update' + ), + 2 => array( + // set commands as returned by `help set` + 'angles', 'arrow', 'autoscale', 'bars', + 'bmargin', 'border', 'boxwidth', 'cbdata', + 'cbdtics', 'cblabel', 'cbmtics', 'cbrange', + 'cbtics', 'clabel', 'clip', 'cntrparam', + 'colorbox', 'contour', 'datafile', 'date_specifiers', + 'decimalsign', 'dgrid3d', 'dummy', 'encoding', + 'fontpath', 'format', 'grid', + 'hidden3d', 'historysize', 'isosamples', 'key', + 'label', 'lmargin', 'loadpath', 'locale', + 'log', 'logscale', 'macros', 'mapping', + 'margin', 'missing', 'mouse', 'multiplot', + 'mx2tics', 'mxtics', 'my2tics', 'mytics', + 'mztics', 'object', 'offsets', 'origin', + 'output', 'palette', 'parametric', 'pm3d', + 'pointsize', 'polar', 'rmargin', + 'rrange', 'samples', 'size', 'style', + 'surface', 'table', 'term', 'terminal', + 'termoption', 'tics', 'ticscale', 'ticslevel', + 'time_specifiers', 'timefmt', 'timestamp', 'title', + 'trange', 'urange', 'view', + 'vrange', 'x2data', 'x2dtics', 'x2label', + 'x2mtics', 'x2range', 'x2tics', 'x2zeroaxis', + 'xdata', 'xdtics', 'xlabel', 'xmtics', + 'xrange', 'xtics', 'xyplane', 'xzeroaxis', + 'y2data', 'y2dtics', 'y2label', 'y2mtics', + 'y2range', 'y2tics', 'y2zeroaxis', 'ydata', + 'ydtics', 'ylabel', 'ymtics', 'yrange', + 'ytics', 'yzeroaxis', 'zdata', 'zdtics', + 'zero', 'zeroaxis', 'zlabel', 'zmtics', + 'zrange', 'ztics', 'zzeroaxis', + // same but with leading no + 'noangles', 'noarrow', 'noautoscale', 'nobars', + 'nobmargin', 'noborder', 'noboxwidth', 'nocbdata', + 'nocbdtics', 'nocblabel', 'nocbmtics', 'nocbrange', + 'nocbtics', 'noclabel', 'noclip', 'nocntrparam', + 'nocolorbox', 'nocontour', 'nodatafile', 'nodate_specifiers', + 'nodecimalsign', 'nodgrid3d', 'nodummy', 'noencoding', + 'nofit', 'nofontpath', 'noformat', 'nogrid', + 'nohidden3d', 'nohistorysize', 'noisosamples', 'nokey', + 'nolabel', 'nolmargin', 'noloadpath', 'nolocale', + 'nolog', 'nologscale', 'nomacros', 'nomapping', + 'nomargin', 'nomissing', 'nomouse', 'nomultiplot', + 'nomx2tics', 'nomxtics', 'nomy2tics', 'nomytics', + 'nomztics', 'noobject', 'nooffsets', 'noorigin', + 'nooutput', 'nopalette', 'noparametric', 'nopm3d', + 'nopointsize', 'nopolar', 'noprint', 'normargin', + 'norrange', 'nosamples', 'nosize', 'nostyle', + 'nosurface', 'notable', 'noterm', 'noterminal', + 'notermoption', 'notics', 'noticscale', 'noticslevel', + 'notime_specifiers', 'notimefmt', 'notimestamp', 'notitle', + 'notmargin', 'notrange', 'nourange', 'noview', + 'novrange', 'nox2data', 'nox2dtics', 'nox2label', + 'nox2mtics', 'nox2range', 'nox2tics', 'nox2zeroaxis', + 'noxdata', 'noxdtics', 'noxlabel', 'noxmtics', + 'noxrange', 'noxtics', 'noxyplane', 'noxzeroaxis', + 'noy2data', 'noy2dtics', 'noy2label', 'noy2mtics', + 'noy2range', 'noy2tics', 'noy2zeroaxis', 'noydata', + 'noydtics', 'noylabel', 'noymtics', 'noyrange', + 'noytics', 'noyzeroaxis', 'nozdata', 'nozdtics', + 'nozero', 'nozeroaxis', 'nozlabel', 'nozmtics', + 'nozrange', 'noztics', 'nozzeroaxis', + ), + 3 => array( + // predefined variables + 'pi', 'NaN', 'GNUTERM', + 'GPVAL_X_MIN', 'GPVAL_X_MAX', 'GPVAL_Y_MIN', 'GPVAL_Y_MAX', + 'GPVAL_TERM', 'GPVAL_TERMOPTIONS', 'GPVAL_OUTPUT', + 'GPVAL_VERSION', 'GPVAL_PATcHLEVEL', 'GPVAL_COMPILE_OPTIONS', + 'MOUSE_KEY', 'MOUSE_X', 'MOUSE_X2', 'MOUSE_Y', 'MOUSE_Y2', + 'MOUSE_BUTTON', 'MOUSE_SHIFT', 'MOUSE_ALT', 'MOUSE_CTRL' + ), + 4 => array( + // predefined functions `help functions` + 'abs', 'acos', 'acosh', 'arg', + 'asin', 'asinh', 'atan', 'atan2', + 'atanh', 'besj0', 'besj1', 'besy0', + 'besy1', 'ceil', 'column', 'cos', + 'cosh', 'defined', 'erf', 'erfc', + 'exists', 'exp', 'floor', 'gamma', + 'gprintf', 'ibeta', 'igamma', 'imag', + 'int', 'inverf', 'invnorm', 'lambertw', + 'lgamma', 'log10', 'norm', + 'rand', 'random', 'real', 'sgn', + 'sin', 'sinh', 'sprintf', 'sqrt', + 'stringcolumn', 'strlen', 'strstrt', 'substr', + 'tan', 'tanh', 'timecolumn', + 'tm_hour', 'tm_mday', 'tm_min', 'tm_mon', + 'tm_sec', 'tm_wday', 'tm_yday', 'tm_year', + 'valid', 'word', 'words', + ), + 5 => array( + // mixed arguments + // there is no sane way to get these ones easily... + 'autofreq', 'x', 'y', 'z', + 'lt', 'linetype', 'lw', 'linewidth', 'ls', 'linestyle', + 'out', 'rotate by', 'screen', + 'enhanced', 'via', + // `help set key` + 'on', 'off', 'default', 'inside', 'outside', 'tmargin', + 'at', 'left', 'right', 'center', 'top', 'bottom', 'vertical', 'horizontal', 'Left', 'Right', + 'noreverse', 'reverse', 'noinvert', 'invert', 'samplen', 'spacing', 'width', 'height', + 'noautotitle', 'autotitle', 'noenhanced', 'nobox', 'box', + + // help set terminal postscript + 'landscape', 'portrait', 'eps', 'defaultplex', 'simplex', 'duplex', + 'fontfile', 'add', 'delete', 'nofontfiles', 'level1', 'leveldefault', + 'color', 'colour', 'monochrome', 'solid', 'dashed', 'dashlength', 'dl', + 'rounded', 'butt', 'palfuncparam', 'blacktext', 'colortext', 'colourtext', + 'font', + + // help set terminal png + 'notransparent', 'transparent', 'nointerlace', 'interlace', + 'notruecolor', 'truecolor', 'tiny', 'small', 'medium', 'large', 'giant', + 'nocrop', 'crop', + + // `help plot` + 'acsplines', 'bezier', 'binary', 'csplines', + 'every', + 'example', 'frequency', 'index', 'matrix', + 'ranges', 'sbezier', 'smooth', + 'special-filenames', 'thru', + 'unique', 'using', 'with', + + // `help plotting styles` + 'boxerrorbars', 'boxes', 'boxxyerrorbars', 'candlesticks', + 'dots', 'errorbars', 'errorlines', 'filledcurves', + 'financebars', 'fsteps', 'histeps', 'histograms', + 'image', 'impulses', 'labels', 'lines', + 'linespoints', 'points', 'rgbimage', 'steps', + 'vectors', 'xerrorbars', 'xerrorlines', 'xyerrorbars', + 'xyerrorlines', 'yerrorbars', 'yerrorlines', + + + // terminals `help terminals` + 'aed512', 'aed767', 'aifm', 'bitgraph', + 'cgm', 'corel', 'dumb', 'dxf', + 'eepic', 'emf', 'emtex', 'epslatex', + 'epson-180dpi', 'epson-60dpi', 'epson-lx800', 'fig', + 'gif', 'gpic', 'hp2623a', 'hp2648', + 'hp500c', 'hpdj', 'hpgl', 'hpljii', + 'hppj', 'imagen', 'jpeg', 'kc-tek40xx', + 'km-tek40xx', 'latex', 'mf', 'mif', + 'mp', 'nec-cp6', 'okidata', 'pbm', + 'pcl5', 'png', 'pop', 'postscript', + 'pslatex', 'pstex', 'pstricks', 'push', + 'qms', 'regis', 'selanar', 'starc', + 'svg', 'tandy-60dpi', 'tek40xx', 'tek410x', + 'texdraw', 'tgif', 'tkcanvas', 'tpic', + 'vttek', 'x11', 'xlib', + ) + ), + 'REGEXPS' => array( + //Variable assignment + 0 => "([a-zA-Z_][a-zA-Z0-9_]*)\s*=", + //Numbers with unit + 1 => "(?<=^|\s)([0-9]*\.?[0-9]+\s*cm)" + ), + 'SYMBOLS' => array( + '-', '+', '~', '!', '$', + '*', '/', '%', '=', '<', '>', '&', + '^', '|', '.', 'eq', 'ne', '?:', ':', '`', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #990000;', + 3 => 'color: #550000;', + 4 => 'color: #7a0874;', + 5 => 'color: #448888;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight:bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000099; font-weight:bold;' + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;', + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #007800;', + 1 => 'color: #cc66cc;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => 'http://www.google.com/search?q=%22set+{FNAME}%22+site%3Ahttp%3A%2F%2Fwww.gnuplot.info%2Fdocs%2F&btnI=lucky', + 3 => '', + 4 => '', + 5 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 4 => array( + 'DISALLOWED_AFTER' => "(?![\.\-a-zA-Z0-9_%])" + ) + ) + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/groovy.php b/examples/includes/geshi/geshi/groovy.php new file mode 100644 index 0000000..332f163 --- /dev/null +++ b/examples/includes/geshi/geshi/groovy.php @@ -0,0 +1,1011 @@ + 'Groovy', + 'COMMENT_SINGLE' => array(1 => '//', 3 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Import and Package directives (Basic Support only) + 2 => '/(?:(?<=import[\\n\\s])|(?<=package[\\n\\s]))[\\n\\s]*([a-zA-Z0-9_]+\\.)*([a-zA-Z0-9_]+|\*)(?=[\n\s;])/i', + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'''", '"""', "'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'case', 'do', 'else', 'for', 'foreach', 'if', 'in', 'switch', + 'while', + ), + 2 => array( + 'abstract', 'as', 'assert', 'break', 'catch', 'class', 'const', + 'continue', 'def', 'default', 'enum', 'extends', + 'false', 'final', 'finally', 'goto', 'implements', 'import', + 'instanceof', 'interface', 'native', 'new', 'null', + 'package', 'private', 'property', 'protected', + 'public', 'return', 'static', 'strictfp', 'super', + 'synchronized', 'this', 'throw', 'throws', + 'transient', 'true', 'try', 'volatile' + ), + 3 => array( + 'AbstractAction', 'AbstractBorder', 'AbstractButton', + 'AbstractCellEditor', 'AbstractCollection', + 'AbstractColorChooserPanel', 'AbstractDocument', + 'AbstractDocument.AttributeContext', + 'AbstractDocument.Content', + 'AbstractDocument.ElementEdit', + 'AbstractLayoutCache', + 'AbstractLayoutCache.NodeDimensions', 'AbstractList', + 'AbstractListModel', 'AbstractMap', + 'AbstractMethodError', 'AbstractSequentialList', + 'AbstractSet', 'AbstractTableModel', + 'AbstractUndoableEdit', 'AbstractWriter', + 'AccessControlContext', 'AccessControlException', + 'AccessController', 'AccessException', 'Accessible', + 'AccessibleAction', 'AccessibleBundle', + 'AccessibleComponent', 'AccessibleContext', + 'AccessibleHyperlink', 'AccessibleHypertext', + 'AccessibleIcon', 'AccessibleObject', + 'AccessibleRelation', 'AccessibleRelationSet', + 'AccessibleResourceBundle', 'AccessibleRole', + 'AccessibleSelection', 'AccessibleState', + 'AccessibleStateSet', 'AccessibleTable', + 'AccessibleTableModelChange', 'AccessibleText', + 'AccessibleValue', 'Acl', 'AclEntry', + 'AclNotFoundException', 'Action', 'ActionEvent', + 'ActionListener', 'ActionMap', 'ActionMapUIResource', + 'Activatable', 'ActivateFailedException', + 'ActivationDesc', 'ActivationException', + 'ActivationGroup', 'ActivationGroupDesc', + 'ActivationGroupDesc.CommandEnvironment', + 'ActivationGroupID', 'ActivationID', + 'ActivationInstantiator', 'ActivationMonitor', + 'ActivationSystem', 'Activator', 'ActiveEvent', + 'Adjustable', 'AdjustmentEvent', + 'AdjustmentListener', 'Adler32', 'AffineTransform', + 'AffineTransformOp', 'AlgorithmParameterGenerator', + 'AlgorithmParameterGeneratorSpi', + 'AlgorithmParameters', 'AlgorithmParameterSpec', + 'AlgorithmParametersSpi', 'AllPermission', + 'AlphaComposite', 'AlreadyBound', + 'AlreadyBoundException', 'AlreadyBoundHelper', + 'AlreadyBoundHolder', 'AncestorEvent', + 'AncestorListener', 'Annotation', 'Any', 'AnyHolder', + 'AnySeqHelper', 'AnySeqHolder', 'Applet', + 'AppletContext', 'AppletInitializer', 'AppletStub', + 'ApplicationException', 'Arc2D', 'Arc2D.Double', + 'Arc2D.Float', 'Area', 'AreaAveragingScaleFilter', + 'ARG_IN', 'ARG_INOUT', 'ARG_OUT', + 'ArithmeticException', 'Array', + 'ArrayIndexOutOfBoundsException', 'ArrayList', + 'Arrays', 'ArrayStoreException', 'AsyncBoxView', + 'Attribute', 'AttributedCharacterIterator', + 'AttributedCharacterIterator.Attribute', + 'AttributedString', 'AttributeInUseException', + 'AttributeList', 'AttributeModificationException', + 'Attributes', 'Attributes.Name', 'AttributeSet', + 'AttributeSet.CharacterAttribute', + 'AttributeSet.ColorAttribute', + 'AttributeSet.FontAttribute', + 'AttributeSet.ParagraphAttribute', 'AudioClip', + 'AudioFileFormat', 'AudioFileFormat.Type', + 'AudioFileReader', 'AudioFileWriter', 'AudioFormat', + 'AudioFormat.Encoding', 'AudioInputStream', + 'AudioPermission', 'AudioSystem', + 'AuthenticationException', + 'AuthenticationNotSupportedException', + 'Authenticator', 'Autoscroll', 'AWTError', + 'AWTEvent', 'AWTEventListener', + 'AWTEventMulticaster', 'AWTException', + 'AWTPermission', 'BadKind', 'BadLocationException', + 'BAD_CONTEXT', 'BAD_INV_ORDER', 'BAD_OPERATION', + 'BAD_PARAM', 'BAD_POLICY', 'BAD_POLICY_TYPE', + 'BAD_POLICY_VALUE', 'BAD_TYPECODE', 'BandCombineOp', + 'BandedSampleModel', 'BasicArrowButton', + 'BasicAttribute', 'BasicAttributes', 'BasicBorders', + 'BasicBorders.ButtonBorder', + 'BasicBorders.FieldBorder', + 'BasicBorders.MarginBorder', + 'BasicBorders.MenuBarBorder', + 'BasicBorders.RadioButtonBorder', + 'BasicBorders.SplitPaneBorder', + 'BasicBorders.ToggleButtonBorder', + 'BasicButtonListener', 'BasicButtonUI', + 'BasicCheckBoxMenuItemUI', 'BasicCheckBoxUI', + 'BasicColorChooserUI', 'BasicComboBoxEditor', + 'BasicComboBoxEditor.UIResource', + 'BasicComboBoxRenderer', + 'BasicComboBoxRenderer.UIResource', + 'BasicComboBoxUI', 'BasicComboPopup', + 'BasicDesktopIconUI', 'BasicDesktopPaneUI', + 'BasicDirectoryModel', 'BasicEditorPaneUI', + 'BasicFileChooserUI', 'BasicGraphicsUtils', + 'BasicHTML', 'BasicIconFactory', + 'BasicInternalFrameTitlePane', + 'BasicInternalFrameUI', 'BasicLabelUI', + 'BasicListUI', 'BasicLookAndFeel', 'BasicMenuBarUI', + 'BasicMenuItemUI', 'BasicMenuUI', + 'BasicOptionPaneUI', + 'BasicOptionPaneUI.ButtonAreaLayout', 'BasicPanelUI', + 'BasicPasswordFieldUI', 'BasicPermission', + 'BasicPopupMenuSeparatorUI', 'BasicPopupMenuUI', + 'BasicProgressBarUI', 'BasicRadioButtonMenuItemUI', + 'BasicRadioButtonUI', 'BasicRootPaneUI', + 'BasicScrollBarUI', 'BasicScrollPaneUI', + 'BasicSeparatorUI', 'BasicSliderUI', + 'BasicSplitPaneDivider', 'BasicSplitPaneUI', + 'BasicStroke', 'BasicTabbedPaneUI', + 'BasicTableHeaderUI', 'BasicTableUI', + 'BasicTextAreaUI', 'BasicTextFieldUI', + 'BasicTextPaneUI', 'BasicTextUI', + 'BasicTextUI.BasicCaret', + 'BasicTextUI.BasicHighlighter', + 'BasicToggleButtonUI', 'BasicToolBarSeparatorUI', + 'BasicToolBarUI', 'BasicToolTipUI', 'BasicTreeUI', + 'BasicViewportUI', 'BatchUpdateException', + 'BeanContext', 'BeanContextChild', + 'BeanContextChildComponentProxy', + 'BeanContextChildSupport', + 'BeanContextContainerProxy', 'BeanContextEvent', + 'BeanContextMembershipEvent', + 'BeanContextMembershipListener', 'BeanContextProxy', + 'BeanContextServiceAvailableEvent', + 'BeanContextServiceProvider', + 'BeanContextServiceProviderBeanInfo', + 'BeanContextServiceRevokedEvent', + 'BeanContextServiceRevokedListener', + 'BeanContextServices', 'BeanContextServicesListener', + 'BeanContextServicesSupport', + 'BeanContextServicesSupport.BCSSServiceProvider', + 'BeanContextSupport', + 'BeanContextSupport.BCSIterator', 'BeanDescriptor', + 'BeanInfo', 'Beans', 'BevelBorder', 'BigDecimal', + 'BigInteger', 'BinaryRefAddr', 'BindException', + 'Binding', 'BindingHelper', 'BindingHolder', + 'BindingIterator', 'BindingIteratorHelper', + 'BindingIteratorHolder', 'BindingIteratorOperations', + 'BindingListHelper', 'BindingListHolder', + 'BindingType', 'BindingTypeHelper', + 'BindingTypeHolder', 'BitSet', 'Blob', 'BlockView', + 'Book', 'Boolean', 'BooleanControl', + 'BooleanControl.Type', 'BooleanHolder', + 'BooleanSeqHelper', 'BooleanSeqHolder', 'Border', + 'BorderFactory', 'BorderLayout', 'BorderUIResource', + 'BorderUIResource.BevelBorderUIResource', + 'BorderUIResource.CompoundBorderUIResource', + 'BorderUIResource.EmptyBorderUIResource', + 'BorderUIResource.EtchedBorderUIResource', + 'BorderUIResource.LineBorderUIResource', + 'BorderUIResource.MatteBorderUIResource', + 'BorderUIResource.TitledBorderUIResource', + 'BoundedRangeModel', 'Bounds', 'Box', 'Box.Filler', + 'BoxedValueHelper', 'BoxLayout', 'BoxView', + 'BreakIterator', 'BufferedImage', + 'BufferedImageFilter', 'BufferedImageOp', + 'BufferedInputStream', 'BufferedOutputStream', + 'BufferedReader', 'BufferedWriter', 'Button', + 'ButtonGroup', 'ButtonModel', 'ButtonUI', 'Byte', + 'ByteArrayInputStream', 'ByteArrayOutputStream', + 'ByteHolder', 'ByteLookupTable', 'Calendar', + 'CallableStatement', 'CannotProceed', + 'CannotProceedException', 'CannotProceedHelper', + 'CannotProceedHolder', 'CannotRedoException', + 'CannotUndoException', 'Canvas', 'CardLayout', + 'Caret', 'CaretEvent', 'CaretListener', 'CellEditor', + 'CellEditorListener', 'CellRendererPane', + 'Certificate', 'Certificate.CertificateRep', + 'CertificateEncodingException', + 'CertificateException', + 'CertificateExpiredException', 'CertificateFactory', + 'CertificateFactorySpi', + 'CertificateNotYetValidException', + 'CertificateParsingException', + 'ChangedCharSetException', 'ChangeEvent', + 'ChangeListener', 'Character', 'Character.Subset', + 'Character.UnicodeBlock', 'CharacterIterator', + 'CharArrayReader', 'CharArrayWriter', + 'CharConversionException', 'CharHolder', + 'CharSeqHelper', 'CharSeqHolder', 'Checkbox', + 'CheckboxGroup', 'CheckboxMenuItem', + 'CheckedInputStream', 'CheckedOutputStream', + 'Checksum', 'Choice', 'ChoiceFormat', 'Class', + 'ClassCastException', 'ClassCircularityError', + 'ClassDesc', 'ClassFormatError', 'ClassLoader', + 'ClassNotFoundException', 'Clip', 'Clipboard', + 'ClipboardOwner', 'Clob', 'Cloneable', + 'CloneNotSupportedException', 'CMMException', + 'CodeSource', 'CollationElementIterator', + 'CollationKey', 'Collator', 'Collection', + 'Collections', 'Color', + 'ColorChooserComponentFactory', 'ColorChooserUI', + 'ColorConvertOp', 'ColorModel', + 'ColorSelectionModel', 'ColorSpace', + 'ColorUIResource', 'ComboBoxEditor', 'ComboBoxModel', + 'ComboBoxUI', 'ComboPopup', 'CommunicationException', + 'COMM_FAILURE', 'Comparable', 'Comparator', + 'Compiler', 'CompletionStatus', + 'CompletionStatusHelper', 'Component', + 'ComponentAdapter', 'ComponentColorModel', + 'ComponentEvent', 'ComponentInputMap', + 'ComponentInputMapUIResource', 'ComponentListener', + 'ComponentOrientation', 'ComponentSampleModel', + 'ComponentUI', 'ComponentView', 'Composite', + 'CompositeContext', 'CompositeName', 'CompositeView', + 'CompoundBorder', 'CompoundControl', + 'CompoundControl.Type', 'CompoundEdit', + 'CompoundName', 'ConcurrentModificationException', + 'ConfigurationException', 'ConnectException', + 'ConnectIOException', 'Connection', 'Constructor', + 'Container', 'ContainerAdapter', 'ContainerEvent', + 'ContainerListener', 'ContentHandler', + 'ContentHandlerFactory', 'ContentModel', 'Context', + 'ContextList', 'ContextNotEmptyException', + 'ContextualRenderedImageFactory', 'Control', + 'Control.Type', 'ControlFactory', + 'ControllerEventListener', 'ConvolveOp', 'CRC32', + 'CRL', 'CRLException', 'CropImageFilter', 'CSS', + 'CSS.Attribute', 'CTX_RESTRICT_SCOPE', + 'CubicCurve2D', 'CubicCurve2D.Double', + 'CubicCurve2D.Float', 'Current', 'CurrentHelper', + 'CurrentHolder', 'CurrentOperations', 'Cursor', + 'Customizer', 'CustomMarshal', 'CustomValue', + 'DatabaseMetaData', 'DataBuffer', 'DataBufferByte', + 'DataBufferInt', 'DataBufferShort', + 'DataBufferUShort', 'DataFlavor', + 'DataFormatException', 'DatagramPacket', + 'DatagramSocket', 'DatagramSocketImpl', + 'DatagramSocketImplFactory', 'DataInput', + 'DataInputStream', 'DataLine', 'DataLine.Info', + 'DataOutput', 'DataOutputStream', 'DataTruncation', + 'DATA_CONVERSION', 'Date', 'DateFormat', + 'DateFormatSymbols', 'DebugGraphics', + 'DecimalFormat', 'DecimalFormatSymbols', + 'DefaultBoundedRangeModel', 'DefaultButtonModel', + 'DefaultCaret', 'DefaultCellEditor', + 'DefaultColorSelectionModel', 'DefaultComboBoxModel', + 'DefaultDesktopManager', 'DefaultEditorKit', + 'DefaultEditorKit.BeepAction', + 'DefaultEditorKit.CopyAction', + 'DefaultEditorKit.CutAction', + 'DefaultEditorKit.DefaultKeyTypedAction', + 'DefaultEditorKit.InsertBreakAction', + 'DefaultEditorKit.InsertContentAction', + 'DefaultEditorKit.InsertTabAction', + 'DefaultEditorKit.PasteAction,', + 'DefaultFocusManager', 'DefaultHighlighter', + 'DefaultHighlighter.DefaultHighlightPainter', + 'DefaultListCellRenderer', + 'DefaultListCellRenderer.UIResource', + 'DefaultListModel', 'DefaultListSelectionModel', + 'DefaultMenuLayout', 'DefaultMetalTheme', + 'DefaultMutableTreeNode', + 'DefaultSingleSelectionModel', + 'DefaultStyledDocument', + 'DefaultStyledDocument.AttributeUndoableEdit', + 'DefaultStyledDocument.ElementSpec', + 'DefaultTableCellRenderer', + 'DefaultTableCellRenderer.UIResource', + 'DefaultTableColumnModel', 'DefaultTableModel', + 'DefaultTextUI', 'DefaultTreeCellEditor', + 'DefaultTreeCellRenderer', 'DefaultTreeModel', + 'DefaultTreeSelectionModel', 'DefinitionKind', + 'DefinitionKindHelper', 'Deflater', + 'DeflaterOutputStream', 'Delegate', 'DesignMode', + 'DesktopIconUI', 'DesktopManager', 'DesktopPaneUI', + 'DGC', 'Dialog', 'Dictionary', 'DigestException', + 'DigestInputStream', 'DigestOutputStream', + 'Dimension', 'Dimension2D', 'DimensionUIResource', + 'DirContext', 'DirectColorModel', 'DirectoryManager', + 'DirObjectFactory', 'DirStateFactory', + 'DirStateFactory.Result', 'DnDConstants', 'Document', + 'DocumentEvent', 'DocumentEvent.ElementChange', + 'DocumentEvent.EventType', 'DocumentListener', + 'DocumentParser', 'DomainCombiner', 'DomainManager', + 'DomainManagerOperations', 'Double', 'DoubleHolder', + 'DoubleSeqHelper', 'DoubleSeqHolder', + 'DragGestureEvent', 'DragGestureListener', + 'DragGestureRecognizer', 'DragSource', + 'DragSourceContext', 'DragSourceDragEvent', + 'DragSourceDropEvent', 'DragSourceEvent', + 'DragSourceListener', 'Driver', 'DriverManager', + 'DriverPropertyInfo', 'DropTarget', + 'DropTarget.DropTargetAutoScroller', + 'DropTargetContext', 'DropTargetDragEvent', + 'DropTargetDropEvent', 'DropTargetEvent', + 'DropTargetListener', 'DSAKey', + 'DSAKeyPairGenerator', 'DSAParameterSpec', + 'DSAParams', 'DSAPrivateKey', 'DSAPrivateKeySpec', + 'DSAPublicKey', 'DSAPublicKeySpec', 'DTD', + 'DTDConstants', 'DynamicImplementation', 'DynAny', + 'DynArray', 'DynEnum', 'DynFixed', 'DynSequence', + 'DynStruct', 'DynUnion', 'DynValue', 'EditorKit', + 'Element', 'ElementIterator', 'Ellipse2D', + 'Ellipse2D.Double', 'Ellipse2D.Float', 'EmptyBorder', + 'EmptyStackException', 'EncodedKeySpec', 'Entity', + 'EnumControl', 'EnumControl.Type', 'Enumeration', + 'Environment', 'EOFException', 'Error', + 'EtchedBorder', 'Event', 'EventContext', + 'EventDirContext', 'EventListener', + 'EventListenerList', 'EventObject', 'EventQueue', + 'EventSetDescriptor', 'Exception', + 'ExceptionInInitializerError', 'ExceptionList', + 'ExpandVetoException', 'ExportException', + 'ExtendedRequest', 'ExtendedResponse', + 'Externalizable', 'FeatureDescriptor', 'Field', + 'FieldNameHelper', 'FieldPosition', 'FieldView', + 'File', 'FileChooserUI', 'FileDescriptor', + 'FileDialog', 'FileFilter', 'FileInputStream', + 'FilenameFilter', 'FileNameMap', + 'FileNotFoundException', 'FileOutputStream', + 'FilePermission', 'FileReader', 'FileSystemView', + 'FileView', 'FileWriter', 'FilteredImageSource', + 'FilterInputStream', 'FilterOutputStream', + 'FilterReader', 'FilterWriter', + 'FixedHeightLayoutCache', 'FixedHolder', + 'FlatteningPathIterator', 'FlavorMap', 'Float', + 'FloatControl', 'FloatControl.Type', 'FloatHolder', + 'FloatSeqHelper', 'FloatSeqHolder', 'FlowLayout', + 'FlowView', 'FlowView.FlowStrategy', 'FocusAdapter', + 'FocusEvent', 'FocusListener', 'FocusManager', + 'Font', 'FontFormatException', 'FontMetrics', + 'FontRenderContext', 'FontUIResource', 'Format', + 'FormatConversionProvider', 'FormView', 'Frame', + 'FREE_MEM', 'GapContent', 'GeneralPath', + 'GeneralSecurityException', 'GlyphJustificationInfo', + 'GlyphMetrics', 'GlyphVector', 'GlyphView', + 'GlyphView.GlyphPainter', 'GradientPaint', + 'GraphicAttribute', 'Graphics', 'Graphics2D', + 'GraphicsConfigTemplate', 'GraphicsConfiguration', + 'GraphicsDevice', 'GraphicsEnvironment', + 'GrayFilter', 'GregorianCalendar', + 'GridBagConstraints', 'GridBagLayout', 'GridLayout', + 'Group', 'Guard', 'GuardedObject', 'GZIPInputStream', + 'GZIPOutputStream', 'HasControls', 'HashMap', + 'HashSet', 'Hashtable', 'HierarchyBoundsAdapter', + 'HierarchyBoundsListener', 'HierarchyEvent', + 'HierarchyListener', 'Highlighter', + 'Highlighter.Highlight', + 'Highlighter.HighlightPainter', 'HTML', + 'HTML.Attribute', 'HTML.Tag', 'HTML.UnknownTag', + 'HTMLDocument', 'HTMLDocument.Iterator', + 'HTMLEditorKit', 'HTMLEditorKit.HTMLFactory', + 'HTMLEditorKit.HTMLTextAction', + 'HTMLEditorKit.InsertHTMLTextAction', + 'HTMLEditorKit.LinkController', + 'HTMLEditorKit.Parser', + 'HTMLEditorKit.ParserCallback', + 'HTMLFrameHyperlinkEvent', 'HTMLWriter', + 'HttpURLConnection', 'HyperlinkEvent', + 'HyperlinkEvent.EventType', 'HyperlinkListener', + 'ICC_ColorSpace', 'ICC_Profile', 'ICC_ProfileGray', + 'ICC_ProfileRGB', 'Icon', 'IconUIResource', + 'IconView', 'IdentifierHelper', 'Identity', + 'IdentityScope', 'IDLEntity', 'IDLType', + 'IDLTypeHelper', 'IDLTypeOperations', + 'IllegalAccessError', 'IllegalAccessException', + 'IllegalArgumentException', + 'IllegalComponentStateException', + 'IllegalMonitorStateException', + 'IllegalPathStateException', 'IllegalStateException', + 'IllegalThreadStateException', 'Image', + 'ImageConsumer', 'ImageFilter', + 'ImageGraphicAttribute', 'ImageIcon', + 'ImageObserver', 'ImageProducer', + 'ImagingOpException', 'IMP_LIMIT', + 'IncompatibleClassChangeError', + 'InconsistentTypeCode', 'IndexColorModel', + 'IndexedPropertyDescriptor', + 'IndexOutOfBoundsException', 'IndirectionException', + 'InetAddress', 'Inflater', 'InflaterInputStream', + 'InheritableThreadLocal', 'InitialContext', + 'InitialContextFactory', + 'InitialContextFactoryBuilder', 'InitialDirContext', + 'INITIALIZE', 'Initializer', 'InitialLdapContext', + 'InlineView', 'InputContext', 'InputEvent', + 'InputMap', 'InputMapUIResource', 'InputMethod', + 'InputMethodContext', 'InputMethodDescriptor', + 'InputMethodEvent', 'InputMethodHighlight', + 'InputMethodListener', 'InputMethodRequests', + 'InputStream', 'InputStreamReader', 'InputSubset', + 'InputVerifier', 'Insets', 'InsetsUIResource', + 'InstantiationError', 'InstantiationException', + 'Instrument', 'InsufficientResourcesException', + 'Integer', 'INTERNAL', 'InternalError', + 'InternalFrameAdapter', 'InternalFrameEvent', + 'InternalFrameListener', 'InternalFrameUI', + 'InterruptedException', 'InterruptedIOException', + 'InterruptedNamingException', 'INTF_REPOS', + 'IntHolder', 'IntrospectionException', + 'Introspector', 'Invalid', + 'InvalidAlgorithmParameterException', + 'InvalidAttributeIdentifierException', + 'InvalidAttributesException', + 'InvalidAttributeValueException', + 'InvalidClassException', + 'InvalidDnDOperationException', + 'InvalidKeyException', 'InvalidKeySpecException', + 'InvalidMidiDataException', 'InvalidName', + 'InvalidNameException', 'InvalidNameHelper', + 'InvalidNameHolder', 'InvalidObjectException', + 'InvalidParameterException', + 'InvalidParameterSpecException', + 'InvalidSearchControlsException', + 'InvalidSearchFilterException', 'InvalidSeq', + 'InvalidTransactionException', 'InvalidValue', + 'INVALID_TRANSACTION', 'InvocationEvent', + 'InvocationHandler', 'InvocationTargetException', + 'InvokeHandler', 'INV_FLAG', 'INV_IDENT', + 'INV_OBJREF', 'INV_POLICY', 'IOException', + 'IRObject', 'IRObjectOperations', 'IstringHelper', + 'ItemEvent', 'ItemListener', 'ItemSelectable', + 'Iterator', 'JApplet', 'JarEntry', 'JarException', + 'JarFile', 'JarInputStream', 'JarOutputStream', + 'JarURLConnection', 'JButton', 'JCheckBox', + 'JCheckBoxMenuItem', 'JColorChooser', 'JComboBox', + 'JComboBox.KeySelectionManager', 'JComponent', + 'JDesktopPane', 'JDialog', 'JEditorPane', + 'JFileChooser', 'JFrame', 'JInternalFrame', + 'JInternalFrame.JDesktopIcon', 'JLabel', + 'JLayeredPane', 'JList', 'JMenu', 'JMenuBar', + 'JMenuItem', 'JobAttributes', + 'JobAttributes.DefaultSelectionType', + 'JobAttributes.DestinationType', + 'JobAttributes.DialogType', + 'JobAttributes.MultipleDocumentHandlingType', + 'JobAttributes.SidesType', 'JOptionPane', 'JPanel', + 'JPasswordField', 'JPopupMenu', + 'JPopupMenu.Separator', 'JProgressBar', + 'JRadioButton', 'JRadioButtonMenuItem', 'JRootPane', + 'JScrollBar', 'JScrollPane', 'JSeparator', 'JSlider', + 'JSplitPane', 'JTabbedPane', 'JTable', + 'JTableHeader', 'JTextArea', 'JTextComponent', + 'JTextComponent.KeyBinding', 'JTextField', + 'JTextPane', 'JToggleButton', + 'JToggleButton.ToggleButtonModel', 'JToolBar', + 'JToolBar.Separator', 'JToolTip', 'JTree', + 'JTree.DynamicUtilTreeNode', + 'JTree.EmptySelectionModel', 'JViewport', 'JWindow', + 'Kernel', 'Key', 'KeyAdapter', 'KeyEvent', + 'KeyException', 'KeyFactory', 'KeyFactorySpi', + 'KeyListener', 'KeyManagementException', 'Keymap', + 'KeyPair', 'KeyPairGenerator', 'KeyPairGeneratorSpi', + 'KeySpec', 'KeyStore', 'KeyStoreException', + 'KeyStoreSpi', 'KeyStroke', 'Label', 'LabelUI', + 'LabelView', 'LastOwnerException', + 'LayeredHighlighter', + 'LayeredHighlighter.LayerPainter', 'LayoutManager', + 'LayoutManager2', 'LayoutQueue', 'LdapContext', + 'LdapReferralException', 'Lease', + 'LimitExceededException', 'Line', 'Line.Info', + 'Line2D', 'Line2D.Double', 'Line2D.Float', + 'LineBorder', 'LineBreakMeasurer', 'LineEvent', + 'LineEvent.Type', 'LineListener', 'LineMetrics', + 'LineNumberInputStream', 'LineNumberReader', + 'LineUnavailableException', 'LinkageError', + 'LinkedList', 'LinkException', 'LinkLoopException', + 'LinkRef', 'List', 'ListCellRenderer', + 'ListDataEvent', 'ListDataListener', 'ListIterator', + 'ListModel', 'ListResourceBundle', + 'ListSelectionEvent', 'ListSelectionListener', + 'ListSelectionModel', 'ListUI', 'ListView', + 'LoaderHandler', 'Locale', 'LocateRegistry', + 'LogStream', 'Long', 'LongHolder', + 'LongLongSeqHelper', 'LongLongSeqHolder', + 'LongSeqHelper', 'LongSeqHolder', 'LookAndFeel', + 'LookupOp', 'LookupTable', 'MalformedLinkException', + 'MalformedURLException', 'Manifest', 'Map', + 'Map.Entry', 'MARSHAL', 'MarshalException', + 'MarshalledObject', 'Math', 'MatteBorder', + 'MediaTracker', 'Member', 'MemoryImageSource', + 'Menu', 'MenuBar', 'MenuBarUI', 'MenuComponent', + 'MenuContainer', 'MenuDragMouseEvent', + 'MenuDragMouseListener', 'MenuElement', 'MenuEvent', + 'MenuItem', 'MenuItemUI', 'MenuKeyEvent', + 'MenuKeyListener', 'MenuListener', + 'MenuSelectionManager', 'MenuShortcut', + 'MessageDigest', 'MessageDigestSpi', 'MessageFormat', + 'MetaEventListener', 'MetalBorders', + 'MetalBorders.ButtonBorder', + 'MetalBorders.Flush3DBorder', + 'MetalBorders.InternalFrameBorder', + 'MetalBorders.MenuBarBorder', + 'MetalBorders.MenuItemBorder', + 'MetalBorders.OptionDialogBorder', + 'MetalBorders.PaletteBorder', + 'MetalBorders.PopupMenuBorder', + 'MetalBorders.RolloverButtonBorder', + 'MetalBorders.ScrollPaneBorder', + 'MetalBorders.TableHeaderBorder', + 'MetalBorders.TextFieldBorder', + 'MetalBorders.ToggleButtonBorder', + 'MetalBorders.ToolBarBorder', 'MetalButtonUI', + 'MetalCheckBoxIcon', 'MetalCheckBoxUI', + 'MetalComboBoxButton', 'MetalComboBoxEditor', + 'MetalComboBoxEditor.UIResource', + 'MetalComboBoxIcon', 'MetalComboBoxUI', + 'MetalDesktopIconUI', 'MetalFileChooserUI', + 'MetalIconFactory', 'MetalIconFactory.FileIcon16', + 'MetalIconFactory.FolderIcon16', + 'MetalIconFactory.PaletteCloseIcon', + 'MetalIconFactory.TreeControlIcon', + 'MetalIconFactory.TreeFolderIcon', + 'MetalIconFactory.TreeLeafIcon', + 'MetalInternalFrameTitlePane', + 'MetalInternalFrameUI', 'MetalLabelUI', + 'MetalLookAndFeel', 'MetalPopupMenuSeparatorUI', + 'MetalProgressBarUI', 'MetalRadioButtonUI', + 'MetalScrollBarUI', 'MetalScrollButton', + 'MetalScrollPaneUI', 'MetalSeparatorUI', + 'MetalSliderUI', 'MetalSplitPaneUI', + 'MetalTabbedPaneUI', 'MetalTextFieldUI', + 'MetalTheme', 'MetalToggleButtonUI', + 'MetalToolBarUI', 'MetalToolTipUI', 'MetalTreeUI', + 'MetaMessage', 'Method', 'MethodDescriptor', + 'MidiChannel', 'MidiDevice', 'MidiDevice.Info', + 'MidiDeviceProvider', 'MidiEvent', 'MidiFileFormat', + 'MidiFileReader', 'MidiFileWriter', 'MidiMessage', + 'MidiSystem', 'MidiUnavailableException', + 'MimeTypeParseException', 'MinimalHTMLWriter', + 'MissingResourceException', 'Mixer', 'Mixer.Info', + 'MixerProvider', 'ModificationItem', 'Modifier', + 'MouseAdapter', 'MouseDragGestureRecognizer', + 'MouseEvent', 'MouseInputAdapter', + 'MouseInputListener', 'MouseListener', + 'MouseMotionAdapter', 'MouseMotionListener', + 'MultiButtonUI', 'MulticastSocket', + 'MultiColorChooserUI', 'MultiComboBoxUI', + 'MultiDesktopIconUI', 'MultiDesktopPaneUI', + 'MultiFileChooserUI', 'MultiInternalFrameUI', + 'MultiLabelUI', 'MultiListUI', 'MultiLookAndFeel', + 'MultiMenuBarUI', 'MultiMenuItemUI', + 'MultiOptionPaneUI', 'MultiPanelUI', + 'MultiPixelPackedSampleModel', 'MultipleMaster', + 'MultiPopupMenuUI', 'MultiProgressBarUI', + 'MultiScrollBarUI', 'MultiScrollPaneUI', + 'MultiSeparatorUI', 'MultiSliderUI', + 'MultiSplitPaneUI', 'MultiTabbedPaneUI', + 'MultiTableHeaderUI', 'MultiTableUI', 'MultiTextUI', + 'MultiToolBarUI', 'MultiToolTipUI', 'MultiTreeUI', + 'MultiViewportUI', 'MutableAttributeSet', + 'MutableComboBoxModel', 'MutableTreeNode', 'Name', + 'NameAlreadyBoundException', 'NameClassPair', + 'NameComponent', 'NameComponentHelper', + 'NameComponentHolder', 'NamedValue', 'NameHelper', + 'NameHolder', 'NameNotFoundException', 'NameParser', + 'NamespaceChangeListener', 'NameValuePair', + 'NameValuePairHelper', 'Naming', 'NamingContext', + 'NamingContextHelper', 'NamingContextHolder', + 'NamingContextOperations', 'NamingEnumeration', + 'NamingEvent', 'NamingException', + 'NamingExceptionEvent', 'NamingListener', + 'NamingManager', 'NamingSecurityException', + 'NegativeArraySizeException', 'NetPermission', + 'NoClassDefFoundError', 'NoInitialContextException', + 'NoninvertibleTransformException', + 'NoPermissionException', 'NoRouteToHostException', + 'NoSuchAlgorithmException', + 'NoSuchAttributeException', 'NoSuchElementException', + 'NoSuchFieldError', 'NoSuchFieldException', + 'NoSuchMethodError', 'NoSuchMethodException', + 'NoSuchObjectException', 'NoSuchProviderException', + 'NotActiveException', 'NotBoundException', + 'NotContextException', 'NotEmpty', 'NotEmptyHelper', + 'NotEmptyHolder', 'NotFound', 'NotFoundHelper', + 'NotFoundHolder', 'NotFoundReason', + 'NotFoundReasonHelper', 'NotFoundReasonHolder', + 'NotOwnerException', 'NotSerializableException', + 'NO_IMPLEMENT', 'NO_MEMORY', 'NO_PERMISSION', + 'NO_RESOURCES', 'NO_RESPONSE', + 'NullPointerException', 'Number', 'NumberFormat', + 'NumberFormatException', 'NVList', 'Object', + 'ObjectChangeListener', 'ObjectFactory', + 'ObjectFactoryBuilder', 'ObjectHelper', + 'ObjectHolder', 'ObjectImpl', 'ObjectInput', + 'ObjectInputStream', 'ObjectInputStream.GetField', + 'ObjectInputValidation', 'ObjectOutput', + 'ObjectOutputStream', 'ObjectOutputStream.PutField', + 'ObjectStreamClass', 'ObjectStreamConstants', + 'ObjectStreamException', 'ObjectStreamField', + 'ObjectView', 'OBJECT_NOT_EXIST', 'ObjID', + 'OBJ_ADAPTER', 'Observable', 'Observer', + 'OctetSeqHelper', 'OctetSeqHolder', 'OMGVMCID', + 'OpenType', 'Operation', + 'OperationNotSupportedException', 'Option', + 'OptionalDataException', 'OptionPaneUI', 'ORB', + 'OutOfMemoryError', 'OutputStream', + 'OutputStreamWriter', 'OverlayLayout', 'Owner', + 'Package', 'PackedColorModel', 'Pageable', + 'PageAttributes', 'PageAttributes.ColorType', + 'PageAttributes.MediaType', + 'PageAttributes.OrientationRequestedType', + 'PageAttributes.OriginType', + 'PageAttributes.PrintQualityType', 'PageFormat', + 'Paint', 'PaintContext', 'PaintEvent', 'Panel', + 'PanelUI', 'Paper', 'ParagraphView', + 'ParameterBlock', 'ParameterDescriptor', + 'ParseException', 'ParsePosition', 'Parser', + 'ParserDelegator', 'PartialResultException', + 'PasswordAuthentication', 'PasswordView', 'Patch', + 'PathIterator', 'Permission', 'PermissionCollection', + 'Permissions', 'PERSIST_STORE', 'PhantomReference', + 'PipedInputStream', 'PipedOutputStream', + 'PipedReader', 'PipedWriter', 'PixelGrabber', + 'PixelInterleavedSampleModel', 'PKCS8EncodedKeySpec', + 'PlainDocument', 'PlainView', 'Point', 'Point2D', + 'Point2D.Double', 'Point2D.Float', 'Policy', + 'PolicyError', 'PolicyHelper', 'PolicyHolder', + 'PolicyListHelper', 'PolicyListHolder', + 'PolicyOperations', 'PolicyTypeHelper', 'Polygon', + 'PopupMenu', 'PopupMenuEvent', 'PopupMenuListener', + 'PopupMenuUI', 'Port', 'Port.Info', + 'PortableRemoteObject', + 'PortableRemoteObjectDelegate', 'Position', + 'Position.Bias', 'PreparedStatement', 'Principal', + 'PrincipalHolder', 'Printable', + 'PrinterAbortException', 'PrinterException', + 'PrinterGraphics', 'PrinterIOException', + 'PrinterJob', 'PrintGraphics', 'PrintJob', + 'PrintStream', 'PrintWriter', 'PrivateKey', + 'PRIVATE_MEMBER', 'PrivilegedAction', + 'PrivilegedActionException', + 'PrivilegedExceptionAction', 'Process', + 'ProfileDataException', 'ProgressBarUI', + 'ProgressMonitor', 'ProgressMonitorInputStream', + 'Properties', 'PropertyChangeEvent', + 'PropertyChangeListener', 'PropertyChangeSupport', + 'PropertyDescriptor', 'PropertyEditor', + 'PropertyEditorManager', 'PropertyEditorSupport', + 'PropertyPermission', 'PropertyResourceBundle', + 'PropertyVetoException', 'ProtectionDomain', + 'ProtocolException', 'Provider', 'ProviderException', + 'Proxy', 'PublicKey', 'PUBLIC_MEMBER', + 'PushbackInputStream', 'PushbackReader', + 'QuadCurve2D', 'QuadCurve2D.Double', + 'QuadCurve2D.Float', 'Random', 'RandomAccessFile', + 'Raster', 'RasterFormatException', 'RasterOp', + 'Reader', 'Receiver', 'Rectangle', 'Rectangle2D', + 'Rectangle2D.Double', 'Rectangle2D.Float', + 'RectangularShape', 'Ref', 'RefAddr', 'Reference', + 'Referenceable', 'ReferenceQueue', + 'ReferralException', 'ReflectPermission', 'Registry', + 'RegistryHandler', 'RemarshalException', 'Remote', + 'RemoteCall', 'RemoteException', 'RemoteObject', + 'RemoteRef', 'RemoteServer', 'RemoteStub', + 'RenderableImage', 'RenderableImageOp', + 'RenderableImageProducer', 'RenderContext', + 'RenderedImage', 'RenderedImageFactory', 'Renderer', + 'RenderingHints', 'RenderingHints.Key', + 'RepaintManager', 'ReplicateScaleFilter', + 'Repository', 'RepositoryIdHelper', 'Request', + 'RescaleOp', 'Resolver', 'ResolveResult', + 'ResourceBundle', 'ResponseHandler', 'ResultSet', + 'ResultSetMetaData', 'ReverbType', 'RGBImageFilter', + 'RMIClassLoader', 'RMIClientSocketFactory', + 'RMIFailureHandler', 'RMISecurityException', + 'RMISecurityManager', 'RMIServerSocketFactory', + 'RMISocketFactory', 'Robot', 'RootPaneContainer', + 'RootPaneUI', 'RoundRectangle2D', + 'RoundRectangle2D.Double', 'RoundRectangle2D.Float', + 'RowMapper', 'RSAKey', 'RSAKeyGenParameterSpec', + 'RSAPrivateCrtKey', 'RSAPrivateCrtKeySpec', + 'RSAPrivateKey', 'RSAPrivateKeySpec', 'RSAPublicKey', + 'RSAPublicKeySpec', 'RTFEditorKit', + 'RuleBasedCollator', 'Runnable', 'Runtime', + 'RunTime', 'RuntimeException', 'RunTimeOperations', + 'RuntimePermission', 'SampleModel', + 'SchemaViolationException', 'Scrollable', + 'Scrollbar', 'ScrollBarUI', 'ScrollPane', + 'ScrollPaneConstants', 'ScrollPaneLayout', + 'ScrollPaneLayout.UIResource', 'ScrollPaneUI', + 'SearchControls', 'SearchResult', + 'SecureClassLoader', 'SecureRandom', + 'SecureRandomSpi', 'Security', 'SecurityException', + 'SecurityManager', 'SecurityPermission', 'Segment', + 'SeparatorUI', 'Sequence', 'SequenceInputStream', + 'Sequencer', 'Sequencer.SyncMode', 'Serializable', + 'SerializablePermission', 'ServantObject', + 'ServerCloneException', 'ServerError', + 'ServerException', 'ServerNotActiveException', + 'ServerRef', 'ServerRequest', + 'ServerRuntimeException', 'ServerSocket', + 'ServiceDetail', 'ServiceDetailHelper', + 'ServiceInformation', 'ServiceInformationHelper', + 'ServiceInformationHolder', + 'ServiceUnavailableException', 'Set', + 'SetOverrideType', 'SetOverrideTypeHelper', 'Shape', + 'ShapeGraphicAttribute', 'Short', 'ShortHolder', + 'ShortLookupTable', 'ShortMessage', 'ShortSeqHelper', + 'ShortSeqHolder', 'Signature', 'SignatureException', + 'SignatureSpi', 'SignedObject', 'Signer', + 'SimpleAttributeSet', 'SimpleBeanInfo', + 'SimpleDateFormat', 'SimpleTimeZone', + 'SinglePixelPackedSampleModel', + 'SingleSelectionModel', 'SizeLimitExceededException', + 'SizeRequirements', 'SizeSequence', 'Skeleton', + 'SkeletonMismatchException', + 'SkeletonNotFoundException', 'SliderUI', 'Socket', + 'SocketException', 'SocketImpl', 'SocketImplFactory', + 'SocketOptions', 'SocketPermission', + 'SocketSecurityException', 'SoftBevelBorder', + 'SoftReference', 'SortedMap', 'SortedSet', + 'Soundbank', 'SoundbankReader', 'SoundbankResource', + 'SourceDataLine', 'SplitPaneUI', 'SQLData', + 'SQLException', 'SQLInput', 'SQLOutput', + 'SQLPermission', 'SQLWarning', 'Stack', + 'StackOverflowError', 'StateEdit', 'StateEditable', + 'StateFactory', 'Statement', 'Streamable', + 'StreamableValue', 'StreamCorruptedException', + 'StreamTokenizer', 'StrictMath', 'String', + 'StringBuffer', 'StringBufferInputStream', + 'StringCharacterIterator', 'StringContent', + 'StringHolder', 'StringIndexOutOfBoundsException', + 'StringReader', 'StringRefAddr', 'StringSelection', + 'StringTokenizer', 'StringValueHelper', + 'StringWriter', 'Stroke', 'Struct', 'StructMember', + 'StructMemberHelper', 'Stub', 'StubDelegate', + 'StubNotFoundException', 'Style', 'StyleConstants', + 'StyleConstants.CharacterConstants', + 'StyleConstants.ColorConstants', + 'StyleConstants.FontConstants', + 'StyleConstants.ParagraphConstants', 'StyleContext', + 'StyledDocument', 'StyledEditorKit', + 'StyledEditorKit.AlignmentAction', + 'StyledEditorKit.BoldAction', + 'StyledEditorKit.FontFamilyAction', + 'StyledEditorKit.FontSizeAction', + 'StyledEditorKit.ForegroundAction', + 'StyledEditorKit.ItalicAction', + 'StyledEditorKit.StyledTextAction', + 'StyledEditorKit.UnderlineAction', 'StyleSheet', + 'StyleSheet.BoxPainter', 'StyleSheet.ListPainter', + 'SwingConstants', 'SwingPropertyChangeSupport', + 'SwingUtilities', 'SyncFailedException', + 'Synthesizer', 'SysexMessage', 'System', + 'SystemColor', 'SystemException', 'SystemFlavorMap', + 'TabableView', 'TabbedPaneUI', 'TabExpander', + 'TableCellEditor', 'TableCellRenderer', + 'TableColumn', 'TableColumnModel', + 'TableColumnModelEvent', 'TableColumnModelListener', + 'TableHeaderUI', 'TableModel', 'TableModelEvent', + 'TableModelListener', 'TableUI', 'TableView', + 'TabSet', 'TabStop', 'TagElement', 'TargetDataLine', + 'TCKind', 'TextAction', 'TextArea', 'TextAttribute', + 'TextComponent', 'TextEvent', 'TextField', + 'TextHitInfo', 'TextLayout', + 'TextLayout.CaretPolicy', 'TextListener', + 'TextMeasurer', 'TextUI', 'TexturePaint', 'Thread', + 'ThreadDeath', 'ThreadGroup', 'ThreadLocal', + 'Throwable', 'Tie', 'TileObserver', 'Time', + 'TimeLimitExceededException', 'Timer', 'TimerTask', + 'Timestamp', 'TimeZone', 'TitledBorder', 'ToolBarUI', + 'Toolkit', 'ToolTipManager', 'ToolTipUI', + 'TooManyListenersException', 'Track', + 'TransactionRequiredException', + 'TransactionRolledbackException', + 'TRANSACTION_REQUIRED', 'TRANSACTION_ROLLEDBACK', + 'Transferable', 'TransformAttribute', 'TRANSIENT', + 'Transmitter', 'Transparency', 'TreeCellEditor', + 'TreeCellRenderer', 'TreeExpansionEvent', + 'TreeExpansionListener', 'TreeMap', 'TreeModel', + 'TreeModelEvent', 'TreeModelListener', 'TreeNode', + 'TreePath', 'TreeSelectionEvent', + 'TreeSelectionListener', 'TreeSelectionModel', + 'TreeSet', 'TreeUI', 'TreeWillExpandListener', + 'TypeCode', 'TypeCodeHolder', 'TypeMismatch', + 'Types', 'UID', 'UIDefaults', + 'UIDefaults.ActiveValue', 'UIDefaults.LazyInputMap', + 'UIDefaults.LazyValue', 'UIDefaults.ProxyLazyValue', + 'UIManager', 'UIManager.LookAndFeelInfo', + 'UIResource', 'ULongLongSeqHelper', + 'ULongLongSeqHolder', 'ULongSeqHelper', + 'ULongSeqHolder', 'UndeclaredThrowableException', + 'UndoableEdit', 'UndoableEditEvent', + 'UndoableEditListener', 'UndoableEditSupport', + 'UndoManager', 'UnexpectedException', + 'UnicastRemoteObject', 'UnionMember', + 'UnionMemberHelper', 'UNKNOWN', 'UnknownError', + 'UnknownException', 'UnknownGroupException', + 'UnknownHostException', 'UnknownObjectException', + 'UnknownServiceException', 'UnknownUserException', + 'UnmarshalException', 'UnrecoverableKeyException', + 'Unreferenced', 'UnresolvedPermission', + 'UnsatisfiedLinkError', 'UnsolicitedNotification', + 'UnsolicitedNotificationEvent', + 'UnsolicitedNotificationListener', + 'UnsupportedAudioFileException', + 'UnsupportedClassVersionError', + 'UnsupportedEncodingException', + 'UnsupportedFlavorException', + 'UnsupportedLookAndFeelException', + 'UnsupportedOperationException', + 'UNSUPPORTED_POLICY', 'UNSUPPORTED_POLICY_VALUE', + 'URL', 'URLClassLoader', 'URLConnection', + 'URLDecoder', 'URLEncoder', 'URLStreamHandler', + 'URLStreamHandlerFactory', 'UserException', + 'UShortSeqHelper', 'UShortSeqHolder', + 'UTFDataFormatException', 'Util', 'UtilDelegate', + 'Utilities', 'ValueBase', 'ValueBaseHelper', + 'ValueBaseHolder', 'ValueFactory', 'ValueHandler', + 'ValueMember', 'ValueMemberHelper', + 'VariableHeightLayoutCache', 'Vector', 'VerifyError', + 'VersionSpecHelper', 'VetoableChangeListener', + 'VetoableChangeSupport', 'View', 'ViewFactory', + 'ViewportLayout', 'ViewportUI', + 'VirtualMachineError', 'Visibility', + 'VisibilityHelper', 'VMID', 'VM_ABSTRACT', + 'VM_CUSTOM', 'VM_NONE', 'VM_TRUNCATABLE', + 'VoiceStatus', 'Void', 'WCharSeqHelper', + 'WCharSeqHolder', 'WeakHashMap', 'WeakReference', + 'Window', 'WindowAdapter', 'WindowConstants', + 'WindowEvent', 'WindowListener', 'WrappedPlainView', + 'WritableRaster', 'WritableRenderedImage', + 'WriteAbortedException', 'Writer', + 'WrongTransaction', 'WStringValueHelper', + 'X509Certificate', 'X509CRL', 'X509CRLEntry', + 'X509EncodedKeySpec', 'X509Extension', 'ZipEntry', + 'ZipException', 'ZipFile', 'ZipInputStream', + 'ZipOutputStream', 'ZoneView', + '_BindingIteratorImplBase', '_BindingIteratorStub', + '_IDLTypeStub', '_NamingContextImplBase', + '_NamingContextStub', '_PolicyStub', '_Remote_Stub' + ), + 4 => array( + 'boolean', 'byte', 'char', 'double', 'float', 'int', 'long', + 'short', 'void' + ), + 5 => array( + 'allProperties', 'asImmutable', 'asSynchronized', 'collect', + 'count', 'each', 'eachProperty', 'eachPropertyName', + 'eachWithIndex', 'find', 'findAll', 'findIndexOf', + 'flatten', 'get', 'grep', 'inject', 'intersect', + 'join', 'max', 'min', 'pop', 'reverse', + 'reverseEach', 'size', 'sort', 'subMap', 'toList' + ), + 6 => array( + 'center', 'contains', 'eachMatch', 'padLeft', 'padRight', + 'toCharacter', 'tokenize', 'toLong', 'toURL' + ), + 7 => array( + 'append', 'eachByte', 'eachFile', 'eachFileRecurse', 'eachLine', + 'eachLines', 'encodeBase64', 'filterLine', 'getText', + 'splitEachLine', 'transformChar', 'transformLine', + 'withOutputStream', 'withPrintWriter', 'withReader', + 'withStream', 'withStreams', 'withWriter', + 'withWriterAppend', 'write', 'writeLine' + ), + 8 => array( + 'dump', 'getLastMatcher', 'inspect', 'invokeMethod', 'print', + 'println', 'start', 'startDaemon', 'step', 'times', + 'upto', 'use' + ), + 9 => array( + 'call', 'close', 'eachRow', 'execute', 'executeUpdate', 'Sql' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '*', '&', '%', '!', ';', '<', '>', '?', '|', '=', + '=>', '||', '-', '+', '<<', '<<<', '&&' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => true, + 1 => false, + 2 => false, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #aaaadd; font-weight: bold;', + 4 => 'color: #993333;', + 5 => 'color: #663399;', + 6 => 'color: #CC0099;', + 7 => 'color: #FFCC33;', + 8 => 'color: #993399;', + 9 => 'color: #993399; font-weight: bold;' + ), + 'COMMENTS' => array( + 1=> 'color: #808080; font-style: italic;', + 2=> 'color: #a1a100;', + 3=> 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;' + ) + ), + 'URLS' => array( + 1 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAMEL}', + 2 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAMEL}', + 3 => 'http://www.google.de/search?as_q={FNAME}&num=100&hl=en&as_occt=url&as_sitesearch=java.sun.com%2Fj2se%2F1.5.0%2Fdocs%2Fapi%2F', + 4 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAME}', + 5 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAME}', + 6 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAME}', + 7 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAME}', + 8 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAME}', + 9 => 'http://www.google.de/search?q=site%3Adocs.codehaus.org/%20{FNAME}' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + //Variables + 0 => '\\$\\{[a-zA-Z_][a-zA-Z0-9_]*\\}' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/haskell.php b/examples/includes/geshi/geshi/haskell.php new file mode 100644 index 0000000..a6841dd --- /dev/null +++ b/examples/includes/geshi/geshi/haskell.php @@ -0,0 +1,198 @@ + 'Haskell', + 'COMMENT_SINGLE' => array( 1 => '--'), + 'COMMENT_MULTI' => array('{-' => '-}'), + 'COMMENT_REGEXP' => array(2 => "/-->/"), + 'CASE_KEYWORDS' => 0, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => "\\", + 'KEYWORDS' => array( + /* main haskell keywords */ + 1 => array( + 'as', + 'case', 'of', 'class', 'data', 'default', + 'deriving', 'do', 'forall', 'hiding', 'if', 'then', + 'else', 'import', 'infix', 'infixl', 'infixr', + 'instance', 'let', 'in', 'module', 'newtype', + 'qualified', 'type', 'where' + ), + /* define names of main librarys, so we can link to it */ + 2 => array( + 'Foreign', 'Numeric', 'Prelude' + ), + /* just link to Prelude functions, cause it's the default opened library when starting Haskell */ + 3 => array( + 'not', 'otherwise', 'maybe', + 'either', 'fst', 'snd', 'curry', 'uncurry', + 'compare', + 'max', 'min', 'succ', 'pred', 'toEnum', 'fromEnum', + 'enumFrom', 'enumFromThen', 'enumFromTo', + 'enumFromThenTo', 'minBound', 'maxBound', + 'negate', 'abs', 'signum', + 'fromInteger', 'toRational', 'quot', 'rem', + 'div', 'mod', 'quotRem', 'divMod', 'toInteger', + 'recip', 'fromRational', 'pi', 'exp', + 'log', 'sqrt', 'logBase', 'sin', 'cos', + 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', + 'tanh', 'asinh', 'acosh', 'atanh', + 'properFraction', 'truncate', 'round', 'ceiling', + 'floor', 'floatRadix', 'floatDigits', 'floatRange', + 'decodeFloat', 'encodeFloat', 'exponent', + 'significand', 'scaleFloat', 'isNaN', 'isInfinite', + 'isDenomalized', 'isNegativeZero', 'isIEEE', + 'atan2', 'subtract', 'even', 'odd', 'gcd', + 'lcm', 'fromIntegral', 'realToFrac', + 'return', 'fail', 'fmap', + 'mapM', 'mapM_', 'sequence', 'sequence_', + 'id', 'const','flip', + 'until', 'asTypeOf', 'error', 'undefined', + 'seq','map','filter', 'head', + 'last', 'tail', 'init', 'null', 'length', + 'reverse', 'foldl', 'foldl1', 'foldr', + 'foldr1', 'and', 'or', 'any', 'all', 'sum', + 'product', 'concat', 'concatMap', 'maximum', + 'minimum', 'scanl', 'scanl1', 'scanr', 'scanr1', + 'iterate', 'repeat', 'cycle', 'take', 'drop', + 'splitAt', 'teakWhile', 'dropWhile', 'span', + 'break', 'elem', 'notElem', 'lookup', 'zip', + 'zip3', 'zipWith', 'zipWith3', 'unzip', 'unzip3', + 'lines', 'words', 'unlines', + 'unwords', 'showPrec', 'show', 'showList', + 'shows', 'showChar', 'showString', 'showParen', + 'readsPrec', 'readList', 'reads', 'readParen', + 'read', 'lex', 'putChar', 'putStr', 'putStrLn', + 'print', 'getChar', 'getLine', 'getContents', + 'interact', 'readFile', 'writeFile', 'appendFile', + 'readIO', 'readLn', 'ioError', 'userError', 'catch' + ), + /* here Prelude Types */ + 4 => array ( + 'Bool', 'Maybe', 'Either', 'Ord', 'Ordering', + 'Char', 'String', 'Eq', 'Enum', 'Bounded', + 'Int', 'Integer', 'Float', 'Double', 'Rational', + 'Num', 'Real', 'Integral', 'Fractional', + 'Floating', 'RealFrac', 'RealFloat', 'Monad', + 'Functor', 'Show', 'ShowS', 'Read', 'ReadS', + 'IO' + ), + /* finally Prelude Exceptions */ + 5 => array ( + 'IOError', 'IOException' + ) + ), + /* highlighting symbols is really important in Haskell */ + 'SYMBOLS' => array( + '|', '->', '<-', '@', '!', '::', '_', '~', '=', '?', + '&&', '||', '==', '/=', '<', '<=', '>', + '>=','+', '-', '*','/', '%', '**', '^', '^^', + '>>=', '>>', '=<<', '$', '.', ',', '$!', + '++', '!!' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, /* functions name are case seinsitive */ + 3 => true, /* types name too */ + 4 => true, /* finally exceptions too */ + 5 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #06c; font-weight: bold;', /* nice blue */ + 2 => 'color: #06c; font-weight: bold;', /* blue as well */ + 3 => 'font-weight: bold;', /* make the preduled functions bold */ + 4 => 'color: #cccc00; font-weight: bold;', /* give types a different bg */ + 5 => 'color: maroon;' + ), + 'COMMENTS' => array( + 1 => 'color: #5d478b; font-style: italic;', + 2 => 'color: #339933; font-weight: bold;', + 'MULTI' => 'color: #5d478b; font-style: italic;' /* light purpHle */ + ), + 'ESCAPE_CHAR' => array( + 0 => 'background-color: #3cb371; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: green;' + ), + 'STRINGS' => array( + 0 => 'background-color: #3cb371;' /* nice green */ + ), + 'NUMBERS' => array( + 0 => 'color: red;' /* pink */ + ), + 'METHODS' => array( + 1 => 'color: #060;' /* dark green */ + ), + 'REGEXPS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #339933; font-weight: bold;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + /* some of keywords are Prelude functions */ + 1 => '', + /* link to the wanted library */ + 2 => 'http://haskell.org/ghc/docs/latest/html/libraries/base/{FNAME}.html', + /* link to Prelude functions */ + 3 => 'http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:{FNAME}', + /* link to Prelude types */ + 4 => 'http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:{FNAME}', + /* link to Prelude exceptions */ + 5 => 'http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:{FNAME}', + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/hq9plus.php b/examples/includes/geshi/geshi/hq9plus.php new file mode 100644 index 0000000..89e0434 --- /dev/null +++ b/examples/includes/geshi/geshi/hq9plus.php @@ -0,0 +1,104 @@ + 'HQ9+', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + ), + 'SYMBOLS' => array( + 'H', 'Q', '9', '+', 'h', 'q' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + ), + 'COMMENTS' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #a16000;' + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'KEYWORDS' => GESHI_NEVER, + 'COMMENTS' => GESHI_NEVER, + 'STRINGS' => GESHI_NEVER, + 'REGEXPS' => GESHI_NEVER, + 'NUMBERS' => GESHI_NEVER + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/html4strict.php b/examples/includes/geshi/geshi/html4strict.php new file mode 100644 index 0000000..68a0e51 --- /dev/null +++ b/examples/includes/geshi/geshi/html4strict.php @@ -0,0 +1,203 @@ + 'HTML', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 2 => array( + 'a', 'abbr', 'acronym', 'address', 'applet', + + 'base', 'basefont', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'b', + + 'caption', 'center', 'cite', 'code', 'colgroup', 'col', + + 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', + + 'em', + + 'fieldset', 'font', 'form', 'frame', 'frameset', + + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', + + 'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'i', + + 'kbd', + + 'label', 'legend', 'link', 'li', + + 'map', 'meta', + + 'noframes', 'noscript', + + 'object', 'ol', 'optgroup', 'option', + + 'param', 'pre', 'p', + + 'q', + + 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'style', 'sub', 'sup', 's', + + 'table', 'tbody', 'td', 'textarea', 'text', 'tfoot', 'thead', 'th', 'title', 'tr', 'tt', + + 'ul', 'u', + + 'var', + ), + 3 => array( + 'abbr', 'accept-charset', 'accept', 'accesskey', 'action', 'align', 'alink', 'alt', 'archive', 'axis', + 'background', 'bgcolor', 'border', + 'cellpadding', 'cellspacing', 'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'classid', 'clear', 'code', 'codebase', 'codetype', 'color', 'cols', 'colspan', 'compact', 'content', 'coords', + 'data', 'datetime', 'declare', 'defer', 'dir', 'disabled', + 'enctype', + 'face', 'for', 'frame', 'frameborder', + 'headers', 'height', 'href', 'hreflang', 'hspace', 'http-equiv', + 'id', 'ismap', + 'label', 'lang', 'language', 'link', 'longdesc', + 'marginheight', 'marginwidth', 'maxlength', 'media', 'method', 'multiple', + 'name', 'nohref', 'noresize', 'noshade', 'nowrap', + 'object', 'onblur', 'onchange', 'onclick', 'ondblclick', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onselect', 'onsubmit', 'onunload', + 'profile', 'prompt', + 'readonly', 'rel', 'rev', 'rowspan', 'rows', 'rules', + 'scheme', 'scope', 'scrolling', 'selected', 'shape', 'size', 'span', 'src', 'standby', 'start', 'style', 'summary', + 'tabindex', 'target', 'text', 'title', 'type', + 'usemap', + 'valign', 'value', 'valuetype', 'version', 'vlink', 'vspace', + 'width' + ) + ), + 'SYMBOLS' => array( + '/', '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + -1 => 'color: #808080; font-style: italic;', // comments + 0 => 'color: #00bbdd;', + 1 => 'color: #ddbb00;', + 2 => 'color: #009900;' + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 2 => 'http://december.com/html/4/element/{FNAMEL}.html', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + -1 => array( + '' + ), + 0 => array( + ' '>' + ), + 1 => array( + '&' => ';' + ), + 2 => array( + '<' => '>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + -1 => false, + 0 => false, + 1 => false, + 2 => true + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 2 => array( + 'DISALLOWED_BEFORE' => '(?<=<|<\/)', + 'DISALLOWED_AFTER' => '(?=\s|\/|>)', + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/idl.php b/examples/includes/geshi/geshi/idl.php new file mode 100644 index 0000000..a641554 --- /dev/null +++ b/examples/includes/geshi/geshi/idl.php @@ -0,0 +1,123 @@ + 'Uno Idl', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'published', 'get', 'set', 'service', 'singleton', 'type', 'module', 'interface', 'struct', + 'const', 'constants', 'exception', 'enum', 'raises', 'typedef' + ), + 2 => array( + 'bound', 'maybeambiguous', 'maybedefault', 'maybevoid', 'oneway', 'optional', + 'readonly', 'in', 'out', 'inout', 'attribute', 'transient', 'removable' + ), + 3 => array( + 'True', 'False', 'TRUE', 'FALSE' + ), + 4 => array( + 'string', 'long', 'byte', 'hyper', 'boolean', 'any', 'char', 'double', + 'void', 'sequence', 'unsigned' + ), + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', '&', ':', ';', '...' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #990078; font-weight: bold', + 2 => 'color: #36dd1c;', + 3 => 'color: #990078; font-weight: bold', + 4 => 'color: #0000ec;' + ), + 'COMMENTS' => array( + 1 => 'color: #3f7f5f;', + 2 => 'color: #808080;', + 'MULTI' => 'color: #4080ff; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #666666; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #808080;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000dd;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + 1 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/ini.php b/examples/includes/geshi/geshi/ini.php new file mode 100644 index 0000000..b6e3a38 --- /dev/null +++ b/examples/includes/geshi/geshi/ini.php @@ -0,0 +1,128 @@ + 'INI', + 'COMMENT_SINGLE' => array(0 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + ), + 'SYMBOLS' => array( + '[', ']', '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + ), + 'COMMENTS' => array( + 0 => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => '' + ), + 'STRINGS' => array( + 0 => 'color: #933;' + ), + 'NUMBERS' => array( + 0 => '' + ), + 'METHODS' => array( + 0 => '' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066; font-weight:bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #000066; font-weight:bold;', + 1 => 'color: #000099;', + 2 => 'color: #660066;' + ), + 'SCRIPT' => array( + 0 => '' + ) + ), + 'URLS' => array( + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Section names + 0 => '\[.+\]', + //Entry names + 1 => array( + GESHI_SEARCH => '^(\s*)([a-zA-Z0-9_\-]+)(\s*=)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + //Entry values + 2 => array( + // Evil hackery to get around GeSHi bug: <>" and ; are added so s can be matched + // Explicit match on variable names because if a comment is before the first < of the span + // gets chewed up... + GESHI_SEARCH => '([<>";a-zA-Z0-9_]+\s*)=(.*)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1=', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/inno.php b/examples/includes/geshi/geshi/inno.php new file mode 100644 index 0000000..5cead10 --- /dev/null +++ b/examples/includes/geshi/geshi/inno.php @@ -0,0 +1,212 @@ + 'Inno', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('(*' => '*)'), + 'CASE_KEYWORDS' => 0, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'Setup','Types','Components','Tasks','Dirs','Files','Icons','INI', + 'InstallDelete','Languages','Messages','CustomMessage', + 'LangOptions','Registry','RUN','UninstallDelete','UninstallRun', + 'app','win','sys','syswow64','src','sd','pf','pf32','pf64','cf', + 'cf32','cf64','tmp','fonts','dao','group','localappdata','sendto', + 'userappdata','commonappdata','userdesktop','commondesktop', + 'userdocs','commondocs','userfavorites','commonfavorites', + 'userprograms','commonprograms','userstartmenu','commonstartmenu', + 'userstartup','commonstartup','usertemplates','commontemplates' + ), + 2 => array( + 'nil', 'false', 'true', 'var', 'type', 'const','And', 'Array', 'As', 'Begin', 'Case', 'Class', 'Constructor', 'Destructor', 'Div', 'Do', 'DownTo', 'Else', + 'End', 'Except', 'File', 'Finally', 'For', 'Function', 'Goto', 'If', 'Implementation', 'In', 'Inherited', 'Interface', + 'Is', 'Mod', 'Not', 'Object', 'Of', 'On', 'Or', 'Packed', 'Procedure', 'Property', 'Raise', 'Record', + 'Repeat', 'Set', 'Shl', 'Shr', 'Then', 'ThreadVar', 'To', 'Try', 'Unit', 'Until', 'Uses', 'While', 'With', 'Xor', + + 'HKCC','HKCR','HKCU','HKLM','HKU','alwaysoverwrite','alwaysskipifsameorolder','append', + 'binary','classic','closeonexit','comparetimestamp','confirmoverwrite', + 'createkeyifdoesntexist','createonlyiffileexists','createvalueifdoesntexist', + 'deleteafterinstall','deletekey','deletevalue','dirifempty','dontcloseonexit', + 'dontcopy','dontcreatekey','disablenouninstallwarning','dword','exclusive','expandsz', + 'external','files','filesandordirs','fixed','fontisnttruetype','ignoreversion','iscustom','isreadme', + 'modern','multisz','new','noerror','none','normal','nowait','onlyifdestfileexists', + 'onlyifdoesntexist','onlyifnewer','overwrite','overwritereadonly','postinstall', + 'preservestringtype','promptifolder','regserver','regtypelib','restart','restartreplace', + 'runhidden','runmaximized','runminimized','sharedfile','shellexec','showcheckbox', + 'skipifnotsilent','skipifsilent','silent','skipifdoesntexist', + 'skipifsourcedoesntexist','sortfilesbyextension','unchecked','uninsalwaysuninstall', + 'uninsclearvalue','uninsdeleteentry','uninsdeletekey','uninsdeletekeyifempty', + 'uninsdeletesection','uninsdeletesectionifempty','uninsdeletevalue', + 'uninsneveruninstall','useapppaths','verysilent','waituntilidle' + ), + 3 => array( + 'Abs', 'Addr', 'AnsiCompareStr', 'AnsiCompareText', 'AnsiContainsStr', 'AnsiEndsStr', 'AnsiIndexStr', 'AnsiLeftStr', + 'AnsiLowerCase', 'AnsiMatchStr', 'AnsiMidStr', 'AnsiPos', 'AnsiReplaceStr', 'AnsiReverseString', 'AnsiRightStr', + 'AnsiStartsStr', 'AnsiUpperCase', 'ArcCos', 'ArcSin', 'ArcTan', 'Assigned', 'BeginThread', 'Bounds', 'CelsiusToFahrenheit', + 'ChangeFileExt', 'Chr', 'CompareStr', 'CompareText', 'Concat', 'Convert', 'Copy', 'Cos', 'CreateDir', 'CurrToStr', + 'CurrToStrF', 'Date', 'DateTimeToFileDate', 'DateTimeToStr', 'DateToStr', 'DayOfTheMonth', 'DayOfTheWeek', 'DayOfTheYear', + 'DayOfWeek', 'DaysBetween', 'DaysInAMonth', 'DaysInAYear', 'DaySpan', 'DegToRad', 'DeleteFile', 'DiskFree', 'DiskSize', + 'DupeString', 'EncodeDate', 'EncodeDateTime', 'EncodeTime', 'EndOfADay', 'EndOfAMonth', 'Eof', 'Eoln', 'Exp', 'ExtractFileDir', + 'ExtractFileDrive', 'ExtractFileExt', 'ExtractFileName', 'ExtractFilePath', 'FahrenheitToCelsius', 'FileAge', + 'FileDateToDateTime', 'FileExists', 'FilePos', 'FileSearch', 'FileSetDate', 'FileSize', 'FindClose', 'FindCmdLineSwitch', + 'FindFirst', 'FindNext', 'FloatToStr', 'FloatToStrF', 'Format', 'FormatCurr', 'FormatDateTime', 'FormatFloat', 'Frac', + 'GetCurrentDir', 'GetLastError', 'GetMem', 'High', 'IncDay', 'IncMinute', 'IncMonth', 'IncYear', 'InputBox', + 'InputQuery', 'Int', 'IntToHex', 'IntToStr', 'IOResult', 'IsInfinite', 'IsLeapYear', 'IsMultiThread', 'IsNaN', + 'LastDelimiter', 'Length', 'Ln', 'Lo', 'Log10', 'Low', 'LowerCase', 'Max', 'Mean', 'MessageDlg', 'MessageDlgPos', + 'MonthOfTheYear', 'Now', 'Odd', 'Ord', 'ParamCount', 'ParamStr', 'Pi', 'Point', 'PointsEqual', 'Pos', 'Pred', + 'Printer', 'PromptForFileName', 'PtInRect', 'RadToDeg', 'Random', 'RandomRange', 'RecodeDate', 'RecodeTime', 'Rect', + 'RemoveDir', 'RenameFile', 'Round', 'SeekEof', 'SeekEoln', 'SelectDirectory', 'SetCurrentDir', 'Sin', 'SizeOf', + 'Slice', 'Sqr', 'Sqrt', 'StringOfChar', 'StringReplace', 'StringToWideChar', 'StrToCurr', 'StrToDate', 'StrToDateTime', + 'StrToFloat', 'StrToInt', 'StrToInt64', 'StrToInt64Def', 'StrToIntDef', 'StrToTime', 'StuffString', 'Succ', 'Sum', 'Tan', + 'Time', 'TimeToStr', 'Tomorrow', 'Trunc', 'UpCase', 'UpperCase', 'VarType', 'WideCharToString', 'WrapText', 'Yesterday', + 'Append', 'AppendStr', 'Assign', 'AssignFile', 'AssignPrn', 'Beep', 'BlockRead', 'BlockWrite', 'Break', + 'ChDir', 'Close', 'CloseFile', 'Continue', 'DateTimeToString', 'Dec', 'DecodeDate', 'DecodeDateTime', + 'DecodeTime', 'Delete', 'Dispose', 'EndThread', 'Erase', 'Exclude', 'Exit', 'FillChar', 'Flush', 'FreeAndNil', + 'FreeMem', 'GetDir', 'GetLocaleFormatSettings', 'Halt', 'Inc', 'Include', 'Insert', 'MkDir', 'Move', 'New', + 'ProcessPath', 'Randomize', 'Read', 'ReadLn', 'ReallocMem', 'Rename', 'ReplaceDate', 'ReplaceTime', + 'Reset', 'ReWrite', 'RmDir', 'RunError', 'Seek', 'SetLength', 'SetString', 'ShowMessage', 'ShowMessageFmt', + 'ShowMessagePos', 'Str', 'Truncate', 'Val', 'Write', 'WriteLn', + + 'AdminPrivilegesRequired','AfterInstall','AllowCancelDuringInstall','AllowNoIcons','AllowRootDirectory','AllowUNCPath','AlwaysRestart','AlwaysShowComponentsList','AlwaysShowDirOnReadyPage','AlwaysShowGroupOnReadyPage ','AlwaysUsePersonalGroup','AppComments','AppContact','AppCopyright','AppendDefaultDirName', + 'AppendDefaultGroupName','AppId','AppModifyPath','AppMutex','AppName','AppPublisher', + 'AppPublisherURL','AppReadmeFile','AppSupportURL','AppUpdatesURL','AppVerName','AppVersion', + 'Attribs','BackColor','BackColor2','BackColorDirection','BackSolid','BeforeInstall', + 'ChangesAssociations','ChangesEnvironment','Check','CodeFile','Comment','Compression','CopyMode', + 'CreateAppDir','CreateUninstallRegKey','DefaultDirName','DefaultGroupName', + 'DefaultUserInfoName','DefaultUserInfoOrg','DefaultUserInfoSerial', + 'Description','DestDir','DestName','DirExistsWarning', + 'DisableDirPage','DisableFinishedPage', + 'DisableProgramGroupPage','DisableReadyMemo','DisableReadyPage', + 'DisableStartupPrompt','DiskClusterSize','DiskSliceSize','DiskSpaceMBLabel', + 'DiskSpanning','DontMergeDuplicateFiles','EnableDirDoesntExistWarning','Encryption', + 'Excludes','ExtraDiskSpaceRequired','Filename','Flags','FlatComponentsList','FontInstall', + 'GroupDescription','HotKey','IconFilename','IconIndex','InfoAfterFile','InfoBeforeFile', + 'InternalCompressLevel','Key','LanguageDetectionMethod', + 'LicenseFile','MergeDuplicateFiles','MessagesFile','MinVersion','Name', + 'OnlyBelowVersion','OutputBaseFilename','OutputManifestFile','OutputDir', + 'Parameters','Password','Permissions','PrivilegesRequired','ReserveBytes', + 'RestartIfNeededByRun','Root','RunOnceId','Section','SetupIconFile', + 'ShowComponentSizes','ShowLanguageDialog','ShowTasksTreeLines','SlicesPerDisk', + 'SolidCompression','Source','SourceDir','StatusMsg','Subkey', + 'TimeStampRounding','TimeStampsInUTC','TouchDate','TouchTime','Type', + 'UninstallDisplayIcon','UninstallDisplayName','UninstallFilesDir','UninstallIconFile', + 'UninstallLogMode','UninstallRestartComputer','UninstallStyle','Uninstallable', + 'UpdateUninstallLogAppName','UsePreviousAppDir','UsePreviousGroup', + 'UsePreviousTasks','UsePreviousSetupType','UsePreviousUserInfo', + 'UserInfoPage','UseSetupLdr','ValueData','ValueName','ValueType', + 'VersionInfoVersion','VersionInfoCompany','VersionInfoDescription','VersionInfoTextVersion', + 'WindowResizable','WindowShowCaption','WindowStartMaximized', + 'WindowVisible','WizardImageBackColor','WizardImageFile','WizardImageStretch','WizardSmallImageBackColor','WizardSmallImageFile','WizardStyle','WorkingDir' + ), + 4 => array( + 'AnsiChar', 'AnsiString', 'Boolean', 'Byte', 'Cardinal', 'Char', 'Comp', 'Currency', 'Double', 'Extended', + 'Int64', 'Integer', 'LongInt', 'LongWord', 'PAnsiChar', 'PAnsiString', 'PChar', 'PCurrency', 'PDateTime', + 'PExtended', 'PInt64', 'Pointer', 'PShortString', 'PString', 'PVariant', 'PWideChar', 'PWideString', + 'Real', 'Real48', 'ShortInt', 'ShortString', 'Single', 'SmallInt', 'String', 'TBits', 'TConvType', 'TDateTime', + 'Text', 'TextFile', 'TFloatFormat', 'TFormatSettings', 'TList', 'TObject', 'TOpenDialog', 'TPoint', + 'TPrintDialog', 'TRect', 'TReplaceFlags', 'TSaveDialog', 'TSearchRec', 'TStringList', 'TSysCharSet', + 'TThreadFunc', 'Variant', 'WideChar', 'WideString', 'Word' + ), + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '@', '%', '&', '*', '|', '/', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;',/*bold Black*/ + 2 => 'color: #000000;font-style: italic;',/*Black*/ + 3 => 'color: #0000FF;',/*blue*/ + 4 => 'color: #CC0000;'/*red*/ + ), + 'COMMENTS' => array( + 1 => 'color: #33FF00; font-style: italic;', + 'MULTI' => 'color: #33FF00; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'REGEXPS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000000; font-weight: bold;', + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/intercal.php b/examples/includes/geshi/geshi/intercal.php new file mode 100644 index 0000000..b4ad049 --- /dev/null +++ b/examples/includes/geshi/geshi/intercal.php @@ -0,0 +1,122 @@ + 'INTERCAL', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + //Politeness + 1 => array( + 'DO', 'DOES', 'DONT', 'DON\'T', 'NOT', 'PLEASE', 'PLEASENT', 'PLEASEN\'T', 'MAYBE' + ), + //Statements + 2 => array( + 'STASH', 'RETRIEVE', 'NEXT', 'RESUME', 'FORGET', 'ABSTAIN', 'ABSTAINING', + 'COME', 'FROM', 'CALCULATING', 'REINSTATE', 'IGNORE', 'REMEMBER', + 'WRITE', 'IN', 'READ', 'OUT', 'GIVE', 'UP' + ) + ), + 'SYMBOLS' => array( + '.', ',', ':', ';', '#', + '~', '$', '&', '?', + '\'', '"', '<-' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000080; font-weight: bold;', + 2 => 'color: #000080; font-weight: bold;' + ), + 'COMMENTS' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 1 => 'color: #808080; font-style: italic;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 1 => '^\(\d+\)' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'COMMENTS' => GESHI_NEVER, + 'STRINGS' => GESHI_NEVER, + 'NUMBERS' => GESHI_NEVER + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/io.php b/examples/includes/geshi/geshi/io.php new file mode 100644 index 0000000..e9117ab --- /dev/null +++ b/examples/includes/geshi/geshi/io.php @@ -0,0 +1,138 @@ + 'Io', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'and', 'break', 'else', 'elseif', 'exit', 'for', 'foreach', 'if', 'ifFalse', 'ifNil', + 'ifTrue', 'or', 'pass', 'raise', 'return', 'then', 'try', 'wait', 'while', 'yield' + ), + 2 => array( + 'activate', 'activeCoroCount', 'asString', 'block', 'catch', 'clone', 'collectGarbage', + 'compileString', 'continue', 'do', 'doFile', 'doMessage', 'doString', 'forward', + 'getSlot', 'getenv', 'hasSlot', 'isActive', 'isNil', 'isResumable', 'list', 'message', + 'method', 'parent', 'pause', 'perform', 'performWithArgList', 'print', 'proto', + 'raiseResumable', 'removeSlot', 'resend', 'resume', 'schedulerSleepSeconds', 'self', + 'sender', 'setSchedulerSleepSeconds', 'setSlot', 'shallowCopy', 'slotNames', 'super', + 'system', 'thisBlock', 'thisContext', 'thisMessage', 'type', 'uniqueId', 'updateSlot', + 'write' + ), + 3 => array( + 'Array', 'AudioDevice', 'AudioMixer', 'Block', 'Box', 'Buffer', 'CFunction', 'CGI', + 'Color', 'Curses', 'DBM', 'DNSResolver', 'DOConnection', 'DOProxy', 'DOServer', + 'Date', 'Directory', 'Duration', 'DynLib', 'Error', 'Exception', 'FFT', 'File', + 'Fnmatch', 'Font', 'Future', 'GL', 'GLE', 'GLScissor', 'GLU', 'GLUCylinder', + 'GLUQuadric', 'GLUSphere', 'GLUT', 'Host', 'Image', 'Importer', 'LinkList', 'List', + 'Lobby', 'Locals', 'MD5', 'MP3Decoder', 'MP3Encoder', 'Map', 'Message', 'Movie', + 'NULL', 'Nil', 'Nop', 'Notifiction', 'Number', 'Object', 'OpenGL', 'Point', 'Protos', + 'Regex', 'SGMLTag', 'SQLite', 'Server', 'ShowMessage', 'SleepyCat', 'SleepyCatCursor', + 'Socket', 'SocketManager', 'Sound', 'Soup', 'Store', 'String', 'Tree', 'UDPSender', + 'UDPReceiver', 'URL', 'User', 'Warning', 'WeakLink' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '@', '%', '&', '*', '|', '/', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + 0 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/java.php b/examples/includes/geshi/geshi/java.php new file mode 100644 index 0000000..7e5dc08 --- /dev/null +++ b/examples/includes/geshi/geshi/java.php @@ -0,0 +1,983 @@ + 'Java', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Import and Package directives (Basic Support only) + 2 => '/(?:(?<=import[\\n\\s])|(?<=package[\\n\\s]))[\\n\\s]*([a-zA-Z0-9_]+\\.)*([a-zA-Z0-9_]+|\*)(?=[\n\s;])/i', + // javadoc comments + 3 => '#/\*\*(?![\*\/]).*\*/#sU' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'for', 'foreach', 'if', 'else', 'while', 'do', + 'switch', 'case', 'return', 'public', + 'private', 'protected', 'extends', 'break', 'class', + 'new', 'try', 'catch', 'throws', 'finally', 'implements', + 'interface', 'throw', 'final', 'native', 'synchronized', 'this', + 'abstract', 'transient', 'instanceof', 'assert', 'continue', + 'default', 'enum', 'package', 'static', 'strictfp', 'super', + 'volatile', 'const', 'goto', 'import' + ), + 2 => array( + 'null', 'false', 'true' + ), + 3 => array( + 'AbstractAction', 'AbstractBorder', 'AbstractButton', + 'AbstractCellEditor', 'AbstractCollection', + 'AbstractColorChooserPanel', 'AbstractDocument', + 'AbstractDocument.AttributeContext', + 'AbstractDocument.Content', + 'AbstractDocument.ElementEdit', + 'AbstractLayoutCache', + 'AbstractLayoutCache.NodeDimensions', 'AbstractList', + 'AbstractListModel', 'AbstractMap', + 'AbstractMethodError', 'AbstractSequentialList', + 'AbstractSet', 'AbstractTableModel', + 'AbstractUndoableEdit', 'AbstractWriter', + 'AccessControlContext', 'AccessControlException', + 'AccessController', 'AccessException', 'Accessible', + 'AccessibleAction', 'AccessibleBundle', + 'AccessibleComponent', 'AccessibleContext', + 'AccessibleHyperlink', 'AccessibleHypertext', + 'AccessibleIcon', 'AccessibleObject', + 'AccessibleRelation', 'AccessibleRelationSet', + 'AccessibleResourceBundle', 'AccessibleRole', + 'AccessibleSelection', 'AccessibleState', + 'AccessibleStateSet', 'AccessibleTable', + 'AccessibleTableModelChange', 'AccessibleText', + 'AccessibleValue', 'Acl', 'AclEntry', + 'AclNotFoundException', 'Action', 'ActionEvent', + 'ActionListener', 'ActionMap', 'ActionMapUIResource', + 'Activatable', 'ActivateFailedException', + 'ActivationDesc', 'ActivationException', + 'ActivationGroup', 'ActivationGroupDesc', + 'ActivationGroupDesc.CommandEnvironment', + 'ActivationGroupID', 'ActivationID', + 'ActivationInstantiator', 'ActivationMonitor', + 'ActivationSystem', 'Activator', 'ActiveEvent', + 'Adjustable', 'AdjustmentEvent', + 'AdjustmentListener', 'Adler32', 'AffineTransform', + 'AffineTransformOp', 'AlgorithmParameterGenerator', + 'AlgorithmParameterGeneratorSpi', + 'AlgorithmParameters', 'AlgorithmParameterSpec', + 'AlgorithmParametersSpi', 'AllPermission', + 'AlphaComposite', 'AlreadyBound', + 'AlreadyBoundException', 'AlreadyBoundHelper', + 'AlreadyBoundHolder', 'AncestorEvent', + 'AncestorListener', 'Annotation', 'Any', 'AnyHolder', + 'AnySeqHelper', 'AnySeqHolder', 'Applet', + 'AppletContext', 'AppletInitializer', 'AppletStub', + 'ApplicationException', 'Arc2D', 'Arc2D.Double', + 'Arc2D.Float', 'Area', 'AreaAveragingScaleFilter', + 'ARG_IN', 'ARG_INOUT', 'ARG_OUT', + 'ArithmeticException', 'Array', + 'ArrayIndexOutOfBoundsException', 'ArrayList', + 'Arrays', 'ArrayStoreException', 'AsyncBoxView', + 'Attribute', 'AttributedCharacterIterator', + 'AttributedCharacterIterator.Attribute', + 'AttributedString', 'AttributeInUseException', + 'AttributeList', 'AttributeModificationException', + 'Attributes', 'Attributes.Name', 'AttributeSet', + 'AttributeSet.CharacterAttribute', + 'AttributeSet.ColorAttribute', + 'AttributeSet.FontAttribute', + 'AttributeSet.ParagraphAttribute', 'AudioClip', + 'AudioFileFormat', 'AudioFileFormat.Type', + 'AudioFileReader', 'AudioFileWriter', 'AudioFormat', + 'AudioFormat.Encoding', 'AudioInputStream', + 'AudioPermission', 'AudioSystem', + 'AuthenticationException', + 'AuthenticationNotSupportedException', + 'Authenticator', 'Autoscroll', 'AWTError', + 'AWTEvent', 'AWTEventListener', + 'AWTEventMulticaster', 'AWTException', + 'AWTPermission', 'BadKind', 'BadLocationException', + 'BAD_CONTEXT', 'BAD_INV_ORDER', 'BAD_OPERATION', + 'BAD_PARAM', 'BAD_POLICY', 'BAD_POLICY_TYPE', + 'BAD_POLICY_VALUE', 'BAD_TYPECODE', 'BandCombineOp', + 'BandedSampleModel', 'BasicArrowButton', + 'BasicAttribute', 'BasicAttributes', 'BasicBorders', + 'BasicBorders.ButtonBorder', + 'BasicBorders.FieldBorder', + 'BasicBorders.MarginBorder', + 'BasicBorders.MenuBarBorder', + 'BasicBorders.RadioButtonBorder', + 'BasicBorders.SplitPaneBorder', + 'BasicBorders.ToggleButtonBorder', + 'BasicButtonListener', 'BasicButtonUI', + 'BasicCheckBoxMenuItemUI', 'BasicCheckBoxUI', + 'BasicColorChooserUI', 'BasicComboBoxEditor', + 'BasicComboBoxEditor.UIResource', + 'BasicComboBoxRenderer', + 'BasicComboBoxRenderer.UIResource', + 'BasicComboBoxUI', 'BasicComboPopup', + 'BasicDesktopIconUI', 'BasicDesktopPaneUI', + 'BasicDirectoryModel', 'BasicEditorPaneUI', + 'BasicFileChooserUI', 'BasicGraphicsUtils', + 'BasicHTML', 'BasicIconFactory', + 'BasicInternalFrameTitlePane', + 'BasicInternalFrameUI', 'BasicLabelUI', + 'BasicListUI', 'BasicLookAndFeel', 'BasicMenuBarUI', + 'BasicMenuItemUI', 'BasicMenuUI', + 'BasicOptionPaneUI', + 'BasicOptionPaneUI.ButtonAreaLayout', 'BasicPanelUI', + 'BasicPasswordFieldUI', 'BasicPermission', + 'BasicPopupMenuSeparatorUI', 'BasicPopupMenuUI', + 'BasicProgressBarUI', 'BasicRadioButtonMenuItemUI', + 'BasicRadioButtonUI', 'BasicRootPaneUI', + 'BasicScrollBarUI', 'BasicScrollPaneUI', + 'BasicSeparatorUI', 'BasicSliderUI', + 'BasicSplitPaneDivider', 'BasicSplitPaneUI', + 'BasicStroke', 'BasicTabbedPaneUI', + 'BasicTableHeaderUI', 'BasicTableUI', + 'BasicTextAreaUI', 'BasicTextFieldUI', + 'BasicTextPaneUI', 'BasicTextUI', + 'BasicTextUI.BasicCaret', + 'BasicTextUI.BasicHighlighter', + 'BasicToggleButtonUI', 'BasicToolBarSeparatorUI', + 'BasicToolBarUI', 'BasicToolTipUI', 'BasicTreeUI', + 'BasicViewportUI', 'BatchUpdateException', + 'BeanContext', 'BeanContextChild', + 'BeanContextChildComponentProxy', + 'BeanContextChildSupport', + 'BeanContextContainerProxy', 'BeanContextEvent', + 'BeanContextMembershipEvent', + 'BeanContextMembershipListener', 'BeanContextProxy', + 'BeanContextServiceAvailableEvent', + 'BeanContextServiceProvider', + 'BeanContextServiceProviderBeanInfo', + 'BeanContextServiceRevokedEvent', + 'BeanContextServiceRevokedListener', + 'BeanContextServices', 'BeanContextServicesListener', + 'BeanContextServicesSupport', + 'BeanContextServicesSupport.BCSSServiceProvider', + 'BeanContextSupport', + 'BeanContextSupport.BCSIterator', 'BeanDescriptor', + 'BeanInfo', 'Beans', 'BevelBorder', 'BigDecimal', + 'BigInteger', 'BinaryRefAddr', 'BindException', + 'Binding', 'BindingHelper', 'BindingHolder', + 'BindingIterator', 'BindingIteratorHelper', + 'BindingIteratorHolder', 'BindingIteratorOperations', + 'BindingListHelper', 'BindingListHolder', + 'BindingType', 'BindingTypeHelper', + 'BindingTypeHolder', 'BitSet', 'Blob', 'BlockView', + 'Book', 'Boolean', 'BooleanControl', + 'BooleanControl.Type', 'BooleanHolder', + 'BooleanSeqHelper', 'BooleanSeqHolder', 'Border', + 'BorderFactory', 'BorderLayout', 'BorderUIResource', + 'BorderUIResource.BevelBorderUIResource', + 'BorderUIResource.CompoundBorderUIResource', + 'BorderUIResource.EmptyBorderUIResource', + 'BorderUIResource.EtchedBorderUIResource', + 'BorderUIResource.LineBorderUIResource', + 'BorderUIResource.MatteBorderUIResource', + 'BorderUIResource.TitledBorderUIResource', + 'BoundedRangeModel', 'Bounds', 'Box', 'Box.Filler', + 'BoxedValueHelper', 'BoxLayout', 'BoxView', + 'BreakIterator', 'BufferedImage', + 'BufferedImageFilter', 'BufferedImageOp', + 'BufferedInputStream', 'BufferedOutputStream', + 'BufferedReader', 'BufferedWriter', 'Button', + 'ButtonGroup', 'ButtonModel', 'ButtonUI', 'Byte', + 'ByteArrayInputStream', 'ByteArrayOutputStream', + 'ByteHolder', 'ByteLookupTable', 'Calendar', + 'CallableStatement', 'CannotProceed', + 'CannotProceedException', 'CannotProceedHelper', + 'CannotProceedHolder', 'CannotRedoException', + 'CannotUndoException', 'Canvas', 'CardLayout', + 'Caret', 'CaretEvent', 'CaretListener', 'CellEditor', + 'CellEditorListener', 'CellRendererPane', + 'Certificate', 'Certificate.CertificateRep', + 'CertificateEncodingException', + 'CertificateException', + 'CertificateExpiredException', 'CertificateFactory', + 'CertificateFactorySpi', + 'CertificateNotYetValidException', + 'CertificateParsingException', + 'ChangedCharSetException', 'ChangeEvent', + 'ChangeListener', 'Character', 'Character.Subset', + 'Character.UnicodeBlock', 'CharacterIterator', + 'CharArrayReader', 'CharArrayWriter', + 'CharConversionException', 'CharHolder', + 'CharSeqHelper', 'CharSeqHolder', 'Checkbox', + 'CheckboxGroup', 'CheckboxMenuItem', + 'CheckedInputStream', 'CheckedOutputStream', + 'Checksum', 'Choice', 'ChoiceFormat', 'Class', + 'ClassCastException', 'ClassCircularityError', + 'ClassDesc', 'ClassFormatError', 'ClassLoader', + 'ClassNotFoundException', 'Clip', 'Clipboard', + 'ClipboardOwner', 'Clob', 'Cloneable', + 'CloneNotSupportedException', 'CMMException', + 'CodeSource', 'CollationElementIterator', + 'CollationKey', 'Collator', 'Collection', + 'Collections', 'Color', + 'ColorChooserComponentFactory', 'ColorChooserUI', + 'ColorConvertOp', 'ColorModel', + 'ColorSelectionModel', 'ColorSpace', + 'ColorUIResource', 'ComboBoxEditor', 'ComboBoxModel', + 'ComboBoxUI', 'ComboPopup', 'CommunicationException', + 'COMM_FAILURE', 'Comparable', 'Comparator', + 'Compiler', 'CompletionStatus', + 'CompletionStatusHelper', 'Component', + 'ComponentAdapter', 'ComponentColorModel', + 'ComponentEvent', 'ComponentInputMap', + 'ComponentInputMapUIResource', 'ComponentListener', + 'ComponentOrientation', 'ComponentSampleModel', + 'ComponentUI', 'ComponentView', 'Composite', + 'CompositeContext', 'CompositeName', 'CompositeView', + 'CompoundBorder', 'CompoundControl', + 'CompoundControl.Type', 'CompoundEdit', + 'CompoundName', 'ConcurrentModificationException', + 'ConfigurationException', 'ConnectException', + 'ConnectIOException', 'Connection', 'Constructor', 'Container', + 'ContainerAdapter', 'ContainerEvent', + 'ContainerListener', 'ContentHandler', + 'ContentHandlerFactory', 'ContentModel', 'Context', + 'ContextList', 'ContextNotEmptyException', + 'ContextualRenderedImageFactory', 'Control', + 'Control.Type', 'ControlFactory', + 'ControllerEventListener', 'ConvolveOp', 'CRC32', + 'CRL', 'CRLException', 'CropImageFilter', 'CSS', + 'CSS.Attribute', 'CTX_RESTRICT_SCOPE', + 'CubicCurve2D', 'CubicCurve2D.Double', + 'CubicCurve2D.Float', 'Current', 'CurrentHelper', + 'CurrentHolder', 'CurrentOperations', 'Cursor', + 'Customizer', 'CustomMarshal', 'CustomValue', + 'DatabaseMetaData', 'DataBuffer', 'DataBufferByte', + 'DataBufferInt', 'DataBufferShort', + 'DataBufferUShort', 'DataFlavor', + 'DataFormatException', 'DatagramPacket', + 'DatagramSocket', 'DatagramSocketImpl', + 'DatagramSocketImplFactory', 'DataInput', + 'DataInputStream', 'DataLine', 'DataLine.Info', + 'DataOutput', 'DataOutputStream', + 'DataTruncation', 'DATA_CONVERSION', 'Date', + 'DateFormat', 'DateFormatSymbols', 'DebugGraphics', + 'DecimalFormat', 'DecimalFormatSymbols', + 'DefaultBoundedRangeModel', 'DefaultButtonModel', + 'DefaultCaret', 'DefaultCellEditor', + 'DefaultColorSelectionModel', 'DefaultComboBoxModel', + 'DefaultDesktopManager', 'DefaultEditorKit', + 'DefaultEditorKit.BeepAction', + 'DefaultEditorKit.CopyAction', + 'DefaultEditorKit.CutAction', + 'DefaultEditorKit.DefaultKeyTypedAction', + 'DefaultEditorKit.InsertBreakAction', + 'DefaultEditorKit.InsertContentAction', + 'DefaultEditorKit.InsertTabAction', + 'DefaultEditorKit.PasteAction,', + 'DefaultFocusManager', 'DefaultHighlighter', + 'DefaultHighlighter.DefaultHighlightPainter', + 'DefaultListCellRenderer', + 'DefaultListCellRenderer.UIResource', + 'DefaultListModel', 'DefaultListSelectionModel', + 'DefaultMenuLayout', 'DefaultMetalTheme', + 'DefaultMutableTreeNode', + 'DefaultSingleSelectionModel', + 'DefaultStyledDocument', + 'DefaultStyledDocument.AttributeUndoableEdit', + 'DefaultStyledDocument.ElementSpec', + 'DefaultTableCellRenderer', + 'DefaultTableCellRenderer.UIResource', + 'DefaultTableColumnModel', 'DefaultTableModel', + 'DefaultTextUI', 'DefaultTreeCellEditor', + 'DefaultTreeCellRenderer', 'DefaultTreeModel', + 'DefaultTreeSelectionModel', 'DefinitionKind', + 'DefinitionKindHelper', 'Deflater', + 'DeflaterOutputStream', 'Delegate', 'DesignMode', + 'DesktopIconUI', 'DesktopManager', 'DesktopPaneUI', + 'DGC', 'Dialog', 'Dictionary', 'DigestException', + 'DigestInputStream', 'DigestOutputStream', + 'Dimension', 'Dimension2D', 'DimensionUIResource', + 'DirContext', 'DirectColorModel', 'DirectoryManager', + 'DirObjectFactory', 'DirStateFactory', + 'DirStateFactory.Result', 'DnDConstants', 'Document', + 'DocumentEvent', 'DocumentEvent.ElementChange', + 'DocumentEvent.EventType', 'DocumentListener', + 'DocumentParser', 'DomainCombiner', 'DomainManager', + 'DomainManagerOperations', 'Double', 'DoubleHolder', + 'DoubleSeqHelper', 'DoubleSeqHolder', + 'DragGestureEvent', 'DragGestureListener', + 'DragGestureRecognizer', 'DragSource', + 'DragSourceContext', 'DragSourceDragEvent', + 'DragSourceDropEvent', 'DragSourceEvent', + 'DragSourceListener', 'Driver', 'DriverManager', + 'DriverPropertyInfo', 'DropTarget', + 'DropTarget.DropTargetAutoScroller', + 'DropTargetContext', 'DropTargetDragEvent', + 'DropTargetDropEvent', 'DropTargetEvent', + 'DropTargetListener', 'DSAKey', + 'DSAKeyPairGenerator', 'DSAParameterSpec', + 'DSAParams', 'DSAPrivateKey', 'DSAPrivateKeySpec', + 'DSAPublicKey', 'DSAPublicKeySpec', 'DTD', + 'DTDConstants', 'DynamicImplementation', 'DynAny', + 'DynArray', 'DynEnum', 'DynFixed', 'DynSequence', + 'DynStruct', 'DynUnion', 'DynValue', 'EditorKit', + 'Element', 'ElementIterator', 'Ellipse2D', + 'Ellipse2D.Double', 'Ellipse2D.Float', 'EmptyBorder', + 'EmptyStackException', 'EncodedKeySpec', 'Entity', + 'EnumControl', 'EnumControl.Type', 'Enumeration', + 'Environment', 'EOFException', 'Error', + 'EtchedBorder', 'Event', 'EventContext', + 'EventDirContext', 'EventListener', + 'EventListenerList', 'EventObject', 'EventQueue', + 'EventSetDescriptor', 'Exception', + 'ExceptionInInitializerError', 'ExceptionList', + 'ExpandVetoException', 'ExportException', + 'ExtendedRequest', 'ExtendedResponse', + 'Externalizable', 'FeatureDescriptor', 'Field', + 'FieldNameHelper', 'FieldPosition', 'FieldView', + 'File', 'FileChooserUI', 'FileDescriptor', + 'FileDialog', 'FileFilter', + 'FileInputStream', 'FilenameFilter', 'FileNameMap', + 'FileNotFoundException', 'FileOutputStream', + 'FilePermission', 'FileReader', 'FileSystemView', + 'FileView', 'FileWriter', 'FilteredImageSource', + 'FilterInputStream', 'FilterOutputStream', + 'FilterReader', 'FilterWriter', + 'FixedHeightLayoutCache', 'FixedHolder', + 'FlatteningPathIterator', 'FlavorMap', 'Float', + 'FloatControl', 'FloatControl.Type', 'FloatHolder', + 'FloatSeqHelper', 'FloatSeqHolder', 'FlowLayout', + 'FlowView', 'FlowView.FlowStrategy', 'FocusAdapter', + 'FocusEvent', 'FocusListener', 'FocusManager', + 'Font', 'FontFormatException', 'FontMetrics', + 'FontRenderContext', 'FontUIResource', 'Format', + 'FormatConversionProvider', 'FormView', 'Frame', + 'FREE_MEM', 'GapContent', 'GeneralPath', + 'GeneralSecurityException', 'GlyphJustificationInfo', + 'GlyphMetrics', 'GlyphVector', 'GlyphView', + 'GlyphView.GlyphPainter', 'GradientPaint', + 'GraphicAttribute', 'Graphics', 'Graphics2D', + 'GraphicsConfigTemplate', 'GraphicsConfiguration', + 'GraphicsDevice', 'GraphicsEnvironment', + 'GrayFilter', 'GregorianCalendar', + 'GridBagConstraints', 'GridBagLayout', 'GridLayout', + 'Group', 'Guard', 'GuardedObject', 'GZIPInputStream', + 'GZIPOutputStream', 'HasControls', 'HashMap', + 'HashSet', 'Hashtable', 'HierarchyBoundsAdapter', + 'HierarchyBoundsListener', 'HierarchyEvent', + 'HierarchyListener', 'Highlighter', + 'Highlighter.Highlight', + 'Highlighter.HighlightPainter', 'HTML', + 'HTML.Attribute', 'HTML.Tag', 'HTML.UnknownTag', + 'HTMLDocument', 'HTMLDocument.Iterator', + 'HTMLEditorKit', 'HTMLEditorKit.HTMLFactory', + 'HTMLEditorKit.HTMLTextAction', + 'HTMLEditorKit.InsertHTMLTextAction', + 'HTMLEditorKit.LinkController', + 'HTMLEditorKit.Parser', + 'HTMLEditorKit.ParserCallback', + 'HTMLFrameHyperlinkEvent', 'HTMLWriter', + 'HttpURLConnection', 'HyperlinkEvent', + 'HyperlinkEvent.EventType', 'HyperlinkListener', + 'ICC_ColorSpace', 'ICC_Profile', 'ICC_ProfileGray', + 'ICC_ProfileRGB', 'Icon', 'IconUIResource', + 'IconView', 'IdentifierHelper', 'Identity', + 'IdentityScope', 'IDLEntity', 'IDLType', + 'IDLTypeHelper', 'IDLTypeOperations', + 'IllegalAccessError', 'IllegalAccessException', + 'IllegalArgumentException', + 'IllegalComponentStateException', + 'IllegalMonitorStateException', + 'IllegalPathStateException', 'IllegalStateException', + 'IllegalThreadStateException', 'Image', + 'ImageConsumer', 'ImageFilter', + 'ImageGraphicAttribute', 'ImageIcon', + 'ImageObserver', 'ImageProducer', + 'ImagingOpException', 'IMP_LIMIT', + 'IncompatibleClassChangeError', + 'InconsistentTypeCode', 'IndexColorModel', + 'IndexedPropertyDescriptor', + 'IndexOutOfBoundsException', 'IndirectionException', + 'InetAddress', 'Inflater', 'InflaterInputStream', + 'InheritableThreadLocal', 'InitialContext', + 'InitialContextFactory', + 'InitialContextFactoryBuilder', 'InitialDirContext', + 'INITIALIZE', 'Initializer', 'InitialLdapContext', + 'InlineView', 'InputContext', 'InputEvent', + 'InputMap', 'InputMapUIResource', 'InputMethod', + 'InputMethodContext', 'InputMethodDescriptor', + 'InputMethodEvent', 'InputMethodHighlight', + 'InputMethodListener', 'InputMethodRequests', + 'InputStream', + 'InputStreamReader', 'InputSubset', 'InputVerifier', + 'Insets', 'InsetsUIResource', 'InstantiationError', + 'InstantiationException', 'Instrument', + 'InsufficientResourcesException', 'Integer', + 'INTERNAL', 'InternalError', 'InternalFrameAdapter', + 'InternalFrameEvent', 'InternalFrameListener', + 'InternalFrameUI', 'InterruptedException', + 'InterruptedIOException', + 'InterruptedNamingException', 'INTF_REPOS', + 'IntHolder', 'IntrospectionException', + 'Introspector', 'Invalid', + 'InvalidAlgorithmParameterException', + 'InvalidAttributeIdentifierException', + 'InvalidAttributesException', + 'InvalidAttributeValueException', + 'InvalidClassException', + 'InvalidDnDOperationException', + 'InvalidKeyException', 'InvalidKeySpecException', + 'InvalidMidiDataException', 'InvalidName', + 'InvalidNameException', + 'InvalidNameHelper', 'InvalidNameHolder', + 'InvalidObjectException', + 'InvalidParameterException', + 'InvalidParameterSpecException', + 'InvalidSearchControlsException', + 'InvalidSearchFilterException', 'InvalidSeq', + 'InvalidTransactionException', 'InvalidValue', + 'INVALID_TRANSACTION', 'InvocationEvent', + 'InvocationHandler', 'InvocationTargetException', + 'InvokeHandler', 'INV_FLAG', 'INV_IDENT', + 'INV_OBJREF', 'INV_POLICY', 'IOException', + 'IRObject', 'IRObjectOperations', 'IstringHelper', + 'ItemEvent', 'ItemListener', 'ItemSelectable', + 'Iterator', 'JApplet', 'JarEntry', 'JarException', + 'JarFile', 'JarInputStream', 'JarOutputStream', + 'JarURLConnection', 'JButton', 'JCheckBox', + 'JCheckBoxMenuItem', 'JColorChooser', 'JComboBox', + 'JComboBox.KeySelectionManager', 'JComponent', + 'JDesktopPane', 'JDialog', 'JEditorPane', + 'JFileChooser', 'JFrame', 'JInternalFrame', + 'JInternalFrame.JDesktopIcon', 'JLabel', + 'JLayeredPane', 'JList', 'JMenu', 'JMenuBar', + 'JMenuItem', 'JobAttributes', + 'JobAttributes.DefaultSelectionType', + 'JobAttributes.DestinationType', + 'JobAttributes.DialogType', + 'JobAttributes.MultipleDocumentHandlingType', + 'JobAttributes.SidesType', 'JOptionPane', 'JPanel', + 'JPasswordField', 'JPopupMenu', + 'JPopupMenu.Separator', 'JProgressBar', + 'JRadioButton', 'JRadioButtonMenuItem', 'JRootPane', + 'JScrollBar', 'JScrollPane', 'JSeparator', 'JSlider', + 'JSplitPane', 'JTabbedPane', 'JTable', + 'JTableHeader', 'JTextArea', 'JTextComponent', + 'JTextComponent.KeyBinding', 'JTextField', + 'JTextPane', 'JToggleButton', + 'JToggleButton.ToggleButtonModel', 'JToolBar', + 'JToolBar.Separator', 'JToolTip', 'JTree', + 'JTree.DynamicUtilTreeNode', + 'JTree.EmptySelectionModel', 'JViewport', 'JWindow', + 'Kernel', 'Key', 'KeyAdapter', 'KeyEvent', + 'KeyException', 'KeyFactory', 'KeyFactorySpi', + 'KeyListener', 'KeyManagementException', 'Keymap', + 'KeyPair', 'KeyPairGenerator', 'KeyPairGeneratorSpi', + 'KeySpec', 'KeyStore', 'KeyStoreException', + 'KeyStoreSpi', 'KeyStroke', 'Label', 'LabelUI', + 'LabelView', 'LastOwnerException', + 'LayeredHighlighter', + 'LayeredHighlighter.LayerPainter', 'LayoutManager', + 'LayoutManager2', 'LayoutQueue', 'LdapContext', + 'LdapReferralException', 'Lease', + 'LimitExceededException', 'Line', 'Line.Info', + 'Line2D', 'Line2D.Double', 'Line2D.Float', + 'LineBorder', 'LineBreakMeasurer', 'LineEvent', + 'LineEvent.Type', 'LineListener', 'LineMetrics', + 'LineNumberInputStream', 'LineNumberReader', + 'LineUnavailableException', 'LinkageError', + 'LinkedList', 'LinkException', 'LinkLoopException', + 'LinkRef', 'List', 'ListCellRenderer', + 'ListDataEvent', 'ListDataListener', 'ListIterator', + 'ListModel', 'ListResourceBundle', + 'ListSelectionEvent', 'ListSelectionListener', + 'ListSelectionModel', 'ListUI', 'ListView', + 'LoaderHandler', 'Locale', 'LocateRegistry', + 'LogStream', 'Long', 'LongHolder', + 'LongLongSeqHelper', 'LongLongSeqHolder', + 'LongSeqHelper', 'LongSeqHolder', 'LookAndFeel', + 'LookupOp', 'LookupTable', 'MalformedLinkException', + 'MalformedURLException', 'Manifest', 'Map', + 'Map.Entry', 'MARSHAL', 'MarshalException', + 'MarshalledObject', 'Math', 'MatteBorder', + 'MediaTracker', 'Member', 'MemoryImageSource', + 'Menu', 'MenuBar', 'MenuBarUI', 'MenuComponent', + 'MenuContainer', 'MenuDragMouseEvent', + 'MenuDragMouseListener', 'MenuElement', 'MenuEvent', + 'MenuItem', 'MenuItemUI', 'MenuKeyEvent', + 'MenuKeyListener', 'MenuListener', + 'MenuSelectionManager', 'MenuShortcut', + 'MessageDigest', 'MessageDigestSpi', 'MessageFormat', + 'MetaEventListener', 'MetalBorders', + 'MetalBorders.ButtonBorder', + 'MetalBorders.Flush3DBorder', + 'MetalBorders.InternalFrameBorder', + 'MetalBorders.MenuBarBorder', + 'MetalBorders.MenuItemBorder', + 'MetalBorders.OptionDialogBorder', + 'MetalBorders.PaletteBorder', + 'MetalBorders.PopupMenuBorder', + 'MetalBorders.RolloverButtonBorder', + 'MetalBorders.ScrollPaneBorder', + 'MetalBorders.TableHeaderBorder', + 'MetalBorders.TextFieldBorder', + 'MetalBorders.ToggleButtonBorder', + 'MetalBorders.ToolBarBorder', 'MetalButtonUI', + 'MetalCheckBoxIcon', 'MetalCheckBoxUI', + 'MetalComboBoxButton', 'MetalComboBoxEditor', + 'MetalComboBoxEditor.UIResource', + 'MetalComboBoxIcon', 'MetalComboBoxUI', + 'MetalDesktopIconUI', 'MetalFileChooserUI', + 'MetalIconFactory', 'MetalIconFactory.FileIcon16', + 'MetalIconFactory.FolderIcon16', + 'MetalIconFactory.PaletteCloseIcon', + 'MetalIconFactory.TreeControlIcon', + 'MetalIconFactory.TreeFolderIcon', + 'MetalIconFactory.TreeLeafIcon', + 'MetalInternalFrameTitlePane', + 'MetalInternalFrameUI', 'MetalLabelUI', + 'MetalLookAndFeel', 'MetalPopupMenuSeparatorUI', + 'MetalProgressBarUI', 'MetalRadioButtonUI', + 'MetalScrollBarUI', 'MetalScrollButton', + 'MetalScrollPaneUI', 'MetalSeparatorUI', + 'MetalSliderUI', 'MetalSplitPaneUI', + 'MetalTabbedPaneUI', 'MetalTextFieldUI', + 'MetalTheme', 'MetalToggleButtonUI', + 'MetalToolBarUI', 'MetalToolTipUI', 'MetalTreeUI', + 'MetaMessage', 'Method', 'MethodDescriptor', + 'MidiChannel', 'MidiDevice', 'MidiDevice.Info', + 'MidiDeviceProvider', 'MidiEvent', 'MidiFileFormat', + 'MidiFileReader', 'MidiFileWriter', 'MidiMessage', + 'MidiSystem', 'MidiUnavailableException', + 'MimeTypeParseException', 'MinimalHTMLWriter', + 'MissingResourceException', 'Mixer', 'Mixer.Info', + 'MixerProvider', 'ModificationItem', 'Modifier', + 'MouseAdapter', 'MouseDragGestureRecognizer', + 'MouseEvent', 'MouseInputAdapter', + 'MouseInputListener', 'MouseListener', + 'MouseMotionAdapter', 'MouseMotionListener', + 'MultiButtonUI', 'MulticastSocket', + 'MultiColorChooserUI', 'MultiComboBoxUI', + 'MultiDesktopIconUI', 'MultiDesktopPaneUI', + 'MultiFileChooserUI', 'MultiInternalFrameUI', + 'MultiLabelUI', 'MultiListUI', 'MultiLookAndFeel', + 'MultiMenuBarUI', 'MultiMenuItemUI', + 'MultiOptionPaneUI', 'MultiPanelUI', + 'MultiPixelPackedSampleModel', 'MultipleMaster', + 'MultiPopupMenuUI', 'MultiProgressBarUI', + 'MultiScrollBarUI', 'MultiScrollPaneUI', + 'MultiSeparatorUI', 'MultiSliderUI', + 'MultiSplitPaneUI', 'MultiTabbedPaneUI', + 'MultiTableHeaderUI', 'MultiTableUI', 'MultiTextUI', + 'MultiToolBarUI', 'MultiToolTipUI', 'MultiTreeUI', + 'MultiViewportUI', 'MutableAttributeSet', + 'MutableComboBoxModel', 'MutableTreeNode', 'Name', + 'NameAlreadyBoundException', 'NameClassPair', + 'NameComponent', 'NameComponentHelper', + 'NameComponentHolder', 'NamedValue', 'NameHelper', + 'NameHolder', 'NameNotFoundException', 'NameParser', + 'NamespaceChangeListener', 'NameValuePair', + 'NameValuePairHelper', 'Naming', 'NamingContext', + 'NamingContextHelper', 'NamingContextHolder', + 'NamingContextOperations', 'NamingEnumeration', + 'NamingEvent', 'NamingException', + 'NamingExceptionEvent', 'NamingListener', + 'NamingManager', 'NamingSecurityException', + 'NegativeArraySizeException', 'NetPermission', + 'NoClassDefFoundError', 'NoInitialContextException', + 'NoninvertibleTransformException', + 'NoPermissionException', 'NoRouteToHostException', + 'NoSuchAlgorithmException', + 'NoSuchAttributeException', 'NoSuchElementException', + 'NoSuchFieldError', 'NoSuchFieldException', + 'NoSuchMethodError', 'NoSuchMethodException', + 'NoSuchObjectException', 'NoSuchProviderException', + 'NotActiveException', 'NotBoundException', + 'NotContextException', 'NotEmpty', 'NotEmptyHelper', + 'NotEmptyHolder', 'NotFound', 'NotFoundHelper', + 'NotFoundHolder', 'NotFoundReason', + 'NotFoundReasonHelper', 'NotFoundReasonHolder', + 'NotOwnerException', 'NotSerializableException', + 'NO_IMPLEMENT', 'NO_MEMORY', 'NO_PERMISSION', + 'NO_RESOURCES', 'NO_RESPONSE', + 'NullPointerException', 'Number', 'NumberFormat', + 'NumberFormatException', 'NVList', 'Object', + 'ObjectChangeListener', 'ObjectFactory', + 'ObjectFactoryBuilder', 'ObjectHelper', + 'ObjectHolder', 'ObjectImpl', + 'ObjectInput', 'ObjectInputStream', + 'ObjectInputStream.GetField', + 'ObjectInputValidation', 'ObjectOutput', + 'ObjectOutputStream', 'ObjectOutputStream.PutField', + 'ObjectStreamClass', 'ObjectStreamConstants', + 'ObjectStreamException', 'ObjectStreamField', + 'ObjectView', 'OBJECT_NOT_EXIST', 'ObjID', + 'OBJ_ADAPTER', 'Observable', 'Observer', + 'OctetSeqHelper', 'OctetSeqHolder', 'OMGVMCID', + 'OpenType', 'Operation', + 'OperationNotSupportedException', 'Option', + 'OptionalDataException', 'OptionPaneUI', 'ORB', + 'OutOfMemoryError', 'OutputStream', + 'OutputStreamWriter', 'OverlayLayout', 'Owner', + 'Package', 'PackedColorModel', 'Pageable', + 'PageAttributes', 'PageAttributes.ColorType', + 'PageAttributes.MediaType', + 'PageAttributes.OrientationRequestedType', + 'PageAttributes.OriginType', + 'PageAttributes.PrintQualityType', 'PageFormat', + 'Paint', 'PaintContext', 'PaintEvent', 'Panel', + 'PanelUI', 'Paper', 'ParagraphView', + 'ParameterBlock', 'ParameterDescriptor', + 'ParseException', 'ParsePosition', 'Parser', + 'ParserDelegator', 'PartialResultException', + 'PasswordAuthentication', 'PasswordView', 'Patch', + 'PathIterator', 'Permission', + 'PermissionCollection', 'Permissions', + 'PERSIST_STORE', 'PhantomReference', + 'PipedInputStream', 'PipedOutputStream', + 'PipedReader', 'PipedWriter', 'PixelGrabber', + 'PixelInterleavedSampleModel', 'PKCS8EncodedKeySpec', + 'PlainDocument', 'PlainView', 'Point', 'Point2D', + 'Point2D.Double', 'Point2D.Float', 'Policy', + 'PolicyError', 'PolicyHelper', + 'PolicyHolder', 'PolicyListHelper', + 'PolicyListHolder', 'PolicyOperations', + 'PolicyTypeHelper', 'Polygon', 'PopupMenu', + 'PopupMenuEvent', 'PopupMenuListener', 'PopupMenuUI', + 'Port', 'Port.Info', 'PortableRemoteObject', + 'PortableRemoteObjectDelegate', 'Position', + 'Position.Bias', 'PreparedStatement', 'Principal', + 'PrincipalHolder', 'Printable', + 'PrinterAbortException', 'PrinterException', + 'PrinterGraphics', 'PrinterIOException', + 'PrinterJob', 'PrintGraphics', 'PrintJob', + 'PrintStream', 'PrintWriter', 'PrivateKey', + 'PRIVATE_MEMBER', 'PrivilegedAction', + 'PrivilegedActionException', + 'PrivilegedExceptionAction', 'Process', + 'ProfileDataException', 'ProgressBarUI', + 'ProgressMonitor', 'ProgressMonitorInputStream', + 'Properties', 'PropertyChangeEvent', + 'PropertyChangeListener', 'PropertyChangeSupport', + 'PropertyDescriptor', 'PropertyEditor', + 'PropertyEditorManager', 'PropertyEditorSupport', + 'PropertyPermission', 'PropertyResourceBundle', + 'PropertyVetoException', 'ProtectionDomain', + 'ProtocolException', 'Provider', 'ProviderException', + 'Proxy', 'PublicKey', 'PUBLIC_MEMBER', + 'PushbackInputStream', 'PushbackReader', + 'QuadCurve2D', 'QuadCurve2D.Double', + 'QuadCurve2D.Float', 'Random', 'RandomAccessFile', + 'Raster', 'RasterFormatException', 'RasterOp', + 'Reader', 'Receiver', 'Rectangle', 'Rectangle2D', + 'Rectangle2D.Double', 'Rectangle2D.Float', + 'RectangularShape', 'Ref', 'RefAddr', 'Reference', + 'Referenceable', 'ReferenceQueue', + 'ReferralException', 'ReflectPermission', 'Registry', + 'RegistryHandler', 'RemarshalException', 'Remote', + 'RemoteCall', 'RemoteException', 'RemoteObject', + 'RemoteRef', 'RemoteServer', 'RemoteStub', + 'RenderableImage', 'RenderableImageOp', + 'RenderableImageProducer', 'RenderContext', + 'RenderedImage', 'RenderedImageFactory', 'Renderer', + 'RenderingHints', 'RenderingHints.Key', + 'RepaintManager', 'ReplicateScaleFilter', + 'Repository', 'RepositoryIdHelper', 'Request', + 'RescaleOp', 'Resolver', 'ResolveResult', + 'ResourceBundle', 'ResponseHandler', 'ResultSet', + 'ResultSetMetaData', 'ReverbType', 'RGBImageFilter', + 'RMIClassLoader', 'RMIClientSocketFactory', + 'RMIFailureHandler', 'RMISecurityException', + 'RMISecurityManager', 'RMIServerSocketFactory', + 'RMISocketFactory', 'Robot', 'RootPaneContainer', + 'RootPaneUI', 'RoundRectangle2D', + 'RoundRectangle2D.Double', 'RoundRectangle2D.Float', + 'RowMapper', 'RSAKey', 'RSAKeyGenParameterSpec', + 'RSAPrivateCrtKey', 'RSAPrivateCrtKeySpec', + 'RSAPrivateKey', 'RSAPrivateKeySpec', 'RSAPublicKey', + 'RSAPublicKeySpec', 'RTFEditorKit', + 'RuleBasedCollator', 'Runnable', 'RunTime', + 'Runtime', 'RuntimeException', 'RunTimeOperations', + 'RuntimePermission', 'SampleModel', + 'SchemaViolationException', 'Scrollable', + 'Scrollbar', 'ScrollBarUI', 'ScrollPane', + 'ScrollPaneConstants', 'ScrollPaneLayout', + 'ScrollPaneLayout.UIResource', 'ScrollPaneUI', + 'SearchControls', 'SearchResult', + 'SecureClassLoader', 'SecureRandom', + 'SecureRandomSpi', 'Security', 'SecurityException', + 'SecurityManager', 'SecurityPermission', 'Segment', + 'SeparatorUI', 'Sequence', 'SequenceInputStream', + 'Sequencer', 'Sequencer.SyncMode', 'Serializable', + 'SerializablePermission', 'ServantObject', + 'ServerCloneException', 'ServerError', + 'ServerException', 'ServerNotActiveException', + 'ServerRef', 'ServerRequest', + 'ServerRuntimeException', 'ServerSocket', + 'ServiceDetail', 'ServiceDetailHelper', + 'ServiceInformation', 'ServiceInformationHelper', + 'ServiceInformationHolder', + 'ServiceUnavailableException', 'Set', + 'SetOverrideType', 'SetOverrideTypeHelper', 'Shape', + 'ShapeGraphicAttribute', 'Short', 'ShortHolder', + 'ShortLookupTable', 'ShortMessage', 'ShortSeqHelper', + 'ShortSeqHolder', 'Signature', 'SignatureException', + 'SignatureSpi', 'SignedObject', 'Signer', + 'SimpleAttributeSet', 'SimpleBeanInfo', + 'SimpleDateFormat', 'SimpleTimeZone', + 'SinglePixelPackedSampleModel', + 'SingleSelectionModel', 'SizeLimitExceededException', + 'SizeRequirements', 'SizeSequence', 'Skeleton', + 'SkeletonMismatchException', + 'SkeletonNotFoundException', 'SliderUI', 'Socket', + 'SocketException', 'SocketImpl', 'SocketImplFactory', + 'SocketOptions', 'SocketPermission', + 'SocketSecurityException', 'SoftBevelBorder', + 'SoftReference', 'SortedMap', 'SortedSet', + 'Soundbank', 'SoundbankReader', 'SoundbankResource', + 'SourceDataLine', 'SplitPaneUI', 'SQLData', + 'SQLException', 'SQLInput', 'SQLOutput', + 'SQLPermission', 'SQLWarning', 'Stack', + 'StackOverflowError', 'StateEdit', 'StateEditable', + 'StateFactory', 'Statement', 'Streamable', + 'StreamableValue', 'StreamCorruptedException', + 'StreamTokenizer', 'StrictMath', 'String', + 'StringBuffer', 'StringBufferInputStream', + 'StringCharacterIterator', 'StringContent', + 'StringHolder', 'StringIndexOutOfBoundsException', + 'StringReader', 'StringRefAddr', 'StringSelection', + 'StringTokenizer', 'StringValueHelper', + 'StringWriter', 'Stroke', 'Struct', 'StructMember', + 'StructMemberHelper', 'Stub', 'StubDelegate', + 'StubNotFoundException', 'Style', 'StyleConstants', + 'StyleConstants.CharacterConstants', + 'StyleConstants.ColorConstants', + 'StyleConstants.FontConstants', + 'StyleConstants.ParagraphConstants', 'StyleContext', + 'StyledDocument', 'StyledEditorKit', + 'StyledEditorKit.AlignmentAction', + 'StyledEditorKit.BoldAction', + 'StyledEditorKit.FontFamilyAction', + 'StyledEditorKit.FontSizeAction', + 'StyledEditorKit.ForegroundAction', + 'StyledEditorKit.ItalicAction', + 'StyledEditorKit.StyledTextAction', + 'StyledEditorKit.UnderlineAction', 'StyleSheet', + 'StyleSheet.BoxPainter', 'StyleSheet.ListPainter', + 'SwingConstants', 'SwingPropertyChangeSupport', + 'SwingUtilities', 'SyncFailedException', + 'Synthesizer', 'SysexMessage', 'System', + 'SystemColor', 'SystemException', 'SystemFlavorMap', + 'TabableView', 'TabbedPaneUI', 'TabExpander', + 'TableCellEditor', 'TableCellRenderer', + 'TableColumn', 'TableColumnModel', + 'TableColumnModelEvent', 'TableColumnModelListener', + 'TableHeaderUI', 'TableModel', 'TableModelEvent', + 'TableModelListener', 'TableUI', 'TableView', + 'TabSet', 'TabStop', 'TagElement', 'TargetDataLine', + 'TCKind', 'TextAction', 'TextArea', 'TextAttribute', + 'TextComponent', 'TextEvent', 'TextField', + 'TextHitInfo', 'TextLayout', + 'TextLayout.CaretPolicy', 'TextListener', + 'TextMeasurer', 'TextUI', 'TexturePaint', 'Thread', + 'ThreadDeath', 'ThreadGroup', 'ThreadLocal', + 'Throwable', 'Tie', 'TileObserver', 'Time', + 'TimeLimitExceededException', 'Timer', + 'TimerTask', 'Timestamp', 'TimeZone', 'TitledBorder', + 'ToolBarUI', 'Toolkit', 'ToolTipManager', + 'ToolTipUI', 'TooManyListenersException', 'Track', + 'TransactionRequiredException', + 'TransactionRolledbackException', + 'TRANSACTION_REQUIRED', 'TRANSACTION_ROLLEDBACK', + 'Transferable', 'TransformAttribute', 'TRANSIENT', + 'Transmitter', 'Transparency', 'TreeCellEditor', + 'TreeCellRenderer', 'TreeExpansionEvent', + 'TreeExpansionListener', 'TreeMap', 'TreeModel', + 'TreeModelEvent', 'TreeModelListener', 'TreeNode', + 'TreePath', 'TreeSelectionEvent', + 'TreeSelectionListener', 'TreeSelectionModel', + 'TreeSet', 'TreeUI', 'TreeWillExpandListener', + 'TypeCode', 'TypeCodeHolder', 'TypeMismatch', + 'Types', 'UID', 'UIDefaults', + 'UIDefaults.ActiveValue', 'UIDefaults.LazyInputMap', + 'UIDefaults.LazyValue', 'UIDefaults.ProxyLazyValue', + 'UIManager', 'UIManager.LookAndFeelInfo', + 'UIResource', 'ULongLongSeqHelper', + 'ULongLongSeqHolder', 'ULongSeqHelper', + 'ULongSeqHolder', 'UndeclaredThrowableException', + 'UndoableEdit', 'UndoableEditEvent', + 'UndoableEditListener', 'UndoableEditSupport', + 'UndoManager', 'UnexpectedException', + 'UnicastRemoteObject', 'UnionMember', + 'UnionMemberHelper', 'UNKNOWN', 'UnknownError', + 'UnknownException', 'UnknownGroupException', + 'UnknownHostException', + 'UnknownObjectException', 'UnknownServiceException', + 'UnknownUserException', 'UnmarshalException', + 'UnrecoverableKeyException', 'Unreferenced', + 'UnresolvedPermission', 'UnsatisfiedLinkError', + 'UnsolicitedNotification', + 'UnsolicitedNotificationEvent', + 'UnsolicitedNotificationListener', + 'UnsupportedAudioFileException', + 'UnsupportedClassVersionError', + 'UnsupportedEncodingException', + 'UnsupportedFlavorException', + 'UnsupportedLookAndFeelException', + 'UnsupportedOperationException', + 'UNSUPPORTED_POLICY', 'UNSUPPORTED_POLICY_VALUE', + 'URL', 'URLClassLoader', 'URLConnection', + 'URLDecoder', 'URLEncoder', 'URLStreamHandler', + 'URLStreamHandlerFactory', 'UserException', + 'UShortSeqHelper', 'UShortSeqHolder', + 'UTFDataFormatException', 'Util', 'UtilDelegate', + 'Utilities', 'ValueBase', 'ValueBaseHelper', + 'ValueBaseHolder', 'ValueFactory', 'ValueHandler', + 'ValueMember', 'ValueMemberHelper', + 'VariableHeightLayoutCache', 'Vector', 'VerifyError', + 'VersionSpecHelper', 'VetoableChangeListener', + 'VetoableChangeSupport', 'View', 'ViewFactory', + 'ViewportLayout', 'ViewportUI', + 'VirtualMachineError', 'Visibility', + 'VisibilityHelper', 'VMID', 'VM_ABSTRACT', + 'VM_CUSTOM', 'VM_NONE', 'VM_TRUNCATABLE', + 'VoiceStatus', 'Void', 'WCharSeqHelper', + 'WCharSeqHolder', 'WeakHashMap', 'WeakReference', + 'Window', 'WindowAdapter', 'WindowConstants', + 'WindowEvent', 'WindowListener', 'WrappedPlainView', + 'WritableRaster', 'WritableRenderedImage', + 'WriteAbortedException', 'Writer', + 'WrongTransaction', 'WStringValueHelper', + 'X509Certificate', 'X509CRL', 'X509CRLEntry', + 'X509EncodedKeySpec', 'X509Extension', 'ZipEntry', + 'ZipException', 'ZipFile', 'ZipInputStream', + 'ZipOutputStream', 'ZoneView', + '_BindingIteratorImplBase', '_BindingIteratorStub', + '_IDLTypeStub', '_NamingContextImplBase', + '_NamingContextStub', '_PolicyStub', '_Remote_Stub' + ), + 4 => array( + 'void', 'double', 'int', 'boolean', 'byte', 'short', 'long', 'char', 'float' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', + '+', '-', '*', '/', '%', + '!', '&', '|', '^', + '<', '>', '=', + '?', ':', ';', + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => true, + 4 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #000066; font-weight: bold;', + 3 => 'color: #003399;', + 4 => 'color: #000066; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #006699;', + 3 => 'color: #008000; font-style: italic; font-weight: bold;', + 3 => 'color: #008000; font-style: italic; font-weight: bold;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006633;', + 2 => 'color: #006633;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.google.com/search?hl=en&q=allinurl%3A{FNAMEL}+java.sun.com&btnI=I%27m%20Feeling%20Lucky', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/java5.php b/examples/includes/geshi/geshi/java5.php new file mode 100644 index 0000000..1766ef9 --- /dev/null +++ b/examples/includes/geshi/geshi/java5.php @@ -0,0 +1,1031 @@ + 'Java(TM) 2 Platform Standard Edition 5.0', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Import and Package directives (Basic Support only) + 2 => '/(?:(?<=import[\\n\\s])|(?<=package[\\n\\s]))[\\n\\s]*([a-zA-Z0-9_]+\\.)*([a-zA-Z0-9_]+|\*)(?=[\n\s;])/i', + // javadoc comments + 3 => '#/\*\*(?![\*\/]).*\*/#sU' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + /* see the authoritative list of all 50 Java keywords at */ + /* http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#229308 */ + + /* java keywords, part 1: control flow */ + 'case', 'default', 'do', 'else', 'for', + 'goto', 'if', 'switch', 'while' + + /* IMO 'break', 'continue', 'return' and 'throw' */ + /* should also be added to this group, as they */ + /* also manage the control flow, */ + /* arguably 'try'/'catch'/'finally' as well */ + ), + 2 => array( + /* java keywords, part 2 */ + + 'break', 'continue', 'return', 'throw', + 'try', 'catch', 'finally', + + 'abstract', 'assert', 'class', 'const', 'enum', 'extends', + 'final', 'implements', 'import', 'instanceof', 'interface', + 'native', 'new', 'package', 'private', 'protected', + 'public', 'static', 'strictfp', 'super', 'synchronized', + 'this', 'throws', 'transient', 'volatile' + ), + 3 => array( + /* Java keywords, part 3: primitive data types and 'void' */ + 'boolean', 'byte', 'char', 'double', + 'float', 'int', 'long', 'short', 'void' + ), + 4 => array( + /* other reserved words in Java: literals */ + /* should be styled to look similar to numbers and Strings */ + 'false', 'null', 'true' + ), + 5 => array ( + 'Applet', 'AppletContext', 'AppletStub', 'AudioClip' + ), + 6 => array ( + 'AWTError', 'AWTEvent', 'AWTEventMulticaster', 'AWTException', 'AWTKeyStroke', 'AWTPermission', 'ActiveEvent', 'Adjustable', 'AlphaComposite', 'BasicStroke', 'BorderLayout', 'BufferCapabilities', 'BufferCapabilities.FlipContents', 'Button', 'Canvas', 'CardLayout', 'Checkbox', 'CheckboxGroup', 'CheckboxMenuItem', 'Choice', 'Color', 'Component', 'ComponentOrientation', 'Composite', 'CompositeContext', 'Container', 'ContainerOrderFocusTraversalPolicy', 'Cursor', 'DefaultFocusTraversalPolicy', 'DefaultKeyboardFocusManager', 'Dialog', 'Dimension', 'DisplayMode', 'EventQueue', 'FileDialog', 'FlowLayout', 'FocusTraversalPolicy', 'Font', 'FontFormatException', 'FontMetrics', 'Frame', 'GradientPaint', 'Graphics', 'Graphics2D', 'GraphicsConfigTemplate', 'GraphicsConfiguration', 'GraphicsDevice', 'GraphicsEnvironment', 'GridBagConstraints', 'GridBagLayout', 'GridLayout', 'HeadlessException', 'IllegalComponentStateException', 'Image', 'ImageCapabilities', 'Insets', 'ItemSelectable', 'JobAttributes', + 'JobAttributes.DefaultSelectionType', 'JobAttributes.DestinationType', 'JobAttributes.DialogType', 'JobAttributes.MultipleDocumentHandlingType', 'JobAttributes.SidesType', 'KeyEventDispatcher', 'KeyEventPostProcessor', 'KeyboardFocusManager', 'Label', 'LayoutManager', 'LayoutManager2', 'MediaTracker', 'Menu', 'MenuBar', 'MenuComponent', 'MenuContainer', 'MenuItem', 'MenuShortcut', 'MouseInfo', 'PageAttributes', 'PageAttributes.ColorType', 'PageAttributes.MediaType', 'PageAttributes.OrientationRequestedType', 'PageAttributes.OriginType', 'PageAttributes.PrintQualityType', 'Paint', 'PaintContext', 'Panel', 'Point', 'PointerInfo', 'Polygon', 'PopupMenu', 'PrintGraphics', 'PrintJob', 'Rectangle', 'RenderingHints', 'RenderingHints.Key', 'Robot', 'ScrollPane', 'ScrollPaneAdjustable', 'Scrollbar', 'Shape', 'Stroke', 'SystemColor', 'TextArea', 'TextComponent', 'TextField', 'TexturePaint', 'Toolkit', 'Transparency', 'Window' + ), + 7 => array ( + 'CMMException', 'ColorSpace', 'ICC_ColorSpace', 'ICC_Profile', 'ICC_ProfileGray', 'ICC_ProfileRGB', 'ProfileDataException' + ), + 8 => array ( + 'Clipboard', 'ClipboardOwner', 'DataFlavor', 'FlavorEvent', 'FlavorListener', 'FlavorMap', 'FlavorTable', 'MimeTypeParseException', 'StringSelection', 'SystemFlavorMap', 'Transferable', 'UnsupportedFlavorException' + ), + 9 => array ( + 'Autoscroll', 'DnDConstants', 'DragGestureEvent', 'DragGestureListener', 'DragGestureRecognizer', 'DragSource', 'DragSourceAdapter', 'DragSourceContext', 'DragSourceDragEvent', 'DragSourceDropEvent', 'DragSourceEvent', 'DragSourceListener', 'DragSourceMotionListener', 'DropTarget', 'DropTarget.DropTargetAutoScroller', 'DropTargetAdapter', 'DropTargetContext', 'DropTargetDragEvent', 'DropTargetDropEvent', 'DropTargetEvent', 'DropTargetListener', 'InvalidDnDOperationException', 'MouseDragGestureRecognizer' + ), + 10 => array ( + 'AWTEventListener', 'AWTEventListenerProxy', 'ActionEvent', 'ActionListener', 'AdjustmentEvent', 'AdjustmentListener', 'ComponentAdapter', 'ComponentEvent', 'ComponentListener', 'ContainerAdapter', 'ContainerEvent', 'ContainerListener', 'FocusAdapter', 'FocusEvent', 'FocusListener', 'HierarchyBoundsAdapter', 'HierarchyBoundsListener', 'HierarchyEvent', 'HierarchyListener', 'InputEvent', 'InputMethodEvent', 'InputMethodListener', 'InvocationEvent', 'ItemEvent', 'ItemListener', 'KeyAdapter', 'KeyEvent', 'KeyListener', 'MouseAdapter', 'MouseListener', 'MouseMotionAdapter', 'MouseMotionListener', 'MouseWheelEvent', 'MouseWheelListener', 'PaintEvent', 'TextEvent', 'TextListener', 'WindowAdapter', 'WindowEvent', 'WindowFocusListener', 'WindowListener', 'WindowStateListener' + ), + 11 => array ( + 'FontRenderContext', 'GlyphJustificationInfo', 'GlyphMetrics', 'GlyphVector', 'GraphicAttribute', 'ImageGraphicAttribute', 'LineBreakMeasurer', 'LineMetrics', 'MultipleMaster', 'NumericShaper', 'ShapeGraphicAttribute', 'TextAttribute', 'TextHitInfo', 'TextLayout', 'TextLayout.CaretPolicy', 'TextMeasurer', 'TransformAttribute' + ), + 12 => array ( + 'AffineTransform', 'Arc2D', 'Arc2D.Double', 'Arc2D.Float', 'Area', 'CubicCurve2D', 'CubicCurve2D.Double', 'CubicCurve2D.Float', 'Dimension2D', 'Ellipse2D', 'Ellipse2D.Double', 'Ellipse2D.Float', 'FlatteningPathIterator', 'GeneralPath', 'IllegalPathStateException', 'Line2D', 'Line2D.Double', 'Line2D.Float', 'NoninvertibleTransformException', 'PathIterator', 'Point2D', 'Point2D.Double', 'Point2D.Float', 'QuadCurve2D', 'QuadCurve2D.Double', 'QuadCurve2D.Float', 'Rectangle2D', 'Rectangle2D.Double', 'Rectangle2D.Float', 'RectangularShape', 'RoundRectangle2D', 'RoundRectangle2D.Double', 'RoundRectangle2D.Float' + ), + 13 => array ( + 'InputContext', 'InputMethodHighlight', 'InputMethodRequests', 'InputSubset' + ), + 14 => array ( + 'InputMethod', 'InputMethodContext', 'InputMethodDescriptor' + ), + 15 => array ( + 'AffineTransformOp', 'AreaAveragingScaleFilter', 'BandCombineOp', 'BandedSampleModel', 'BufferStrategy', 'BufferedImage', 'BufferedImageFilter', 'BufferedImageOp', 'ByteLookupTable', 'ColorConvertOp', 'ColorModel', 'ComponentColorModel', 'ComponentSampleModel', 'ConvolveOp', 'CropImageFilter', 'DataBuffer', 'DataBufferByte', 'DataBufferDouble', 'DataBufferFloat', 'DataBufferInt', 'DataBufferShort', 'DataBufferUShort', 'DirectColorModel', 'FilteredImageSource', 'ImageConsumer', 'ImageFilter', 'ImageObserver', 'ImageProducer', 'ImagingOpException', 'IndexColorModel', 'Kernel', 'LookupOp', 'LookupTable', 'MemoryImageSource', 'MultiPixelPackedSampleModel', 'PackedColorModel', 'PixelGrabber', 'PixelInterleavedSampleModel', 'RGBImageFilter', 'Raster', 'RasterFormatException', 'RasterOp', 'RenderedImage', 'ReplicateScaleFilter', 'RescaleOp', 'SampleModel', 'ShortLookupTable', 'SinglePixelPackedSampleModel', 'TileObserver', 'VolatileImage', 'WritableRaster', 'WritableRenderedImage' + ), + 16 => array ( + 'ContextualRenderedImageFactory', 'ParameterBlock', 'RenderContext', 'RenderableImage', 'RenderableImageOp', 'RenderableImageProducer', 'RenderedImageFactory' + ), + 17 => array ( + 'Book', 'PageFormat', 'Pageable', 'Paper', 'Printable', 'PrinterAbortException', 'PrinterException', 'PrinterGraphics', 'PrinterIOException', 'PrinterJob' + ), + 18 => array ( + 'AppletInitializer', 'BeanDescriptor', 'BeanInfo', 'Beans', 'Customizer', 'DefaultPersistenceDelegate', 'DesignMode', 'Encoder', 'EventHandler', 'EventSetDescriptor', 'ExceptionListener', 'Expression', 'FeatureDescriptor', 'IndexedPropertyChangeEvent', 'IndexedPropertyDescriptor', 'Introspector', 'MethodDescriptor', 'ParameterDescriptor', 'PersistenceDelegate', 'PropertyChangeEvent', 'PropertyChangeListener', 'PropertyChangeListenerProxy', 'PropertyChangeSupport', 'PropertyDescriptor', 'PropertyEditor', 'PropertyEditorManager', 'PropertyEditorSupport', 'PropertyVetoException', 'SimpleBeanInfo', 'VetoableChangeListener', 'VetoableChangeListenerProxy', 'VetoableChangeSupport', 'Visibility', 'XMLDecoder', 'XMLEncoder' + ), + 19 => array ( + 'BeanContext', 'BeanContextChild', 'BeanContextChildComponentProxy', 'BeanContextChildSupport', 'BeanContextContainerProxy', 'BeanContextEvent', 'BeanContextMembershipEvent', 'BeanContextMembershipListener', 'BeanContextProxy', 'BeanContextServiceAvailableEvent', 'BeanContextServiceProvider', 'BeanContextServiceProviderBeanInfo', 'BeanContextServiceRevokedEvent', 'BeanContextServiceRevokedListener', 'BeanContextServices', 'BeanContextServicesListener', 'BeanContextServicesSupport', 'BeanContextServicesSupport.BCSSServiceProvider', 'BeanContextSupport', 'BeanContextSupport.BCSIterator' + ), + 20 => array ( + 'BufferedInputStream', 'BufferedOutputStream', 'BufferedReader', 'BufferedWriter', 'ByteArrayInputStream', 'ByteArrayOutputStream', 'CharArrayReader', 'CharArrayWriter', 'CharConversionException', 'Closeable', 'DataInput', 'DataOutput', 'EOFException', 'Externalizable', 'File', 'FileDescriptor', 'FileInputStream', 'FileNotFoundException', 'FileOutputStream', 'FilePermission', 'FileReader', 'FileWriter', 'FilenameFilter', 'FilterInputStream', 'FilterOutputStream', 'FilterReader', 'FilterWriter', 'Flushable', 'IOException', 'InputStreamReader', 'InterruptedIOException', 'InvalidClassException', 'InvalidObjectException', 'LineNumberInputStream', 'LineNumberReader', 'NotActiveException', 'NotSerializableException', 'ObjectInput', 'ObjectInputStream', 'ObjectInputStream.GetField', 'ObjectInputValidation', 'ObjectOutput', 'ObjectOutputStream', 'ObjectOutputStream.PutField', 'ObjectStreamClass', 'ObjectStreamConstants', 'ObjectStreamException', 'ObjectStreamField', 'OptionalDataException', 'OutputStreamWriter', + 'PipedInputStream', 'PipedOutputStream', 'PipedReader', 'PipedWriter', 'PrintStream', 'PrintWriter', 'PushbackInputStream', 'PushbackReader', 'RandomAccessFile', 'Reader', 'SequenceInputStream', 'Serializable', 'SerializablePermission', 'StreamCorruptedException', 'StreamTokenizer', 'StringBufferInputStream', 'StringReader', 'StringWriter', 'SyncFailedException', 'UTFDataFormatException', 'UnsupportedEncodingException', 'WriteAbortedException', 'Writer' + ), + 21 => array ( + 'AbstractMethodError', 'Appendable', 'ArithmeticException', 'ArrayIndexOutOfBoundsException', 'ArrayStoreException', 'AssertionError', 'Boolean', 'Byte', 'CharSequence', 'Character', 'Character.Subset', 'Character.UnicodeBlock', 'Class', 'ClassCastException', 'ClassCircularityError', 'ClassFormatError', 'ClassLoader', 'ClassNotFoundException', 'CloneNotSupportedException', 'Cloneable', 'Comparable', 'Compiler', 'Deprecated', 'Double', 'Enum', 'EnumConstantNotPresentException', 'Error', 'Exception', 'ExceptionInInitializerError', 'Float', 'IllegalAccessError', 'IllegalAccessException', 'IllegalArgumentException', 'IllegalMonitorStateException', 'IllegalStateException', 'IllegalThreadStateException', 'IncompatibleClassChangeError', 'IndexOutOfBoundsException', 'InheritableThreadLocal', 'InstantiationError', 'InstantiationException', 'Integer', 'InternalError', 'InterruptedException', 'Iterable', 'LinkageError', 'Long', 'Math', 'NegativeArraySizeException', 'NoClassDefFoundError', 'NoSuchFieldError', + 'NoSuchFieldException', 'NoSuchMethodError', 'NoSuchMethodException', 'NullPointerException', 'Number', 'NumberFormatException', 'OutOfMemoryError', 'Override', 'Package', 'Process', 'ProcessBuilder', 'Readable', 'Runnable', 'Runtime', 'RuntimeException', 'RuntimePermission', 'SecurityException', 'SecurityManager', 'Short', 'StackOverflowError', 'StackTraceElement', 'StrictMath', 'String', 'StringBuffer', 'StringBuilder', 'StringIndexOutOfBoundsException', 'SuppressWarnings', 'System', 'Thread', 'Thread.State', 'Thread.UncaughtExceptionHandler', 'ThreadDeath', 'ThreadGroup', 'ThreadLocal', 'Throwable', 'TypeNotPresentException', 'UnknownError', 'UnsatisfiedLinkError', 'UnsupportedClassVersionError', 'UnsupportedOperationException', 'VerifyError', 'VirtualMachineError', 'Void' + ), + 22 => array ( + 'AnnotationFormatError', 'AnnotationTypeMismatchException', 'Documented', 'ElementType', 'IncompleteAnnotationException', 'Inherited', 'Retention', 'RetentionPolicy', 'Target' + ), + 23 => array ( + 'ClassDefinition', 'ClassFileTransformer', 'IllegalClassFormatException', 'Instrumentation', 'UnmodifiableClassException' + ), + 24 => array ( + 'ClassLoadingMXBean', 'CompilationMXBean', 'GarbageCollectorMXBean', 'ManagementFactory', 'ManagementPermission', 'MemoryMXBean', 'MemoryManagerMXBean', 'MemoryNotificationInfo', 'MemoryPoolMXBean', 'MemoryType', 'MemoryUsage', 'OperatingSystemMXBean', 'RuntimeMXBean', 'ThreadInfo', 'ThreadMXBean' + ), + 25 => array ( + 'PhantomReference', 'ReferenceQueue', 'SoftReference', 'WeakReference' + ), + 26 => array ( + 'AccessibleObject', 'AnnotatedElement', 'Constructor', 'Field', 'GenericArrayType', 'GenericDeclaration', 'GenericSignatureFormatError', 'InvocationHandler', 'InvocationTargetException', 'MalformedParameterizedTypeException', 'Member', 'Method', 'Modifier', 'ParameterizedType', 'ReflectPermission', 'Type', 'TypeVariable', 'UndeclaredThrowableException', 'WildcardType' + ), + 27 => array ( + 'BigDecimal', 'BigInteger', 'MathContext', 'RoundingMode' + ), + 28 => array ( + 'Authenticator', 'Authenticator.RequestorType', 'BindException', 'CacheRequest', 'CacheResponse', 'ContentHandlerFactory', 'CookieHandler', 'DatagramPacket', 'DatagramSocket', 'DatagramSocketImpl', 'DatagramSocketImplFactory', 'FileNameMap', 'HttpRetryException', 'HttpURLConnection', 'Inet4Address', 'Inet6Address', 'InetAddress', 'InetSocketAddress', 'JarURLConnection', 'MalformedURLException', 'MulticastSocket', 'NetPermission', 'NetworkInterface', 'NoRouteToHostException', 'PasswordAuthentication', 'PortUnreachableException', 'ProtocolException', 'Proxy.Type', 'ProxySelector', 'ResponseCache', 'SecureCacheResponse', 'ServerSocket', 'Socket', 'SocketAddress', 'SocketException', 'SocketImpl', 'SocketImplFactory', 'SocketOptions', 'SocketPermission', 'SocketTimeoutException', 'URI', 'URISyntaxException', 'URL', 'URLClassLoader', 'URLConnection', 'URLDecoder', 'URLEncoder', 'URLStreamHandler', 'URLStreamHandlerFactory', 'UnknownServiceException' + ), + 29 => array ( + 'Buffer', 'BufferOverflowException', 'BufferUnderflowException', 'ByteBuffer', 'ByteOrder', 'CharBuffer', 'DoubleBuffer', 'FloatBuffer', 'IntBuffer', 'InvalidMarkException', 'LongBuffer', 'MappedByteBuffer', 'ReadOnlyBufferException', 'ShortBuffer' + ), + 30 => array ( + 'AlreadyConnectedException', 'AsynchronousCloseException', 'ByteChannel', 'CancelledKeyException', 'Channel', 'Channels', 'ClosedByInterruptException', 'ClosedChannelException', 'ClosedSelectorException', 'ConnectionPendingException', 'DatagramChannel', 'FileChannel', 'FileChannel.MapMode', 'FileLock', 'FileLockInterruptionException', 'GatheringByteChannel', 'IllegalBlockingModeException', 'IllegalSelectorException', 'InterruptibleChannel', 'NoConnectionPendingException', 'NonReadableChannelException', 'NonWritableChannelException', 'NotYetBoundException', 'NotYetConnectedException', 'OverlappingFileLockException', 'Pipe', 'Pipe.SinkChannel', 'Pipe.SourceChannel', 'ReadableByteChannel', 'ScatteringByteChannel', 'SelectableChannel', 'SelectionKey', 'Selector', 'ServerSocketChannel', 'SocketChannel', 'UnresolvedAddressException', 'UnsupportedAddressTypeException', 'WritableByteChannel' + ), + 31 => array ( + 'AbstractInterruptibleChannel', 'AbstractSelectableChannel', 'AbstractSelectionKey', 'AbstractSelector', 'SelectorProvider' + ), + 32 => array ( + 'CharacterCodingException', 'Charset', 'CharsetDecoder', 'CharsetEncoder', 'CoderMalfunctionError', 'CoderResult', 'CodingErrorAction', 'IllegalCharsetNameException', 'MalformedInputException', 'UnmappableCharacterException', 'UnsupportedCharsetException' + ), + 33 => array ( + 'CharsetProvider' + ), + 34 => array ( + 'AccessException', 'AlreadyBoundException', 'ConnectIOException', 'MarshalException', 'MarshalledObject', 'Naming', 'NoSuchObjectException', 'NotBoundException', 'RMISecurityException', 'RMISecurityManager', 'Remote', 'RemoteException', 'ServerError', 'ServerException', 'ServerRuntimeException', 'StubNotFoundException', 'UnexpectedException', 'UnmarshalException' + ), + 35 => array ( + 'Activatable', 'ActivateFailedException', 'ActivationDesc', 'ActivationException', 'ActivationGroup', 'ActivationGroupDesc', 'ActivationGroupDesc.CommandEnvironment', 'ActivationGroupID', 'ActivationGroup_Stub', 'ActivationID', 'ActivationInstantiator', 'ActivationMonitor', 'ActivationSystem', 'Activator', 'UnknownGroupException', 'UnknownObjectException' + ), + 36 => array ( + 'DGC', 'Lease', 'VMID' + ), + 37 => array ( + 'LocateRegistry', 'Registry', 'RegistryHandler' + ), + 38 => array ( + 'ExportException', 'LoaderHandler', 'LogStream', 'ObjID', 'Operation', 'RMIClassLoader', 'RMIClassLoaderSpi', 'RMIClientSocketFactory', 'RMIFailureHandler', 'RMIServerSocketFactory', 'RMISocketFactory', 'RemoteCall', 'RemoteObject', 'RemoteObjectInvocationHandler', 'RemoteRef', 'RemoteServer', 'RemoteStub', 'ServerCloneException', 'ServerNotActiveException', 'ServerRef', 'Skeleton', 'SkeletonMismatchException', 'SkeletonNotFoundException', 'SocketSecurityException', 'UID', 'UnicastRemoteObject', 'Unreferenced' + ), + 39 => array ( + 'AccessControlContext', 'AccessControlException', 'AccessController', 'AlgorithmParameterGenerator', 'AlgorithmParameterGeneratorSpi', 'AlgorithmParameters', 'AlgorithmParametersSpi', 'AllPermission', 'AuthProvider', 'BasicPermission', 'CodeSigner', 'CodeSource', 'DigestException', 'DigestInputStream', 'DigestOutputStream', 'DomainCombiner', 'GeneralSecurityException', 'Guard', 'GuardedObject', 'Identity', 'IdentityScope', 'InvalidAlgorithmParameterException', 'InvalidParameterException', 'Key', 'KeyException', 'KeyFactory', 'KeyFactorySpi', 'KeyManagementException', 'KeyPair', 'KeyPairGenerator', 'KeyPairGeneratorSpi', 'KeyRep', 'KeyRep.Type', 'KeyStore', 'KeyStore.Builder', 'KeyStore.CallbackHandlerProtection', 'KeyStore.Entry', 'KeyStore.LoadStoreParameter', 'KeyStore.PasswordProtection', 'KeyStore.PrivateKeyEntry', 'KeyStore.ProtectionParameter', 'KeyStore.SecretKeyEntry', 'KeyStore.TrustedCertificateEntry', 'KeyStoreException', 'KeyStoreSpi', 'MessageDigest', 'MessageDigestSpi', + 'NoSuchAlgorithmException', 'NoSuchProviderException', 'PermissionCollection', 'Permissions', 'PrivateKey', 'PrivilegedAction', 'PrivilegedActionException', 'PrivilegedExceptionAction', 'ProtectionDomain', 'Provider', 'Provider.Service', 'ProviderException', 'PublicKey', 'SecureClassLoader', 'SecureRandom', 'SecureRandomSpi', 'Security', 'SecurityPermission', 'Signature', 'SignatureException', 'SignatureSpi', 'SignedObject', 'Signer', 'UnrecoverableEntryException', 'UnrecoverableKeyException', 'UnresolvedPermission' + ), + 40 => array ( + 'Acl', 'AclEntry', 'AclNotFoundException', 'Group', 'LastOwnerException', 'NotOwnerException', 'Owner' + ), + 41 => array ( + 'CRL', 'CRLException', 'CRLSelector', 'CertPath', 'CertPath.CertPathRep', 'CertPathBuilder', 'CertPathBuilderException', 'CertPathBuilderResult', 'CertPathBuilderSpi', 'CertPathParameters', 'CertPathValidator', 'CertPathValidatorException', 'CertPathValidatorResult', 'CertPathValidatorSpi', 'CertSelector', 'CertStore', 'CertStoreException', 'CertStoreParameters', 'CertStoreSpi', 'Certificate.CertificateRep', 'CertificateFactory', 'CertificateFactorySpi', 'CollectionCertStoreParameters', 'LDAPCertStoreParameters', 'PKIXBuilderParameters', 'PKIXCertPathBuilderResult', 'PKIXCertPathChecker', 'PKIXCertPathValidatorResult', 'PKIXParameters', 'PolicyNode', 'PolicyQualifierInfo', 'TrustAnchor', 'X509CRL', 'X509CRLEntry', 'X509CRLSelector', 'X509CertSelector', 'X509Extension' + ), + 42 => array ( + 'DSAKey', 'DSAKeyPairGenerator', 'DSAParams', 'DSAPrivateKey', 'DSAPublicKey', 'ECKey', 'ECPrivateKey', 'ECPublicKey', 'RSAKey', 'RSAMultiPrimePrivateCrtKey', 'RSAPrivateCrtKey', 'RSAPrivateKey', 'RSAPublicKey' + ), + 43 => array ( + 'AlgorithmParameterSpec', 'DSAParameterSpec', 'DSAPrivateKeySpec', 'DSAPublicKeySpec', 'ECField', 'ECFieldF2m', 'ECFieldFp', 'ECGenParameterSpec', 'ECParameterSpec', 'ECPoint', 'ECPrivateKeySpec', 'ECPublicKeySpec', 'EllipticCurve', 'EncodedKeySpec', 'InvalidKeySpecException', 'InvalidParameterSpecException', 'KeySpec', 'MGF1ParameterSpec', 'PKCS8EncodedKeySpec', 'PSSParameterSpec', 'RSAKeyGenParameterSpec', 'RSAMultiPrimePrivateCrtKeySpec', 'RSAOtherPrimeInfo', 'RSAPrivateCrtKeySpec', 'RSAPrivateKeySpec', 'RSAPublicKeySpec', 'X509EncodedKeySpec' + ), + 44 => array ( + 'BatchUpdateException', 'Blob', 'CallableStatement', 'Clob', 'Connection', 'DataTruncation', 'DatabaseMetaData', 'Driver', 'DriverManager', 'DriverPropertyInfo', 'ParameterMetaData', 'PreparedStatement', 'Ref', 'ResultSet', 'ResultSetMetaData', 'SQLData', 'SQLException', 'SQLInput', 'SQLOutput', 'SQLPermission', 'SQLWarning', 'Savepoint', 'Struct', 'Time', 'Types' + ), + 45 => array ( + 'AttributedCharacterIterator', 'AttributedCharacterIterator.Attribute', 'AttributedString', 'Bidi', 'BreakIterator', 'CharacterIterator', 'ChoiceFormat', 'CollationElementIterator', 'CollationKey', 'Collator', 'DateFormat', 'DateFormat.Field', 'DateFormatSymbols', 'DecimalFormat', 'DecimalFormatSymbols', 'FieldPosition', 'Format', 'Format.Field', 'MessageFormat', 'MessageFormat.Field', 'NumberFormat', 'NumberFormat.Field', 'ParseException', 'ParsePosition', 'RuleBasedCollator', 'SimpleDateFormat', 'StringCharacterIterator' + ), + 46 => array ( + 'AbstractCollection', 'AbstractList', 'AbstractMap', 'AbstractQueue', 'AbstractSequentialList', 'AbstractSet', 'ArrayList', 'Arrays', 'BitSet', 'Calendar', 'Collection', 'Collections', 'Comparator', 'ConcurrentModificationException', 'Currency', 'Dictionary', 'DuplicateFormatFlagsException', 'EmptyStackException', 'EnumMap', 'EnumSet', 'Enumeration', 'EventListenerProxy', 'EventObject', 'FormatFlagsConversionMismatchException', 'Formattable', 'FormattableFlags', 'Formatter.BigDecimalLayoutForm', 'FormatterClosedException', 'GregorianCalendar', 'HashMap', 'HashSet', 'Hashtable', 'IdentityHashMap', 'IllegalFormatCodePointException', 'IllegalFormatConversionException', 'IllegalFormatException', 'IllegalFormatFlagsException', 'IllegalFormatPrecisionException', 'IllegalFormatWidthException', 'InputMismatchException', 'InvalidPropertiesFormatException', 'Iterator', 'LinkedHashMap', 'LinkedHashSet', 'LinkedList', 'ListIterator', 'ListResourceBundle', 'Locale', 'Map', 'Map.Entry', 'MissingFormatArgumentException', + 'MissingFormatWidthException', 'MissingResourceException', 'NoSuchElementException', 'Observable', 'Observer', 'PriorityQueue', 'Properties', 'PropertyPermission', 'PropertyResourceBundle', 'Queue', 'Random', 'RandomAccess', 'ResourceBundle', 'Scanner', 'Set', 'SimpleTimeZone', 'SortedMap', 'SortedSet', 'Stack', 'StringTokenizer', 'TimeZone', 'TimerTask', 'TooManyListenersException', 'TreeMap', 'TreeSet', 'UUID', 'UnknownFormatConversionException', 'UnknownFormatFlagsException', 'Vector', 'WeakHashMap' + ), + 47 => array ( + 'AbstractExecutorService', 'ArrayBlockingQueue', 'BlockingQueue', 'BrokenBarrierException', 'Callable', 'CancellationException', 'CompletionService', 'ConcurrentHashMap', 'ConcurrentLinkedQueue', 'ConcurrentMap', 'CopyOnWriteArrayList', 'CopyOnWriteArraySet', 'CountDownLatch', 'CyclicBarrier', 'DelayQueue', 'Delayed', 'Exchanger', 'ExecutionException', 'Executor', 'ExecutorCompletionService', 'ExecutorService', 'Executors', 'Future', 'FutureTask', 'LinkedBlockingQueue', 'PriorityBlockingQueue', 'RejectedExecutionException', 'RejectedExecutionHandler', 'ScheduledExecutorService', 'ScheduledFuture', 'ScheduledThreadPoolExecutor', 'Semaphore', 'SynchronousQueue', 'ThreadFactory', 'ThreadPoolExecutor', 'ThreadPoolExecutor.AbortPolicy', 'ThreadPoolExecutor.CallerRunsPolicy', 'ThreadPoolExecutor.DiscardOldestPolicy', 'ThreadPoolExecutor.DiscardPolicy', 'TimeUnit', 'TimeoutException' + ), + 48 => array ( + 'AtomicBoolean', 'AtomicInteger', 'AtomicIntegerArray', 'AtomicIntegerFieldUpdater', 'AtomicLong', 'AtomicLongArray', 'AtomicLongFieldUpdater', 'AtomicMarkableReference', 'AtomicReference', 'AtomicReferenceArray', 'AtomicReferenceFieldUpdater', 'AtomicStampedReference' + ), + 49 => array ( + 'AbstractQueuedSynchronizer', 'Condition', 'Lock', 'LockSupport', 'ReadWriteLock', 'ReentrantLock', 'ReentrantReadWriteLock', 'ReentrantReadWriteLock.ReadLock', 'ReentrantReadWriteLock.WriteLock' + ), + 50 => array ( + 'Attributes.Name', 'JarEntry', 'JarException', 'JarFile', 'JarInputStream', 'JarOutputStream', 'Manifest', 'Pack200', 'Pack200.Packer', 'Pack200.Unpacker' + ), + 51 => array ( + 'ConsoleHandler', 'ErrorManager', 'FileHandler', 'Filter', 'Handler', 'Level', 'LogManager', 'LogRecord', 'Logger', 'LoggingMXBean', 'LoggingPermission', 'MemoryHandler', 'SimpleFormatter', 'SocketHandler', 'StreamHandler', 'XMLFormatter' + ), + 52 => array ( + 'AbstractPreferences', 'BackingStoreException', 'InvalidPreferencesFormatException', 'NodeChangeEvent', 'NodeChangeListener', 'PreferenceChangeEvent', 'PreferenceChangeListener', 'Preferences', 'PreferencesFactory' + ), + 53 => array ( + 'MatchResult', 'Matcher', 'Pattern', 'PatternSyntaxException' + ), + 54 => array ( + 'Adler32', 'CRC32', 'CheckedInputStream', 'CheckedOutputStream', 'Checksum', 'DataFormatException', 'Deflater', 'DeflaterOutputStream', 'GZIPInputStream', 'GZIPOutputStream', 'Inflater', 'InflaterInputStream', 'ZipEntry', 'ZipException', 'ZipFile', 'ZipInputStream', 'ZipOutputStream' + ), + 55 => array ( + 'Accessible', 'AccessibleAction', 'AccessibleAttributeSequence', 'AccessibleBundle', 'AccessibleComponent', 'AccessibleContext', 'AccessibleEditableText', 'AccessibleExtendedComponent', 'AccessibleExtendedTable', 'AccessibleExtendedText', 'AccessibleHyperlink', 'AccessibleHypertext', 'AccessibleIcon', 'AccessibleKeyBinding', 'AccessibleRelation', 'AccessibleRelationSet', 'AccessibleResourceBundle', 'AccessibleRole', 'AccessibleSelection', 'AccessibleState', 'AccessibleStateSet', 'AccessibleStreamable', 'AccessibleTable', 'AccessibleTableModelChange', 'AccessibleText', 'AccessibleTextSequence', 'AccessibleValue' + ), + 56 => array ( + 'ActivityCompletedException', 'ActivityRequiredException', 'InvalidActivityException' + ), + 57 => array ( + 'BadPaddingException', 'Cipher', 'CipherInputStream', 'CipherOutputStream', 'CipherSpi', 'EncryptedPrivateKeyInfo', 'ExemptionMechanism', 'ExemptionMechanismException', 'ExemptionMechanismSpi', 'IllegalBlockSizeException', 'KeyAgreement', 'KeyAgreementSpi', 'KeyGenerator', 'KeyGeneratorSpi', 'Mac', 'MacSpi', 'NoSuchPaddingException', 'NullCipher', 'SealedObject', 'SecretKey', 'SecretKeyFactory', 'SecretKeyFactorySpi', 'ShortBufferException' + ), + 58 => array ( + 'DHKey', 'DHPrivateKey', 'DHPublicKey', 'PBEKey' + ), + 59 => array ( + 'DESKeySpec', 'DESedeKeySpec', 'DHGenParameterSpec', 'DHParameterSpec', 'DHPrivateKeySpec', 'DHPublicKeySpec', 'IvParameterSpec', 'OAEPParameterSpec', 'PBEKeySpec', 'PBEParameterSpec', 'PSource', 'PSource.PSpecified', 'RC2ParameterSpec', 'RC5ParameterSpec', 'SecretKeySpec' + ), + 60 => array ( + 'IIOException', 'IIOImage', 'IIOParam', 'IIOParamController', 'ImageIO', 'ImageReadParam', 'ImageReader', 'ImageTranscoder', 'ImageTypeSpecifier', 'ImageWriteParam', 'ImageWriter' + ), + 61 => array ( + 'IIOReadProgressListener', 'IIOReadUpdateListener', 'IIOReadWarningListener', 'IIOWriteProgressListener', 'IIOWriteWarningListener' + ), + 62 => array ( + 'IIOInvalidTreeException', 'IIOMetadata', 'IIOMetadataController', 'IIOMetadataFormat', 'IIOMetadataFormatImpl', 'IIOMetadataNode' + ), + 63 => array ( + 'BMPImageWriteParam' + ), + 64 => array ( + 'JPEGHuffmanTable', 'JPEGImageReadParam', 'JPEGImageWriteParam', 'JPEGQTable' + ), + 65 => array ( + 'IIORegistry', 'IIOServiceProvider', 'ImageInputStreamSpi', 'ImageOutputStreamSpi', 'ImageReaderSpi', 'ImageReaderWriterSpi', 'ImageTranscoderSpi', 'ImageWriterSpi', 'RegisterableService', 'ServiceRegistry', 'ServiceRegistry.Filter' + ), + 66 => array ( + 'FileCacheImageInputStream', 'FileCacheImageOutputStream', 'FileImageInputStream', 'FileImageOutputStream', 'IIOByteBuffer', 'ImageInputStream', 'ImageInputStreamImpl', 'ImageOutputStream', 'ImageOutputStreamImpl', 'MemoryCacheImageInputStream', 'MemoryCacheImageOutputStream' + ), + 67 => array ( + 'AttributeChangeNotification', 'AttributeChangeNotificationFilter', 'AttributeNotFoundException', 'AttributeValueExp', 'BadAttributeValueExpException', 'BadBinaryOpValueExpException', 'BadStringOperationException', 'Descriptor', 'DescriptorAccess', 'DynamicMBean', 'InstanceAlreadyExistsException', 'InstanceNotFoundException', 'InvalidApplicationException', 'JMException', 'JMRuntimeException', 'ListenerNotFoundException', 'MBeanAttributeInfo', 'MBeanConstructorInfo', 'MBeanException', 'MBeanFeatureInfo', 'MBeanInfo', 'MBeanNotificationInfo', 'MBeanOperationInfo', 'MBeanParameterInfo', 'MBeanPermission', 'MBeanRegistration', 'MBeanRegistrationException', 'MBeanServer', 'MBeanServerBuilder', 'MBeanServerConnection', 'MBeanServerDelegate', 'MBeanServerDelegateMBean', 'MBeanServerFactory', 'MBeanServerInvocationHandler', 'MBeanServerNotification', 'MBeanServerPermission', 'MBeanTrustPermission', 'MalformedObjectNameException', 'NotCompliantMBeanException', 'Notification', 'NotificationBroadcaster', + 'NotificationBroadcasterSupport', 'NotificationEmitter', 'NotificationFilter', 'NotificationFilterSupport', 'NotificationListener', 'ObjectInstance', 'ObjectName', 'OperationsException', 'PersistentMBean', 'Query', 'QueryEval', 'QueryExp', 'ReflectionException', 'RuntimeErrorException', 'RuntimeMBeanException', 'RuntimeOperationsException', 'ServiceNotFoundException', 'StandardMBean', 'StringValueExp', 'ValueExp' + ), + 68 => array ( + 'ClassLoaderRepository', 'MLet', 'MLetMBean', 'PrivateClassLoader', 'PrivateMLet' + ), + 69 => array ( + 'DescriptorSupport', 'InvalidTargetObjectTypeException', 'ModelMBean', 'ModelMBeanAttributeInfo', 'ModelMBeanConstructorInfo', 'ModelMBeanInfo', 'ModelMBeanInfoSupport', 'ModelMBeanNotificationBroadcaster', 'ModelMBeanNotificationInfo', 'ModelMBeanOperationInfo', 'RequiredModelMBean', 'XMLParseException' + ), + 70 => array ( + 'CounterMonitor', 'CounterMonitorMBean', 'GaugeMonitor', 'GaugeMonitorMBean', 'Monitor', 'MonitorMBean', 'MonitorNotification', 'MonitorSettingException', 'StringMonitor', 'StringMonitorMBean' + ), + 71 => array ( + 'ArrayType', 'CompositeData', 'CompositeDataSupport', 'CompositeType', 'InvalidOpenTypeException', 'KeyAlreadyExistsException', 'OpenDataException', 'OpenMBeanAttributeInfo', 'OpenMBeanAttributeInfoSupport', 'OpenMBeanConstructorInfo', 'OpenMBeanConstructorInfoSupport', 'OpenMBeanInfo', 'OpenMBeanInfoSupport', 'OpenMBeanOperationInfo', 'OpenMBeanOperationInfoSupport', 'OpenMBeanParameterInfo', 'OpenMBeanParameterInfoSupport', 'SimpleType', 'TabularData', 'TabularDataSupport', 'TabularType' + ), + 72 => array ( + 'InvalidRelationIdException', 'InvalidRelationServiceException', 'InvalidRelationTypeException', 'InvalidRoleInfoException', 'InvalidRoleValueException', 'MBeanServerNotificationFilter', 'Relation', 'RelationException', 'RelationNotFoundException', 'RelationNotification', 'RelationService', 'RelationServiceMBean', 'RelationServiceNotRegisteredException', 'RelationSupport', 'RelationSupportMBean', 'RelationType', 'RelationTypeNotFoundException', 'RelationTypeSupport', 'Role', 'RoleInfo', 'RoleInfoNotFoundException', 'RoleList', 'RoleNotFoundException', 'RoleResult', 'RoleStatus', 'RoleUnresolved', 'RoleUnresolvedList' + ), + 73 => array ( + 'JMXAuthenticator', 'JMXConnectionNotification', 'JMXConnector', 'JMXConnectorFactory', 'JMXConnectorProvider', 'JMXConnectorServer', 'JMXConnectorServerFactory', 'JMXConnectorServerMBean', 'JMXConnectorServerProvider', 'JMXPrincipal', 'JMXProviderException', 'JMXServerErrorException', 'JMXServiceURL', 'MBeanServerForwarder', 'NotificationResult', 'SubjectDelegationPermission', 'TargetedNotification' + ), + 74 => array ( + 'RMIConnection', 'RMIConnectionImpl', 'RMIConnectionImpl_Stub', 'RMIConnector', 'RMIConnectorServer', 'RMIIIOPServerImpl', 'RMIJRMPServerImpl', 'RMIServer', 'RMIServerImpl', 'RMIServerImpl_Stub' + ), + 75 => array ( + 'TimerAlarmClockNotification', 'TimerMBean', 'TimerNotification' + ), + 76 => array ( + 'AuthenticationNotSupportedException', 'BinaryRefAddr', 'CannotProceedException', 'CommunicationException', 'CompositeName', 'CompoundName', 'ConfigurationException', 'ContextNotEmptyException', 'InitialContext', 'InsufficientResourcesException', 'InterruptedNamingException', 'InvalidNameException', 'LimitExceededException', 'LinkException', 'LinkLoopException', 'LinkRef', 'MalformedLinkException', 'Name', 'NameAlreadyBoundException', 'NameClassPair', 'NameNotFoundException', 'NameParser', 'NamingEnumeration', 'NamingException', 'NamingSecurityException', 'NoInitialContextException', 'NoPermissionException', 'NotContextException', 'OperationNotSupportedException', 'PartialResultException', 'RefAddr', 'Referenceable', 'ReferralException', 'ServiceUnavailableException', 'SizeLimitExceededException', 'StringRefAddr', 'TimeLimitExceededException' + ), + 77 => array ( + 'AttributeInUseException', 'AttributeModificationException', 'BasicAttribute', 'BasicAttributes', 'DirContext', 'InitialDirContext', 'InvalidAttributeIdentifierException', 'InvalidAttributesException', 'InvalidSearchControlsException', 'InvalidSearchFilterException', 'ModificationItem', 'NoSuchAttributeException', 'SchemaViolationException', 'SearchControls', 'SearchResult' + ), + 78 => array ( + 'EventContext', 'EventDirContext', 'NamespaceChangeListener', 'NamingEvent', 'NamingExceptionEvent', 'NamingListener', 'ObjectChangeListener' + ), + 79 => array ( + 'BasicControl', 'ControlFactory', 'ExtendedRequest', 'ExtendedResponse', 'HasControls', 'InitialLdapContext', 'LdapContext', 'LdapName', 'LdapReferralException', 'ManageReferralControl', 'PagedResultsControl', 'PagedResultsResponseControl', 'Rdn', 'SortControl', 'SortKey', 'SortResponseControl', 'StartTlsRequest', 'StartTlsResponse', 'UnsolicitedNotification', 'UnsolicitedNotificationEvent', 'UnsolicitedNotificationListener' + ), + 80 => array ( + 'DirObjectFactory', 'DirStateFactory', 'DirStateFactory.Result', 'DirectoryManager', 'InitialContextFactory', 'InitialContextFactoryBuilder', 'NamingManager', 'ObjectFactory', 'ObjectFactoryBuilder', 'ResolveResult', 'Resolver', 'StateFactory' + ), + 81 => array ( + 'ServerSocketFactory', 'SocketFactory' + ), + 82 => array ( + 'CertPathTrustManagerParameters', 'HandshakeCompletedEvent', 'HandshakeCompletedListener', 'HostnameVerifier', 'HttpsURLConnection', 'KeyManager', 'KeyManagerFactory', 'KeyManagerFactorySpi', 'KeyStoreBuilderParameters', 'ManagerFactoryParameters', 'SSLContext', 'SSLContextSpi', 'SSLEngine', 'SSLEngineResult', 'SSLEngineResult.HandshakeStatus', 'SSLEngineResult.Status', 'SSLException', 'SSLHandshakeException', 'SSLKeyException', 'SSLPeerUnverifiedException', 'SSLPermission', 'SSLProtocolException', 'SSLServerSocket', 'SSLServerSocketFactory', 'SSLSession', 'SSLSessionBindingEvent', 'SSLSessionBindingListener', 'SSLSessionContext', 'SSLSocket', 'SSLSocketFactory', 'TrustManager', 'TrustManagerFactory', 'TrustManagerFactorySpi', 'X509ExtendedKeyManager', 'X509KeyManager', 'X509TrustManager' + ), + 83 => array ( + 'AttributeException', 'CancelablePrintJob', 'Doc', 'DocFlavor', 'DocFlavor.BYTE_ARRAY', 'DocFlavor.CHAR_ARRAY', 'DocFlavor.INPUT_STREAM', 'DocFlavor.READER', 'DocFlavor.SERVICE_FORMATTED', 'DocFlavor.STRING', 'DocFlavor.URL', 'DocPrintJob', 'FlavorException', 'MultiDoc', 'MultiDocPrintJob', 'MultiDocPrintService', 'PrintException', 'PrintService', 'PrintServiceLookup', 'ServiceUI', 'ServiceUIFactory', 'SimpleDoc', 'StreamPrintService', 'StreamPrintServiceFactory', 'URIException' + ), + 84 => array ( + 'AttributeSetUtilities', 'DateTimeSyntax', 'DocAttribute', 'DocAttributeSet', 'EnumSyntax', 'HashAttributeSet', 'HashDocAttributeSet', 'HashPrintJobAttributeSet', 'HashPrintRequestAttributeSet', 'HashPrintServiceAttributeSet', 'IntegerSyntax', 'PrintJobAttribute', 'PrintJobAttributeSet', 'PrintRequestAttribute', 'PrintRequestAttributeSet', 'PrintServiceAttribute', 'PrintServiceAttributeSet', 'ResolutionSyntax', 'SetOfIntegerSyntax', 'Size2DSyntax', 'SupportedValuesAttribute', 'TextSyntax', 'URISyntax', 'UnmodifiableSetException' + ), + 85 => array ( + 'Chromaticity', 'ColorSupported', 'Compression', 'Copies', 'CopiesSupported', 'DateTimeAtCompleted', 'DateTimeAtCreation', 'DateTimeAtProcessing', 'Destination', 'DocumentName', 'Fidelity', 'Finishings', 'JobHoldUntil', 'JobImpressions', 'JobImpressionsCompleted', 'JobImpressionsSupported', 'JobKOctets', 'JobKOctetsProcessed', 'JobKOctetsSupported', 'JobMediaSheets', 'JobMediaSheetsCompleted', 'JobMediaSheetsSupported', 'JobMessageFromOperator', 'JobName', 'JobOriginatingUserName', 'JobPriority', 'JobPrioritySupported', 'JobSheets', 'JobState', 'JobStateReason', 'JobStateReasons', 'Media', 'MediaName', 'MediaPrintableArea', 'MediaSize', 'MediaSize.Engineering', 'MediaSize.ISO', 'MediaSize.JIS', 'MediaSize.NA', 'MediaSize.Other', 'MediaSizeName', 'MediaTray', 'MultipleDocumentHandling', 'NumberOfDocuments', 'NumberOfInterveningJobs', 'NumberUp', 'NumberUpSupported', 'OrientationRequested', 'OutputDeviceAssigned', 'PDLOverrideSupported', 'PageRanges', 'PagesPerMinute', 'PagesPerMinuteColor', + 'PresentationDirection', 'PrintQuality', 'PrinterInfo', 'PrinterIsAcceptingJobs', 'PrinterLocation', 'PrinterMakeAndModel', 'PrinterMessageFromOperator', 'PrinterMoreInfo', 'PrinterMoreInfoManufacturer', 'PrinterName', 'PrinterResolution', 'PrinterState', 'PrinterStateReason', 'PrinterStateReasons', 'PrinterURI', 'QueuedJobCount', 'ReferenceUriSchemesSupported', 'RequestingUserName', 'Severity', 'SheetCollate', 'Sides' + ), + 86 => array ( + 'PrintEvent', 'PrintJobAdapter', 'PrintJobAttributeEvent', 'PrintJobAttributeListener', 'PrintJobEvent', 'PrintJobListener', 'PrintServiceAttributeEvent', 'PrintServiceAttributeListener' + ), + 87 => array ( + 'PortableRemoteObject' + ), + 88 => array ( + 'ClassDesc', 'PortableRemoteObjectDelegate', 'Stub', 'StubDelegate', 'Tie', 'Util', 'UtilDelegate', 'ValueHandler', 'ValueHandlerMultiFormat' + ), + 89 => array ( + 'SslRMIClientSocketFactory', 'SslRMIServerSocketFactory' + ), + 90 => array ( + 'AuthPermission', 'DestroyFailedException', 'Destroyable', 'PrivateCredentialPermission', 'RefreshFailedException', 'Refreshable', 'Subject', 'SubjectDomainCombiner' + ), + 91 => array ( + 'Callback', 'CallbackHandler', 'ChoiceCallback', 'ConfirmationCallback', 'LanguageCallback', 'NameCallback', 'PasswordCallback', 'TextInputCallback', 'TextOutputCallback', 'UnsupportedCallbackException' + ), + 92 => array ( + 'DelegationPermission', 'KerberosKey', 'KerberosPrincipal', 'KerberosTicket', 'ServicePermission' + ), + 93 => array ( + 'AccountException', 'AccountExpiredException', 'AccountLockedException', 'AccountNotFoundException', 'AppConfigurationEntry', 'AppConfigurationEntry.LoginModuleControlFlag', 'Configuration', 'CredentialException', 'CredentialExpiredException', 'CredentialNotFoundException', 'FailedLoginException', 'LoginContext', 'LoginException' + ), + 94 => array ( + 'LoginModule' + ), + 95 => array ( + 'X500Principal', 'X500PrivateCredential' + ), + 96 => array ( + 'AuthorizeCallback', 'RealmCallback', 'RealmChoiceCallback', 'Sasl', 'SaslClient', 'SaslClientFactory', 'SaslException', 'SaslServer', 'SaslServerFactory' + ), + 97 => array ( + 'ControllerEventListener', 'Instrument', 'InvalidMidiDataException', 'MetaEventListener', 'MetaMessage', 'MidiChannel', 'MidiDevice', 'MidiDevice.Info', 'MidiEvent', 'MidiFileFormat', 'MidiMessage', 'MidiSystem', 'MidiUnavailableException', 'Patch', 'Receiver', 'Sequence', 'Sequencer', 'Sequencer.SyncMode', 'ShortMessage', 'Soundbank', 'SoundbankResource', 'Synthesizer', 'SysexMessage', 'Track', 'Transmitter', 'VoiceStatus' + ), + 98 => array ( + 'MidiDeviceProvider', 'MidiFileReader', 'MidiFileWriter', 'SoundbankReader' + ), + 99 => array ( + 'AudioFileFormat', 'AudioFileFormat.Type', 'AudioFormat', 'AudioFormat.Encoding', 'AudioInputStream', 'AudioPermission', 'AudioSystem', 'BooleanControl', 'BooleanControl.Type', 'Clip', 'CompoundControl', 'CompoundControl.Type', 'Control.Type', 'DataLine', 'DataLine.Info', 'EnumControl', 'EnumControl.Type', 'FloatControl', 'FloatControl.Type', 'Line', 'Line.Info', 'LineEvent', 'LineEvent.Type', 'LineListener', 'LineUnavailableException', 'Mixer', 'Mixer.Info', 'Port', 'Port.Info', 'ReverbType', 'SourceDataLine', 'TargetDataLine', 'UnsupportedAudioFileException' + ), + 100 => array ( + 'AudioFileReader', 'AudioFileWriter', 'FormatConversionProvider', 'MixerProvider' + ), + 101 => array ( + 'ConnectionEvent', 'ConnectionEventListener', 'ConnectionPoolDataSource', 'DataSource', 'PooledConnection', 'RowSet', 'RowSetEvent', 'RowSetInternal', 'RowSetListener', 'RowSetMetaData', 'RowSetReader', 'RowSetWriter', 'XAConnection', 'XADataSource' + ), + 102 => array ( + 'BaseRowSet', 'CachedRowSet', 'FilteredRowSet', 'JdbcRowSet', 'JoinRowSet', 'Joinable', 'Predicate', 'RowSetMetaDataImpl', 'RowSetWarning', 'WebRowSet' + ), + 103 => array ( + 'SQLInputImpl', 'SQLOutputImpl', 'SerialArray', 'SerialBlob', 'SerialClob', 'SerialDatalink', 'SerialException', 'SerialJavaObject', 'SerialRef', 'SerialStruct' + ), + 104 => array ( + 'SyncFactory', 'SyncFactoryException', 'SyncProvider', 'SyncProviderException', 'SyncResolver', 'TransactionalWriter', 'XmlReader', 'XmlWriter' + ), + 105 => array ( + 'AbstractAction', 'AbstractButton', 'AbstractCellEditor', 'AbstractListModel', 'AbstractSpinnerModel', 'Action', 'ActionMap', 'BorderFactory', 'BoundedRangeModel', 'Box', 'Box.Filler', 'BoxLayout', 'ButtonGroup', 'ButtonModel', 'CellEditor', 'CellRendererPane', 'ComboBoxEditor', 'ComboBoxModel', 'ComponentInputMap', 'DebugGraphics', 'DefaultBoundedRangeModel', 'DefaultButtonModel', 'DefaultCellEditor', 'DefaultComboBoxModel', 'DefaultDesktopManager', 'DefaultFocusManager', 'DefaultListCellRenderer', 'DefaultListCellRenderer.UIResource', 'DefaultListModel', 'DefaultListSelectionModel', 'DefaultSingleSelectionModel', 'DesktopManager', 'FocusManager', 'GrayFilter', 'Icon', 'ImageIcon', 'InputMap', 'InputVerifier', 'InternalFrameFocusTraversalPolicy', 'JApplet', 'JButton', 'JCheckBox', 'JCheckBoxMenuItem', 'JColorChooser', 'JComboBox', 'JComboBox.KeySelectionManager', 'JComponent', 'JDesktopPane', 'JDialog', 'JEditorPane', 'JFileChooser', 'JFormattedTextField', 'JFormattedTextField.AbstractFormatter', + 'JFormattedTextField.AbstractFormatterFactory', 'JFrame', 'JInternalFrame', 'JInternalFrame.JDesktopIcon', 'JLabel', 'JLayeredPane', 'JList', 'JMenu', 'JMenuBar', 'JMenuItem', 'JOptionPane', 'JPanel', 'JPasswordField', 'JPopupMenu', 'JPopupMenu.Separator', 'JProgressBar', 'JRadioButton', 'JRadioButtonMenuItem', 'JRootPane', 'JScrollBar', 'JScrollPane', 'JSeparator', 'JSlider', 'JSpinner', 'JSpinner.DateEditor', 'JSpinner.DefaultEditor', 'JSpinner.ListEditor', 'JSpinner.NumberEditor', 'JSplitPane', 'JTabbedPane', 'JTable', 'JTable.PrintMode', 'JTextArea', 'JTextField', 'JTextPane', 'JToggleButton', 'JToggleButton.ToggleButtonModel', 'JToolBar', 'JToolBar.Separator', 'JToolTip', 'JTree', 'JTree.DynamicUtilTreeNode', 'JTree.EmptySelectionModel', 'JViewport', 'JWindow', 'KeyStroke', 'LayoutFocusTraversalPolicy', 'ListCellRenderer', 'ListModel', 'ListSelectionModel', 'LookAndFeel', 'MenuElement', 'MenuSelectionManager', 'MutableComboBoxModel', 'OverlayLayout', 'Popup', 'PopupFactory', 'ProgressMonitor', + 'ProgressMonitorInputStream', 'Renderer', 'RepaintManager', 'RootPaneContainer', 'ScrollPaneConstants', 'ScrollPaneLayout', 'ScrollPaneLayout.UIResource', 'Scrollable', 'SingleSelectionModel', 'SizeRequirements', 'SizeSequence', 'SortingFocusTraversalPolicy', 'SpinnerDateModel', 'SpinnerListModel', 'SpinnerModel', 'SpinnerNumberModel', 'Spring', 'SpringLayout', 'SpringLayout.Constraints', 'SwingConstants', 'SwingUtilities', 'ToolTipManager', 'TransferHandler', 'UIDefaults', 'UIDefaults.ActiveValue', 'UIDefaults.LazyInputMap', 'UIDefaults.LazyValue', 'UIDefaults.ProxyLazyValue', 'UIManager', 'UIManager.LookAndFeelInfo', 'UnsupportedLookAndFeelException', 'ViewportLayout', 'WindowConstants' + ), + 106 => array ( + 'AbstractBorder', 'BevelBorder', 'Border', 'CompoundBorder', 'EmptyBorder', 'EtchedBorder', 'LineBorder', 'MatteBorder', 'SoftBevelBorder', 'TitledBorder' + ), + 107 => array ( + 'AbstractColorChooserPanel', 'ColorChooserComponentFactory', 'ColorSelectionModel', 'DefaultColorSelectionModel' + ), + 108 => array ( + 'AncestorEvent', 'AncestorListener', 'CaretEvent', 'CaretListener', 'CellEditorListener', 'ChangeEvent', 'ChangeListener', 'DocumentEvent.ElementChange', 'DocumentEvent.EventType', 'DocumentListener', 'EventListenerList', 'HyperlinkEvent', 'HyperlinkEvent.EventType', 'HyperlinkListener', 'InternalFrameAdapter', 'InternalFrameEvent', 'InternalFrameListener', 'ListDataEvent', 'ListDataListener', 'ListSelectionEvent', 'ListSelectionListener', 'MenuDragMouseEvent', 'MenuDragMouseListener', 'MenuEvent', 'MenuKeyEvent', 'MenuKeyListener', 'MenuListener', 'MouseInputAdapter', 'MouseInputListener', 'PopupMenuEvent', 'PopupMenuListener', 'SwingPropertyChangeSupport', 'TableColumnModelEvent', 'TableColumnModelListener', 'TableModelEvent', 'TableModelListener', 'TreeExpansionEvent', 'TreeExpansionListener', 'TreeModelEvent', 'TreeModelListener', 'TreeSelectionEvent', 'TreeSelectionListener', 'TreeWillExpandListener', 'UndoableEditEvent', 'UndoableEditListener' + ), + 109 => array ( + 'FileSystemView', 'FileView' + ), + 110 => array ( + 'ActionMapUIResource', 'BorderUIResource', 'BorderUIResource.BevelBorderUIResource', 'BorderUIResource.CompoundBorderUIResource', 'BorderUIResource.EmptyBorderUIResource', 'BorderUIResource.EtchedBorderUIResource', 'BorderUIResource.LineBorderUIResource', 'BorderUIResource.MatteBorderUIResource', 'BorderUIResource.TitledBorderUIResource', 'ButtonUI', 'ColorChooserUI', 'ColorUIResource', 'ComboBoxUI', 'ComponentInputMapUIResource', 'ComponentUI', 'DesktopIconUI', 'DesktopPaneUI', 'DimensionUIResource', 'FileChooserUI', 'FontUIResource', 'IconUIResource', 'InputMapUIResource', 'InsetsUIResource', 'InternalFrameUI', 'LabelUI', 'ListUI', 'MenuBarUI', 'MenuItemUI', 'OptionPaneUI', 'PanelUI', 'PopupMenuUI', 'ProgressBarUI', 'RootPaneUI', 'ScrollBarUI', 'ScrollPaneUI', 'SeparatorUI', 'SliderUI', 'SpinnerUI', 'SplitPaneUI', 'TabbedPaneUI', 'TableHeaderUI', 'TableUI', 'TextUI', 'ToolBarUI', 'ToolTipUI', 'TreeUI', 'UIResource', 'ViewportUI' + ), + 111 => array ( + 'BasicArrowButton', 'BasicBorders', 'BasicBorders.ButtonBorder', 'BasicBorders.FieldBorder', 'BasicBorders.MarginBorder', 'BasicBorders.MenuBarBorder', 'BasicBorders.RadioButtonBorder', 'BasicBorders.RolloverButtonBorder', 'BasicBorders.SplitPaneBorder', 'BasicBorders.ToggleButtonBorder', 'BasicButtonListener', 'BasicButtonUI', 'BasicCheckBoxMenuItemUI', 'BasicCheckBoxUI', 'BasicColorChooserUI', 'BasicComboBoxEditor', 'BasicComboBoxEditor.UIResource', 'BasicComboBoxRenderer', 'BasicComboBoxRenderer.UIResource', 'BasicComboBoxUI', 'BasicComboPopup', 'BasicDesktopIconUI', 'BasicDesktopPaneUI', 'BasicDirectoryModel', 'BasicEditorPaneUI', 'BasicFileChooserUI', 'BasicFormattedTextFieldUI', 'BasicGraphicsUtils', 'BasicHTML', 'BasicIconFactory', 'BasicInternalFrameTitlePane', 'BasicInternalFrameUI', 'BasicLabelUI', 'BasicListUI', 'BasicLookAndFeel', 'BasicMenuBarUI', 'BasicMenuItemUI', 'BasicMenuUI', 'BasicOptionPaneUI', 'BasicOptionPaneUI.ButtonAreaLayout', 'BasicPanelUI', 'BasicPasswordFieldUI', + 'BasicPopupMenuSeparatorUI', 'BasicPopupMenuUI', 'BasicProgressBarUI', 'BasicRadioButtonMenuItemUI', 'BasicRadioButtonUI', 'BasicRootPaneUI', 'BasicScrollBarUI', 'BasicScrollPaneUI', 'BasicSeparatorUI', 'BasicSliderUI', 'BasicSpinnerUI', 'BasicSplitPaneDivider', 'BasicSplitPaneUI', 'BasicTabbedPaneUI', 'BasicTableHeaderUI', 'BasicTableUI', 'BasicTextAreaUI', 'BasicTextFieldUI', 'BasicTextPaneUI', 'BasicTextUI', 'BasicTextUI.BasicCaret', 'BasicTextUI.BasicHighlighter', 'BasicToggleButtonUI', 'BasicToolBarSeparatorUI', 'BasicToolBarUI', 'BasicToolTipUI', 'BasicTreeUI', 'BasicViewportUI', 'ComboPopup', 'DefaultMenuLayout' + ), + 112 => array ( + 'DefaultMetalTheme', 'MetalBorders', 'MetalBorders.ButtonBorder', 'MetalBorders.Flush3DBorder', 'MetalBorders.InternalFrameBorder', 'MetalBorders.MenuBarBorder', 'MetalBorders.MenuItemBorder', 'MetalBorders.OptionDialogBorder', 'MetalBorders.PaletteBorder', 'MetalBorders.PopupMenuBorder', 'MetalBorders.RolloverButtonBorder', 'MetalBorders.ScrollPaneBorder', 'MetalBorders.TableHeaderBorder', 'MetalBorders.TextFieldBorder', 'MetalBorders.ToggleButtonBorder', 'MetalBorders.ToolBarBorder', 'MetalButtonUI', 'MetalCheckBoxIcon', 'MetalCheckBoxUI', 'MetalComboBoxButton', 'MetalComboBoxEditor', 'MetalComboBoxEditor.UIResource', 'MetalComboBoxIcon', 'MetalComboBoxUI', 'MetalDesktopIconUI', 'MetalFileChooserUI', 'MetalIconFactory', 'MetalIconFactory.FileIcon16', 'MetalIconFactory.FolderIcon16', 'MetalIconFactory.PaletteCloseIcon', 'MetalIconFactory.TreeControlIcon', 'MetalIconFactory.TreeFolderIcon', 'MetalIconFactory.TreeLeafIcon', 'MetalInternalFrameTitlePane', 'MetalInternalFrameUI', 'MetalLabelUI', + 'MetalLookAndFeel', 'MetalMenuBarUI', 'MetalPopupMenuSeparatorUI', 'MetalProgressBarUI', 'MetalRadioButtonUI', 'MetalRootPaneUI', 'MetalScrollBarUI', 'MetalScrollButton', 'MetalScrollPaneUI', 'MetalSeparatorUI', 'MetalSliderUI', 'MetalSplitPaneUI', 'MetalTabbedPaneUI', 'MetalTextFieldUI', 'MetalTheme', 'MetalToggleButtonUI', 'MetalToolBarUI', 'MetalToolTipUI', 'MetalTreeUI', 'OceanTheme' + ), + 113 => array ( + 'MultiButtonUI', 'MultiColorChooserUI', 'MultiComboBoxUI', 'MultiDesktopIconUI', 'MultiDesktopPaneUI', 'MultiFileChooserUI', 'MultiInternalFrameUI', 'MultiLabelUI', 'MultiListUI', 'MultiLookAndFeel', 'MultiMenuBarUI', 'MultiMenuItemUI', 'MultiOptionPaneUI', 'MultiPanelUI', 'MultiPopupMenuUI', 'MultiProgressBarUI', 'MultiRootPaneUI', 'MultiScrollBarUI', 'MultiScrollPaneUI', 'MultiSeparatorUI', 'MultiSliderUI', 'MultiSpinnerUI', 'MultiSplitPaneUI', 'MultiTabbedPaneUI', 'MultiTableHeaderUI', 'MultiTableUI', 'MultiTextUI', 'MultiToolBarUI', 'MultiToolTipUI', 'MultiTreeUI', 'MultiViewportUI' + ), + 114 => array ( + 'ColorType', 'Region', 'SynthConstants', 'SynthContext', 'SynthGraphicsUtils', 'SynthLookAndFeel', 'SynthPainter', 'SynthStyle', 'SynthStyleFactory' + ), + 115 => array ( + 'AbstractTableModel', 'DefaultTableCellRenderer', 'DefaultTableCellRenderer.UIResource', 'DefaultTableColumnModel', 'DefaultTableModel', 'JTableHeader', 'TableCellEditor', 'TableCellRenderer', 'TableColumn', 'TableColumnModel', 'TableModel' + ), + 116 => array ( + 'AbstractDocument', 'AbstractDocument.AttributeContext', 'AbstractDocument.Content', 'AbstractDocument.ElementEdit', 'AbstractWriter', 'AsyncBoxView', 'AttributeSet.CharacterAttribute', 'AttributeSet.ColorAttribute', 'AttributeSet.FontAttribute', 'AttributeSet.ParagraphAttribute', 'BadLocationException', 'BoxView', 'Caret', 'ChangedCharSetException', 'ComponentView', 'CompositeView', 'DateFormatter', 'DefaultCaret', 'DefaultEditorKit', 'DefaultEditorKit.BeepAction', 'DefaultEditorKit.CopyAction', 'DefaultEditorKit.CutAction', 'DefaultEditorKit.DefaultKeyTypedAction', 'DefaultEditorKit.InsertBreakAction', 'DefaultEditorKit.InsertContentAction', 'DefaultEditorKit.InsertTabAction', 'DefaultEditorKit.PasteAction', 'DefaultFormatter', 'DefaultFormatterFactory', 'DefaultHighlighter', 'DefaultHighlighter.DefaultHighlightPainter', 'DefaultStyledDocument', 'DefaultStyledDocument.AttributeUndoableEdit', 'DefaultStyledDocument.ElementSpec', 'DefaultTextUI', 'DocumentFilter', 'DocumentFilter.FilterBypass', + 'EditorKit', 'ElementIterator', 'FieldView', 'FlowView', 'FlowView.FlowStrategy', 'GapContent', 'GlyphView', 'GlyphView.GlyphPainter', 'Highlighter', 'Highlighter.Highlight', 'Highlighter.HighlightPainter', 'IconView', 'InternationalFormatter', 'JTextComponent', 'JTextComponent.KeyBinding', 'Keymap', 'LabelView', 'LayeredHighlighter', 'LayeredHighlighter.LayerPainter', 'LayoutQueue', 'MaskFormatter', 'MutableAttributeSet', 'NavigationFilter', 'NavigationFilter.FilterBypass', 'NumberFormatter', 'PasswordView', 'PlainDocument', 'PlainView', 'Position', 'Position.Bias', 'Segment', 'SimpleAttributeSet', 'StringContent', 'Style', 'StyleConstants', 'StyleConstants.CharacterConstants', 'StyleConstants.ColorConstants', 'StyleConstants.FontConstants', 'StyleConstants.ParagraphConstants', 'StyleContext', 'StyledDocument', 'StyledEditorKit', 'StyledEditorKit.AlignmentAction', 'StyledEditorKit.BoldAction', 'StyledEditorKit.FontFamilyAction', 'StyledEditorKit.FontSizeAction', 'StyledEditorKit.ForegroundAction', + 'StyledEditorKit.ItalicAction', 'StyledEditorKit.StyledTextAction', 'StyledEditorKit.UnderlineAction', 'TabExpander', 'TabSet', 'TabStop', 'TabableView', 'TableView', 'TextAction', 'Utilities', 'View', 'ViewFactory', 'WrappedPlainView', 'ZoneView' + ), + 117 => array ( + 'BlockView', 'CSS', 'CSS.Attribute', 'FormSubmitEvent', 'FormSubmitEvent.MethodType', 'FormView', 'HTML', 'HTML.Attribute', 'HTML.Tag', 'HTML.UnknownTag', 'HTMLDocument', 'HTMLDocument.Iterator', 'HTMLEditorKit', 'HTMLEditorKit.HTMLFactory', 'HTMLEditorKit.HTMLTextAction', 'HTMLEditorKit.InsertHTMLTextAction', 'HTMLEditorKit.LinkController', 'HTMLEditorKit.Parser', 'HTMLEditorKit.ParserCallback', 'HTMLFrameHyperlinkEvent', 'HTMLWriter', 'ImageView', 'InlineView', 'ListView', 'MinimalHTMLWriter', 'ObjectView', 'Option', 'StyleSheet', 'StyleSheet.BoxPainter', 'StyleSheet.ListPainter' + ), + 118 => array ( + 'ContentModel', 'DTD', 'DTDConstants', 'DocumentParser', 'ParserDelegator', 'TagElement' + ), + 119 => array ( + 'RTFEditorKit' + ), + 120 => array ( + 'AbstractLayoutCache', 'AbstractLayoutCache.NodeDimensions', 'DefaultMutableTreeNode', 'DefaultTreeCellEditor', 'DefaultTreeCellRenderer', 'DefaultTreeModel', 'DefaultTreeSelectionModel', 'ExpandVetoException', 'FixedHeightLayoutCache', 'MutableTreeNode', 'RowMapper', 'TreeCellEditor', 'TreeCellRenderer', 'TreeModel', 'TreeNode', 'TreePath', 'TreeSelectionModel', 'VariableHeightLayoutCache' + ), + 121 => array ( + 'AbstractUndoableEdit', 'CannotRedoException', 'CannotUndoException', 'CompoundEdit', 'StateEdit', 'StateEditable', 'UndoManager', 'UndoableEdit', 'UndoableEditSupport' + ), + 122 => array ( + 'InvalidTransactionException', 'TransactionRequiredException', 'TransactionRolledbackException' + ), + 123 => array ( + 'XAException', 'XAResource', 'Xid' + ), + 124 => array ( + 'XMLConstants' + ), + 125 => array ( + 'DatatypeConfigurationException', 'DatatypeConstants', 'DatatypeConstants.Field', 'DatatypeFactory', 'Duration', 'XMLGregorianCalendar' + ), + 126 => array ( + 'NamespaceContext', 'QName' + ), + 127 => array ( + 'DocumentBuilder', 'DocumentBuilderFactory', 'FactoryConfigurationError', 'ParserConfigurationException', 'SAXParser', 'SAXParserFactory' + ), + 128 => array ( + 'ErrorListener', 'OutputKeys', 'Result', 'Source', 'SourceLocator', 'Templates', 'Transformer', 'TransformerConfigurationException', 'TransformerException', 'TransformerFactory', 'TransformerFactoryConfigurationError', 'URIResolver' + ), + 129 => array ( + 'DOMResult', 'DOMSource' + ), + 130 => array ( + 'SAXResult', 'SAXSource', 'SAXTransformerFactory', 'TemplatesHandler', 'TransformerHandler' + ), + 131 => array ( + 'StreamResult', 'StreamSource' + ), + 132 => array ( + 'Schema', 'SchemaFactory', 'SchemaFactoryLoader', 'TypeInfoProvider', 'Validator', 'ValidatorHandler' + ), + 133 => array ( + 'XPath', 'XPathConstants', 'XPathException', 'XPathExpression', 'XPathExpressionException', 'XPathFactory', 'XPathFactoryConfigurationException', 'XPathFunction', 'XPathFunctionException', 'XPathFunctionResolver', 'XPathVariableResolver' + ), + 134 => array ( + 'ChannelBinding', 'GSSContext', 'GSSCredential', 'GSSException', 'GSSManager', 'GSSName', 'MessageProp', 'Oid' + ), + 135 => array ( + 'ACTIVITY_COMPLETED', 'ACTIVITY_REQUIRED', 'ARG_IN', 'ARG_INOUT', 'ARG_OUT', 'Any', 'AnyHolder', 'AnySeqHolder', 'BAD_CONTEXT', 'BAD_INV_ORDER', 'BAD_OPERATION', 'BAD_PARAM', 'BAD_POLICY', 'BAD_POLICY_TYPE', 'BAD_POLICY_VALUE', 'BAD_QOS', 'BAD_TYPECODE', 'BooleanHolder', 'BooleanSeqHelper', 'BooleanSeqHolder', 'ByteHolder', 'CODESET_INCOMPATIBLE', 'COMM_FAILURE', 'CTX_RESTRICT_SCOPE', 'CharHolder', 'CharSeqHelper', 'CharSeqHolder', 'CompletionStatus', 'CompletionStatusHelper', 'ContextList', 'CurrentHolder', 'CustomMarshal', 'DATA_CONVERSION', 'DefinitionKind', 'DefinitionKindHelper', 'DomainManager', 'DomainManagerOperations', 'DoubleHolder', 'DoubleSeqHelper', 'DoubleSeqHolder', 'Environment', 'ExceptionList', 'FREE_MEM', 'FixedHolder', 'FloatHolder', 'FloatSeqHelper', 'FloatSeqHolder', 'IDLType', 'IDLTypeHelper', 'IDLTypeOperations', 'IMP_LIMIT', 'INITIALIZE', 'INTERNAL', 'INTF_REPOS', 'INVALID_ACTIVITY', 'INVALID_TRANSACTION', 'INV_FLAG', 'INV_IDENT', 'INV_OBJREF', 'INV_POLICY', 'IRObject', + 'IRObjectOperations', 'IdentifierHelper', 'IntHolder', 'LocalObject', 'LongHolder', 'LongLongSeqHelper', 'LongLongSeqHolder', 'LongSeqHelper', 'LongSeqHolder', 'MARSHAL', 'NO_IMPLEMENT', 'NO_MEMORY', 'NO_PERMISSION', 'NO_RESOURCES', 'NO_RESPONSE', 'NVList', 'NamedValue', 'OBJECT_NOT_EXIST', 'OBJ_ADAPTER', 'OMGVMCID', 'ObjectHelper', 'ObjectHolder', 'OctetSeqHelper', 'OctetSeqHolder', 'PERSIST_STORE', 'PRIVATE_MEMBER', 'PUBLIC_MEMBER', 'ParameterMode', 'ParameterModeHelper', 'ParameterModeHolder', 'PolicyError', 'PolicyErrorCodeHelper', 'PolicyErrorHelper', 'PolicyErrorHolder', 'PolicyHelper', 'PolicyHolder', 'PolicyListHelper', 'PolicyListHolder', 'PolicyOperations', 'PolicyTypeHelper', 'PrincipalHolder', 'REBIND', 'RepositoryIdHelper', 'Request', 'ServerRequest', 'ServiceDetail', 'ServiceDetailHelper', 'ServiceInformation', 'ServiceInformationHelper', 'ServiceInformationHolder', 'SetOverrideType', 'SetOverrideTypeHelper', 'ShortHolder', 'ShortSeqHelper', 'ShortSeqHolder', 'StringHolder', + 'StringSeqHelper', 'StringSeqHolder', 'StringValueHelper', 'StructMember', 'StructMemberHelper', 'SystemException', 'TCKind', 'TIMEOUT', 'TRANSACTION_MODE', 'TRANSACTION_REQUIRED', 'TRANSACTION_ROLLEDBACK', 'TRANSACTION_UNAVAILABLE', 'TRANSIENT', 'TypeCode', 'TypeCodeHolder', 'ULongLongSeqHelper', 'ULongLongSeqHolder', 'ULongSeqHelper', 'ULongSeqHolder', 'UNSUPPORTED_POLICY', 'UNSUPPORTED_POLICY_VALUE', 'UShortSeqHelper', 'UShortSeqHolder', 'UnionMember', 'UnionMemberHelper', 'UnknownUserException', 'UnknownUserExceptionHelper', 'UnknownUserExceptionHolder', 'UserException', 'VM_ABSTRACT', 'VM_CUSTOM', 'VM_NONE', 'VM_TRUNCATABLE', 'ValueBaseHelper', 'ValueBaseHolder', 'ValueMember', 'ValueMemberHelper', 'VersionSpecHelper', 'VisibilityHelper', 'WCharSeqHelper', 'WCharSeqHolder', 'WStringSeqHelper', 'WStringSeqHolder', 'WStringValueHelper', 'WrongTransaction', 'WrongTransactionHelper', 'WrongTransactionHolder', '_IDLTypeStub', '_PolicyStub' + ), + 136 => array ( + 'Invalid', 'InvalidSeq' + ), + 137 => array ( + 'BadKind' + ), + 138 => array ( + 'ApplicationException', 'BoxedValueHelper', 'CustomValue', 'IDLEntity', 'IndirectionException', 'InvokeHandler', 'RemarshalException', 'ResponseHandler', 'ServantObject', 'Streamable', 'StreamableValue', 'UnknownException', 'ValueBase', 'ValueFactory', 'ValueInputStream', 'ValueOutputStream' + ), + 139 => array ( + 'BindingHelper', 'BindingHolder', 'BindingIterator', 'BindingIteratorHelper', 'BindingIteratorHolder', 'BindingIteratorOperations', 'BindingIteratorPOA', 'BindingListHelper', 'BindingListHolder', 'BindingType', 'BindingTypeHelper', 'BindingTypeHolder', 'IstringHelper', 'NameComponent', 'NameComponentHelper', 'NameComponentHolder', 'NameHelper', 'NameHolder', 'NamingContext', 'NamingContextExt', 'NamingContextExtHelper', 'NamingContextExtHolder', 'NamingContextExtOperations', 'NamingContextExtPOA', 'NamingContextHelper', 'NamingContextHolder', 'NamingContextOperations', 'NamingContextPOA', '_BindingIteratorImplBase', '_BindingIteratorStub', '_NamingContextExtStub', '_NamingContextImplBase', '_NamingContextStub' + ), + 140 => array ( + 'AddressHelper', 'InvalidAddress', 'InvalidAddressHelper', 'InvalidAddressHolder', 'StringNameHelper', 'URLStringHelper' + ), + 141 => array ( + 'AlreadyBound', 'AlreadyBoundHelper', 'AlreadyBoundHolder', 'CannotProceed', 'CannotProceedHelper', 'CannotProceedHolder', 'InvalidNameHolder', 'NotEmpty', 'NotEmptyHelper', 'NotEmptyHolder', 'NotFound', 'NotFoundHelper', 'NotFoundHolder', 'NotFoundReason', 'NotFoundReasonHelper', 'NotFoundReasonHolder' + ), + 142 => array ( + 'Parameter' + ), + 143 => array ( + 'DynAnyFactory', 'DynAnyFactoryHelper', 'DynAnyFactoryOperations', 'DynAnyHelper', 'DynAnyOperations', 'DynAnySeqHelper', 'DynArrayHelper', 'DynArrayOperations', 'DynEnumHelper', 'DynEnumOperations', 'DynFixedHelper', 'DynFixedOperations', 'DynSequenceHelper', 'DynSequenceOperations', 'DynStructHelper', 'DynStructOperations', 'DynUnionHelper', 'DynUnionOperations', 'DynValueBox', 'DynValueBoxOperations', 'DynValueCommon', 'DynValueCommonOperations', 'DynValueHelper', 'DynValueOperations', 'NameDynAnyPair', 'NameDynAnyPairHelper', 'NameDynAnyPairSeqHelper', 'NameValuePairSeqHelper', '_DynAnyFactoryStub', '_DynAnyStub', '_DynArrayStub', '_DynEnumStub', '_DynFixedStub', '_DynSequenceStub', '_DynStructStub', '_DynUnionStub', '_DynValueStub' + ), + 144 => array ( + 'InconsistentTypeCodeHelper' + ), + 145 => array ( + 'InvalidValueHelper' + ), + 146 => array ( + 'CodeSets', 'Codec', 'CodecFactory', 'CodecFactoryHelper', 'CodecFactoryOperations', 'CodecOperations', 'ComponentIdHelper', 'ENCODING_CDR_ENCAPS', 'Encoding', 'ExceptionDetailMessage', 'IOR', 'IORHelper', 'IORHolder', 'MultipleComponentProfileHelper', 'MultipleComponentProfileHolder', 'ProfileIdHelper', 'RMICustomMaxStreamFormat', 'ServiceContext', 'ServiceContextHelper', 'ServiceContextHolder', 'ServiceContextListHelper', 'ServiceContextListHolder', 'ServiceIdHelper', 'TAG_ALTERNATE_IIOP_ADDRESS', 'TAG_CODE_SETS', 'TAG_INTERNET_IOP', 'TAG_JAVA_CODEBASE', 'TAG_MULTIPLE_COMPONENTS', 'TAG_ORB_TYPE', 'TAG_POLICIES', 'TAG_RMI_CUSTOM_MAX_STREAM_FORMAT', 'TaggedComponent', 'TaggedComponentHelper', 'TaggedComponentHolder', 'TaggedProfile', 'TaggedProfileHelper', 'TaggedProfileHolder', 'TransactionService' + ), + 147 => array ( + 'UnknownEncoding', 'UnknownEncodingHelper' + ), + 148 => array ( + 'FormatMismatch', 'FormatMismatchHelper', 'InvalidTypeForEncoding', 'InvalidTypeForEncodingHelper' + ), + 149 => array ( + 'SYNC_WITH_TRANSPORT', 'SyncScopeHelper' + ), + 150 => array ( + 'ACTIVE', 'AdapterManagerIdHelper', 'AdapterNameHelper', 'AdapterStateHelper', 'ClientRequestInfo', 'ClientRequestInfoOperations', 'ClientRequestInterceptor', 'ClientRequestInterceptorOperations', 'DISCARDING', 'HOLDING', 'INACTIVE', 'IORInfo', 'IORInfoOperations', 'IORInterceptor', 'IORInterceptorOperations', 'IORInterceptor_3_0', 'IORInterceptor_3_0Helper', 'IORInterceptor_3_0Holder', 'IORInterceptor_3_0Operations', 'Interceptor', 'InterceptorOperations', 'InvalidSlot', 'InvalidSlotHelper', 'LOCATION_FORWARD', 'NON_EXISTENT', 'ORBIdHelper', 'ORBInitInfo', 'ORBInitInfoOperations', 'ORBInitializer', 'ORBInitializerOperations', 'ObjectReferenceFactory', 'ObjectReferenceFactoryHelper', 'ObjectReferenceFactoryHolder', 'ObjectReferenceTemplate', 'ObjectReferenceTemplateHelper', 'ObjectReferenceTemplateHolder', 'ObjectReferenceTemplateSeqHelper', 'ObjectReferenceTemplateSeqHolder', 'PolicyFactory', 'PolicyFactoryOperations', 'RequestInfo', 'RequestInfoOperations', 'SUCCESSFUL', 'SYSTEM_EXCEPTION', + 'ServerIdHelper', 'ServerRequestInfo', 'ServerRequestInfoOperations', 'ServerRequestInterceptor', 'ServerRequestInterceptorOperations', 'TRANSPORT_RETRY', 'USER_EXCEPTION' + ), + 151 => array ( + 'DuplicateName', 'DuplicateNameHelper' + ), + 152 => array ( + 'AdapterActivator', 'AdapterActivatorOperations', 'ID_ASSIGNMENT_POLICY_ID', 'ID_UNIQUENESS_POLICY_ID', 'IMPLICIT_ACTIVATION_POLICY_ID', 'IdAssignmentPolicy', 'IdAssignmentPolicyOperations', 'IdAssignmentPolicyValue', 'IdUniquenessPolicy', 'IdUniquenessPolicyOperations', 'IdUniquenessPolicyValue', 'ImplicitActivationPolicy', 'ImplicitActivationPolicyOperations', 'ImplicitActivationPolicyValue', 'LIFESPAN_POLICY_ID', 'LifespanPolicy', 'LifespanPolicyOperations', 'LifespanPolicyValue', 'POA', 'POAHelper', 'POAManager', 'POAManagerOperations', 'POAOperations', 'REQUEST_PROCESSING_POLICY_ID', 'RequestProcessingPolicy', 'RequestProcessingPolicyOperations', 'RequestProcessingPolicyValue', 'SERVANT_RETENTION_POLICY_ID', 'Servant', 'ServantActivator', 'ServantActivatorHelper', 'ServantActivatorOperations', 'ServantActivatorPOA', 'ServantLocator', 'ServantLocatorHelper', 'ServantLocatorOperations', 'ServantLocatorPOA', 'ServantManager', 'ServantManagerOperations', 'ServantRetentionPolicy', + 'ServantRetentionPolicyOperations', 'ServantRetentionPolicyValue', 'THREAD_POLICY_ID', 'ThreadPolicy', 'ThreadPolicyOperations', 'ThreadPolicyValue', '_ServantActivatorStub', '_ServantLocatorStub' + ), + 153 => array ( + 'NoContext', 'NoContextHelper' + ), + 154 => array ( + 'AdapterInactive', 'AdapterInactiveHelper', 'State' + ), + 155 => array ( + 'AdapterAlreadyExists', 'AdapterAlreadyExistsHelper', 'AdapterNonExistent', 'AdapterNonExistentHelper', 'InvalidPolicy', 'InvalidPolicyHelper', 'NoServant', 'NoServantHelper', 'ObjectAlreadyActive', 'ObjectAlreadyActiveHelper', 'ObjectNotActive', 'ObjectNotActiveHelper', 'ServantAlreadyActive', 'ServantAlreadyActiveHelper', 'ServantNotActive', 'ServantNotActiveHelper', 'WrongAdapter', 'WrongAdapterHelper', 'WrongPolicy', 'WrongPolicyHelper' + ), + 156 => array ( + 'CookieHolder' + ), + 157 => array ( + 'RunTime', 'RunTimeOperations' + ), + 158 => array ( + '_Remote_Stub' + ), + 159 => array ( + 'Attr', 'CDATASection', 'CharacterData', 'Comment', 'DOMConfiguration', 'DOMError', 'DOMErrorHandler', 'DOMException', 'DOMImplementation', 'DOMImplementationList', 'DOMImplementationSource', 'DOMStringList', 'DocumentFragment', 'DocumentType', 'EntityReference', 'NameList', 'NamedNodeMap', 'Node', 'NodeList', 'Notation', 'ProcessingInstruction', 'Text', 'TypeInfo', 'UserDataHandler' + ), + 160 => array ( + 'DOMImplementationRegistry' + ), + 161 => array ( + 'EventException', 'EventTarget', 'MutationEvent', 'UIEvent' + ), + 162 => array ( + 'DOMImplementationLS', 'LSException', 'LSInput', 'LSLoadEvent', 'LSOutput', 'LSParser', 'LSParserFilter', 'LSProgressEvent', 'LSResourceResolver', 'LSSerializer', 'LSSerializerFilter' + ), + 163 => array ( + 'DTDHandler', 'DocumentHandler', 'EntityResolver', 'ErrorHandler', 'HandlerBase', 'InputSource', 'Locator', 'SAXException', 'SAXNotRecognizedException', 'SAXNotSupportedException', 'SAXParseException', 'XMLFilter', 'XMLReader' + ), + 164 => array ( + 'Attributes2', 'Attributes2Impl', 'DeclHandler', 'DefaultHandler2', 'EntityResolver2', 'LexicalHandler', 'Locator2', 'Locator2Impl' + ), + 165 => array ( + 'AttributeListImpl', 'AttributesImpl', 'DefaultHandler', 'LocatorImpl', 'NamespaceSupport', 'ParserAdapter', 'ParserFactory', 'XMLFilterImpl', 'XMLReaderAdapter', 'XMLReaderFactory' + ), + /* ambiguous class names (appear in more than one package) */ + 166 => array ( + 'Annotation', 'AnySeqHelper', 'Array', 'Attribute', 'AttributeList', 'AttributeSet', 'Attributes', 'AuthenticationException', 'Binding', 'Bounds', 'Certificate', 'CertificateEncodingException', 'CertificateException', 'CertificateExpiredException', 'CertificateNotYetValidException', 'CertificateParsingException', 'ConnectException', 'ContentHandler', 'Context', 'Control', 'Current', 'CurrentHelper', 'CurrentOperations', 'DOMLocator', 'DataInputStream', 'DataOutputStream', 'Date', 'DefaultLoaderRepository', 'Delegate', 'Document', 'DocumentEvent', 'DynAny', 'DynArray', 'DynEnum', 'DynFixed', 'DynSequence', 'DynStruct', 'DynUnion', 'DynValue', 'DynamicImplementation', 'Element', 'Entity', 'Event', 'EventListener', 'FieldNameHelper', 'FileFilter', 'Formatter', 'ForwardRequest', 'ForwardRequestHelper', 'InconsistentTypeCode', 'InputStream', 'IntrospectionException', 'InvalidAttributeValueException', 'InvalidKeyException', 'InvalidName', 'InvalidNameHelper', 'InvalidValue', 'List', 'MouseEvent', + 'NameValuePair', 'NameValuePairHelper', 'ORB', 'Object', 'ObjectIdHelper', 'ObjectImpl', 'OpenType', 'OutputStream', 'ParagraphView', 'Parser', 'Permission', 'Policy', 'Principal', 'Proxy', 'Reference', 'Statement', 'Timer', 'Timestamp', 'TypeMismatch', 'TypeMismatchHelper', 'UNKNOWN', 'UnknownHostException', 'X509Certificate' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '*', '&', '%', '!', ';', '<', '>', '?' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + /* all Java keywords are case sensitive */ + 1 => true, 2 => true, 3 => true, 4 => true, + 5 => true, 6 => true, 7 => true, 8 => true, 9 => true, + 10 => true, 11 => true, 12 => true, 13 => true, 14 => true, + 15 => true, 16 => true, 17 => true, 18 => true, 19 => true, + 20 => true, 21 => true, 22 => true, 23 => true, 24 => true, + 25 => true, 26 => true, 27 => true, 28 => true, 29 => true, + 30 => true, 31 => true, 32 => true, 33 => true, 34 => true, + 35 => true, 36 => true, 37 => true, 38 => true, 39 => true, + 40 => true, 41 => true, 42 => true, 43 => true, 44 => true, + 45 => true, 46 => true, 47 => true, 48 => true, 49 => true, + 50 => true, 51 => true, 52 => true, 53 => true, 54 => true, + 55 => true, 56 => true, 57 => true, 58 => true, 59 => true, + 60 => true, 61 => true, 62 => true, 63 => true, 64 => true, + 65 => true, 66 => true, 67 => true, 68 => true, 69 => true, + 70 => true, 71 => true, 72 => true, 73 => true, 74 => true, + 75 => true, 76 => true, 77 => true, 78 => true, 79 => true, + 80 => true, 81 => true, 82 => true, 83 => true, 84 => true, + 85 => true, 86 => true, 87 => true, 88 => true, 89 => true, + 90 => true, 91 => true, 92 => true, 93 => true, 94 => true, + 95 => true, 96 => true, 97 => true, 98 => true, 99 => true, + 100 => true, 101 => true, 102 => true, 103 => true, 104 => true, + 105 => true, 106 => true, 107 => true, 108 => true, 109 => true, + 110 => true, 111 => true, 112 => true, 113 => true, 114 => true, + 115 => true, 116 => true, 117 => true, 118 => true, 119 => true, + 120 => true, 121 => true, 122 => true, 123 => true, 124 => true, + 125 => true, 126 => true, 127 => true, 128 => true, 129 => true, + 130 => true, 131 => true, 132 => true, 133 => true, 134 => true, + 135 => true, 136 => true, 137 => true, 138 => true, 139 => true, + 140 => true, 141 => true, 142 => true, 143 => true, 144 => true, + 145 => true, 146 => true, 147 => true, 148 => true, 149 => true, + 150 => true, 151 => true, 152 => true, 153 => true, 154 => true, + 155 => true, 156 => true, 157 => true, 158 => true, 159 => true, + 160 => true, 161 => true, 162 => true, 163 => true, 164 => true, + 165 => true, 166 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #006600; font-weight: bold;', + 4 => 'color: #006600; font-weight: bold;', + 5 => 'color: #003399; font-weight: bold;', + 6 => 'color: #003399; font-weight: bold;', + 7 => 'color: #003399; font-weight: bold;', + 8 => 'color: #003399; font-weight: bold;', + 9 => 'color: #003399; font-weight: bold;', + 10 => 'color: #003399; font-weight: bold;', + 11 => 'color: #003399; font-weight: bold;', + 12 => 'color: #003399; font-weight: bold;', + 13 => 'color: #003399; font-weight: bold;', + 14 => 'color: #003399; font-weight: bold;', + 15 => 'color: #003399; font-weight: bold;', + 16 => 'color: #003399; font-weight: bold;', + 17 => 'color: #003399; font-weight: bold;', + 18 => 'color: #003399; font-weight: bold;', + 19 => 'color: #003399; font-weight: bold;', + 20 => 'color: #003399; font-weight: bold;', + 21 => 'color: #003399; font-weight: bold;', + 22 => 'color: #003399; font-weight: bold;', + 23 => 'color: #003399; font-weight: bold;', + 24 => 'color: #003399; font-weight: bold;', + 25 => 'color: #003399; font-weight: bold;', + 26 => 'color: #003399; font-weight: bold;', + 27 => 'color: #003399; font-weight: bold;', + 28 => 'color: #003399; font-weight: bold;', + 29 => 'color: #003399; font-weight: bold;', + 30 => 'color: #003399; font-weight: bold;', + 31 => 'color: #003399; font-weight: bold;', + 32 => 'color: #003399; font-weight: bold;', + 33 => 'color: #003399; font-weight: bold;', + 34 => 'color: #003399; font-weight: bold;', + 35 => 'color: #003399; font-weight: bold;', + 36 => 'color: #003399; font-weight: bold;', + 37 => 'color: #003399; font-weight: bold;', + 38 => 'color: #003399; font-weight: bold;', + 39 => 'color: #003399; font-weight: bold;', + 40 => 'color: #003399; font-weight: bold;', + 41 => 'color: #003399; font-weight: bold;', + 42 => 'color: #003399; font-weight: bold;', + 43 => 'color: #003399; font-weight: bold;', + 44 => 'color: #003399; font-weight: bold;', + 45 => 'color: #003399; font-weight: bold;', + 46 => 'color: #003399; font-weight: bold;', + 47 => 'color: #003399; font-weight: bold;', + 48 => 'color: #003399; font-weight: bold;', + 49 => 'color: #003399; font-weight: bold;', + 50 => 'color: #003399; font-weight: bold;', + 51 => 'color: #003399; font-weight: bold;', + 52 => 'color: #003399; font-weight: bold;', + 53 => 'color: #003399; font-weight: bold;', + 54 => 'color: #003399; font-weight: bold;', + 55 => 'color: #003399; font-weight: bold;', + 56 => 'color: #003399; font-weight: bold;', + 57 => 'color: #003399; font-weight: bold;', + 58 => 'color: #003399; font-weight: bold;', + 59 => 'color: #003399; font-weight: bold;', + 60 => 'color: #003399; font-weight: bold;', + 61 => 'color: #003399; font-weight: bold;', + 62 => 'color: #003399; font-weight: bold;', + 63 => 'color: #003399; font-weight: bold;', + 64 => 'color: #003399; font-weight: bold;', + 65 => 'color: #003399; font-weight: bold;', + 66 => 'color: #003399; font-weight: bold;', + 67 => 'color: #003399; font-weight: bold;', + 68 => 'color: #003399; font-weight: bold;', + 69 => 'color: #003399; font-weight: bold;', + 70 => 'color: #003399; font-weight: bold;', + 71 => 'color: #003399; font-weight: bold;', + 72 => 'color: #003399; font-weight: bold;', + 73 => 'color: #003399; font-weight: bold;', + 74 => 'color: #003399; font-weight: bold;', + 75 => 'color: #003399; font-weight: bold;', + 76 => 'color: #003399; font-weight: bold;', + 77 => 'color: #003399; font-weight: bold;', + 78 => 'color: #003399; font-weight: bold;', + 79 => 'color: #003399; font-weight: bold;', + 80 => 'color: #003399; font-weight: bold;', + 81 => 'color: #003399; font-weight: bold;', + 82 => 'color: #003399; font-weight: bold;', + 83 => 'color: #003399; font-weight: bold;', + 84 => 'color: #003399; font-weight: bold;', + 85 => 'color: #003399; font-weight: bold;', + 86 => 'color: #003399; font-weight: bold;', + 87 => 'color: #003399; font-weight: bold;', + 88 => 'color: #003399; font-weight: bold;', + 89 => 'color: #003399; font-weight: bold;', + 90 => 'color: #003399; font-weight: bold;', + 91 => 'color: #003399; font-weight: bold;', + 92 => 'color: #003399; font-weight: bold;', + 93 => 'color: #003399; font-weight: bold;', + 94 => 'color: #003399; font-weight: bold;', + 95 => 'color: #003399; font-weight: bold;', + 96 => 'color: #003399; font-weight: bold;', + 97 => 'color: #003399; font-weight: bold;', + 98 => 'color: #003399; font-weight: bold;', + 99 => 'color: #003399; font-weight: bold;', + 100 => 'color: #003399; font-weight: bold;', + 101 => 'color: #003399; font-weight: bold;', + 102 => 'color: #003399; font-weight: bold;', + 103 => 'color: #003399; font-weight: bold;', + 104 => 'color: #003399; font-weight: bold;', + 105 => 'color: #003399; font-weight: bold;', + 106 => 'color: #003399; font-weight: bold;', + 107 => 'color: #003399; font-weight: bold;', + 108 => 'color: #003399; font-weight: bold;', + 109 => 'color: #003399; font-weight: bold;', + 110 => 'color: #003399; font-weight: bold;', + 111 => 'color: #003399; font-weight: bold;', + 112 => 'color: #003399; font-weight: bold;', + 113 => 'color: #003399; font-weight: bold;', + 114 => 'color: #003399; font-weight: bold;', + 115 => 'color: #003399; font-weight: bold;', + 116 => 'color: #003399; font-weight: bold;', + 117 => 'color: #003399; font-weight: bold;', + 118 => 'color: #003399; font-weight: bold;', + 119 => 'color: #003399; font-weight: bold;', + 120 => 'color: #003399; font-weight: bold;', + 121 => 'color: #003399; font-weight: bold;', + 122 => 'color: #003399; font-weight: bold;', + 123 => 'color: #003399; font-weight: bold;', + 124 => 'color: #003399; font-weight: bold;', + 125 => 'color: #003399; font-weight: bold;', + 126 => 'color: #003399; font-weight: bold;', + 127 => 'color: #003399; font-weight: bold;', + 128 => 'color: #003399; font-weight: bold;', + 129 => 'color: #003399; font-weight: bold;', + 130 => 'color: #003399; font-weight: bold;', + 131 => 'color: #003399; font-weight: bold;', + 132 => 'color: #003399; font-weight: bold;', + 133 => 'color: #003399; font-weight: bold;', + 134 => 'color: #003399; font-weight: bold;', + 135 => 'color: #003399; font-weight: bold;', + 136 => 'color: #003399; font-weight: bold;', + 137 => 'color: #003399; font-weight: bold;', + 138 => 'color: #003399; font-weight: bold;', + 139 => 'color: #003399; font-weight: bold;', + 140 => 'color: #003399; font-weight: bold;', + 141 => 'color: #003399; font-weight: bold;', + 142 => 'color: #003399; font-weight: bold;', + 143 => 'color: #003399; font-weight: bold;', + 144 => 'color: #003399; font-weight: bold;', + 145 => 'color: #003399; font-weight: bold;', + 146 => 'color: #003399; font-weight: bold;', + 147 => 'color: #003399; font-weight: bold;', + 148 => 'color: #003399; font-weight: bold;', + 149 => 'color: #003399; font-weight: bold;', + 150 => 'color: #003399; font-weight: bold;', + 151 => 'color: #003399; font-weight: bold;', + 152 => 'color: #003399; font-weight: bold;', + 153 => 'color: #003399; font-weight: bold;', + 154 => 'color: #003399; font-weight: bold;', + 155 => 'color: #003399; font-weight: bold;', + 156 => 'color: #003399; font-weight: bold;', + 157 => 'color: #003399; font-weight: bold;', + 158 => 'color: #003399; font-weight: bold;', + 159 => 'color: #003399; font-weight: bold;', + 160 => 'color: #003399; font-weight: bold;', + 161 => 'color: #003399; font-weight: bold;', + 162 => 'color: #003399; font-weight: bold;', + 163 => 'color: #003399; font-weight: bold;', + 164 => 'color: #003399; font-weight: bold;', + 165 => 'color: #003399; font-weight: bold;', + 166 => 'color: #003399; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #006699;', + 3 => 'color: #008000; font-style: italic; font-weight: bold;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006633;', + 2 => 'color: #006633;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/applet/{FNAME}.html', + 6 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/{FNAME}.html', + 7 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/color/{FNAME}.html', + 8 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/datatransfer/{FNAME}.html', + 9 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/dnd/{FNAME}.html', + 10 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/event/{FNAME}.html', + 11 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/font/{FNAME}.html', + 12 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/{FNAME}.html', + 13 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/im/{FNAME}.html', + 14 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/im/spi/{FNAME}.html', + 15 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/image/{FNAME}.html', + 16 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/image/renderable/{FNAME}.html', + 17 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/awt/print/{FNAME}.html', + 18 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/beans/{FNAME}.html', + 19 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/beans/beancontext/{FNAME}.html', + 20 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/io/{FNAME}.html', + 21 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/lang/{FNAME}.html', + 22 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/lang/annotation/{FNAME}.html', + 23 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/lang/instrument/{FNAME}.html', + 24 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/{FNAME}.html', + 25 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ref/{FNAME}.html', + 26 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/{FNAME}.html', + 27 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/math/{FNAME}.html', + 28 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/net/{FNAME}.html', + 29 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/nio/{FNAME}.html', + 30 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/nio/channels/{FNAME}.html', + 31 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/nio/channels/spi/{FNAME}.html', + 32 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/nio/charset/{FNAME}.html', + 33 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/nio/charset/spi/{FNAME}.html', + 34 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/rmi/{FNAME}.html', + 35 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/rmi/activation/{FNAME}.html', + 36 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/rmi/dgc/{FNAME}.html', + 37 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/rmi/registry/{FNAME}.html', + 38 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/rmi/server/{FNAME}.html', + 39 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/security/{FNAME}.html', + 40 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/security/acl/{FNAME}.html', + 41 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/security/cert/{FNAME}.html', + 42 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/security/interfaces/{FNAME}.html', + 43 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/security/spec/{FNAME}.html', + 44 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/sql/{FNAME}.html', + 45 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/text/{FNAME}.html', + 46 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/{FNAME}.html', + 47 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/{FNAME}.html', + 48 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/{FNAME}.html', + 49 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/{FNAME}.html', + 50 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/jar/{FNAME}.html', + 51 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/logging/{FNAME}.html', + 52 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/prefs/{FNAME}.html', + 53 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/{FNAME}.html', + 54 => 'http://java.sun.com/j2se/1.5.0/docs/api/java/util/zip/{FNAME}.html', + 55 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/accessibility/{FNAME}.html', + 56 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/activity/{FNAME}.html', + 57 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/crypto/{FNAME}.html', + 58 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/crypto/interfaces/{FNAME}.html', + 59 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/crypto/spec/{FNAME}.html', + 60 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/{FNAME}.html', + 61 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/event/{FNAME}.html', + 62 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/metadata/{FNAME}.html', + 63 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/plugins/bmp/{FNAME}.html', + 64 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/plugins/jpeg/{FNAME}.html', + 65 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/spi/{FNAME}.html', + 66 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/stream/{FNAME}.html', + 67 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/{FNAME}.html', + 68 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/loading/{FNAME}.html', + 69 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/modelmbean/{FNAME}.html', + 70 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/monitor/{FNAME}.html', + 71 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/openmbean/{FNAME}.html', + 72 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/relation/{FNAME}.html', + 73 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/remote/{FNAME}.html', + 74 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/remote/rmi/{FNAME}.html', + 75 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/management/timer/{FNAME}.html', + 76 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/{FNAME}.html', + 77 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/directory/{FNAME}.html', + 78 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/event/{FNAME}.html', + 79 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/ldap/{FNAME}.html', + 80 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/spi/{FNAME}.html', + 81 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/net/{FNAME}.html', + 82 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/net/ssl/{FNAME}.html', + 83 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/print/{FNAME}.html', + 84 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/print/attribute/{FNAME}.html', + 85 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/print/attribute/standard/{FNAME}.html', + 86 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/print/event/{FNAME}.html', + 87 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/rmi/{FNAME}.html', + 88 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/rmi/CORBA/{FNAME}.html', + 89 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/rmi/ssl/{FNAME}.html', + 90 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/{FNAME}.html', + 91 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/callback/{FNAME}.html', + 92 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/kerberos/{FNAME}.html', + 93 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/{FNAME}.html', + 94 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/spi/{FNAME}.html', + 95 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/x500/{FNAME}.html', + 96 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/security/sasl/{FNAME}.html', + 97 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/midi/{FNAME}.html', + 98 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/midi/spi/{FNAME}.html', + 99 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/sampled/{FNAME}.html', + 100 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/sampled/spi/{FNAME}.html', + 101 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/{FNAME}.html', + 102 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/rowset/{FNAME}.html', + 103 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/rowset/serial/{FNAME}.html', + 104 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/rowset/spi/{FNAME}.html', + 105 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/{FNAME}.html', + 106 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/border/{FNAME}.html', + 107 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/colorchooser/{FNAME}.html', + 108 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/event/{FNAME}.html', + 109 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/filechooser/{FNAME}.html', + 110 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/plaf/{FNAME}.html', + 111 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/plaf/basic/{FNAME}.html', + 112 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/plaf/metal/{FNAME}.html', + 113 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/plaf/multi/{FNAME}.html', + 114 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/plaf/synth/{FNAME}.html', + 115 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/table/{FNAME}.html', + 116 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/{FNAME}.html', + 117 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/html/{FNAME}.html', + 118 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/html/parser/{FNAME}.html', + 119 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/rtf/{FNAME}.html', + 120 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/tree/{FNAME}.html', + 121 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/undo/{FNAME}.html', + 122 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/transaction/{FNAME}.html', + 123 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/transaction/xa/{FNAME}.html', + 124 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/{FNAME}.html', + 125 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/datatype/{FNAME}.html', + 126 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/namespace/{FNAME}.html', + 127 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/parsers/{FNAME}.html', + 128 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/transform/{FNAME}.html', + 129 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/transform/dom/{FNAME}.html', + 130 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/transform/sax/{FNAME}.html', + 131 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/transform/stream/{FNAME}.html', + 132 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/validation/{FNAME}.html', + 133 => 'http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/xpath/{FNAME}.html', + 134 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/ietf/jgss/{FNAME}.html', + 135 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CORBA/{FNAME}.html', + 136 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CORBA/DynAnyPackage/{FNAME}.html', + 137 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CORBA/TypeCodePackage/{FNAME}.html', + 138 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CORBA/portable/{FNAME}.html', + 139 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CosNaming/{FNAME}.html', + 140 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CosNaming/NamingContextExtPackage/{FNAME}.html', + 141 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/CosNaming/NamingContextPackage/{FNAME}.html', + 142 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/Dynamic/{FNAME}.html', + 143 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/DynamicAny/{FNAME}.html', + 144 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/DynamicAny/DynAnyFactoryPackage/{FNAME}.html', + 145 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/DynamicAny/DynAnyPackage/{FNAME}.html', + 146 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/IOP/{FNAME}.html', + 147 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/IOP/CodecFactoryPackage/{FNAME}.html', + 148 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/IOP/CodecPackage/{FNAME}.html', + 149 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/Messaging/{FNAME}.html', + 150 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableInterceptor/{FNAME}.html', + 151 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableInterceptor/ORBInitInfoPackage/{FNAME}.html', + 152 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableServer/{FNAME}.html', + 153 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableServer/CurrentPackage/{FNAME}.html', + 154 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableServer/POAManagerPackage/{FNAME}.html', + 155 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableServer/POAPackage/{FNAME}.html', + 156 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/PortableServer/ServantLocatorPackage/{FNAME}.html', + 157 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/SendingContext/{FNAME}.html', + 158 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/omg/stub/java/rmi/{FNAME}.html', + 159 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/{FNAME}.html', + 160 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/bootstrap/{FNAME}.html', + 161 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/events/{FNAME}.html', + 162 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/ls/{FNAME}.html', + 163 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/xml/sax/{FNAME}.html', + 164 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/xml/sax/ext/{FNAME}.html', + 165 => 'http://java.sun.com/j2se/1.5.0/docs/api/org/xml/sax/helpers/{FNAME}.html', + /* ambiguous class names (appear in more than one package) */ + 166 => 'http://www.google.com/search?sitesearch=java.sun.com&q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+{FNAME}' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + /* Java does not use '::' */ + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/javascript.php b/examples/includes/geshi/geshi/javascript.php new file mode 100644 index 0000000..1232a8a --- /dev/null +++ b/examples/includes/geshi/geshi/javascript.php @@ -0,0 +1,150 @@ + 'Javascript', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + //Regular Expressions + 'COMMENT_REGEXP' => array(2 => "/(?<=[\\s^])s\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[gimsu]*(?=[\\s$\\.\\;])|(?<=[\\s^(=])m?\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[gimsu]*(?=[\\s$\\.\\,\\;\\)])/iU"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'as', 'break', 'case', 'catch', 'continue', 'decodeURI', 'delete', 'do', + 'else', 'encodeURI', 'eval', 'finally', 'for', 'if', 'in', 'is', 'item', + 'instanceof', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'void', + 'while', 'write', 'with' + ), + 2 => array( + 'class', 'const', 'default', 'debugger', 'export', 'extends', 'false', + 'function', 'import', 'namespace', 'new', 'null', 'package', 'private', + 'protected', 'public', 'super', 'true', 'use', 'var' + ), + 3 => array( + // common functions for Window object + 'alert', 'back', 'blur', 'close', 'confirm', 'focus', 'forward', 'home', + 'name', 'navigate', 'onblur', 'onerror', 'onfocus', 'onload', 'onmove', + 'onresize', 'onunload', 'open', 'print', 'prompt', 'scroll', 'status', + 'stop', + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', + '+', '-', '*', '/', '%', + '!', '@', '&', '|', '^', + '<', '>', '=', + ',', ';', '?', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000066; font-weight: bold;', + 2 => 'color: #003366; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #006600; font-style: italic;', + 2 => 'color: #009966; font-style: italic;', + 'MULTI' => 'color: #006600; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #3366CC;' + ), + 'NUMBERS' => array( + 0 => 'color: #CC0000;' + ), + 'METHODS' => array( + 1 => 'color: #660066;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + '' + ), + 1 => array( + '' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true + ) +); + +?> diff --git a/examples/includes/geshi/geshi/kixtart.php b/examples/includes/geshi/geshi/kixtart.php new file mode 100644 index 0000000..3b4dc4c --- /dev/null +++ b/examples/includes/geshi/geshi/kixtart.php @@ -0,0 +1,329 @@ + 'KiXtart', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'While', 'Loop', + 'Use', + 'Small', + 'Sleep', + 'Shell', + 'SetTime', + 'SetM', + 'SetL', + 'Set', + 'Select', 'Case', + 'Run', + 'Return', + 'Redim', + 'RD', + 'Quit', + 'Play', + 'Move', + 'MD', + 'Include', + 'If', 'Else', 'Endif', + 'GoTo', + 'GoSub', + 'Go', + 'Global', + 'GetS', + 'Get', + 'Function', 'Endfunction', + 'For', 'Next', + 'Each', + 'FlushKb', + 'Exit', + 'Do', 'Until', + 'Display', + 'Dim', + 'Del', + 'Debug', + 'Copy', + 'Cookie1', + 'Color', + 'CLS', + 'CD', + 'Call', + 'Break', + 'Big', + 'Beep', + ), + 2 => array( + '@Address', + '@Build', + '@Color', + '@Comment', + '@CPU', + '@CRLF', + '@CSD', + '@CurDir', + '@Date', + '@Day', + '@Domain', + '@DOS', + '@Error', + '@FullName', + '@HomeDir', + '@HomeDrive', + '@HomeShr', + '@HostName', + '@InWin', + '@IPaddressX', + '@KiX', + '@LanRoot', + '@LDomain', + '@LDrive', + '@LM', + '@LogonMode', + '@LongHomeDir', + '@LServer', + '@MaxPWAge', + '@MDayNo', + '@MHz', + '@MonthNo', + '@Month', + '@MSecs', + '@OnWoW64', + '@PID', + '@PrimaryGroup', + '@Priv', + '@ProductSuite', + '@ProductType', + '@PWAge', + '@RAS', + '@Result', + '@RServer', + '@ScriptDir', + '@ScriptExe', + '@ScriptName', + '@SError', + '@SID', + '@Site', + '@StartDir', + '@SysLang', + '@Ticks', + '@Time', + '@TsSession', + '@UserID', + '@UserLang', + '@WDayNo', + '@Wksta', + '@WUserID', + '@YDayNo', + '@Year', + ), + 3 => array( + 'WriteValue', + 'WriteProfileString', + 'WriteLine', + 'VarTypeName', + 'VarType', + 'Val', + 'UnloadHive', + 'UCase', + 'Ubound', + 'Trim', + 'Substr', + 'SRnd', + 'Split', + 'SidToName', + 'ShutDown', + 'ShowProgramGroup', + 'SetWallpaper', + 'SetTitle', + 'SetSystemState', + 'SetOption', + 'SetFocus', + 'SetFileAttr', + 'SetDefaultPrinter', + 'SetConsole', + 'SetAscii', + 'SendMessage', + 'SendKeys', + 'SaveKey', + 'RTrim', + 'Round', + 'Rnd', + 'Right', + 'RedirectOutput', + 'ReadValue', + 'ReadType', + 'ReadProfileString', + 'ReadLine', + 'Open', + 'MessageBox', + 'MemorySize', + 'LTrim', + 'Logoff', + 'LogEvent', + 'LoadKey', + 'LoadHive', + 'Len', + 'Left', + 'LCase', + 'KeyExist', + 'KbHit', + 'Join', + 'IsDeclared', + 'Int', + 'InStrRev', + 'InStr', + 'InGroup', + 'IIF', + 'GetObject', + 'GetFileVersion', + 'GetFileTime', + 'GetFileSize', + 'GetFileAttr', + 'GetDiskSpace', + 'FreeFileHandle', + 'FormatNumber', + 'Fix', + 'ExpandEnvironmentVars', + 'Exist', + 'Execute', + 'EnumValue', + 'EnumLocalGroup', + 'EnumKey', + 'EnumIpInfo', + 'EnumGroup', + 'Dir', + 'DelValue', + 'DelTree', + 'DelProgramItem', + 'DelProgramGroup', + 'DelPrinterConnection', + 'DelKey', + 'DecToHex', + 'CStr', + 'CreateObject', + 'CompareFileTimes', + 'Close', + 'ClearEventLog', + 'CInt', + 'Chr', + 'CDbl', + 'Box', + 'BackupEventLog', + 'At', + 'AScan', + 'Asc', + 'AddProgramItem', + 'AddProgramGroup', + 'AddPrinterConnection', + 'AddKey', + 'Abs' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '?', ':', '+', '-', '*', '/', '&', '|', '^', '~', '<', '>', '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://www.kixtart.org/manual/Commands/{FNAMEL}.htm', + 2 => '', + 3 => 'http://www.kixtart.org/manual/Functions/{FNAMEL}.htm' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/klonec.php b/examples/includes/geshi/geshi/klonec.php new file mode 100644 index 0000000..599f56b --- /dev/null +++ b/examples/includes/geshi/geshi/klonec.php @@ -0,0 +1,282 @@ + 'KLone C', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'),//#pour precede les include de C + 'COMMENT_MULTI' => array('/*' => '*/', '' ),//comentaires C et KLone suivi de ceux pour HTML + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array(//mots-cles C + 'if', 'return', 'while', 'case', 'class', 'continue', 'default', + 'do', 'else', 'for', 'switch', 'goto', + 'null', 'break', 'true', 'enum', 'extern', 'inline', 'false' + ), + 2 => array(//mots-cles KLone + 'out', 'request', 'response', + ), + 3 => array(//fonctions C usuelles + 'printf', 'malloc', 'fopen', 'fclose', 'free', 'fputs', 'fgets', 'feof', 'fwrite', + 'perror', 'ferror', 'qsort', 'stats', 'sscanf', 'scanf', + 'strdup', 'strcpy', 'strcmp', 'strncpy', 'strcasecmp', 'cat', 'strcat', 'strstr', + 'strlen', 'strtof', 'strtod', 'strtok', 'towlower', 'towupper', + 'cd', 'system', 'exit', 'exec', 'fork', 'vfork', 'kill', 'signal', 'syslog', + 'usleep', 'utime', 'wait', 'waitpid', 'waitid', + 'ceil', 'eval', 'round', 'floor', + 'atoi', 'atol', 'abs', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'exp', + 'time', 'ctime', 'localtime', 'asctime', 'gmtime', 'difftime', 'date' + ), + 4 => array(//fonctions KLone usuelles + 'request_get_cookies', 'request_get_cookie', 'request_get_args', 'request_get_arg', + 'request_io', 'request_get_uri', 'request_get_filename', 'request_get_query_string', 'request_get_path_info', + 'request_get_if_modified_since', 'request_get_http', 'request_get_client_request', + 'request_get_content_length', 'request_get_uploads', 'request_get_uploaded_file', + 'request_get_method', 'request_get_protocol', 'request_get_resolved_filename', + 'request_get_resolved_path_info', 'request_get_addr', 'request_get_peer_addr', + 'request_get_header', 'request_get_field', 'request_get_field_value', + 'response_set_content_encoding', 'response_disable_caching', 'response_enable_caching', + 'response_set_cookie', 'response_set_method', 'response_get_method', + 'response_print_header', 'response_set_field', 'response_del_field', + 'response_set_content_type', 'response_set_date', 'response_set_last_modified', + 'response_set_content_length', 'response_get_status', 'response_get_header', + 'response_io', 'response_redirect', 'response_set_status', + 'session_get_vars', 'session_get', 'session_set', 'session_age', 'session_clean', 'session_del', + 'io_type', 'io_pipe', 'io_dup', 'io_copy', 'io_seek', 'io_tell', 'io_close', + 'io_free', 'io_read', 'io_printf', 'io_flush', 'io_write', 'io_putc', 'io_getc', + 'io_get_until', 'io_gets', 'io_codec_add_head', 'io_codec_add_tail', + 'io_codecs_remove', 'io_name_set', 'io_name_get' + ), + 5 => array(//types C + 'auto', 'char', 'const', 'double', 'float', 'int', 'long', + 'register', 'short', 'signed', 'sizeof', 'static', 'string', 'struct', + 'typedef', 'union', 'unsigned', 'void', 'volatile', + 'wchar_t', 'time_t', 'FILE' + ), + 6 => array(//mots-cles HTML + 'a', 'abbr', 'acronym', 'address', 'applet', + + 'base', 'basefont', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'b', + + 'caption', 'center', 'cite', 'code', 'colgroup', 'col', + + 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', + + 'em', + + 'fieldset', 'font', 'form', 'frame', 'frameset', + + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', + + 'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'i', + + 'kbd', + + 'label', 'legend', 'link', 'li', + + 'map', 'meta', + + 'noframes', 'noscript', + + 'object', 'ol', 'optgroup', 'option', + + 'param', 'pre', 'p', + + 'q', + + 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'style', 'sub', 'sup', 's', + + 'table', 'tbody', 'td', 'textarea', 'text', 'tfoot', 'thead', 'th', 'title', 'tr', 'tt', + + 'ul', 'u', + + 'var', + ), + 7 => array(//autres mots-cles HTML + 'abbr', 'accept-charset', 'accept', 'accesskey', 'action', 'align', 'alink', 'alt', 'archive', 'axis', + 'background', 'bgcolor', 'border', + 'cellpadding', 'cellspacing', 'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'classid', 'clear', 'code', 'codebase', 'codetype', 'color', 'cols', 'colspan', 'compact', 'content', 'coords', + 'data', 'datetime', 'declare', 'defer', 'dir', 'disabled', + 'enctype', + 'face', 'for', 'frame', 'frameborder', + 'headers', 'height', 'href', 'hreflang', 'hspace', 'http-equiv', + 'id', 'ismap', + 'label', 'lang', 'language', 'link', 'longdesc', + 'marginheight', 'marginwidth', 'maxlength', 'media', 'method', 'multiple', + 'name', 'nohref', 'noresize', 'noshade', 'nowrap', + 'object', 'onblur', 'onchange', 'onclick', 'ondblclick', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onselect', 'onsubmit', 'onunload', + 'profile', 'prompt', + 'readonly', 'rel', 'rev', 'rowspan', 'rows', 'rules', + 'scheme', 'scope', 'scrolling', 'selected', 'shape', 'size', 'span', 'src', 'standby', 'start', 'style', 'summary', + 'tabindex', 'target', 'text', 'title', 'type', + 'usemap', + 'valign', 'value', 'valuetype', 'version', 'vlink', 'vspace', + 'width' + ) + ), + 'SYMBOLS' => array( + 1 => array( + '<%=', '<%!', '<%', '%>' + ), + 0 => array( + '(', ')', '[', ']', '{', '}', + '!', '%', '&', '|', '/', + '<', '>', + '=', '-', '+', '*', + '.', ':', ',', ';', '^' + ) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100; font-weight: bold;',//pour les mots-cles C + 2 => 'color: #000000; font-weight: bold;',//pour les mots-cles KLone + 3 => 'color: #6600FF;',//pour les fonctions C + 4 => 'color: #6600FF;',//pour les fonctions Klone + 5 => 'color: #0099FF; font-weight: bold;',//pour les types C + 6 => 'color: #990099; font-weight: bold;',//pour les mots-cles HTML + 7 => 'color: #000066;'//pour les autres mots-cles HTML + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;',//commentaire sur une ligne C et KLone + 2 => 'color: #339933;',//pour les #... en C + 'MULTI' => 'color: #808080; font-style: italic;'//commentaire sur plusieurs lignes C et KLone + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;', + 1 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array(), + 'SCRIPT' => array( + 0 => 'background-color:#ffccff; font-weight: bold; color:#000000;', + 1 => '', + 2 => '', + 3 => 'color: #00bbdd; font-weight: bold;', + 4 => 'color: #ddbb00;', + 5 => 'color: #009900;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.opengroup.org/onlinepubs/009695399/functions/{FNAMEL}.html', + 4 => 'http://www.koanlogic.com/klone/api/html/globals.html', + 5 => '', + 6 => 'http://december.com/html/4/element/{FNAMEL}.html', + 7 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + //delimiteurs pour KLone + 0 => array( + '<%=' => '%>' + ), + 1 => array( + '<%!' => '%>' + ), + 2 => array( + '<%' => '%>' + ), + //delimiteur pour HTML + 3 => array( + ' '>' + ), + 4 => array( + '&' => ';' + ), + 5 => array( + '<' => '>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => false, + 1 => true, + 2 => true, + 3 => false, + 4 => false, + 5 => true + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 6 => array( + 'DISALLOWED_BEFORE' => '(?<=<|<\/)', + 'DISALLOWED_AFTER' => '(?=\s|\/|>)', + ), + 7 => array( + 'DISALLOWED_AFTER' => '(?=\s*=)', + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/klonecpp.php b/examples/includes/geshi/geshi/klonecpp.php new file mode 100644 index 0000000..7be4f40 --- /dev/null +++ b/examples/includes/geshi/geshi/klonecpp.php @@ -0,0 +1,310 @@ + 'KLone C++', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'),//#pour precede les include de C + 'COMMENT_MULTI' => array('/*' => '*/', '' ),//comentaires C et KLone suivi de ceux pour HTML + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array(//mots-cles C++ + 'if', 'return', 'while', 'case', 'continue', 'default', + 'do', 'else', 'for', 'switch', 'goto', + 'break', 'true', 'enum', 'extern', 'inline', 'false', + 'errno', 'stdin', 'stdout', 'stderr', + 'virtual', 'public', 'private', 'protected', 'template', 'using', 'namespace', + 'try', 'catch', 'dynamic_cast', 'const_cast', 'reinterpret_cast', + 'static_cast', 'explicit', 'friend', 'typename', 'typeid', 'class', + 'EDOM', 'ERANGE', 'FLT_RADIX', 'FLT_ROUNDS', 'FLT_DIG', 'DBL_DIG', 'LDBL_DIG', + 'FLT_EPSILON', 'DBL_EPSILON', 'LDBL_EPSILON', 'FLT_MANT_DIG', 'DBL_MANT_DIG', + 'LDBL_MANT_DIG', 'FLT_MAX', 'DBL_MAX', 'LDBL_MAX', 'FLT_MAX_EXP', 'DBL_MAX_EXP', + 'LDBL_MAX_EXP', 'FLT_MIN', 'DBL_MIN', 'LDBL_MIN', 'FLT_MIN_EXP', 'DBL_MIN_EXP', + 'LDBL_MIN_EXP', 'CHAR_BIT', 'CHAR_MAX', 'CHAR_MIN', 'SCHAR_MAX', 'SCHAR_MIN', + 'UCHAR_MAX', 'SHRT_MAX', 'SHRT_MIN', 'USHRT_MAX', 'INT_MAX', 'INT_MIN', + 'UINT_MAX', 'LONG_MAX', 'LONG_MIN', 'ULONG_MAX', 'HUGE_VAL', 'SIGABRT', + 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', 'SIG_DFL', 'SIG_ERR', + 'SIG_IGN', 'BUFSIZ', 'EOF', 'FILENAME_MAX', 'FOPEN_MAX', 'L_tmpnam', 'NULL', + 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', + 'EXIT_FAILURE', 'EXIT_SUCCESS', 'RAND_MAX', 'CLOCKS_PER_SEC' + ), + 2 => array(//mots-cles KLone + 'out', 'request', 'response', + ), + 3 => array(//fonctions C++ usuelles + 'cin', 'cerr', 'clog', 'cout', 'delete', 'new', 'this', + 'printf', 'fprintf', 'snprintf', 'sprintf', 'assert', + 'isalnum', 'isalpha', 'isdigit', 'iscntrl', 'isgraph', 'islower', 'isprint', + 'ispunct', 'isspace', 'isupper', 'isxdigit', 'tolower', 'toupper', + 'exp', 'log', 'log10', 'pow', 'sqrt', 'ceil', 'floor', 'fabs', 'ldexp', + 'frexp', 'modf', 'fmod', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', + 'sinh', 'cosh', 'tanh', 'setjmp', 'longjmp', + 'va_start', 'va_arg', 'va_end', 'offsetof', 'sizeof', 'fopen', 'freopen', + 'fflush', 'fclose', 'remove', 'rename', 'tmpfile', 'tmpname', 'setvbuf', + 'setbuf', 'vfprintf', 'vprintf', 'vsprintf', 'fscanf', 'scanf', 'sscanf', + 'fgetc', 'fgets', 'fputc', 'fputs', 'getc', 'getchar', 'gets', 'putc', + 'putchar', 'puts', 'ungetc', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', + 'fgetpos', 'fsetpos', 'clearerr', 'feof', 'ferror', 'perror', 'abs', 'labs', + 'div', 'ldiv', 'atof', 'atoi', 'atol', 'strtod', 'strtol', 'strtoul', 'calloc', + 'malloc', 'realloc', 'free', 'abort', 'exit', 'atexit', 'system', 'getenv', + 'bsearch', 'qsort', 'rand', 'srand', 'strcpy', 'strncpy', 'strcat', 'strncat', + 'strcmp', 'strncmp', 'strcoll', 'strchr', 'strrchr', 'strspn', 'strcspn', + 'strpbrk', 'strstr', 'strlen', 'strerror', 'strtok', 'strxfrm', 'memcpy', + 'memmove', 'memcmp', 'memchr', 'memset', 'clock', 'time', 'difftime', 'mktime', + 'asctime', 'ctime', 'gmtime', 'localtime', 'strftime' + ), + 4 => array(//fonctions KLone usuelles + 'request_get_cookies', 'request_get_cookie', 'request_get_args', 'request_get_arg', + 'request_io', 'request_get_uri', 'request_get_filename', 'request_get_query_string', 'request_get_path_info', + 'request_get_if_modified_since', 'request_get_http', 'request_get_client_request', + 'request_get_content_length', 'request_get_uploads', 'request_get_uploaded_file', + 'request_get_method', 'request_get_protocol', 'request_get_resolved_filename', + 'request_get_resolved_path_info', 'request_get_addr', 'request_get_peer_addr', + 'request_get_header', 'request_get_field', 'request_get_field_value', + 'response_set_content_encoding', 'response_disable_caching', 'response_enable_caching', + 'response_set_cookie', 'response_set_method', 'response_get_method', + 'response_print_header', 'response_set_field', 'response_del_field', + 'response_set_content_type', 'response_set_date', 'response_set_last_modified', + 'response_set_content_length', 'response_get_status', 'response_get_header', + 'response_io', 'response_redirect', 'response_set_status', + 'session_get_vars', 'session_get', 'session_set', 'session_age', 'session_clean', 'session_del', + 'io_type', 'io_pipe', 'io_dup', 'io_copy', 'io_seek', 'io_tell', 'io_close', + 'io_free', 'io_read', 'io_printf', 'io_flush', 'io_write', 'io_putc', 'io_getc', + 'io_get_until', 'io_gets', 'io_codec_add_head', 'io_codec_add_tail', + 'io_codecs_remove', 'io_name_set', 'io_name_get' + ), + 5 => array(//types C++ + 'auto', 'bool', 'char', 'const', 'double', 'float', 'int', 'long', 'longint', + 'register', 'short', 'shortint', 'signed', 'static', 'struct', + 'typedef', 'union', 'unsigned', 'void', 'volatile', 'jmp_buf', + 'signal', 'raise', 'va_list', 'ptrdiff_t', 'size_t', 'FILE', 'fpos_t', + 'div_t', 'ldiv_t', 'clock_t', 'time_t', 'tm', + 'string', 'wchar_t' + ), + 6 => array(//mots-cles HTML + 'a', 'abbr', 'acronym', 'address', 'applet', + + 'base', 'basefont', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'b', + + 'caption', 'center', 'cite', 'code', 'colgroup', 'col', + + 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', + + 'em', + + 'fieldset', 'font', 'form', 'frame', 'frameset', + + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', + + 'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'i', + + 'kbd', + + 'label', 'legend', 'link', 'li', + + 'map', 'meta', + + 'noframes', 'noscript', + + 'object', 'ol', 'optgroup', 'option', + + 'param', 'pre', 'p', + + 'q', + + 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'style', 'sub', 'sup', 's', + + 'table', 'tbody', 'td', 'textarea', 'text', 'tfoot', 'thead', 'th', 'title', 'tr', 'tt', + + 'ul', 'u', + + 'var', + ), + 7 => array(//autres mots-cles HTML + 'abbr', 'accept-charset', 'accept', 'accesskey', 'action', 'align', 'alink', 'alt', 'archive', 'axis', + 'background', 'bgcolor', 'border', + 'cellpadding', 'cellspacing', 'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'classid', 'clear', 'code', 'codebase', 'codetype', 'color', 'cols', 'colspan', 'compact', 'content', 'coords', + 'data', 'datetime', 'declare', 'defer', 'dir', 'disabled', + 'enctype', + 'face', 'for', 'frame', 'frameborder', + 'headers', 'height', 'href', 'hreflang', 'hspace', 'http-equiv', + 'id', 'ismap', + 'label', 'lang', 'language', 'link', 'longdesc', + 'marginheight', 'marginwidth', 'maxlength', 'media', 'method', 'multiple', + 'name', 'nohref', 'noresize', 'noshade', 'nowrap', + 'object', 'onblur', 'onchange', 'onclick', 'ondblclick', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onselect', 'onsubmit', 'onunload', + 'profile', 'prompt', + 'readonly', 'rel', 'rev', 'rowspan', 'rows', 'rules', + 'scheme', 'scope', 'scrolling', 'selected', 'shape', 'size', 'span', 'src', 'standby', 'start', 'style', 'summary', + 'tabindex', 'target', 'text', 'title', 'type', + 'usemap', + 'valign', 'value', 'valuetype', 'version', 'vlink', 'vspace', + 'width' + ) + ), + 'SYMBOLS' => array( + 1 => array( + '<%=', '<%!', '<%', '%>' + ), + 0 => array( + '(', ')', '[', ']', '{', '}', + '!', '%', '&', '|', '/', + '<', '>', + '=', '-', '+', '*', + '.', ':', ',', ';', '^' + ) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100; font-weight: bold;',//pour les mots-cles C++ + 2 => 'color: #000000; font-weight: bold;',//pour les mots-cles KLone + 3 => 'color: #6600FF;',//pour les fonctions C++ + 4 => 'color: #6600FF;',//pour les fonctions Klone + 5 => 'color: #0099FF; font-weight: bold;',//pour les types C++ + 6 => 'color: #990099; font-weight: bold;',//pour les mots-cles HTML + 7 => 'color: #000066;'//pour les autres mots-cles HTML + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;',//commentaire sur une ligne C++ et KLone + 2 => 'color: #339933;',//pour les #... en C++ + 'MULTI' => 'color: #808080; font-style: italic;'//commentaire sur plusieurs lignes C++ et KLone + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;', + 1 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array(), + 'SCRIPT' => array( + 0 => 'background-color:#ffccff; font-weight: bold; color:#000000;', + 1 => '', + 2 => '', + 3 => 'color: #00bbdd; font-weight: bold;', + 4 => 'color: #ddbb00;', + 5 => 'color: #009900;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.opengroup.org/onlinepubs/009695399/functions/{FNAMEL}.html', + 4 => 'http://www.koanlogic.com/klone/api/html/globals.html', + 5 => '', + 6 => 'http://december.com/html/4/element/{FNAMEL}.html', + 7 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + //delimiteurs pour KLone + 0 => array( + '<%=' => '%>' + ), + 1 => array( + '<%!' => '%>' + ), + 2 => array( + '<%' => '%>' + ), + //delimiteur pour HTML + 3 => array( + ' '>' + ), + 4 => array( + '&' => ';' + ), + 5 => array( + '<' => '>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => false, + 1 => true, + 2 => true, + 3 => false, + 4 => false, + 5 => true + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 6 => array( + 'DISALLOWED_BEFORE' => '(?<=<|<\/)', + 'DISALLOWED_AFTER' => '(?=\s|\/|>)', + ), + 7 => array( + 'DISALLOWED_AFTER' => '(?=\s*=)', + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/latex.php b/examples/includes/geshi/geshi/latex.php new file mode 100644 index 0000000..e4926d9 --- /dev/null +++ b/examples/includes/geshi/geshi/latex.php @@ -0,0 +1,209 @@ + 'LaTeX', + 'COMMENT_SINGLE' => array( + 1 => '%' + ), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'appendix','backmatter','caption','captionabove','captionbelow', + 'def','documentclass','edef','equation','flushleft','flushright', + 'footnote','frontmatter','hline','include','input','item','label', + 'let','listfiles','listoffigures','listoftables','mainmatter', + 'makeatletter','makeatother','makebox','mbox','par','raggedleft', + 'raggedright','raisebox','ref','rule','table','tableofcontents', + 'textbf','textit','texttt','today' + ) + ), + 'SYMBOLS' => array( + "&", "\\", "{", "}", "[", "]" + ), + 'CASE_SENSITIVE' => array( + 1 => true, + GESHI_COMMENTS => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #800000; font-weight: bold;', + ), + 'COMMENTS' => array( + 1 => 'color: #2C922C; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000000; font-weight: bold;' + ), + 'BRACKETS' => array( + ), + 'STRINGS' => array( + 0 => 'color: #000000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #E02020; ' + ), + 'REGEXPS' => array( + 1 => 'color: #8020E0; font-weight: normal;', // Math inner + 2 => 'color: #C08020; font-weight: normal;', // [Option] + 3 => 'color: #8020E0; font-weight: normal;', // Maths + 4 => 'color: #800000; font-weight: normal;', // Structure: Labels + 5 => 'color: #00008B; font-weight: bold;', // Structure (\section{->x<-}) + 6 => 'color: #800000; font-weight: normal;', // Structure (\section) + 7 => 'color: #0000D0; font-weight: normal;', // Environment \end or \begin{->x<-} (brighter blue) + 8 => 'color: #C00000; font-weight: normal;', // Structure \end or \begin + 9 => 'color: #2020C0; font-weight: normal;', // {...} + 10 => 'color: #800000; font-weight: normal;', // \%, \& etc. + 11 => 'color: #E00000; font-weight: normal;', // \@keyword + 12 => 'color: #800000; font-weight: normal;', // \keyword + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://www.golatex.de/wiki/index.php?title=\\{FNAME}', + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + // Math inner + 1 => array( + GESHI_SEARCH => "(\\\\begin\\{(equation|displaymath|eqnarray|subeqnarray|math|multline|gather|align|alignat|flalign)\\})(.*)(\\\\end\\{\\2\\})", + GESHI_REPLACE => '\3', + GESHI_MODIFIERS => 'Us', + GESHI_BEFORE => '\1', + GESHI_AFTER => '\4' + ), + // [options] + 2 => array( + GESHI_SEARCH => "(?<=\[).+(?=\])", + GESHI_REPLACE => '\0', + GESHI_MODIFIERS => 'Us', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + // Math mode with $ ... $ + 3 => array( + GESHI_SEARCH => "\\$.+\\$", + GESHI_REPLACE => '\0', + GESHI_MODIFIERS => 'Us', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + // Structure: Label + 4 => "\\\\(?:label|pageref|ref|cite)(?=[^a-zA-Z])", + // Structure: sections + 5 => array( + GESHI_SEARCH => "(\\\\(?:part|chapter|(?:sub){0,2}section|(?:sub)?paragraph|addpart|addchap|addsec)\*?\\{)(.*)(?=\\})", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'U', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + // Structure: sections + 6 => "\\\\(?:part|chapter|(?:sub){0,2}section|(?:sub)?paragraph|addpart|addchap|addsec)\*?(?=[^a-zA-Z])", + // environment \begin{} and \end{} (i.e. the things inside the {}) + 7 => array( + GESHI_SEARCH => "(\\\\(?:begin|end)\\{)(.*)(?=\\})", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'U', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + // Structure \begin and \end + 8 => "\\\\(?:end|begin)(?=[^a-zA-Z])", + // {parameters} + 9 => array( + GESHI_SEARCH => "(?<=\\{)(?!<\|!REG3XP5!>).*(?=\\})", + GESHI_REPLACE => '\0', + GESHI_MODIFIERS => 'Us', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + // \%, \& usw. + 10 => "\\\\(?:[_$%]|&)", + // \@keywords + 11 => "(?)\\\\@[a-zA-Z]+\*?", + // \keywords + 12 => "(?)\\\\[a-zA-Z]+\*?", + +// --------------------------------------------- + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'COMMENTS' => array( + 'DISALLOWED_BEFORE' => '\\' + ), + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(?<=\\\\)", + 'DISALLOWED_AFTER' => "(?=\b)(?!\w)" + ), + 'ENABLE_FLAGS' => array( + 'NUMBERS' => GESHI_NEVER, + 'BRACKETS' => GESHI_NEVER + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/lisp.php b/examples/includes/geshi/geshi/lisp.php new file mode 100644 index 0000000..de08d9c --- /dev/null +++ b/examples/includes/geshi/geshi/lisp.php @@ -0,0 +1,144 @@ + 'Lisp', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(';|' => '|;'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'not','defun','princ','when', + 'eval','apply','funcall','quote','identity','function', + 'complement','backquote','lambda','set','setq','setf', + 'defmacro','gensym','make','symbol','intern', + 'name','value','plist','get', + 'getf','putprop','remprop','hash','array','aref', + 'car','cdr','caar','cadr','cdar','cddr','caaar','caadr','cadar', + 'caddr','cdaar','cdadr','cddar','cdddr','caaaar','caaadr', + 'caadar','caaddr','cadaar','cadadr','caddar','cadddr', + 'cdaaar','cdaadr','cdadar','cdaddr','cddaar','cddadr', + 'cdddar','cddddr','cons','list','append','reverse','last','nth', + 'nthcdr','member','assoc','subst','sublis','nsubst', + 'nsublis','remove','length', + 'mapc','mapcar','mapl','maplist','mapcan','mapcon','rplaca', + 'rplacd','nconc','delete','atom','symbolp','numberp', + 'boundp','null','listp','consp','minusp','zerop','plusp', + 'evenp','oddp','eq','eql','equal','cond','case','and','or', + 'let','l','if','prog','prog1','prog2','progn','go','return', + 'do','dolist','dotimes','catch','throw','error','cerror','break', + 'continue','errset','baktrace','evalhook','truncate','float', + 'rem','min','max','abs','sin','cos','tan','expt','exp','sqrt', + 'random','logand','logior','logxor','lognot','bignums','logeqv', + 'lognand','lognor','logorc2','logtest','logbitp','logcount', + 'integer','nil','parse-integer' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', + '!', '%', '^', '&', + ' + ',' - ',' * ',' / ', + '=','<','>', + '.',':',',',';', + '|' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #555;', + 1 => 'color: #555;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + '::', ':' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'OOLANG' => array( + 'MATCH_AFTER' => '[a-zA-Z][a-zA-Z0-9_\-]*' + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/locobasic.php b/examples/includes/geshi/geshi/locobasic.php new file mode 100644 index 0000000..02e6a7a --- /dev/null +++ b/examples/includes/geshi/geshi/locobasic.php @@ -0,0 +1,130 @@ + 'Locomotive Basic', + 'COMMENT_SINGLE' => array(1 => "'", 2 => 'REM'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + "AFTER", "AND", "AUTO", "BORDER", "BREAK", "CALL", "CAT", "CHAIN", + "CLEAR", "CLG", "CLS", "CLOSEIN", "CLOSEOUT", "CONT", "CURSOR", + "DATA", "DEF", "DEFINT", "DEFREAL", "DEFSTR", "DEG", "DELETE", + "DERR", "DI", "DIM", "DRAW", "DRAWR", "EDIT", "EI", "ELSE", "END", + "ENV", "ENT", "EOF", "ERASE", "ERL", "ERR", "ERROR", "EVERY", + "FILL", "FN", "FOR", "FRAME", "GOSUB", "GOTO", "GRAPHICS", "HIMEM", + "IF", "INK", "INPUT", "KEY", "LET", "LINE", "LIST", "LOAD", + "LOCATE", "MASK", "MEMORY", "MERGE", "MODE", "MOVE", "MOVER", "NEW", + "NEXT", "NOT", "ON", "OPENIN", "OPENOUT", "OR", "ORIGIN", "PAPER", + "PEEK", "PEN", "PLOT", "PLOTR", "POKE", "PRINT", "RAD", "RANDOMIZE", + "READ", "RELEASE", "REMAIN", "RENUM", "RESTORE", "RESUME", "RETURN", + "RUN", "SAVE", "SPEED", "SOUND", "SPC", "SQ", "STEP", "STOP", "SWAP", + "SYMBOL", "TAB", "TAG", "TAGOFF", "TEST", "TESTR", "TIME", "TO", + "THEN", "TRON", "TROFF", "USING", "WAIT", "WEND", "WHILE", "WIDTH", + "WINDOW", "WRITE", "XOR", "ZONE" + ), + 2 => array( + "ABS", "ASC", "ATN", "BIN", "CHR", "CINT", "COPYCHR", "COS", + "CREAL", "DEC", "FIX", "FRE", "EXP", "HEX", "INKEY", "INP", "INSTR", + "INT", "JOY", "LEFT", "LEN", "LOG", "LOG10", "LOWER", "MAX", "MID", + "MIN", "MOD", "OUT", "PI", "POS", "RIGHT", "RND", "ROUND", "SGN", + "SIN", "SPACE", "SQR", "STR", "STRING", "TAN", "UNT", "UPPER", + "VAL", "VPOS", "XPOS", "YPOS" + ) + ), + 'SYMBOLS' => array( + '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff; font-weight: bold;', + 2 => 'color: #008888; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080;', + 2 => 'color: #808080;' + ), + 'BRACKETS' => array( + 0 => 'color: #ff0000;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #0044ff;' + ), + 'METHODS' => array( + 0 => 'color: #66cc66;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/lolcode.php b/examples/includes/geshi/geshi/lolcode.php new file mode 100644 index 0000000..19b42f5 --- /dev/null +++ b/examples/includes/geshi/geshi/lolcode.php @@ -0,0 +1,152 @@ + 'LOLcode', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + 1 => "/\bBTW\b.*$/im", + 2 => "/(^|\b)(?:OBTW\b.+?\bTLDR|LOL\b.+?\/LOL)(\b|$)/si" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + 1 => '/:[)>o":]/', + 2 => '/:\([\da-f]+\)/i', + 3 => '/:\{\w+\}/i', + 4 => '/:\[\w+\]/i', + ), + 'KEYWORDS' => array( + //Statements + 1 => array( + 'VISIBLE', 'HAI', 'KTHX', 'KTHXBYE', 'SMOOSH', 'GIMMEH', 'PLZ', + 'ON', 'INVISIBLE', 'R', 'ITZ', 'GTFO', 'COMPLAIN', 'GIMME', + + 'OPEN', 'FILE', 'I HAS A', 'AWSUM THX', 'O NOES', 'CAN', 'HAS', 'HAZ', + 'HOW DOES I', 'IF U SAY SO', 'FOUND YR', 'BORROW', 'OWN', 'ALONG', + 'WITH', 'WIT', 'LOOK', 'AT', 'AWSUM', 'THX' + ), + //Conditionals + 2 => array( + 'IZ', 'YARLY', 'NOWAI', 'WTF?', 'MEBBE', 'OMG', 'OMGWTF', + 'ORLY?', 'OF', 'NOPE', 'SO', 'IM', 'MAI', + + 'O RLY?', 'SUM', 'BOTH SAEM', 'DIFFRINT', 'BOTH', 'EITHER', 'WON', + 'DIFF', 'PRODUKT', 'QUOSHUNT', 'MOD', 'MKAY', 'OK', 'THING', + 'BIGNESS' + ), + //Repetition + 3 => array( + 'IN', 'OUTTA', 'LOOP', 'WHILE' + ), + //Operators \Math + 4 => array( + 'AN', 'AND', 'NOT', 'UP', 'YR', 'UPPIN', 'NERF', 'NERFIN', 'NERFZ', + 'SMASHING', 'UR', 'KINDA', 'LIKE', 'SAEM', 'BIG', 'SMALL', + 'BIGGR', 'SMALLR', 'BIGGER', 'SMALLER', 'GOOD', 'CUTE', 'THAN' + ) + ), + 'SYMBOLS' => array( + '.', ',', '?', + '!!' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #008000;', + 2 => 'color: #000080;', + 3 => 'color: #000080;', + 4 => 'color: #800000;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; style: italic;', + 2 => 'color: #666666; style: italic;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'SPACE_AS_WHITESPACE' => true + ) + ), + 'TAB_WIDTH' => 4 +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/lotusformulas.php b/examples/includes/geshi/geshi/lotusformulas.php new file mode 100644 index 0000000..010fb22 --- /dev/null +++ b/examples/includes/geshi/geshi/lotusformulas.php @@ -0,0 +1,318 @@ + 'Lotus Notes @Formulas', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array('REM' => ';'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array ( + '[ZoomPreview]', '[WorkspaceStackReplicaIcons]', + '[WorkspaceProperties]', '[WindowWorkspace]', + '[WindowTile]', '[WindowRestore]', '[WindowNext]', + '[WindowMinimizeAll]', '[WindowMinimize]', '[WindowMaximizeAll]', + '[WindowMaximize]', '[WindowCascade]', '[ViewSwitchForm]', + '[ViewShowUnread]', '[ViewShowServerNames]', '[ViewShowSearchBar]', + '[ViewShowRuler]', '[ViewShowPageBreaks]', '[ViewShowOnlyUnread]', + '[ViewShowOnlySelected]', '[ViewShowOnlySearchResults]', + '[ViewShowOnlyCategories]', '[ViewShowObject]', + '[ViewShowFieldHelp]', '[ViewRenamePerson]', '[ViewRefreshUnread]', + '[ViewRefreshFields]', '[ViewNavigatorsNone]', + '[ViewNavigatorsFolders]', '[ViewMoveName]', '[ViewHorizScrollbar]', + '[ViewExpandWithChildren]', '[ViewExpandAll]', '[ViewExpand]', + '[ViewCollapseAll]', '[ViewCollapse]', '[ViewChange]', + '[ViewCertify]', '[ViewBesideFolders]', '[ViewBelowFolders]', + '[ViewArrangeIcons]', '[V3EditPrevField]', '[V3EditNextField]', + '[UserIDSwitch]', '[UserIDSetPassword]', '[UserIDMergeCopy]', + '[UserIDInfo]', '[UserIDEncryptionKeys]', '[UserIDCreateSafeCopy]', + '[UserIDClearPassword]', '[UserIDCertificates]', + '[ToolsUserLogoff]', '[ToolsSpellCheck]', '[ToolsSmartIcons]', + '[ToolsSetupUserSetup]', '[ToolsSetupPorts]', '[ToolsSetupMail]', + '[ToolsSetupLocation]', '[ToolsScanUnreadSelected]', + '[ToolsScanUnreadPreferred]', '[ToolsScanUnreadChoose]', + '[ToolsRunMacro]', '[ToolsRunBackgroundMacros]', '[ToolsReplicate]', + '[ToolsRefreshSelectedDocs]', '[ToolsRefreshAllDocs]', + '[ToolsMarkSelectedUnread]', '[ToolsMarkSelectedRead]', + '[ToolsMarkAllUnread]', '[ToolsMarkAllRead]', '[ToolsHangUp]', + '[ToolsCategorize]', '[ToolsCall]', '[TextUnderline]', + '[TextSpacingSingle]', '[TextSpacingOneAndaHalf]', + '[TextSpacingDouble]', '[TextSetFontSize]', '[TextSetFontFace]', + '[TextSetFontColor]', '[TextReduceFont]', '[TextPermanentPen]', + '[TextParagraphStyles]', '[TextParagraph]', '[TextOutdent]', + '[TextNumbers]', '[TextNormal]', '[TextItalic]', '[TextFont]', + '[TextEnlargeFont]', '[TextCycleSpacing]', '[TextBullet]', + '[TextBold]', '[TextAlignRight]', '[TextAlignNone]', + '[TextAlignLeft]', '[TextAlignFull]', '[TextAlignCenter]', + '[SwitchView]', '[SwitchForm]', '[StyleCycleKey]', + '[SmartIconsNextSet]', '[SmartIconsFloating]', '[ShowProperties]', + '[ShowHidePreviewPane]', '[ShowHideParentPreview]', + '[ShowHideLinkPreview]', '[ShowHideIMContactList]', + '[SetCurrentLocation]', '[SendInstantMessage]', + '[SectionRemoveHeader]', '[SectionProperties]', + '[SectionExpandAll]', '[SectionExpand]', '[SectionDefineEditors]', + '[SectionCollapseAll]', '[SectionCollapse]', '[RunScheduledAgents]', + '[RunAgent]', '[ReplicatorStop]', '[ReplicatorStart]', + '[ReplicatorSendReceiveMail]', '[ReplicatorSendMail]', + '[ReplicatorReplicateWithServer]', '[ReplicatorReplicateSelected]', + '[ReplicatorReplicateNext]', '[ReplicatorReplicateHigh]', + '[Replicator]', '[RenameDatabase]', '[RemoveFromFolder]', + '[RemoteDebugLotusScript]', '[ReloadWindow]', '[RefreshWindow]', + '[RefreshParentNote]', '[RefreshHideFormulas]', '[RefreshFrame]', + '[PublishDatabase]', '[PictureProperties]', '[PasteBitmapAsObject]', + '[PasteBitmapAsBackground]', '[OpenView]', '[OpenPage]', + '[OpenNavigator]', '[OpenInNewWindow]', '[OpenHelpDocument]', + '[OpenFrameset]', '[OpenDocument]', '[OpenCalendar]', + '[ObjectProperties]', '[ObjectOpen]', '[ObjectDisplayAs]', + '[NavPrevUnread]', '[NavPrevSelected]', '[NavPrevMain]', + '[NavPrev]', '[NavNextUnread]', '[NavNextSelected]', + '[NavNextMain]', '[NavNext]', '[NavigatorTest]', + '[NavigatorProperties]', '[NavigateToBacklink]', + '[NavigatePrevUnread]', '[NavigatePrevSelected]', + '[NavigatePrevMain]', '[NavigatePrevHighlight]', '[NavigatePrev]', + '[NavigateNextUnread]', '[NavigateNextSelected]', + '[NavigateNextMain]', '[NavigateNextHighlight]', '[NavigateNext]', + '[MoveToTrash]', '[MailSendPublicKey]', '[MailSendEncryptionKey]', + '[MailSendCertificateRequest]', '[MailSend]', '[MailScanUnread]', + '[MailRequestNewPublicKey]', '[MailRequestNewName]', + '[MailRequestCrossCert]', '[MailOpen]', '[MailForwardAsAttachment]', + '[MailForward]', '[MailComposeMemo]', '[MailAddress]', + '[LayoutProperties]', '[LayoutElementSendToBack]', + '[LayoutElementProperties]', '[LayoutElementBringToFront]', + '[LayoutAddText]', '[LayoutAddGraphic]', '[InsertSubform]', + '[HotspotProperties]', '[HotspotClear]', '[HelpUsingDatabase]', + '[HelpAboutNotes]', '[HelpAboutDatabase]', '[GoUpLevel]', + '[FormTestDocument]', '[FormActions]', '[FolderRename]', + '[FolderProperties]', '[FolderMove]', '[FolderExpandWithChildren]', + '[FolderExpandAll]', '[FolderExpand]', '[FolderDocuments]', + '[FolderCustomize]', '[FolderCollapse]', '[Folder]', + '[FindFreeTimeDialog]', '[FileSaveNewVersion]', '[FileSave]', + '[FilePrintSetup]', '[FilePrint]', '[FilePageSetup]', + '[FileOpenDBRepID]', '[FileOpenDatabase]', '[FileNewReplica]', + '[FileNewDatabase]', '[FileImport]', '[FileFullTextUpdate]', + '[FileFullTextInfo]', '[FileFullTextDelete]', + '[FileFullTextCreate]', '[FileExport]', '[FileExit]', + '[FileDatabaseUseServer]', '[FileDatabaseRemove]', + '[FileDatabaseInfo]', '[FileDatabaseDelete]', '[FileDatabaseCopy]', + '[FileDatabaseCompact]', '[FileDatabaseACL]', '[FileCloseWindow]', + '[ExitNotes]', '[Execute]', '[ExchangeUnreadMarks]', '[EmptyTrash]', + '[EditUp]', '[EditUntruncate]', '[EditUndo]', '[EditTop]', + '[EditTableInsertRowColumn]', '[EditTableFormat]', + '[EditTableDeleteRowColumn]', '[EditShowHideHiddenChars]', + '[EditSelectByDate]', '[EditSelectAll]', '[EditRight]', + '[EditRestoreDocument]', '[EditResizePicture]', + '[EditQuoteSelection]', '[EditProfileDocument]', '[EditProfile]', + '[EditPrevField]', '[EditPhoneNumbers]', '[EditPasteSpecial]', + '[EditPaste]', '[EditOpenLink]', '[EditNextField]', + '[EditMakeDocLink]', '[EditLocations]', '[EditLinks]', '[EditLeft]', + '[EditInsertText]', '[EditInsertTable]', '[EditInsertPopup]', + '[EditInsertPageBreak]', '[EditInsertObject]', + '[EditInsertFileAttachment]', '[EditInsertButton]', + '[EditIndentFirstLine]', '[EditIndent]', '[EditHorizScrollbar]', + '[EditHeaderFooter]', '[EditGotoField]', '[EditFindNext]', + '[EditFindInPreview]', '[EditFind]', '[EditEncryptionKeys]', + '[EditDown]', '[EditDocument]', '[EditDetach]', '[EditDeselectAll]', + '[EditCut]', '[EditCopy]', '[EditClear]', '[EditButton]', + '[EditBottom]', '[DiscoverFolders]', '[Directories]', + '[DialingRules]', '[DesignViewSelectFormula]', '[DesignViews]', + '[DesignViewNewColumn]', '[DesignViewFormFormula]', + '[DesignViewEditActions]', '[DesignViewColumnDef]', + '[DesignViewAttributes]', '[DesignViewAppendColumn]', + '[DesignSynopsis]', '[DesignSharedFields]', '[DesignReplace]', + '[DesignRefresh]', '[DesignMacros]', '[DesignIcon]', + '[DesignHelpUsingDocument]', '[DesignHelpAboutDocument]', + '[DesignFormWindowTitle]', '[DesignFormUseField]', + '[DesignFormShareField]', '[DesignForms]', '[DesignFormNewField]', + '[DesignFormFieldDef]', '[DesignFormAttributes]', + '[DesignDocumentInfo]', '[DebugLotusScript]', + '[DatabaseReplSettings]', '[DatabaseDelete]', '[CreateView]', + '[CreateTextbox]', '[CreateSubForm]', '[CreateSection]', + '[CreateRectangularHotspot]', '[CreateRectangle]', + '[CreatePolyline]', '[CreatePolygon]', '[CreateNavigator]', + '[CreateLayoutRegion]', '[CreateForm]', '[CreateFolder]', + '[CreateEllipse]', '[CreateControlledAccessSection]', + '[CreateAgent]', '[CreateAction]', '[CopySelectedAsTable]', + '[ComposeWithReference]', '[Compose]', '[CloseWindow]', '[Clear]', + '[ChooseFolders]', '[CalendarGoTo]', '[CalendarFormat]', + '[AttachmentView]', '[AttachmentProperties]', '[AttachmentLaunch]', + '[AttachmentDetachAll]', '[AgentTestRun]', '[AgentSetServerName]', + '[AgentRun]', '[AgentLog]', '[AgentEnableDisable]', '[AgentEdit]', + '[AdminTraceConnection]', '[AdminStatisticsConfig]', + '[AdminSendMailTrace]', '[AdminRemoteConsole]', + '[AdminRegisterUser]', '[AdminRegisterServer]', + '[AdminRegisterFromFile]', '[AdminOutgoingMail]', + '[AdminOpenUsersView]', '[AdminOpenStatistics]', + '[AdminOpenServersView]', '[AdminOpenServerLog]', + '[AdminOpenGroupsView]', '[AdminOpenCertLog]', '[AdminOpenCatalog]', + '[AdminOpenAddressBook]', '[AdminNewOrgUnit]', + '[AdminNewOrganization]', '[Administration]', + '[AdminIDFileSetPassword]', '[AdminIDFileExamine]', + '[AdminIDFileClearPassword]', '[AdminDatabaseQuotas]', + '[AdminDatabaseAnalysis]', '[AdminCrossCertifyKey]', + '[AdminCrossCertifyIDFile]', '[AdminCreateGroup]', '[AdminCertify]', + '[AddToIMContactList]', '[AddDatabaseRepID]', '[AddDatabase]', + '[AddBookmark]' + ), + 2 => array( + 'SELECT', 'FIELD', 'ENVIRONMENT', 'DEFAULT', '@Zone ', '@Yesterday', + '@Yes', '@Year', '@Word', '@Wide', '@While', '@Weekday', + '@WebDbName', '@ViewTitle', '@ViewShowThisUnread', '@Version', + '@VerifyPassword', '@ValidateInternetAddress', '@V4UserAccess', + '@V3UserName', '@V2If', '@UserRoles', '@UserPrivileges', + '@UserNamesList', '@UserNameLanguage', '@UserName', '@UserAccess', + '@UrlQueryString', '@URLOpen', '@URLHistory', '@URLGetHeader', + '@URLEncode', '@URLDecode', '@UpperCase', '@UpdateFormulaContext', + '@Unique', '@UndeleteDocument', '@Unavailable', '@True', '@Trim', + '@Transform', '@ToTime', '@ToNumber', '@Tomorrow', '@Today', + '@TimeZoneToText', '@TimeToTextInZone', '@TimeMerge', '@Time', + '@ThisValue', '@ThisName', '@TextToTime', '@TextToNumber', '@Text', + '@TemplateVersion', '@Tan', '@Sum', '@Success', '@Subset', + '@StatusBar', '@Sqrt', '@Soundex', '@Sort', '@Sin', '@Sign', + '@SetViewInfo', '@SetTargetFrame', '@SetProfileField', + '@SetHTTPHeader', '@SetField', '@SetEnvironment', '@SetDocField', + '@Set', '@ServerName', '@ServerAccess', '@Select', '@Second', + '@Round', '@RightBack', '@Right', '@Return', '@Responses', + '@ReplicaID', '@ReplaceSubstring', '@Replace', '@Repeat', + '@RegQueryValue', '@RefreshECL', '@Random', '@ProperCase', + '@Prompt', '@Power', '@PostedCommand', '@PolicyIsFieldLocked', + '@Platform', '@PickList', '@Pi', '@PasswordQuality', '@Password', + '@OrgDir', '@OptimizeMailAddress', '@OpenInNewWindow', '@Now', + '@Nothing', '@NoteID', '@No', '@NewLine', '@Narrow', '@NameLookup', + '@Name', '@Month', '@Modulo', '@Modified', '@Minute', '@Min', + '@MiddleBack', '@Middle', '@Member', '@Max', '@Matches', + '@MailSignPreference', '@MailSend', '@MailSavePreference', + '@MailEncryptSentPreference', '@MailEncryptSavedPreference', + '@MailDbName', '@LowerCase', '@Log', '@Locale', '@Ln', '@Like', + '@Length', '@LeftBack', '@Left', '@LDAPServer', '@LaunchApp', + '@LanguagePreference', '@Keywords', '@IsVirtualizedDirectory', + '@IsValid', '@IsUsingJavaElement', '@IsUnavailable', '@IsTime', + '@IsText', '@IsResponseDoc', '@IsNumber', '@IsNull', '@IsNotMember', + '@IsNewDoc', '@IsModalHelp', '@IsMember', '@IsExpandable', + '@IsError', '@IsEmbeddedInsideWCT', '@IsDocTruncated', + '@IsDocBeingSaved', '@IsDocBeingRecalculated', '@IsDocBeingMailed', + '@IsDocBeingLoaded', '@IsDocBeingEdited', '@IsDB2', '@IsCategory', + '@IsAvailable', '@IsAppInstalled', '@IsAgentEnabled', '@Integer', + '@InheritedDocumentUniqueID', '@Implode', '@IfError', '@If', + '@Hour', '@HashPassword', '@HardDeleteDocument', '@GetViewInfo', + '@GetProfileField', '@GetPortsList', '@GetIMContactListGroupNames', + '@GetHTTPHeader', '@GetFocusTable', '@GetField', '@GetDocField', + '@GetCurrentTimeZone', '@GetAddressBooks', '@FormLanguage', '@For', + '@FontList', '@FloatEq', '@FileDir', '@False', '@Failure', + '@Explode', '@Exp', '@Eval', '@Error', '@Environment', '@Ends', + '@EnableAlarms', '@Elements', '@EditUserECL', '@EditECL', + '@DoWhile', '@Domain', '@DocumentUniqueID', '@DocSiblings', + '@DocParentNumber', '@DocOmmittedLength', '@DocNumber', '@DocMark', + '@DocLock', '@DocLevel', '@DocLength', '@DocFields', + '@DocDescendants', '@DocChildren', '@Do', '@DialogBox', + '@DeleteField', '@DeleteDocument', '@DDETerminate', '@DDEPoke', + '@DDEInitiate', '@DDEExecute', '@DbTitle', '@DbName', '@DbManager', + '@DbLookup', '@DbExists', '@DbCommand', '@DbColumn', '@DB2Schema', + '@Day', '@Date', '@Created', '@Count', '@Cos', '@Contains', + '@ConfigFile', '@Compare', '@Command', '@ClientType', + '@CheckFormulaSyntax', '@CheckAlarms', '@Char', '@Certificate', + '@BusinessDays', '@BrowserInfo', '@Begins', '@Author', + '@Attachments', '@AttachmentNames', '@AttachmentModifiedTimes', + '@AttachmentLengths', '@ATan2', '@ATan', '@ASin', '@Ascii', + '@AllDescendants', '@AllChildren', '@All', '@AdminECLIsLocked', + '@Adjust', '@AddToFolder', '@ACos', '@Accessed', '@AbstractSimple', + '@Abstract', '@Abs' + ) + ), + 'SYMBOLS' => array( + '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #800000;', + 2 => 'color: #0000FF;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #FF00FF;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF00FF;' + ), + 'METHODS' => array( + 1 => 'color: #0000AA;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 2 + ); + +?> diff --git a/examples/includes/geshi/geshi/lotusscript.php b/examples/includes/geshi/geshi/lotusscript.php new file mode 100644 index 0000000..598da3b --- /dev/null +++ b/examples/includes/geshi/geshi/lotusscript.php @@ -0,0 +1,191 @@ + 'LotusScript', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array('%REM' => '%END REM'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"' , "|"), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array ( + 'Yield', 'Year', 'Xor', 'Write', 'With', 'Width', 'While', 'Wend', + 'Weekday', 'VarType', 'Variant', 'Val', 'UString', 'UString$', + 'UseLSX', 'Use', 'Until', 'Unlock', 'Unicode', 'Uni', 'UChr', + 'UChr$', 'UCase', 'UCase$', 'UBound', 'TypeName', 'Type', 'TRUE', + 'Trim', 'Trim$', 'Today', 'To', 'TimeValue', 'TimeSerial', 'Timer', + 'TimeNumber', 'Time', 'Time$', 'Then', 'Text', 'Tan', 'Tab', 'Sub', + 'StrToken', 'StrToken$', 'StrRightBack', 'StrRightBack$', + 'StrRight', 'StrRight$', 'StrLeftBack', 'StrLeftBack$', 'StrLeft', + 'StrLeft$', 'String', 'String$', 'StrConv', 'StrCompare', 'StrComp', + 'Str', 'Str$', 'Stop', 'Step', 'Static', 'Sqr', 'Split', 'Spc', + 'Space', 'Space$', 'Sleep', 'Single', 'Sin', 'Shell', 'Shared', + 'Sgn', 'SetFileAttr', 'SetAttr', 'Set', 'SendKeys', 'Select', + 'Seek', 'Second', 'RTrim', 'RTrim$', 'RSet', 'Round', 'Rnd', + 'RmDir', 'RightC', 'RightC$', 'RightBP', 'RightBP$', 'RightB', + 'RightB$', 'Right', 'Right$', 'Return', 'Resume', 'Reset', + 'Replace', 'Remove', 'Rem', 'ReDim', 'Read', 'Randomize', + 'Random', 'Put', 'Public', 'Property', 'Private', 'Print', + 'Preserve', 'Pitch', 'PI', 'Output', 'Or', 'Option', 'Open', 'On', + 'Oct', 'Oct$', 'NULL', 'Now', 'NOTHING', 'Not', 'NoPitch', 'NoCase', + 'Next', 'New', 'Name', 'MsgBox', 'Month', 'Mod', 'MkDir', 'Minute', + 'MidC', 'MidC$', 'MidBP', 'MidBP$', 'MidB', 'MidB$', 'Mid', 'Mid$', + 'MessageBox', 'Me', 'LTrim', 'LTrim$', 'LSServer', 'LSI_Info', + 'LSet', 'Loop', 'Long', 'Log', 'LOF', 'Lock', 'LOC', 'LMBCS', + 'ListTag', 'List', 'Line', 'Like', 'Lib', 'Let', 'LenC', 'LenBP', + 'LenB', 'Len', 'LeftC', 'LeftC$', 'LeftBP', 'LeftBP$', 'LeftB', + 'LeftB$', 'Left', 'Left$', 'LCase', 'LCase$', 'LBound', 'Kill', + 'Join', 'IsUnknown', 'IsScalar', 'IsObject', 'IsNumeric', 'IsNull', + 'IsList', 'IsEmpty', 'IsElement', 'IsDate', 'IsArray', 'IsA', 'Is', + 'Integer', 'Int', 'InStrC', 'InStrBP', 'InStrB', 'InStr', 'InputBP', + 'InputBP$', 'InputBox', 'InputBox$', 'InputB', 'InputB$', 'Input', + 'Input$', 'In', 'IMSetMode', 'Implode', 'Implode$', 'Imp', + 'IMEStatus', 'If', 'Hour', 'Hex', 'Hex$', 'Goto', 'GoSub', + 'GetThreadInfo', 'GetFileAttr', 'GetAttr', 'Get', 'Function', + 'FullTrim', 'From', 'FreeFile', 'Fraction', 'Format', 'Format$', + 'ForAll', 'For', 'Fix', 'FileLen', 'FileDateTime', 'FileCopy', + 'FileAttr', 'FALSE', 'Explicit', 'Exp', 'Exit', 'Execute', 'Event', + 'Evaluate', 'Error', 'Error$', 'Err', 'Erl', 'Erase', 'Eqv', 'EOF', + 'Environ', 'Environ$', 'End', 'ElseIf', 'Else', 'Double', 'DoEvents', + 'Do', 'Dir', 'Dir$', 'Dim', 'DestroyLock', 'Delete', 'DefVar', + 'DefStr', 'DefSng', 'DefLng', 'DefInt', 'DefDbl', 'DefCur', + 'DefByte', 'DefBool', 'Declare', 'Day', 'DateValue', 'DateSerial', + 'DateNumber', 'Date', 'Date$', 'DataType', 'CVDate', 'CVar', + 'Currency', 'CurDrive', 'CurDrive$', 'CurDir', 'CurDir$', 'CStr', + 'CSng', 'CreateLock', 'Cos', 'Const', 'Compare', 'Command', + 'Command$', 'CodeUnlock', 'CodeLockCheck', 'CodeLock', 'Close', + 'CLng', 'Class', 'CInt', 'Chr', 'Chr$', 'ChDrive', 'ChDir', 'CDbl', + 'CDat', 'CCur', 'CByte', 'CBool', 'Case', 'Call', 'ByVal', 'Byte', + 'Boolean', 'Bind', 'Binary', 'Bin', 'Bin$', 'Beep', 'Base', 'Atn2', + 'Atn', 'ASin', 'Asc', 'As', 'ArrayUnique', 'ArrayReplace', + 'ArrayGetIndex', 'ArrayAppend', 'Append', 'AppActivate', 'Any', + 'And', 'Alias', 'ActivateApp', 'ACos', 'Access', 'Abs', '%Include', + '%If', '%END', '%ElseIf', '%Else' + ), + 2 => array ( + 'NotesXSLTransformer', 'NotesXMLProcessor', 'NotesViewNavigator', + 'NotesViewEntryCollection', 'NotesViewEntry', 'NotesViewColumn', + 'NotesView', 'NotesUIWorkspace', 'NotesUIView', 'NotesUIScheduler', + 'NotesUIDocument', 'NotesUIDatabase', 'NotesTimer', 'NotesStream', + 'NotesSession', 'NotesSAXParser', 'NotesSAXException', + 'NotesSAXAttributeList', 'NotesRichTextTable', 'NotesRichTextTab', + 'NotesRichTextStyle', 'NotesRichTextSection', 'NotesRichTextRange', + 'NotesRichTextParagraphStyle', 'NotesRichTextNavigator', + 'NotesRichTextItem', 'NotesRichTextDocLink', + 'NotesReplicationEntry', 'NotesReplication', 'NotesRegistration', + 'NotesOutlineEntry', 'NotesOutline', 'NotesNoteCollection', + 'NotesNewsLetter', 'NotesName', 'NotesMIMEHeader', + 'NotesMIMEEntity', 'NotesLog', 'NotesItem', 'NotesInternational', + 'NotesForm', 'NotesEmbeddedObject', 'NotesDXLImporter', + 'NotesDXLExporter', 'NotesDOMXMLDeclNode', 'NotesDOMTextNode', + 'NotesDOMProcessingInstructionNode', 'NotesDOMParser', + 'NotesDOMNotationNode', 'NotesDOMNodeList', 'NotesDOMNode', + 'NotesDOMNamedNodeMap', 'NotesDOMEntityReferenceNode', + 'NotesDOMEntityNode', 'NotesDOMElementNode', + 'NotesDOMDocumentTypeNode', 'NotesDOMDocumentNode', + 'NotesDOMDocumentFragmentNode', 'NotesDOMCommentNode', + 'NotesDOMCharacterDataNote', 'NotesDOMCDATASectionNode', + 'NotesDOMAttributeNode', 'NotesDocumentCollection', 'NotesDocument', + 'NotesDbDirectory', 'NotesDateTime', 'NotesDateRange', + 'NotesDatabase', 'NotesColorObject', 'NotesAgent', + 'NotesAdministrationProcess', 'NotesACLEntry', 'NotesACL', + 'Navigator', 'Field', 'Button' + ) + ) , + 'SYMBOLS' => array( + '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000FF;', + 2 => 'color: #0000EE;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #000000;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF00FF;' + ), + 'METHODS' => array( + 1 => 'color: #0000AA;' + ), + 'SYMBOLS' => array( + 0 => 'color: #006600;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 2 +); + +?> diff --git a/examples/includes/geshi/geshi/lscript.php b/examples/includes/geshi/geshi/lscript.php new file mode 100644 index 0000000..57bb2ba --- /dev/null +++ b/examples/includes/geshi/geshi/lscript.php @@ -0,0 +1,387 @@ + 'LScript', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + //Yes, I'm aware these are out of order, + //I had to rearrange and couldn't be bothered changing the numbers... + 7 => array( + '@data', '@define', '@else', '@end', '@fpdepth', '@if', '@include', + '@insert', '@library', '@localipc', '@name', '@save', '@script', + '@sequence', '@version', '@warnings' + ), + 1 => array( + 'break', 'case', 'continue', 'else', 'end', 'false', 'for', + 'foreach', 'if', 'return', 'switch', 'true', 'while', + ), + 3 => array( + 'active', 'alertlevel', 'alpha', 'alphaprefix', 'animfilename', 'autokeycreate', + 'backdroptype', 'blue', 'boxthreshold', 'button', + 'channelsvisible', 'childrenvisible', 'compfg', 'compbg', 'compfgalpha', + 'coneangles', 'cosine', 'count', 'ctl', 'curFilename', 'curFrame', + 'currenttime', 'curTime', 'curType', + 'depth', 'diffshade', 'diffuse', 'dimensions', 'displayopts', 'dynamicupdate', + 'end', 'eta', + 'filename', 'flags', 'fogtype', 'fps', 'frame', 'frameend', 'frameheight', + 'framestart', 'framestep', 'framewidth', + 'generalopts', 'genus', 'geometry', 'gNorm', 'goal', 'green', + 'h', 'hasAlpha', 'height', + 'id', 'innerlimit', 'isColor', + 'keyCount', 'keys', + 'limiteregion', 'locked', 'luminous', + 'maxsamplesperpixel', 'minsamplesperpixel', 'mirror', 'motionx', 'motiony', + 'name', 'newFilename', 'newFrame', 'newTime', 'newType', 'null', 'numthreads', + 'objID', 'oPos', 'outerlimit', 'oXfrm', + 'parent', 'pixel', 'pixelaspect', 'point', 'points', 'pointcount', 'polNum', + 'polycount', 'polygon', 'polygons', 'postBehavior', 'preBehavior', 'previewend', + 'previewstart', 'previewstep', + 'range', 'rawblue', 'rawgreen', 'rawred', 'rayLength', 'raySource', 'red', + 'reflectblue', 'reflectgreen', 'reflectred', 'recursiondepth', 'renderend', + 'renderopts', 'renderstart', 'renderstep', 'rendertype', 'restlength', + 'rgbprefix', 'roughness', + 'selected', 'setColor', 'setPattern', 'shading', 'shadow', 'shadows', + 'shadowtype', 'size', 'source', 'special', 'specshade', 'specular', + 'spotsize', 'start', 'sx', 'sy', 'sz', + 'target', 'totallayers', 'totalpoints', 'totalpolygons', 'trans', 'transparency', + 'type', + 'value', 'view', 'visible', 'visibility', + 'w', 'width', 'wNorm', 'wPos', 'wXfrm', + 'x', 'xoffset', + 'y', 'yoffset', + 'z' + ), + 4 => array( + 'addLayer', 'addParticle', 'alphaspot', 'ambient', 'asAsc', 'asBin', + 'asInt', 'asNum', 'asStr', 'asVec', 'attach', 'axislocks', + 'backdropColor', 'backdropRay', 'backdropSqueeze', 'bone', 'blurLength', + 'close', 'color', 'contains', 'copy', 'createKey', + 'deleteKey', 'detach', 'drawCircle', 'drawLine', 'drawPoint', 'drawText', + 'drawTriangle', + 'edit', 'eof', 'event', + 'firstChannel', 'firstLayer', 'firstSelect', 'focalLength', 'fogColor', + 'fogMaxAmount', 'fogMaxDist', 'fogMinAmount', 'fogMinDist', + 'fovAngles', 'fStop', 'firstChild', 'focalDistance', + 'get', 'getChannelGroup', 'getEnvelope', 'getForward', 'getKeyBias', + 'getKeyContinuity', 'getKeyCurve', 'getKeyHermite', 'getKeyTension', + 'getKeyTime', 'getKeyValue', 'getParticle', 'getPivot', 'getPosition', + 'getRight', 'getRotation', 'getSelect', 'getScaling', 'getTag', 'getTexture', + 'getUp', 'getValue', 'getWorldPosition', 'getWorldForward', 'getWorldRight', + 'getWorldRotation', 'getWorldUp', 'globalBlur', 'globalMask', 'globalResolution', + 'hasCCEnd', 'hasCCStart', + 'illuminate', 'indexOf', 'isAscii', 'isAlnum', 'isAlpha', 'isBone', + 'isCamera', 'isChannel', 'isChannelGroup', 'isCntrl', 'isCurve', 'isDigit', + 'isEnvelope', 'isImage', 'isInt', 'isLight', 'isLower', 'isMapped', 'isMesh', + 'isNil', 'isNum', 'IsOpen', 'isOriginal', 'isPrint', 'isPunct', 'isScene', + 'isSpace', 'isStr', 'isUpper', 'isValid', 'isVMap', 'isVec', 'isXDigit', + 'keyExists', + 'layer', 'layerName', 'layerVisible', 'limits', 'line', 'linecount', 'load', 'luma', + 'next', 'nextLayer', 'nextSelect', 'nextChannel', 'nextChild', 'nl', + 'offset', 'open', + 'pack', 'param', 'parse', 'paste', 'persist', 'polygonCount', 'position', + 'rayCast', 'rayTrace', 'read', 'readByte', 'readInt', 'readNumber', + 'readDouble', 'readShort', 'readString', 'readVector', 'reduce', + 'remParticle', 'renderCamera', 'reopen', 'replace', 'reset', 'restParam', + 'rewind', 'rgb', 'rgbambient', 'rgbcolor', 'rgbspot', + 'save', 'schemaPosition', 'select', 'set', 'setChannelGroup', 'setKeyBias', + 'setKeyContinuity', 'setKeyCurve', + 'setKeyHermite', 'setKeyTension', 'setKeyValue', 'setParticle', 'setPoints', + 'setTag', 'setValue', 'server', 'serverFlags', 'sortA', 'sortD', 'surface', + 'trunc', + 'write', 'writeln', 'writeByte', 'writeData', 'writeNumber', 'writeDouble', + 'writeShort', 'writeString', 'writeVector', + 'vertex', 'vertexCount', + 'zoomFactor' + ), + 2 => array( + 'abs', 'acos', 'angle', 'append', 'ascii', 'asin', 'atan', + 'binary', + 'ceil', 'center', 'chdir', 'clearimage', 'cloned', 'comringattach', + 'comringdecode', 'comringdetach', 'comringencode', 'comringmsg', 'cos', + 'cosh', 'cot', 'cross2d', 'cross3d', 'csc', 'ctlstring', 'ctlinteger', + 'ctlnumber', 'ctlvector', 'ctldistance', 'ctlchoice', 'ctltext', + 'ctlcolor', 'ctlsurface', 'ctlfont', 'ctlpopup', 'ctledit', 'ctlpercent', + 'ctlangle', 'ctlrgb', 'ctlhsv', 'ctlcheckbox', 'ctlstate', 'ctlfilename', + 'ctlbutton', 'ctllistbox', 'ctlslider', 'ctlminislider', 'ctlsep', 'ctlimage', + 'ctltab', 'ctlallitems', 'ctlmeshitems', 'ctlcameraitems', 'ctllightitems', + 'ctlboneitems', 'ctlimageitems', 'ctlchannel', 'ctlviewport', 'Control_Management', + 'ctlpage', 'ctlgroup', 'ctlposition', 'ctlactive', 'ctlvisible', 'ctlalign', + 'ctlrefresh', 'ctlmenu', 'ctlinfo', + 'date', 'debug', 'deg', 'dot2d', 'dot3d', 'drawborder', 'drawbox', 'drawcircle', + 'drawelipse', 'drawerase', 'drawfillcircle', 'drawfillelipse', 'drawline', + 'drawpixel', 'drawtext', 'drawtextwidth', 'drawtextheight', 'dump', + 'error', 'exp', 'expose', 'extent', + 'fac', 'filecrc', 'filedelete', 'fileexists', 'filefind', 'filerename', + 'filestat', 'floor', 'format', 'frac', 'fullpath', + 'gamma', 'getdir', 'getenv', 'getfile', 'getfirstitem', 'getsep', 'getvalue', + 'globalrecall', 'globalstore', + 'hash', 'hex', 'hostBuild', 'hostVersion', 'hypot', + 'info', 'integer', + 'library', 'licenseId', 'lscriptVersion', 'load', 'loadimage', 'log', 'log10', + 'matchdirs', 'matchfiles', 'max', 'min', 'mkdir', 'mod', 'monend', 'moninit', 'monstep', + 'nil', 'normalize', 'number', + 'octal', 'overlayglyph', + 'parse', 'platform', 'pow', + 'rad', 'random', 'randu', 'range', 'read', 'readdouble', 'readInt', 'readNumber', + 'readShort', 'recall', 'regexp', 'reqabort', 'reqbegin', 'reqend', 'reqisopen', + 'reqkeyboard', 'reqopen', 'reqposition', 'reqpost', 'reqredraw', + 'reqsize', 'reqresize', 'requpdate', 'rmdir', 'round', 'runningUnder', + 'save', 'sec', 'select', 'selector', 'setdesc', 'setvalue', 'sin', 'sinh', 'size', + 'sizeof', 'sleep', 'spawn', 'split', 'sqrt', 'step', 'store', 'string', 'strleft', + 'strlower', 'strright', 'strsub', 'strupper', + 'tan', 'tanh', 'targetobject', 'terminate', 'text', 'time', + 'wait', 'warn', 'when', 'write', 'writeDouble', 'writeInt', 'writeNumber', 'writeShort', + 'var', 'vector', 'visitnodes', 'vmag', + ), + 5 => array( + 'addcurve', 'addpoint', 'addpolygon', 'addquad', 'addtriangle', 'alignpols', + 'autoflex', 'axisdrill', + 'bend', 'bevel', 'boolean', 'boundingbox', + 'changepart', 'changesurface', 'close', 'closeall', 'cmdseq', 'copy', 'copysurface', + 'createsurface', 'cut', + 'deformregion', 'delete', + 'editbegin', 'editend', 'exit', 'extrude', + 'fixedflex', 'flip', 'fontclear', 'fontcount', 'fontindex', 'fontload', + 'fontname', 'fracsubdivide', 'freezecurves', + 'getdefaultsurface', + 'jitter', + 'lathe', 'layerName', 'layerVisible', 'lyrbg', 'lyrdata', 'lyrempty', 'lyremptybg', + 'lyremptyfg', 'lyrfg', 'lyrsetbg', 'lyrsetfg', 'lyrswap', + 'magnet', 'make4patch', 'makeball', 'makebox', 'makecone', 'makedisc', + 'maketesball', 'maketext', 'mergepoints', 'mergepols', 'meshedit', 'mirror', + 'morphpols', 'move', + 'new', 'nextsurface', + 'paste', 'pathclone', 'pathextrude', 'pixel', 'pointcount', 'pointinfo', + 'pointmove', 'pole', 'polycount', 'polyinfo', 'polynormal', 'polypointcount', + 'polypoints', 'polysurface', + 'quantize', + 'railclone', 'railextrude', 'redo', 'removepols', 'rempoint', 'rempoly', + 'renamesurface', 'revert', 'rotate', + 'scale', 'selhide', 'selinvert', 'selmode', 'selpoint', 'selpolygon', 'selunhide', + 'selectvmap', 'setlayername', 'setobject', 'setpivot', 'setsurface', 'shapebevel', + 'shear', 'skinpols', 'smooth', 'smoothcurves', 'smoothscale', 'smoothshift', + 'soliddrill', 'splitpols', 'subdivide', 'swaphidden', + 'taper', 'triple', 'toggleCCend', 'toggleCCstart', 'togglepatches', 'twist', + 'undo', 'undogroupend', 'undogroupbegin', 'unifypols', 'unweld', + 'vortex', + 'weldaverage', 'weldpoints' + ), + 6 => array( + 'About', 'AboutOpenGL', 'AdaptiveSampling', 'AdaptiveThreshold', + 'AddAreaLight', 'AddBone', 'AddButton', 'AddCamera', 'AddChildBone', + 'AddDistantLight', 'AddEnvelope', 'AddLinearLight', 'AddNull', + 'AddPartigon', 'AddPlugins', 'AddPointLight', 'AddPosition', + 'AddRotation', 'AddScale', 'AddSpotlight', 'AddToSelection', + 'AdjustRegionTool', 'AffectCaustics', 'AffectDiffuse', 'AffectOpenGL', + 'AffectSpecular', 'AlertLevel', 'AmbientColor', 'AmbientIntensity', + 'Antialiasing', 'ApertureHeight', 'ApplyServer', 'AreaLight', + 'AutoConfirm', 'AutoFrameAdvance', 'AutoKey', + 'BackdropColor', 'BackView', 'BController', 'BLimits', 'BLurLength', 'BoneActive', + 'BoneFalloffType', 'BoneJointComp', 'BoneJointCompAmounts', 'BoneJointCompParent', + 'BoneLimitedRange', 'BoneMaxRange', 'BoneMinRange', 'BoneMuscleFlex', + 'BoneMuscleFlexAmounts', 'BoneMuscleFlexParent', 'BoneNormalization', + 'BoneRestLength', 'BoneRestPosition', 'BoneRestRotation', 'BoneSource', + 'BoneStrength', 'BoneStrengthMultiply', 'BoneWeightMapName', 'BoneWeightMapOnly', + 'BoneWeightShade', 'BoneXRay', 'BottomView', 'BoundingBoxThreshold', + 'BStiffness', + 'CacheCaustics', 'CacheRadiosity', 'CacheShadowMap', + 'CameraMask', 'CameraView', 'CameraZoomTool', 'CastShadow', 'CausticIntensity', + 'CenterItem', 'CenterMouse', 'ChangeTool', 'ClearAllBones', 'ClearAllCameras', + 'ClearAllLights', 'ClearAllObjects', 'ClearAudio', 'ClearScene', 'ClearSelected', + 'Clone', 'CommandHistory', 'CommandInput', 'Compositing', 'ConeAngleTool', + 'ContentDirectory', 'CreateKey', + 'DecreaseGrid', 'DeleteKey', 'DepthBufferAA', 'DepthOfField', 'DisplayOptions', + 'DistantLight', 'DrawAntialiasing', 'DrawBones', 'DrawChildBones', 'DynamicUpdate', + 'EditBones', 'EditCameras', 'EditKeys', 'EditLights', + 'EditMenus', 'EditObjects', 'EditPlugins', 'EditServer', 'EnableCaustics', + 'EnableDeformations', 'EnableIK', 'EnableLensFlares', 'EnableRadiosity', 'EnableServer', + 'EnableShadowMaps', 'EnableVIPER', 'EnableVolumetricLights', 'EnableXH', + 'EnableYP', 'EnableZB', 'EnahancedAA', 'ExcludeLight', 'ExcludeObject', + 'EyeSeparation', + 'FasterBones', 'FirstFrame', 'FirstItem', 'FitAll', 'FitSelected', + 'FlareIntensity', 'FlareOptions', 'FocalDistance', 'FogColor', 'FogMaxAmount', + 'FogMaxDistance', 'FogMinAmount', 'FogMinDistance', 'FogType', 'FractionalFrames', + 'FrameSize', 'FramesPerSecond', 'FrameStep', 'FreePreview', 'FrontView', 'FullTimeIK', + 'GeneralOptions', 'Generics', 'GlobalApertureHeight', 'GlobalBlurLength', + 'GlobalFrameSize', 'GlobalIllumination', 'GlobalMaskPosition', 'GlobalMotionBlur', + 'GlobalParticleBlur', 'GlobalPixelAspect', 'GlobalResolutionMulitplier', 'GoalItem', + 'GoalStrength', 'GoToFrame', 'GradientBackdrop', 'GraphEditor', 'GridSize', 'GroundColor', + 'HController', 'HideToolbar', 'HideWindows', 'HLimits', 'HStiffness', + 'ImageEditor', 'ImageProcessing', 'IncludeLight', 'IncludeObject', 'IncreaseGrid', + 'IndirectBounces', 'Item_SetWindowPos', 'ItemActive', 'ItemColor', 'ItemLock', + 'ItemProperties', 'ItemVisibilty', + 'KeepGoalWithinReach', + 'LastFrame', 'LastItem', 'LastPluginInterface', 'Layout_SetWindowPos', + 'Layout_SetWindowSize', 'LeftView', 'LensFlare', 'LensFStop', 'LightColor', + 'LightConeAngle', 'LightEdgeAngle', 'LightFalloffType', 'LightIntensity', + 'LightIntensityTool', 'LightQuality', 'LightRange', 'LightView', 'LimitB', + 'LimitDynamicRange', 'LimitedRegion', 'LimitH', 'LimitP', 'LinearLight', + 'LoadAudio', 'LoadFromScene', 'LoadMotion', 'LoadObject', 'LoadObjectLayer', + 'LoadPreview', 'LoadScene', 'LocalCoordinateSystem', + 'MakePreview', 'MaskColor', 'MaskPosition', 'MasterPlugins', 'MatchGoalOrientation', + 'MatteColor', 'MatteObject', 'MetaballResolution', 'Model', 'MorphAmount', + 'MorphAmountTool', 'MorphMTSE', 'MorphSurfaces', 'MorphTarget', 'MotionBlur', + 'MotionBlurDOFPreview', 'MotionOptions', 'MovePathTool', 'MovePivotTool', 'MoveTool', + 'NadirColor', 'NetRender', 'NextFrame', 'NextItem', 'NextKey', 'NextSibling', + 'NextViewLayout', 'NoiseReduction', 'Numeric', + 'ObjectDissolve', + 'ParentCoordinateSystem', 'ParentInPlace', 'ParentItem', + 'ParticleBlur', 'PathAlignLookAhead', 'PathAlignMaxLookSteps', 'PathAlignReliableDist', + 'Pause', 'PController', 'PerspectiveView', + 'PivotPosition', 'PivotRotation', 'PixelAspect', 'PlayAudio', 'PlayBackward', + 'PlayForward', 'PlayPreview', 'PLimits', 'PointLight', 'PolygonEdgeColor', + 'PolygonEdgeFlags', 'PolygonEdgeThickness', 'PolygonEdgeZScale', 'PolygonSize', + 'Position', 'Presets', 'PreviewFirstFrame', 'PreviewFrameStep', 'PreviewLastFrame', + 'PreviewOptions', 'PreviousFrame', 'PreviousItem', 'PreviousKey', 'PreviousSibling', + 'PreviousViewLayout', 'PStiffness', + 'Quit', + 'RadiosityIntensity', 'RadiosityTolerance', 'RadiosityType', 'RayRecursionLimit', + 'RayTraceReflection', 'RayTraceShadows', + 'RayTraceTransparency', 'ReceiveShadow', 'RecentContentDirs', 'RecentScenes', + 'ReconstructionFilter', 'RecordMaxAngles', 'RecordMinAngles', 'RecordPivotRotation', + 'RecordRestPosition', 'Redraw', 'RedrawNow', 'Refresh', 'RefreshNow', 'RegionPosition', + 'RemoveEnvelope', 'RemoveFromSelection', 'RemoveServer', 'Rename', 'RenderFrame', + 'RenderOptions', 'RenderScene', 'RenderSelected', 'RenderThreads', + 'ReplaceObjectLayer', 'ReplaceWithNull', 'ReplaceWithObject', 'Reset', + 'ResolutionMultiplier', 'RestLengthTool', 'RightView', 'RotatePivotTool', + 'RotateTool', 'Rotation', + 'SaveAllObjects', 'SaveCommandList', 'SaveCommandMessages', + 'SaveEndomorph', 'SaveLight', 'SaveLWSC1', 'SaveMotion', 'SaveObject', 'SaveObjectCopy', + 'SavePreview', 'SaveScene', 'SaveSceneAs', 'SaveSceneCopy', 'SaveTransformed', + 'SaveViewLayout', 'Scale', 'Scene_SetWindowPos', 'Scene_SetWindowSize', + 'SceneEditor', 'SchematicPosition', 'SchematicView', 'SelectAllBones', + 'SelectAllCameras', 'SelectAllLights', 'SelectAllObjects', 'SelectByName', + 'SelectChild', 'SelectItem', 'SelectParent', 'SelfShadow', 'ShadowColor', + 'ShadowExclusion', 'ShadowMapAngle', 'ShadowMapFitCone', 'ShadowMapFuzziness', + 'ShadowMapSize', 'ShadowType', 'ShowCages', 'ShowFieldChart', 'ShowHandles', + 'ShowIKChains', 'ShowMotionPaths', 'ShowSafeAreas', 'ShowTargetLines', + 'ShrinkEdgesWithDistance', 'SingleView', 'SizeTool', 'SkelegonsToBones', 'SkyColor', + 'Spotlight', 'SquashTool', 'Statistics', 'StatusMsg', 'Stereoscopic', 'StretchTool', + 'SubdivisionOrder', 'SubPatchLevel', 'SurfaceEditor', 'Synchronize', + 'TargetItem', 'TopView', + 'UnaffectedByFog', 'UnaffectedByIK', 'Undo', 'UnseenByAlphaChannel', 'UnseenByCamera', + 'UnseenByRays', 'UseGlobalResolution', 'UseGlobalBlur', 'UseGlobalMask', + 'UseMorphedPositions', + 'ViewLayout', 'VIPER', 'VolumetricLighting', + 'VolumetricLightingOptions', 'VolumetricRadiosity', 'Volumetrics', + 'WorldCoordinateSystem', + 'XYView', 'XZView', + 'ZenithColor', 'ZoomFactor', 'ZoomIn', 'ZoomInX2', 'ZoomOut', 'ZoomOutX2', 'ZYView', + 'Camera', 'Channel', 'ChannelGroup', 'Envelope', 'File', 'Glyph', 'Icon', 'Image', + 'Light', 'Mesh', 'Scene', 'Surface', 'VMap' + ), + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '<', '>', '+', '-', '*', '/', '!', '%', '&', '@' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => true, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #FF6820; font-weight: bold;', //LS_COMMANDS + 3 => 'color: #007F7F; font-weight: bold;', //LS_MEMBERS + 4 => 'color: #800080; font-weight: bold;', //LS_METHODS + 5 => 'color: #51BD95; font-weight: bold;', //LS_MODELER + 6 => 'color: #416F85; font-weight: bold;', //LS_GENERAL + 7 => 'color: #C92929; font-weight: bold;' //LS_COMMANDS (cont) + ), + 'COMMENTS' => array( + 1 => 'color: #7F7F7F;', + 'MULTI' => 'color: #7F7F7F;' + ), + 'BRACKETS' => array( + 0 => 'color: #0040A0;' + ), + 'STRINGS' => array( + 0 => 'color: #00C800;' + ), + 'NUMBERS' => array( + 0 => 'color: #6953AC;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #0040A0;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ), + 'ESCAPE_CHAR' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 3 => array( + 'DISALLOWED_BEFORE' => '(?<=\.)' + ), + 4 => array( + 'DISALLOWED_BEFORE' => '(?<=\.)' + ) + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/lsl2.php b/examples/includes/geshi/geshi/lsl2.php new file mode 100644 index 0000000..27c5580 --- /dev/null +++ b/examples/includes/geshi/geshi/lsl2.php @@ -0,0 +1,898 @@ + 'LSL2', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( // flow control + 'do', + 'else', + 'for', + 'if', + 'jump', + 'return', + 'state', + 'while', + ), + 2 => array( // manifest constants + 'ACTIVE', + 'AGENT', + 'AGENT_ALWAYS_RUN', + 'AGENT_ATTACHMENTS', + 'AGENT_AWAY', + 'AGENT_BUSY', + 'AGENT_CROUCHING', + 'AGENT_FLYING', + 'AGENT_IN_AIR', + 'AGENT_MOUSELOOK', + 'AGENT_ON_OBJECT', + 'AGENT_SCRIPTED', + 'AGENT_SITTING', + 'AGENT_TYPING', + 'AGENT_WALKING', + 'ALL_SIDES', + 'ANIM_ON', + 'ATTACH_BACK', + 'ATTACH_BELLY', + 'ATTACH_CHEST', + 'ATTACH_CHIN', + 'ATTACH_HEAD', + 'ATTACH_HUD_BOTTOM', + 'ATTACH_HUD_BOTTOM_LEFT', + 'ATTACH_HUD_BOTTOM_RIGHT', + 'ATTACH_HUD_CENTER_1', + 'ATTACH_HUD_CENTER_2', + 'ATTACH_HUD_TOP_CENTER', + 'ATTACH_HUD_TOP_LEFT', + 'ATTACH_HUD_TOP_RIGHT', + 'ATTACH_LEAR', + 'ATTACH_LEYE', + 'ATTACH_LFOOT', + 'ATTACH_LHAND', + 'ATTACH_LHIP', + 'ATTACH_LLARM', + 'ATTACH_LLLEG', + 'ATTACH_LPEC', + 'ATTACH_LSHOULDER', + 'ATTACH_LUARM', + 'ATTACH_LULEG', + 'ATTACH_MOUTH', + 'ATTACH_NOSE', + 'ATTACH_PELVIS', + 'ATTACH_REAR', + 'ATTACH_REYE', + 'ATTACH_RFOOT', + 'ATTACH_RHAND', + 'ATTACH_RHIP', + 'ATTACH_RLARM', + 'ATTACH_RLLEG', + 'ATTACH_RPEC', + 'ATTACH_RSHOULDER', + 'ATTACH_RUARM', + 'ATTACH_RULEG', + 'CAMERA_ACTIVE', + 'CAMERA_BEHINDNESS_ANGLE', + 'CAMERA_BEHINDNESS_LAG', + 'CAMERA_DISTANCE', + 'CAMERA_FOCUS', + 'CAMERA_FOCUS_LAG', + 'CAMERA_FOCUS_LOCKED', + 'CAMERA_FOCUS_OFFSET', + 'CAMERA_FOCUS_THRESHOLD', + 'CAMERA_PITCH', + 'CAMERA_POSITION', + 'CAMERA_POSITION_LAG', + 'CAMERA_POSITION_LOCKED', + 'CAMERA_POSITION_THRESHOLD', + 'CHANGED_ALLOWED_DROP', + 'CHANGED_COLOR', + 'CHANGED_INVENTORY', + 'CHANGED_LINK', + 'CHANGED_OWNER', + 'CHANGED_REGION', + 'CHANGED_SCALE', + 'CHANGED_SHAPE', + 'CHANGED_TELEPORT', + 'CHANGED_TEXTURE', + 'CLICK_ACTION_NONE', + 'CLICK_ACTION_OPEN', + 'CLICK_ACTION_OPEN_MEDIA', + 'CLICK_ACTION_PAY', + 'CLICK_ACTION_SIT', + 'CLICK_ACTION_TOUCH', + 'CONTROL_BACK', + 'CONTROL_DOWN', + 'CONTROL_FWD', + 'CONTROL_LBUTTON', + 'CONTROL_LEFT', + 'CONTROL_ML_LBUTTON', + 'CONTROL_RIGHT', + 'CONTROL_ROT_LEFT', + 'CONTROL_ROT_RIGHT', + 'CONTROL_UP', + 'DATA_BORN', + 'DATA_NAME', + 'DATA_ONLINE', + 'DATA_PAYINFO', + 'DATA_RATING', + 'DATA_SIM_POS', + 'DATA_SIM_RATING', + 'DATA_SIM_STATUS', + 'DEBUG_CHANNEL', + 'DEG_TO_RAD', + 'EOF', + 'FALSE', + 'HTTP_BODY_MAXLENGTH', + 'HTTP_BODY_TRUNCATED', + 'HTTP_METHOD', + 'HTTP_MIMETYPE', + 'HTTP_VERIFY_CERT', + 'INVENTORY_ALL', + 'INVENTORY_ANIMATION', + 'INVENTORY_BODYPART', + 'INVENTORY_CLOTHING', + 'INVENTORY_GESTURE', + 'INVENTORY_LANDMARK', + 'INVENTORY_NONE', + 'INVENTORY_NOTECARD', + 'INVENTORY_OBJECT', + 'INVENTORY_SCRIPT', + 'INVENTORY_SOUND', + 'INVENTORY_TEXTURE', + 'LAND_LEVEL', + 'LAND_LOWER', + 'LAND_NOISE', + 'LAND_RAISE', + 'LAND_REVERT', + 'LAND_SMOOTH', + 'LINK_ALL_CHILDREN', + 'LINK_ALL_OTHERS', + 'LINK_ROOT', + 'LINK_SET', + 'LINK_THIS', + 'LIST_STAT_GEOMETRIC_MEAN', + 'LIST_STAT_MAX', + 'LIST_STAT_MEAN', + 'LIST_STAT_MEDIAN', + 'LIST_STAT_MIN', + 'LIST_STAT_NUM_COUNT', + 'LIST_STAT_RANGE', + 'LIST_STAT_STD_DEV', + 'LIST_STAT_SUM', + 'LIST_STAT_SUM_SQUARES', + 'LOOP', + 'MASK_BASE', + 'MASK_EVERYONE', + 'MASK_GROUP', + 'MASK_NEXT', + 'MASK_OWNER', + 'NULL_KEY', + 'OBJECT_CREATOR', + 'OBJECT_DESC', + 'OBJECT_GROUP', + 'OBJECT_NAME', + 'OBJECT_OWNER', + 'OBJECT_POS', + 'OBJECT_ROT', + 'OBJECT_UNKNOWN_DETAIL', + 'OBJECT_VELOCITY', + 'PARCEL_DETAILS_AREA', + 'PARCEL_DETAILS_DESC', + 'PARCEL_DETAILS_GROUP', + 'PARCEL_DETAILS_NAME', + 'PARCEL_DETAILS_OWNER', + 'PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY', + 'PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS', + 'PARCEL_FLAG_ALLOW_CREATE_OBJECTS', + 'PARCEL_FLAG_ALLOW_DAMAGE', + 'PARCEL_FLAG_ALLOW_FLY', + 'PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY', + 'PARCEL_FLAG_ALLOW_GROUP_SCRIPTS', + 'PARCEL_FLAG_ALLOW_LANDMARK', + 'PARCEL_FLAG_ALLOW_SCRIPTS', + 'PARCEL_FLAG_ALLOW_TERRAFORM', + 'PARCEL_FLAG_LOCAL_SOUND_ONLY', + 'PARCEL_FLAG_RESTRICT_PUSHOBJECT', + 'PARCEL_FLAG_USE_ACCESS_GROUP', + 'PARCEL_FLAG_USE_ACCESS_LIST', + 'PARCEL_FLAG_USE_BAN_LIST', + 'PARCEL_FLAG_USE_LAND_PASS_LIST', + 'PARCEL_MEDIA_COMMAND_AGENT', + 'PARCEL_MEDIA_COMMAND_AUTO_ALIGN', + 'PARCEL_MEDIA_COMMAND_DESC', + 'PARCEL_MEDIA_COMMAND_LOOP_SET', + 'PARCEL_MEDIA_COMMAND_PAUSE', + 'PARCEL_MEDIA_COMMAND_PLAY', + 'PARCEL_MEDIA_COMMAND_SIZE', + 'PARCEL_MEDIA_COMMAND_STOP', + 'PARCEL_MEDIA_COMMAND_TEXTURE', + 'PARCEL_MEDIA_COMMAND_TIME', + 'PARCEL_MEDIA_COMMAND_TYPE', + 'PARCEL_MEDIA_COMMAND_URL', + 'PASSIVE', + 'PAYMENT_INFO_ON_FILE', + 'PAYMENT_INFO_USED', + 'PAY_DEFAULT', + 'PAY_HIDE', + 'PERMISSION_ATTACH', + 'PERMISSION_CHANGE_LINKS', + 'PERMISSION_CONTROL_CAMERA', + 'PERMISSION_DEBIT', + 'PERMISSION_TAKE_CONTROLS', + 'PERMISSION_TRACK_CAMERA', + 'PERMISSION_TRIGGER_ANIMATION', + 'PERM_ALL', + 'PERM_COPY', + 'PERM_MODIFY', + 'PERM_MOVE', + 'PERM_TRANSFER', + 'PI', + 'PI_BY_TWO', + 'PRIM_BUMP_BARK', + 'PRIM_BUMP_BLOBS', + 'PRIM_BUMP_BRICKS', + 'PRIM_BUMP_BRIGHT', + 'PRIM_BUMP_CHECKER', + 'PRIM_BUMP_CONCRETE', + 'PRIM_BUMP_DARK', + 'PRIM_BUMP_DISKS', + 'PRIM_BUMP_GRAVEL', + 'PRIM_BUMP_LARGETILE', + 'PRIM_BUMP_NONE', + 'PRIM_BUMP_SHINY', + 'PRIM_BUMP_SIDING', + 'PRIM_BUMP_STONE', + 'PRIM_BUMP_STUCCO', + 'PRIM_BUMP_SUCTION', + 'PRIM_BUMP_TILE', + 'PRIM_BUMP_WEAVE', + 'PRIM_BUMP_WOOD', + 'PRIM_COLOR', + 'PRIM_FULLBRIGHT', + 'PRIM_HOLE_CIRCLE', + 'PRIM_HOLE_DEFAULT', + 'PRIM_HOLE_SQUARE', + 'PRIM_HOLE_TRIANGLE', + 'PRIM_MATERIAL', + 'PRIM_MATERIAL_FLESH', + 'PRIM_MATERIAL_GLASS', + 'PRIM_MATERIAL_LIGHT', + 'PRIM_MATERIAL_METAL', + 'PRIM_MATERIAL_PLASTIC', + 'PRIM_MATERIAL_RUBBER', + 'PRIM_MATERIAL_STONE', + 'PRIM_MATERIAL_WOOD', + 'PRIM_PHANTOM', + 'PRIM_PHYSICS', + 'PRIM_POSITION', + 'PRIM_ROTATION', + 'PRIM_SHINY_HIGH', + 'PRIM_SHINY_LOW', + 'PRIM_SHINY_MEDIUM', + 'PRIM_SHINY_NONE', + 'PRIM_SIZE', + 'PRIM_TEMP_ON_REZ', + 'PRIM_TEXTURE', + 'PRIM_TYPE', + 'PRIM_TYPE_BOX', + 'PRIM_TYPE_CYLINDER', + 'PRIM_TYPE_PRISM', + 'PRIM_TYPE_RING', + 'PRIM_TYPE_SPHERE', + 'PRIM_TYPE_TORUS', + 'PRIM_TYPE_TUBE', + 'PSYS_PART_BOUNCE_MASK', + 'PSYS_PART_EMISSIVE_MASK', + 'PSYS_PART_END_ALPHA', + 'PSYS_PART_END_COLOR', + 'PSYS_PART_END_SCALE', + 'PSYS_PART_FLAGS', + 'PSYS_PART_FOLLOW_SRC_MASK', + 'PSYS_PART_FOLLOW_VELOCITY_MASK', + 'PSYS_PART_INTERP_COLOR_MASK', + 'PSYS_PART_INTERP_SCALE_MASK', + 'PSYS_PART_MAX_AGE', + 'PSYS_PART_START_ALPHA', + 'PSYS_PART_START_COLOR', + 'PSYS_PART_START_SCALE', + 'PSYS_PART_TARGET_LINEAR_MASK', + 'PSYS_PART_TARGET_POS_MASK', + 'PSYS_PART_WIND_MASK', + 'PSYS_SRC_ACCEL', + 'PSYS_SRC_ANGLE_BEGIN', + 'PSYS_SRC_ANGLE_END', + 'PSYS_SRC_BURST_PART_COUNT', + 'PSYS_SRC_BURST_RADIUS', + 'PSYS_SRC_BURST_RATE', + 'PSYS_SRC_BURST_SPEED_MAX', + 'PSYS_SRC_BURST_SPEED_MIN', + 'PSYS_SRC_INNERANGLE', + 'PSYS_SRC_MAX_AGE', + 'PSYS_SRC_OMEGA', + 'PSYS_SRC_OUTERANGLE', + 'PSYS_SRC_PATTERN', + 'PSYS_SRC_PATTERN_ANGLE', + 'PSYS_SRC_PATTERN_ANGLE_CONE', + 'PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY', + 'PSYS_SRC_PATTERN_DROP', + 'PSYS_SRC_PATTERN_EXPLODE', + 'PSYS_SRC_TARGET_KEY', + 'PSYS_SRC_TEXTURE', + 'RAD_TO_DEG', + 'REMOTE_DATA_CHANNEL', + 'REMOTE_DATA_REQUEST', + 'SCRIPTED', + 'SQRT2', + 'STATUS_BLOCK_GRAB', + 'STATUS_DIE_AT_EDGE', + 'STATUS_PHANTOM', + 'STATUS_PHYSICS', + 'STATUS_RETURN_AT_EDGE', + 'STATUS_ROTATE_X', + 'STATUS_ROTATE_Y', + 'STATUS_ROTATE_Z', + 'STATUS_SANDBOX', + 'TRUE', + 'TWO_PI', + 'VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY', + 'VEHICLE_ANGULAR_DEFLECTION_TIMESCALE', + 'VEHICLE_ANGULAR_FRICTION_TIMESCALE', + 'VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE', + 'VEHICLE_ANGULAR_MOTOR_DIRECTION', + 'VEHICLE_ANGULAR_MOTOR_TIMESCALE', + 'VEHICLE_BANKING_EFFICIENCY', + 'VEHICLE_BANKING_MIX', + 'VEHICLE_BANKING_TIMESCALE', + 'VEHICLE_BUOYANCY', + 'VEHICLE_FLAG_CAMERA_DECOUPLED', + 'VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT', + 'VEHICLE_FLAG_HOVER_TERRAIN_ONLY', + 'VEHICLE_FLAG_HOVER_UP_ONLY', + 'VEHICLE_FLAG_HOVER_WATER_ONLY', + 'VEHICLE_FLAG_LIMIT_MOTOR_UP', + 'VEHICLE_FLAG_LIMIT_ROLL_ONLY', + 'VEHICLE_FLAG_MOUSELOOK_BANK', + 'VEHICLE_FLAG_MOUSELOOK_STEER', + 'VEHICLE_FLAG_NO_DEFLECTION_UP', + 'VEHICLE_HOVER_EFFICIENCY', + 'VEHICLE_HOVER_HEIGHT', + 'VEHICLE_HOVER_TIMESCALE', + 'VEHICLE_LINEAR_DEFLECTION_EFFICIENCY', + 'VEHICLE_LINEAR_DEFLECTION_TIMESCALE', + 'VEHICLE_LINEAR_FRICTION_TIMESCALE', + 'VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE', + 'VEHICLE_LINEAR_MOTOR_DIRECTION', + 'VEHICLE_LINEAR_MOTOR_OFFSET', + 'VEHICLE_LINEAR_MOTOR_TIMESCALE', + 'VEHICLE_REFERENCE_FRAME', + 'VEHICLE_TYPE_AIRPLANE', + 'VEHICLE_TYPE_BALLOON', + 'VEHICLE_TYPE_BOAT', + 'VEHICLE_TYPE_CAR', + 'VEHICLE_TYPE_NONE', + 'VEHICLE_TYPE_SLED', + 'VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY', + 'VEHICLE_VERTICAL_ATTRACTION_TIMESCALE', + 'ZERO_ROTATION', + 'ZERO_VECTOR', + ), + 3 => array( // handlers + 'at_rot_target', + 'at_target', + 'attached', + 'changed', + 'collision', + 'collision_end', + 'collision_start', + 'control', + 'dataserver', + 'email', + 'http_response', + 'land_collision', + 'land_collision_end', + 'land_collision_start', + 'link_message', + 'listen', + 'money', + 'moving_end', + 'moving_start', + 'no_sensor', + 'not_at_rot_target', + 'not_at_target', + 'object_rez', + 'on_rez', + 'remote_data', + 'run_time_permissions', + 'sensor', + 'state_entry', + 'state_exit', + 'timer', + 'touch', + 'touch_end', + 'touch_start', + ), + 4 => array( // data types + 'float', + 'integer', + 'key', + 'list', + 'rotation', + 'string', + 'vector', + ), + 5 => array( // library + 'default', + 'llAbs', + 'llAcos', + 'llAddToLandBanList', + 'llAddToLandPassList', + 'llAdjustSoundVolume', + 'llAllowInventoryDrop', + 'llAngleBetween', + 'llApplyImpulse', + 'llApplyRotationalImpulse', + 'llAsin', + 'llAtan2', + 'llAttachToAvatar', + 'llAvatarOnSitTarget', + 'llAxes2Rot', + 'llAxisAngle2Rot', + 'llBase64ToInteger', + 'llBase64ToString', + 'llBreakAllLinks', + 'llBreakLink', + 'llCeil', + 'llClearCameraParams', + 'llCloseRemoteDataChannel', + 'llCloud', + 'llCollisionFilter', + 'llCollisionSound', + 'llCollisionSprite', + 'llCos', + 'llCreateLink', + 'llCSV2List', + 'llDeleteSubList', + 'llDeleteSubString', + 'llDetachFromAvatar', + 'llDetectedGrab', + 'llDetectedGroup', + 'llDetectedKey', + 'llDetectedLinkNumber', + 'llDetectedName', + 'llDetectedOwner', + 'llDetectedPos', + 'llDetectedRot', + 'llDetectedTouchBinormal', + 'llDetectedTouchFace', + 'llDetectedTouchNormal', + 'llDetectedTouchPos', + 'llDetectedTouchST', + 'llDetectedTouchUV', + 'llDetectedType', + 'llDetectedVel', + 'llDialog', + 'llDie', + 'llDumpList2String', + 'llEdgeOfWorld', + 'llEjectFromLand', + 'llEmail', + 'llEscapeURL', + 'llEuler2Rot', + 'llFabs', + 'llFloor', + 'llForceMouselook', + 'llFrand', + 'llGetAccel', + 'llGetAgentInfo', + 'llGetAgentLanguage', + 'llGetAgentSize', + 'llGetAlpha', + 'llGetAndResetTime', + 'llGetAnimation', + 'llGetAnimationList', + 'llGetAttached', + 'llGetBoundingBox', + 'llGetCameraPos', + 'llGetCameraRot', + 'llGetCenterOfMass', + 'llGetColor', + 'llGetCreator', + 'llGetDate', + 'llGetEnergy', + 'llGetForce', + 'llGetFreeMemory', + 'llGetGeometricCenter', + 'llGetGMTclock', + 'llGetInventoryCreator', + 'llGetInventoryKey', + 'llGetInventoryName', + 'llGetInventoryNumber', + 'llGetInventoryPermMask', + 'llGetInventoryType', + 'llGetKey', + 'llGetLandOwnerAt', + 'llGetLinkKey', + 'llGetLinkName', + 'llGetLinkNumber', + 'llGetListEntryType', + 'llGetListLength', + 'llGetLocalPos', + 'llGetLocalRot', + 'llGetMass', + 'llGetNextEmail', + 'llGetNotecardLine', + 'llGetNumberOfNotecardLines', + 'llGetNumberOfPrims', + 'llGetNumberOfSides', + 'llGetObjectDesc', + 'llGetObjectDetails', + 'llGetObjectMass', + 'llGetObjectName', + 'llGetObjectPermMask', + 'llGetObjectPrimCount', + 'llGetOmega', + 'llGetOwner', + 'llGetOwnerKey', + 'llGetParcelDetails', + 'llGetParcelFlags', + 'llGetParcelMaxPrims', + 'llGetParcelPrimCount', + 'llGetParcelPrimOwners', + 'llGetPermissions', + 'llGetPermissionsKey', + 'llGetPos', + 'llGetPrimitiveParams', + 'llGetRegionAgentCount', + 'llGetRegionCorner', + 'llGetRegionFlags', + 'llGetRegionFPS', + 'llGetRegionName', + 'llGetRegionTimeDilation', + 'llGetRootPosition', + 'llGetRootRotation', + 'llGetRot', + 'llGetScale', + 'llGetScriptName', + 'llGetScriptState', + 'llGetSimulatorHostname', + 'llGetStartParameter', + 'llGetStatus', + 'llGetSubString', + 'llGetSunDirection', + 'llGetTexture', + 'llGetTextureOffset', + 'llGetTextureRot', + 'llGetTextureScale', + 'llGetTime', + 'llGetTimeOfDay', + 'llGetTimestamp', + 'llGetTorque', + 'llGetUnixTime', + 'llGetVel', + 'llGetWallclock', + 'llGiveInventory', + 'llGiveInventoryList', + 'llGiveMoney', + 'llGround', + 'llGroundContour', + 'llGroundNormal', + 'llGroundRepel', + 'llGroundSlope', + 'llHTTPRequest', + 'llInsertString', + 'llInstantMessage', + 'llIntegerToBase64', + 'llKey2Name', + 'llList2CSV', + 'llList2Float', + 'llList2Integer', + 'llList2Key', + 'llList2List', + 'llList2ListStrided', + 'llList2Rot', + 'llList2String', + 'llList2Vector', + 'llListen', + 'llListenControl', + 'llListenRemove', + 'llListFindList', + 'llListInsertList', + 'llListRandomize', + 'llListReplaceList', + 'llListSort', + 'llListStatistics', + 'llLoadURL', + 'llLog', + 'llLog10', + 'llLookAt', + 'llLoopSound', + 'llLoopSoundMaster', + 'llLoopSoundSlave', + 'llMapDestination', + 'llMD5String', + 'llMessageLinked', + 'llMinEventDelay', + 'llModifyLand', + 'llModPow', + 'llMoveToTarget', + 'llOffsetTexture', + 'llOpenRemoteDataChannel', + 'llOverMyLand', + 'llOwnerSay', + 'llParcelMediaCommandList', + 'llParcelMediaQuery', + 'llParseString2List', + 'llParseStringKeepNulls', + 'llParticleSystem', + 'llPassCollisions', + 'llPassTouches', + 'llPlaySound', + 'llPlaySoundSlave', + 'llPow', + 'llPreloadSound', + 'llPushObject', + 'llRegionSay', + 'llReleaseControls', + 'llRemoteDataReply', + 'llRemoteDataSetRegion', + 'llRemoteLoadScriptPin', + 'llRemoveFromLandBanList', + 'llRemoveFromLandPassList', + 'llRemoveInventory', + 'llRemoveVehicleFlags', + 'llRequestAgentData', + 'llRequestInventoryData', + 'llRequestPermissions', + 'llRequestSimulatorData', + 'llResetLandBanList', + 'llResetLandPassList', + 'llResetOtherScript', + 'llResetScript', + 'llResetTime', + 'llRezAtRoot', + 'llRezObject', + 'llRot2Angle', + 'llRot2Axis', + 'llRot2Euler', + 'llRot2Fwd', + 'llRot2Left', + 'llRot2Up', + 'llRotateTexture', + 'llRotBetween', + 'llRotLookAt', + 'llRotTarget', + 'llRotTargetRemove', + 'llRound', + 'llSameGroup', + 'llSay', + 'llScaleTexture', + 'llScriptDanger', + 'llSendRemoteData', + 'llSensor', + 'llSensorRemove', + 'llSensorRepeat', + 'llSetAlpha', + 'llSetBuoyancy', + 'llSetCameraAtOffset', + 'llSetCameraEyeOffset', + 'llSetCameraParams', + 'llSetClickAction', + 'llSetColor', + 'llSetDamage', + 'llSetForce', + 'llSetForceAndTorque', + 'llSetHoverHeight', + 'llSetLinkAlpha', + 'llSetLinkColor', + 'llSetLinkPrimitiveParams', + 'llSetLinkTexture', + 'llSetLocalRot', + 'llSetObjectDesc', + 'llSetObjectName', + 'llSetParcelMusicURL', + 'llSetPayPrice', + 'llSetPos', + 'llSetPrimitiveParams', + 'llSetRemoteScriptAccessPin', + 'llSetRot', + 'llSetScale', + 'llSetScriptState', + 'llSetSitText', + 'llSetSoundQueueing', + 'llSetSoundRadius', + 'llSetStatus', + 'llSetText', + 'llSetTexture', + 'llSetTextureAnim', + 'llSetTimerEvent', + 'llSetTorque', + 'llSetTouchText', + 'llSetVehicleFlags', + 'llSetVehicleFloatParam', + 'llSetVehicleRotationParam', + 'llSetVehicleType', + 'llSetVehicleVectorParam', + 'llSHA1String', + 'llShout', + 'llSin', + 'llSitTarget', + 'llSleep', + 'llSqrt', + 'llStartAnimation', + 'llStopAnimation', + 'llStopHover', + 'llStopLookAt', + 'llStopMoveToTarget', + 'llStopSound', + 'llStringLength', + 'llStringToBase64', + 'llStringTrim', + 'llSubStringIndex', + 'llTakeControls', + 'llTan', + 'llTarget', + 'llTargetOmega', + 'llTargetRemove', + 'llTeleportAgentHome', + 'llToLower', + 'llToUpper', + 'llTriggerSound', + 'llTriggerSoundLimited', + 'llUnescapeURL', + 'llUnSit', + 'llVecDist', + 'llVecMag', + 'llVecNorm', + 'llVolumeDetect', + 'llWater', + 'llWhisper', + 'llWind', + 'llXorBase64StringsCorrect', + ), + 6 => array( // deprecated + 'llMakeExplosion', + 'llMakeFire', + 'llMakeFountain', + 'llMakeSmoke', + 'llSound', + 'llSoundPreload', + 'llXorBase64Strings', + ), + 7 => array( // unimplemented + 'llPointAt', + 'llRefreshPrimURL', + 'llReleaseCamera', + 'llRemoteLoadScript', + 'llSetPrimURL', + 'llStopPointAt', + 'llTakeCamera', + 'llTextBox', + ), + 8 => array( // God mode + 'llGodLikeRezObject', + 'llSetInventoryPermMask', + 'llSetObjectPermMask', + ), + ), + 'SYMBOLS' => array( + '{', '}', '(', ')', '[', ']', + '=', '+', '-', '*', '/', + '+=', '-=', '*=', '/=', '++', '--', + '!', '%', '&', '|', '&&', '||', + '==', '!=', '<', '>', '<=', '>=', + '~', '<<', '>>', '^', ':', + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => true, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff;', + 2 => 'color: #000080;', + 3 => 'color: #008080;', + 4 => 'color: #228b22;', + 5 => 'color: #b22222;', + 6 => 'color: #8b0000; background-color: #ffff00;', + 7 => 'color: #8b0000; background-color: #fa8072;', + 8 => 'color: #000000; background-color: #ba55d3;', + ), + 'COMMENTS' => array( + 1 => 'color: #ff7f50; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #006400;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.lslwiki.net/lslwiki/wakka.php?wakka={FNAME}', // http://wiki.secondlife.com/wiki/{FNAME} + 4 => 'http://www.lslwiki.net/lslwiki/wakka.php?wakka={FNAME}', // http://wiki.secondlife.com/wiki/{FNAME} + 5 => 'http://www.lslwiki.net/lslwiki/wakka.php?wakka={FNAME}', // http://wiki.secondlife.com/wiki/{FNAME} + 6 => 'http://www.lslwiki.net/lslwiki/wakka.php?wakka={FNAME}', // http://wiki.secondlife.com/wiki/{FNAME} + 7 => 'http://www.lslwiki.net/lslwiki/wakka.php?wakka={FNAME}', // http://wiki.secondlife.com/wiki/{FNAME} + 8 => 'http://www.lslwiki.net/lslwiki/wakka.php?wakka={FNAME}', // http://wiki.secondlife.com/wiki/{FNAME} + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/lua.php b/examples/includes/geshi/geshi/lua.php new file mode 100644 index 0000000..58ed30a --- /dev/null +++ b/examples/includes/geshi/geshi/lua.php @@ -0,0 +1,137 @@ + 'Lua', + 'COMMENT_SINGLE' => array(1 => "--"), + 'COMMENT_MULTI' => array('--[[' => ']]'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'and','break','do','else','elseif','end','false','for','function','if', + 'in','local','nil','not','or','repeat','return','then','true','until','while', + '_VERSION','assert','collectgarbage','dofile','error','gcinfo','loadfile','loadstring', + 'print','tonumber','tostring','type','unpack', + '_ALERT','_ERRORMESSAGE','_INPUT','_PROMPT','_OUTPUT', + '_STDERR','_STDIN','_STDOUT','call','dostring','foreach','foreachi','getn','globals','newtype', + 'rawget','rawset','require','sort','tinsert','tremove', + 'abs','acos','asin','atan','atan2','ceil','cos','deg','exp', + 'floor','format','frexp','gsub','ldexp','log','log10','max','min','mod','rad','random','randomseed', + 'sin','sqrt','strbyte','strchar','strfind','strlen','strlower','strrep','strsub','strupper','tan', + 'openfile','closefile','readfrom','writeto','appendto', + 'remove','rename','flush','seek','tmpfile','tmpname','read','write', + 'clock','date','difftime','execute','exit','getenv','setlocale','time', + '_G','getfenv','getmetatable','ipairs','loadlib','next','pairs','pcall', + 'rawegal','setfenv','setmetatable','xpcall', + 'string.byte','string.char','string.dump','string.find','string.len', + 'string.lower','string.rep','string.sub','string.upper','string.format','string.gfind','string.gsub', + 'table.concat','table.foreach','table.foreachi','table.getn','table.sort','table.insert','table.remove','table.setn', + 'math.abs','math.acos','math.asin','math.atan','math.atan2','math.ceil','math.cos','math.deg','math.exp', + 'math.floor','math.frexp','math.ldexp','math.log','math.log10','math.max','math.min','math.mod', + 'math.pi','math.rad','math.random','math.randomseed','math.sin','math.sqrt','math.tan', + 'coroutine.create','coroutine.resume','coroutine.status', + 'coroutine.wrap','coroutine.yield', + 'io.close','io.flush','io.input','io.lines','io.open','io.output','io.read','io.tmpfile','io.type','io.write', + 'io.stdin','io.stdout','io.stderr', + 'os.clock','os.date','os.difftime','os.execute','os.exit','os.getenv','os.remove','os.rename', + 'os.setlocale','os.time','os.tmpname', + 'string','table','math','coroutine','io','os','debug' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '!', '@', '%', '&', '*', '|', '/', '<', '>', '=', ';' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #b1b100;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/m68k.php b/examples/includes/geshi/geshi/m68k.php new file mode 100644 index 0000000..9c16d7d --- /dev/null +++ b/examples/includes/geshi/geshi/m68k.php @@ -0,0 +1,143 @@ + 'Motorola 68000 Assembler', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /*CPU*/ + 1 => array( + 'adc','add','ais','aix','and','asl','asr','bcc','bclr','bcs','beq', + 'bge','bgt','bhcc','bhcs','bhi','bhs','bih','bil','bit','ble','blo', + 'bls','blt','bmc','bmi','bms','bne','bpl','bra','brclr','brn', + 'brset','bset','bsr','cbeq','clc','cli','clr','cmp','com','cphx', + 'cpx','daa','dbnz','dec','div','eor','inc','jmp','jsr','lda','ldhx', + 'ldx','lsl','lsr','mov','mul','neg','nop','nsa','ora','psha','pshh', + 'pshx','pula','pulh','pulx','rol','ror','rsp','rti','rts','sbc', + 'sec','sei','sta','sthx','stop','stx','sub','swi','tap','tax','tpa', + 'tst','tsx','txa','txs','wait' + ), + /*registers*/ + 2 => array( + 'a','h','x', + 'hx','sp' + ), + /*Directive*/ + 3 => array( + '#define','#endif','#else','#ifdef','#ifndef','#include','#undef', + '.db','.dd','.df','.dq','.dt','.dw','.end','.org','equ' + ), + ), + 'SYMBOLS' => array( + ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff; font-weight:bold;', + 2 => 'color: #0000ff;', + 3 => 'color: #46aa03; font-weight:bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #0000ff;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #dd22dd;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + 0 => 'color: #22bbff;', + 1 => 'color: #22bbff;', + 2 => 'color: #993333;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Hex numbers + 0 => '#?0[0-9a-fA-F]{1,32}[hH]', + //Binary numbers + 1 => '\%[01]{1,64}[bB]', + //Labels + 2 => '^[_a-zA-Z][_a-zA-Z0-9]*?\:' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 8 +); + +?> diff --git a/examples/includes/geshi/geshi/make.php b/examples/includes/geshi/geshi/make.php new file mode 100644 index 0000000..b15f459 --- /dev/null +++ b/examples/includes/geshi/geshi/make.php @@ -0,0 +1,151 @@ + + * Copyright: (c) 2008 Neil Bird + * Release Version: 1.0.8.3 + * Date Started: 2008/08/26 + * + * make language file for GeSHi. + * + * (GNU make specific) + * + * CHANGES + * ------- + * 2008/09/05 (1.0.0) + * - First Release + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'GNU make', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_REGEXP' => array( + //Escaped String Starters + 2 => "/\\\\['\"]/siU" + ), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + // core + 'ifeq', 'else', 'endif', 'ifneq', 'ifdef', 'ifndef', + 'include', 'vpath', 'export', 'unexport', 'override', + 'info', 'warning', 'error' + ), + 2 => array( + // macros, literals + '.SUFFIXES', '.PHONY', '.DEFAULT', '.PRECIOUS', '.IGNORE', '.SILENT', '.EXPORT_ALL_VARIABLES', '.KEEP_STATE', + '.LIBPATTERNS', '.NOTPARALLEL', '.DELETE_ON_ERROR', '.INTERMEDIATE', '.POSIX', '.SECONDARY' + ), + /* + 3 => array( + // funcs - see regex + //'subst', 'addprefix', 'addsuffix', 'basename', 'call', 'dir', 'error', 'eval', 'filter-out', 'filter', + //'findstring', 'firstword', 'foreach', 'if', 'join', 'notdir', 'origin', 'patsubst', 'shell', 'sort', 'strip', + //'suffix', 'warning', 'wildcard', 'word', 'wordlist', 'words' + )*/ + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', + '!', '@', '%', '&', '|', '/', + '<', '>', + '=', '-', '+', '*', + '.', ':', ',', ';', + '$' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + //3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #666622; font-weight: bold;', + 2 => 'color: #990000;', + //3 => 'color: #000000; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #339900; font-style: italic;', + 2 => 'color: #000099; font-weight: bold;', + 'MULTI' => '' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( # keep same as symbols so as to make ${} and $() equiv. + 0 => 'color: #004400;' + ), + 'STRINGS' => array( + 0 => 'color: #CC2200;' + ), + 'NUMBERS' => array( + 0 => 'color: #CC2200;' + ), + 'SYMBOLS' => array( + 0 => 'color: #004400;' + ), + 'REGEXPS' => array( + 0 => 'color: #000088; font-weight: bold;', + 1 => 'color: #0000CC; font-weight: bold;', + 2 => 'color: #000088;' + ), + 'SCRIPT' => array(), + 'METHODS' => array() + ), + 'URLS' => array( + 1 => '', + 2 => '', + //3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + //Simple variables + 0 => "\\$(?:[^{(&]|&(?:amp|lt|gt);)", + //Complex variables/functions [built-ins] + 1 => array( + GESHI_SEARCH => '(\\$[({])(subst|addprefix|addsuffix|basename|call|dir|error|eval|filter-out|filter,|findstring|firstword|foreach|if|join|notdir|origin|patsubst|shell|sort|strip,|suffix|warning|wildcard|word|wordlist|words)([ })])', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + //Complex variables/functions [others] + 2 => array( + GESHI_SEARCH => '(\\$[({])([A-Za-z_][A-Za-z_0-9]*)([ })])', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array(), + 'TAB_WIDTH' => 8 +// vim: set sw=4 sts=4 : +); +?> diff --git a/examples/includes/geshi/geshi/matlab.php b/examples/includes/geshi/geshi/matlab.php new file mode 100644 index 0000000..d3963ef --- /dev/null +++ b/examples/includes/geshi/geshi/matlab.php @@ -0,0 +1,227 @@ + 'Matlab M', + 'COMMENT_SINGLE' => array(1 => '%'), + 'COMMENT_MULTI' => array(), + //Matlab Strings + 'COMMENT_REGEXP' => array( + 2 => "/(? GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'break', 'case', 'catch', 'continue', 'elseif', 'else', 'end', 'for', + 'function', 'global', 'if', 'otherwise', 'persistent', 'return', + 'switch', 'try', 'while' + ), + 2 => array( + 'all','any','exist','is','logical','mislocked', + + 'abs','acos','acosh','acot','acoth','acsc','acsch','airy','angle', + 'ans','area','asec','asech','asin','asinh','atan','atan2','atanh', + 'auread','autumn','auwrite','axes','axis','balance','bar','bar3', + 'bar3h','barh','besselh','besseli','besselj','besselk','Bessely', + 'beta','betainc','betaln','bicg','bicgstab','bin2dec','bitand', + 'bitcmp','bitget','bitmax','bitor','bitset','bitshift','bitxor', + 'blkdiag','bone','box','brighten','builtin','bwcontr','calendar', + 'camdolly','camlight','camlookat','camorbit','campan','campos', + 'camproj','camroll','camtarget','camup','camva','camzoom','capture', + 'cart2pol','cart2sph','cat','caxis','cdf2rdf','ceil','cell', + 'cell2struct','celldisp','cellfun','cellplot','cellstr','cgs', + 'char','chol','cholinc','cholupdate','cla','clabel','class','clc', + 'clf','clg','clock','close','colmmd','colorbar','colorcube', + 'colordef','colormap','colperm','comet','comet3','compan','compass', + 'complex','computer','cond','condeig','condest','coneplot','conj', + 'contour','contourc','contourf','contourslice','contrast','conv', + 'conv2','convhull','cool','copper','copyobj','corrcoef','cos', + 'cosh','cot','coth','cov','cplxpair','cputime','cross','csc','csch', + 'cumprod','cumsum','cumtrapz','cylinder','daspect','date','datenum', + 'datestr','datetick','datevec','dbclear','dbcont','dbdown', + 'dblquad','dbmex','dbquit','dbstack','dbstatus','dbstep','dbstop', + 'dbtype','dbup','deblank','dec2bin','dec2hex','deconv','del2', + 'delaunay','det','diag','dialog','diff','diffuse','dlmread', + 'dlmwrite','dmperm','double','dragrect','drawnow','dsearch','eig', + 'eigs','ellipj','ellipke','eomday','eps','erf','erfc','erfcx', + 'erfiny','error','errorbar','errordlg','etime','eval','evalc', + 'evalin','exp','expint','expm','eye','ezcontour','ezcontourf', + 'ezmesh','ezmeshc','ezplot','ezplot3','ezpolar','ezsurf','ezsurfc', + 'factor','factorial','fclose','feather','feof','ferror','feval', + 'fft','fft2','fftshift','fgetl','fgets','fieldnames','figure', + 'fill','fill3','filter','filter2','find','findfigs','findobj', + 'findstr','fix','flag','flipdim','fliplr','flipud','floor','flops', + 'fmin','fmins','fopen','fplot','fprintf','fread','frewind','fscanf', + 'fseek','ftell','full','funm','fwrite','fzero','gallery','gamma', + 'gammainc','gammaln','gca','gcbo','gcd','gcf','gco','get', + 'getfield','ginput','gmres','gradient','gray','graymon','grid', + 'griddata','gsvd','gtext','hadamard','hankel','hdf','helpdlg', + 'hess','hex2dec','hex2num','hidden','hilb','hist','hold','hot', + 'hsv','hsv2rgb','i','ifft','ifft2','ifftn','ifftshift','imag', + 'image','imfinfo','imread','imwrite','ind2sub','Inf','inferiorto', + 'inline','inpolygon','input','inputdlg','inputname','int16', + 'int2str','int32','int8','interp1','interp2','interp3','interpft', + 'interpn','intersect','inv','invhilb','ipermute','isa','ishandle', + 'ismember','isocaps','isonormals','isosurface','j','jet','keyboard', + 'lcm','legend','legendre','light','lighting','lightingangle', + 'lin2mu','line','lines','linspace','listdlg','loadobj','log', + 'log10','log2','loglog','logm','logspace','lower','lscov','lu', + 'luinc','magic','mat2str','material','max','mean','median','menu', + 'menuedit','mesh','meshc','meshgrid','min','mod','msgbox','mu2lin', + 'NaN','nargchk','nargin','nargout','nchoosek','ndgrid','ndims', + 'newplot','nextpow2','nnls','nnz','nonzeros','norm','normest','now', + 'null','num2cell','num2str','nzmax','ode113,','ode15s,','ode23s,', + 'ode23t,','ode23tb','ode45,','odefile','odeget','odeset','ones', + 'orient','orth','pagedlg','pareto','pascal','patch','pause', + 'pbaspect','pcg','pcolor','peaks','perms','permute','pi','pie', + 'pie3','pinv','plot','plot3','plotmatrix','plotyy','pol2cart', + 'polar','poly','polyarea','polyder','polyeig','polyfit','polyval', + 'polyvalm','pow2','primes','print','printdlg','printopt','prism', + 'prod','propedit','qmr','qr','qrdelete','qrinsert','qrupdate', + 'quad','questdlg','quiver','quiver3','qz','rand','randn','randperm', + 'rank','rat','rats','rbbox','rcond','real','realmax','realmin', + 'rectangle','reducepatch','reducevolume','refresh','rem','repmat', + 'reset','reshape','residue','rgb2hsv','rgbplot','ribbon','rmfield', + 'roots','rose','rot90','rotate','rotate3d','round','rref', + 'rrefmovie','rsf2csf','saveobj','scatter','scatter3','schur', + 'script','sec','sech','selectmoveresize','semilogx','semilogy', + 'set','setdiff','setfield','setxor','shading','shg','shiftdim', + 'shrinkfaces','sign','sin','single','sinh','slice','smooth3','sort', + 'sortrows','sound','soundsc','spalloc','sparse','spconvert', + 'spdiags','specular','speye','spfun','sph2cart','sphere','spinmap', + 'spline','spones','spparms','sprand','sprandn','sprandsym','spring', + 'sprintf','sqrt','sqrtm','squeeze','sscanf','stairs','std','stem', + 'stem3','str2double','str2num','strcat','strcmp','strcmpi', + 'stream2','stream3','streamline','strings','strjust','strmatch', + 'strncmp','strrep','strtok','struct','struct2cell','strvcat', + 'sub2ind','subplot','subspace','subvolume','sum','summer', + 'superiorto','surf','surf2patch','surface','surfc','surfl', + 'surfnorm','svd','svds','symmmd','symrcm','symvar','tan','tanh', + 'texlabel','text Create','textread','textwrap','tic','title','toc', + 'toeplitz','trace','trapz','tril','trimesh','trisurf','triu', + 'tsearch','uicontext Create','uicontextmenu','uicontrol', + 'uigetfile','uimenu','uint32','uint8','uiputfile','uiresume', + 'uisetcolor','uisetfont','uiwait Used','union','unique','unwrap', + 'upper','var','varargin','varargout','vectorize','view','viewmtx', + 'voronoi','waitbar','waitforbuttonpress','warndlg','warning', + 'waterfall','wavread','wavwrite','weekday','whitebg','wilkinson', + 'winter','wk1read','wk1write','xlabel','xlim','ylabel','ylim', + 'zeros','zlabel','zlim','zoom', + //'[Keywords 6]', + 'addpath','cd','clear','copyfile','delete','diary','dir','disp', + 'doc','docopt','echo','edit','fileparts','format','fullfile','help', + 'helpdesk','helpwin','home','inmem','lasterr','lastwarn','length', + 'load','lookfor','ls','matlabrc','matlabroot','mkdir','mlock', + 'more','munlock','open','openvar','pack','partialpath','path', + 'pathtool','profile','profreport','pwd','quit','rmpath','save', + 'saveas','size','tempdir','tempname','type','ver','version','web', + 'what','whatsnew','which','who','whos','workspace' + ) + ), + 'SYMBOLS' => array( + '...' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + //3 => false, + //4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000FF;', + 2 => 'color: #0000FF;' + ), + 'COMMENTS' => array( + 1 => 'color: #228B22;', + 2 => 'color:#A020F0;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => 'color: #080;' + ), + 'STRINGS' => array( + //0 => 'color: #A020F0;' + ), + 'NUMBERS' => array( + 0 => 'color: #33f;' + ), + 'METHODS' => array( + 1 => '', + 2 => '' + ), + 'SYMBOLS' => array( + 0 => 'color: #080;' + ), + 'REGEXPS' => array( + 0 => 'color: #33f;' + ), + 'SCRIPT' => array( + 0 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => 'http://www.mathworks.com/access/helpdesk/help/techdoc/ref/{FNAMEL}.html' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + //Complex numbers + 0 => '(? GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/mirc.php b/examples/includes/geshi/geshi/mirc.php new file mode 100644 index 0000000..1547ff4 --- /dev/null +++ b/examples/includes/geshi/geshi/mirc.php @@ -0,0 +1,173 @@ + 'mIRC Scripting', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'alias', 'menu', 'dialog', + ), + 2 => array( + 'if', 'elseif', 'else', 'while', 'return', 'goto','var' + ), + 3 => array( + 'action','ajinvite','amsg','ame','anick','aop','auser', + 'avoice','auto','autojoin','away','background','ban','beep', + 'channel','clear','clearall','clipboard','close','closemsg','color', + 'copy','creq','ctcp','ctcpreply','ctcps','dcc','dde','ddeserver', + 'debug','describe','disable','disconnect','dlevel','dll','dns', + 'dqwindow','ebeeps','echo','editbox','emailaddr','enable','events', + 'exit','filter','findtext','finger','flash','flood','flush', + 'flushini','font','fsend','fserve','fullname','ghide','gload', + 'gmove','gopts','gplay','gpoint','gqreq','groups','gshow','gsize', + 'gstop','gtalk','gunload','guser','help','hop','ignore','invite', + 'join','kick','linesep','links','list','load','loadbuf','localinfo', + 'log','me','mdi','mkdir','mnick','mode','msg','names','nick','noop', + 'notice','notify','omsg','onotice','part','partall','pdcc', + 'perform','ping','play','pop','protect','pvoice','qmsg','qme', + 'query','queryrn','quit','raw','remini','remote','remove','rename', + 'enwin','resetidle','rlevel','rmdir','run','ruser','save','savebuf', + 'saveini','say','server','showmirc','sline','sound','speak','splay', + 'sreq','strip','time', + //'timer[N/name]', //Handled as a regular expression below ... + 'timers','timestamp','titlebar','tnick','tokenize','topic','ulist', + 'unload','updatenl','url','uwho','window','winhelp','write', + 'writeini','who','whois','whowas' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #994444;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #990000; font-weight: bold;', + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #FF0000;', + ), + 'STRINGS' => array( + ), + 'NUMBERS' => array( + 0 => '', + ), + 'METHODS' => array( + 0 => 'color: #008000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #FF0000;', + ), + 'REGEXPS' => array( + 0 => 'color: #000099;', + 1 => 'color: #990000;', + 2 => 'color: #000099;', + 3 => 'color: #888800;', + 4 => 'color: #888800;', + 5 => 'color: #000099;', + 6 => 'color: #990000; font-weight: bold;', + 7 => 'color: #990000; font-weight: bold;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.mirc.com/{FNAMEL}' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array('.'), + 'REGEXPS' => array( + //Variable names + 0 => '\$[a-zA-Z0-9]+', + //Variable names + 1 => '(%|&)[a-zA-Z0-9äöü]+', + //Client to Client Protocol handling + 2 => '(on|ctcp) (!|@|&)?(\d|\*):[a-zA-Z]+:', + /*4 => array( + GESHI_SEARCH => '((on|ctcp) (!|@|&)?(\d|\*):(Action|Active|Agent|AppActive|Ban|Chat|Close|Connect|Ctcp|CtcpReply|DccServer|DeHelp|DeOp|DeVoice|Dialog|Dns|Error|Exit|FileRcvd|FileSent|GetFail|Help|Hotlink|Input|Invite|Join|KeyDown|KeyUp|Kick|Load|Logon|MidiEnd|Mode|Mp3End|Nick|NoSound|Notice|Notify|Op|Open|Part|Ping|Pong|PlayEnd|Quit|Raw|RawMode|SendFail|Serv|ServerMode|ServerOp|Signal|Snotice|Start|Text|Topic|UnBan|Unload|Unotify|User|Mode|Voice|Wallops|WaveEnd):)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ),*/ + //Channel names + 3 => '(#|@)[a-zA-Z0-9]+', + 4 => '-[a-z\d]+', + //Raw protocol handling + 5 => 'raw (\d|\*):', + //Timer handling + 6 => '\/timer(?!s\b)[0-9a-zA-Z_]+', + // /... + 7 => '\/[a-zA-Z0-9]+' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'NUMBERS' => GESHI_NEVER + ), + 'KEYWORDS' => array( + 2 => array( + 'DISALLOWED_BEFORE' => '(?^&\/])' + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/modula3.php b/examples/includes/geshi/geshi/modula3.php new file mode 100644 index 0000000..a136442 --- /dev/null +++ b/examples/includes/geshi/geshi/modula3.php @@ -0,0 +1,135 @@ + 'Modula-3', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('(*' => '*)'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array("''"), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'AND', 'ANY', 'ARRAY', 'AS', 'BEGIN', 'BITS', 'BRANDED', 'BY', 'CASE', + 'CONST', 'DIV', 'DO', 'ELSE', 'ELSIF', 'END', 'EVAL', 'EXCEPT', 'EXCEPTION', + 'EXIT', 'EXPORTS', 'FINALLY', 'FOR', 'FROM', 'GENERIC', 'IF', 'IMPORT', 'IN', + 'INTERFACE', 'LOCK', 'LOOP', 'METHODS', 'MOD', 'MODULE', 'NOT', 'OBJECT', 'OF', + 'OR', 'OVERRIDE', 'PROCEDURE', 'RAISE', 'RAISES', 'READONLY', 'RECORD', 'REF', + 'REPEAT', 'RETURN', 'REVEAL', 'ROOT', 'SET', 'THEN', 'TO', 'TRY', 'TYPE', 'TYPECASE', + 'UNSAFE', 'UNTIL', 'UNTRACED', 'VALUE', 'VAR', 'WHILE', 'WITH' + ), + 2 => array( + 'NIL', 'NULL', 'FALSE', 'TRUE', + ), + 3 => array( + 'ABS','ADR','ADRSIZE','BITSIZE','BYTESIZE','CEILING','DEC','DISPOSE', + 'EXTENDED','FIRST','FLOAT','FLOOR','INC','ISTYPE','LAST','LOOPHOLE','MAX','MIN', + 'NARROW','NEW','NUMBER','ORD','ROUND','SUBARRAY','TRUNC','TYPECODE', 'VAL' + ), + 4 => array( + 'ADDRESS', 'BOOLEAN', 'CARDINAL', 'CHAR', 'INTEGER', + 'LONGREAL', 'MUTEX', 'REAL', 'REFANY', 'TEXT' + ), + ), + 'SYMBOLS' => array( + ',', ':', '=', '+', '-', '*', '/', '#' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;', + 4 => 'color: #000066; font-weight: bold;' + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;', + 'HARD' => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #0066ee;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/mpasm.php b/examples/includes/geshi/geshi/mpasm.php new file mode 100644 index 0000000..30b192c --- /dev/null +++ b/examples/includes/geshi/geshi/mpasm.php @@ -0,0 +1,164 @@ + 'Microchip Assembler', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /*Directive Language*/ + 4 => array( + 'CONSTANT', '#DEFINE', 'END', 'EQU', 'ERROR', 'ERROR-LEVEL', '#INCLUDE', 'LIST', + 'MESSG', 'NOLIST', 'ORG', 'PAGE', 'PROCESSOR', 'RADIX', 'SET', 'SPACE', 'SUBTITLE', + 'TITLE', '#UNDEFINE', 'VARIABLE', 'ELSE', 'ENDIF', 'ENDW', 'IF', 'IFDEF', 'IFNDEF', + 'WHILE', '__BADRAM', 'CBLOCK', '__CONFIG', 'DA', 'DATA', 'DB', 'DE', 'DT', 'DW', + 'ENDC', 'FILL', '__IDLOCS', '__MAXRAM', 'RES', 'ENDM', 'EXITM', 'EXPAND', 'LOCAL', + 'MACRO', 'NOEXPAND', 'BANKISEL', 'BANKSEL', 'CODE', 'EXTERN', 'GLOBAL', 'IDATA', + 'PAGESEL', 'UDATA', 'UDATA_ACS', 'UDATA_OVR', 'UDATA_SHR' + ), + /* 12&14-bit Specific Instruction Set*/ + 1 => array( + 'andlw', 'call', 'clrwdt', 'goto', 'iorlw', 'movlw', 'option', 'retlw', 'sleep', + 'tris', 'xorlw', 'addwf', 'andwf', 'clrf', 'clrw', 'comf', 'decf', 'decfsz', 'incf', + 'incfsz', 'iorwf', 'movf', 'nop', 'rlf', 'rrf', 'subwf', 'swapf', 'xorwf', + 'bcf', 'bsf', 'btfsc', 'btfss', + 'addlw', 'retfie', 'return', 'sublw', 'addcf', 'adddcf', 'b', 'bc', 'bdc', + 'bnc', 'bndc', 'bnz', 'bz', 'clrc', 'clrdc', 'clrz', 'lcall', 'lgoto', 'movfw', + 'negf', 'setc', 'setdc', 'setz', 'skpc', 'skpdc', 'skpnc', 'skpndc', 'skpnz', 'skpz', + 'subcf', 'subdcf', 'tstf' + ), + /* 16-bit Specific Instructiob Set */ + 2 => array ( + 'movfp', 'movlb', 'movlp', 'movpf', 'movwf', 'tablrd', 'tablwt', 'tlrd', 'tlwt', + 'addwfc', 'daw', 'mullw', 'negw', 'rlcf', 'rlncf', 'rrcf', 'rrncf', 'setf', 'subwfb', + 'btg', 'cpfseq', 'cpfsgt', 'cpfslt', 'dcfsnz', 'infsnz', 'tstfsz', 'lfsr', 'bnn', + 'bnov', 'bra', 'pop', 'push', 'rcall', 'reset' + ), + /* Registers */ + 3 => array( + 'INDF', 'TMR0', 'PCL', 'STATUS', 'FSR', 'PORTA', 'PORTB', 'PORTC', 'PORTD', 'PORTE', + 'PCLATH', 'INTCON', 'PIR1', 'PIR2', 'TMR1L', 'TMR1H', 'T1CON', 'TMR2', 'T2CON', 'TMR2L', + 'TMR2H', 'TMR0H', 'TMR0L', 'SSPBUF', 'SSPCON', 'CCPR1L', 'CCPR1H', 'CCP1CON', 'RCSTA', + 'TXREG', 'RCREG', 'CCPR2L', 'CCPR2H', 'CCP2CON', 'OPTION', 'TRISA', 'TRISB', 'TRISC', + 'TRISD', 'TRISE', 'PIE2', 'PIE1', 'PR2', 'SSPADD', 'SSPSTAT', 'TXSTA', 'SPBRG' + ), + /*Operands*/ + 5 => array( + 'high','low' + ) + ), + 'SYMBOLS' => array( + '[', ']', '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00007f;', + 2 => 'color: #0000ff;', + 3 => 'color: #007f00;', + 4 => 'color: #46aa03; font-weight:bold;', + 5 => 'color: #7f0000;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff0000;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + 0 => 'color: #ff0000;', + 1 => 'color: #ff0000;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Hex numbers + 0 => '[0-9a-fA-F]{1,32}[hH]', + //Binary numbers + 1 => '[01]{1,64}[bB]' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/mxml.php b/examples/includes/geshi/geshi/mxml.php new file mode 100644 index 0000000..939632b --- /dev/null +++ b/examples/includes/geshi/geshi/mxml.php @@ -0,0 +1,145 @@ + 'MXML', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(''), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + 0 => 'color: #00bbdd;', + 1 => 'color: #ddbb00;', + 2 => 'color: #339933;', + 3 => 'color: #000000;' + ), + 'REGEXPS' => array( + 0 => 'font-weight: bold; color: black;', + 1 => 'color: #7400FF;', + 2 => 'color: #7400FF;' + ) + ), + 'URLS' => array( + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + // xml declaration + 0 => array( + GESHI_SEARCH => '(<[\/?|(\?xml)]?[a-z0-9_\-:]*(\?>))', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + // opening tags + 1 => array( + GESHI_SEARCH => '(<\/?[a-z]+:[a-z]+)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + // closing tags + 2 => array( + GESHI_SEARCH => '(\/?>)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + ' '>' + ), + 1 => array( + '&' => ';' + ), + 2 => array( + //' ']]>' + '' => '' + ), + 3 => array( + '<' => '>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => false, + 1 => false, + 2 => false, + 3 => true + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/mysql.php b/examples/includes/geshi/geshi/mysql.php new file mode 100644 index 0000000..0017eef --- /dev/null +++ b/examples/includes/geshi/geshi/mysql.php @@ -0,0 +1,475 @@ + 'MySQL', + //'COMMENT_SINGLE' => array(1 =>'--', 2 => '#'), // '--' MUST be folowed by whitespace,not necessarily a space + 'COMMENT_SINGLE' => array( + 1 =>'-- ', + 2 => '#' + ), + 'COMMENT_REGEXP' => array( + 1 => "/(?:--\s).*?$/", // double dash followed by any whitespace + ), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, // @@@ would be nice if this could be defined per group! + 'QUOTEMARKS' => array("'", '"', '`'), + 'ESCAPE_CHAR' => '\\', // by default only, can be specified + 'ESCAPE_REGEXP' => array( + 1 => "/[_%]/", // search wildcards + ), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | + GESHI_NUMBER_OCT_PREFIX | + GESHI_NUMBER_HEX_PREFIX | + GESHI_NUMBER_FLT_NONSCI | + GESHI_NUMBER_FLT_SCI_SHORT | + GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + // Mix: statement keywords and keywords that don't fit in any other + // category, or have multiple usage/meanings + 'ACTION','ADD','AFTER','ALGORITHM','ALL','ALTER','ANALYZE','ANY', + 'ASC','AS','BDB','BEGIN','BERKELEYDB','BINARY','BTREE','CALL', + 'CASCADED','CASCADE','CHAIN','CHECK','COLUMNS','COLUMN','COMMENT', + 'COMMIT','COMMITTED','CONSTRAINT','CONTAINS SQL','CONSISTENT', + 'CONVERT','CREATE','CROSS','DATA','DATABASES', + 'DECLARE','DEFINER','DELAYED','DELETE','DESCRIBE','DESC', + 'DETERMINISTIC','DISABLE','DISCARD','DISTINCTROW','DISTINCT','DO', + 'DROP','DUMPFILE','DUPLICATE KEY','ENABLE','ENCLOSED BY','ENGINE', + 'ERRORS','ESCAPED BY','EXISTS','EXPLAIN','EXTENDED','FIELDS', + 'FIRST','FOR EACH ROW','FORCE','FOREIGN KEY','FROM','FULL', + 'FUNCTION','GLOBAL','GRANT','GROUP BY','HANDLER','HASH','HAVING', + 'HELP','HIGH_PRIORITY','IF NOT EXISTS','IGNORE','IMPORT','INDEX', + 'INFILE','INNER','INNODB','INOUT','INTO','INVOKER', + 'ISOLATION LEVEL','JOIN','KEYS','KEY','KILL','LANGUAGE SQL','LAST', + 'LIMIT','LINES','LOAD','LOCAL','LOCK','LOW_PRIORITY', + 'MASTER_SERVER_ID','MATCH','MERGE','MIDDLEINT','MODIFIES SQL DATA', + 'MODIFY','MRG_MYISAM','NATURAL','NEXT','NO SQL','NO','ON', + 'OPTIMIZE','OPTIONALLY','OPTION','ORDER BY','OUTER','OUTFILE','OUT', + 'PARTIAL','PREV','PRIMARY KEY','PRIVILEGES','PROCEDURE','PURGE', + 'QUICK','READS SQL DATA','READ','REFERENCES','RELEASE','RENAME', + 'REPEATABLE','REQUIRE','RESTRICT','RETURNS','REVOKE', + 'ROLLBACK','ROUTINE','RTREE','SAVEPOINT','SELECT', + 'SERIALIZABLE','SESSION','SET','SHARE MODE','SHOW','SIMPLE', + 'SNAPSHOT','SOME','SONAME','SQL SECURITY','SQL_BIG_RESULT', + 'SQL_BUFFER_RESULT','SQL_CACHE','SQL_CALC_FOUND_ROWS', + 'SQL_NO_CACHE','SQL_SMALL_RESULT','SSL','START','STARTING BY', + 'STATUS','STRAIGHT_JOIN','STRIPED','TABLESPACE','TABLES','TABLE', + 'TEMPORARY','TEMPTABLE','TERMINATED BY','TO','TRANSACTIONS', + 'TRANSACTION','TRIGGER','TYPES','TYPE','UNCOMMITTED','UNDEFINED', + 'UNION','UNLOCK_TABLES','UPDATE','USAGE','USE','USER_RESOURCES', + 'USING','VALUES','VALUE','VIEW','WARNINGS','WHERE','WITH ROLLUP', + 'WITH','WORK','WRITE', + ), + 2 => array( //No ( must follow + // Mix: statement keywords distinguished from functions by the same name + "CURRENT_USER", "DATABASE", "IN", "INSERT", "DEFAULT", "REPLACE", "SCHEMA", "TRUNCATE" + ), + 3 => array( + // Values (Constants) + 'FALSE','NULL','TRUE', + ), + 4 => array( + // Column Data Types + 'BIGINT','BIT','BLOB','BOOLEAN','BOOL','CHARACTER VARYING', + 'CHAR VARYING','DATETIME','DECIMAL','DEC','DOUBLE PRECISION', + 'DOUBLE','ENUM','FIXED','FLOAT','GEOMETRYCOLLECTION','GEOMETRY', + 'INTEGER','INT','LINESTRING','LONGBLOB','LONGTEXT','MEDIUMBLOB', + 'MEDIUMINT','MEDIUMTEXT','MULTIPOINT','MULTILINESTRING', + 'MULTIPOLYGON','NATIONAL CHARACTER','NATIONAL CHARACTER VARYING', + 'NATIONAL CHAR VARYING','NATIONAL VARCHAR','NCHAR VARCHAR','NCHAR', + 'NUMERIC','POINT','POLYGON','REAL','SERIAL', + 'SMALLINT','TEXT','TIMESTAMP','TINYBLOB','TINYINT', + 'TINYTEXT','VARBINARY','VARCHARACTER','VARCHAR', + ), + 5 => array( //No ( must follow + // Column data types distinguished from functions by the same name + "CHAR", "DATE", "TIME" + ), + 6 => array( + // Table, Column & Index Attributes + 'AUTO_INCREMENT','AVG_ROW_LENGTH','BOTH','CHECKSUM','CONNECTION', + 'DATA DIRECTORY','DEFAULT NULL','DELAY_KEY_WRITE','FULLTEXT', + 'INDEX DIRECTORY','INSERT_METHOD','LEADING','MAX_ROWS','MIN_ROWS', + 'NOT NULL','PACK_KEYS','ROW_FORMAT','SERIAL DEFAULT VALUE','SIGNED', + 'SPATIAL','TRAILING','UNIQUE','UNSIGNED','ZEROFILL' + ), + 7 => array( //No ( must follow + // Column attribute distinguished from function by the same name + "CHARSET" + ), + 8 => array( + // Date and Time Unit Specifiers + 'DAY_HOUR','DAY_MICROSECOND','DAY_MINUTE','DAY_SECOND', + 'HOUR_MICROSECOND','HOUR_MINUTE','HOUR_SECOND', + 'MINUTE_MICROSECOND','MINUTE_SECOND', + 'SECOND_MICROSECOND','YEAR_MONTH' + ), + 9 => array( //No ( must follow + // Date-time unit specifiers distinguished from functions by the same name + "DAY", "HOUR", "MICROSECOND", "MINUTE", "MONTH", "QUARTER", "SECOND", "WEEK", "YEAR" + ), + 10 => array( + // Operators (see also Symbols) + 'AND','BETWEEN','CHARACTER SET','COLLATE','DIV','IS NOT NULL', + 'IS NOT','IS NULL','IS','LIKE','NOT','OFFSET','OR','REGEXP','RLIKE', + 'SOUNDS LIKE','XOR' + ), + 11 => array( //No ( must follow + // Operator distinghuished from function by the same name + "INTERVAL" + ), + 12 => array( + // Control Flow (functions) + 'CASE','ELSE','END','IFNULL','IF','NULLIF','THEN','WHEN', + ), + 13 => array( + // String Functions + 'ASCII','BIN','BIT_LENGTH','CHAR_LENGTH','CHARACTER_LENGTH', + 'CONCAT_WS','CONCAT','ELT','EXPORT_SET','FIELD', + 'FIND_IN_SET','FORMAT','HEX','INSTR','LCASE','LEFT','LENGTH', + 'LOAD_FILE','LOCATE','LOWER','LPAD','LTRIM','MAKE_SET','MID', + 'OCTET_LENGTH','ORD','POSITION','QUOTE','REPEAT','REVERSE', + 'RIGHT','RPAD','RTRIM','SOUNDEX','SPACE','STRCMP','SUBSTRING_INDEX', + 'SUBSTRING','TRIM','UCASE','UNHEX','UPPER', + ), + 14 => array( //A ( must follow + // String functions distinguished from other keywords by the same name + "INSERT", "REPLACE", "CHAR" + ), + 15 => array( + // Numeric Functions + 'ABS','ACOS','ASIN','ATAN2','ATAN','CEILING','CEIL', + 'CONV','COS','COT','CRC32','DEGREES','EXP','FLOOR','LN','LOG10', + 'LOG2','LOG','MOD','OCT','PI','POWER','POW','RADIANS','RAND', + 'ROUND','SIGN','SIN','SQRT','TAN', + ), + 16 => array( //A ( must follow + // Numeric function distinguished from other keyword by the same name + "TRUNCATE" + ), + 17 => array( + // Date and Time Functions + 'ADDDATE','ADDTIME','CONVERT_TZ','CURDATE','CURRENT_DATE', + 'CURRENT_TIME','CURRENT_TIMESTAMP','CURTIME','DATE_ADD', + 'DATE_FORMAT','DATE_SUB','DATEDIFF','DAYNAME','DAYOFMONTH', + 'DAYOFWEEK','DAYOFYEAR','EXTRACT','FROM_DAYS','FROM_UNIXTIME', + 'GET_FORMAT','LAST_DAY','LOCALTIME','LOCALTIMESTAMP','MAKEDATE', + 'MAKETIME','MONTHNAME','NOW','PERIOD_ADD', + 'PERIOD_DIFF','SEC_TO_TIME','STR_TO_DATE','SUBDATE','SUBTIME', + 'SYSDATE','TIME_FORMAT','TIME_TO_SEC', + 'TIMESTAMPADD','TIMESTAMPDIFF','TO_DAYS', + 'UNIX_TIMESTAMP','UTC_DATE','UTC_TIME','UTC_TIMESTAMP','WEEKDAY', + 'WEEKOFYEAR','YEARWEEK', + ), + 18 => array( //A ( must follow + // Date-time functions distinguished from other keywords by the same name + "DATE", "DAY", "HOUR", "MICROSECOND", "MINUTE", "MONTH", "QUARTER", + "SECOND", "TIME", "WEEK", "YEAR" + ), + 19 => array( + // Comparison Functions + 'COALESCE','GREATEST','ISNULL','LEAST', + ), + 20 => array( //A ( must follow + // Comparison functions distinguished from other keywords by the same name + "IN", "INTERVAL" + ), + 21 => array( + // Encryption and Compression Functions + 'AES_DECRYPT','AES_ENCRYPT','COMPRESS','DECODE','DES_DECRYPT', + 'DES_ENCRYPT','ENCODE','ENCRYPT','MD5','OLD_PASSWORD','PASSWORD', + 'SHA1','SHA','UNCOMPRESS','UNCOMPRESSED_LENGTH', + ), + 22 => array( + // GROUP BY (aggregate) Functions + 'AVG','BIT_AND','BIT_OR','BIT_XOR','COUNT','GROUP_CONCAT', + 'MAX','MIN','STDDEV_POP','STDDEV_SAMP','STDDEV','STD','SUM', + 'VAR_POP','VAR_SAMP','VARIANCE', + ), + 23 => array( + // Information Functions + 'BENCHMARK','COERCIBILITY','COLLATION','CONNECTION_ID', + 'FOUND_ROWS','LAST_INSERT_ID','ROW_COUNT', + 'SESSION_USER','SYSTEM_USER','USER','VERSION', + ), + 24 => array( //A ( must follow + // Information functions distinguished from other keywords by the same name + "CURRENT_USER", "DATABASE", "SCHEMA", "CHARSET" + ), + 25 => array( + // Miscellaneous Functions + 'ExtractValue','BIT_COUNT','GET_LOCK','INET_ATON','INET_NTOA', + 'IS_FREE_LOCK','IS_USED_LOCK','MASTER_POS_WAIT','NAME_CONST', + 'RELEASE_LOCK','SLEEP','UpdateXML','UUID', + ), + 26 => array( //A ( must follow + // Miscellaneous function distinguished from other keyword by the same name + "DEFAULT" + ), + 27 => array( + // Geometry Functions + 'Area','AsBinary','AsText','AsWKB','AsWKT','Boundary','Buffer', + 'Centroid','Contains','ConvexHull','Crosses', + 'Difference','Dimension','Disjoint','Distance', + 'EndPoint','Envelope','Equals','ExteriorRing', + 'GLength','GeomCollFromText','GeomCollFromWKB','GeomFromText', + 'GeomFromWKB','GeometryCollectionFromText', + 'GeometryCollectionFromWKB','GeometryFromText','GeometryFromWKB', + 'GeometryN','GeometryType', + 'InteriorRingN','Intersection','Intersects','IsClosed','IsEmpty', + 'IsRing','IsSimple', + 'LineFromText','LineFromWKB','LineStringFromText', + 'LineStringFromWKB', + 'MBRContains','MBRDisjoint','MBREqual','MBRIntersects', + 'MBROverlaps','MBRTouches','MBRWithin','MLineFromText', + 'MLineFromWKB','MPointFromText','MPointFromWKB','MPolyFromText', + 'MPolyFromWKB','MultiLineStringFromText','MultiLineStringFromWKB', + 'MultiPointFromText','MultiPointFromWKB','MultiPolygonFromText', + 'MultiPolygonFromWKB', + 'NumGeometries','NumInteriorRings','NumPoints', + 'Overlaps', + 'PointFromText','PointFromWKB','PointN','PointOnSurface', + 'PolyFromText','PolyFromWKB','PolygonFromText','PolygonFromWKB', + 'Related','SRID','StartPoint','SymDifference', + 'Touches', + 'Union', + 'Within', + 'X', + 'Y', + ), + ), + 'SYMBOLS' => array( + 1 => array( + /* Operators */ + '=', ':=', // assignment operators + '||', '&&', '!', // locical operators + '=', '<=>', '>=', '>', '<=', '<', '<>', '!=', // comparison operators + '|', '&', '^', '~', '<<', '>>', // bitwise operators + '-', '+', '*', '/', '%', // numerical operators + ), + 2 => array( + /* Other syntactical symbols */ + '(', ')', + ',', ';', + ), + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false, + 8 => false, + 9 => false, + 10 => false, + 11 => false, + 12 => false, + 13 => false, + 13 => false, + 14 => false, + 15 => false, + 16 => false, + 17 => false, + 18 => false, + 19 => false, + 20 => false, + 21 => false, + 22 => false, + 23 => false, + 24 => false, + 25 => false, + 26 => false, + 27 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #990099; font-weight: bold;', // mix + 2 => 'color: #990099; font-weight: bold;', // mix + 3 => 'color: #9900FF; font-weight: bold;', // constants + 4 => 'color: #999900; font-weight: bold;', // column data types + 5 => 'color: #999900; font-weight: bold;', // column data types + 6 => 'color: #FF9900; font-weight: bold;', // attributes + 7 => 'color: #FF9900; font-weight: bold;', // attributes + 8 => 'color: #9900FF; font-weight: bold;', // date-time units + 9 => 'color: #9900FF; font-weight: bold;', // date-time units + + 10 => 'color: #CC0099; font-weight: bold;', // operators + 11 => 'color: #CC0099; font-weight: bold;', // operators + + 12 => 'color: #009900;', // control flow (functions) + 13 => 'color: #000099;', // string functions + 14 => 'color: #000099;', // string functions + 15 => 'color: #000099;', // numeric functions + 16 => 'color: #000099;', // numeric functions + 17 => 'color: #000099;', // date-time functions + 18 => 'color: #000099;', // date-time functions + 19 => 'color: #000099;', // comparison functions + 20 => 'color: #000099;', // comparison functions + 21 => 'color: #000099;', // encryption functions + 22 => 'color: #000099;', // aggregate functions + 23 => 'color: #000099;', // information functions + 24 => 'color: #000099;', // information functions + 25 => 'color: #000099;', // miscellaneous functions + 26 => 'color: #000099;', // miscellaneous functions + 27 => 'color: #00CC00;', // geometry functions + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #808000; font-style: italic;', + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #004000; font-weight: bold;', + 1 => 'color: #008080; font-weight: bold;' // search wildcards + ), + 'BRACKETS' => array( + 0 => 'color: #FF00FF;' + ), + 'STRINGS' => array( + 0 => 'color: #008000;' + ), + 'NUMBERS' => array( + 0 => 'color: #008080;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 1 => 'color: #CC0099;', // operators + 2 => 'color: #000033;', // syntax + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 2 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 3 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 4 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 5 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 6 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 7 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 8 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + 9 => 'http://search.mysql.com/search?site=refman-51&q={FNAME}&lr=lang_en', + + 10 => 'http://dev.mysql.com/doc/refman/5.1/en/non-typed-operators.html', + 11 => 'http://dev.mysql.com/doc/refman/5.1/en/non-typed-operators.html', + + 12 => 'http://dev.mysql.com/doc/refman/5.1/en/control-flow-functions.html', + 13 => 'http://dev.mysql.com/doc/refman/5.1/en/string-functions.html', + 14 => 'http://dev.mysql.com/doc/refman/5.1/en/string-functions.html', + 15 => 'http://dev.mysql.com/doc/refman/5.1/en/numeric-functions.html', + 16 => 'http://dev.mysql.com/doc/refman/5.1/en/numeric-functions.html', + 17 => 'http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html', + 18 => 'http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html', + 19 => 'http://dev.mysql.com/doc/refman/5.1/en/comparison-operators.html', + 20 => 'http://dev.mysql.com/doc/refman/5.1/en/comparison-operators.html', + 21 => 'http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html', + 22 => 'http://dev.mysql.com/doc/refman/5.1/en/group-by-functions-and-modifiers.html', + 23 => 'http://dev.mysql.com/doc/refman/5.1/en/information-functions.html', + 24 => 'http://dev.mysql.com/doc/refman/5.1/en/information-functions.html', + 25 => 'http://dev.mysql.com/doc/refman/5.1/en/func-op-summary-ref.html', + 26 => 'http://dev.mysql.com/doc/refman/5.1/en/func-op-summary-ref.html', + 27 => 'http://dev.mysql.com/doc/refman/5.1/en/analysing-spatial-information.html', + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 2 => array( + 'DISALLOWED_AFTER' => '(?![\(\w])' + ), + 5 => array( + 'DISALLOWED_AFTER' => '(?![\(\w])' + ), + 7 => array( + 'DISALLOWED_AFTER' => '(?![\(\w])' + ), + 9 => array( + 'DISALLOWED_AFTER' => '(?![\(\w])' + ), + 11 => array( + 'DISALLOWED_AFTER' => '(?![\(\w])' + ), + + 14 => array( + 'DISALLOWED_AFTER' => '(?=\()' + ), + 16 => array( + 'DISALLOWED_AFTER' => '(?=\()' + ), + 18 => array( + 'DISALLOWED_AFTER' => '(?=\()' + ), + 20 => array( + 'DISALLOWED_AFTER' => '(?=\()' + ), + 24 => array( + 'DISALLOWED_AFTER' => '(?=\()' + ), + 26 => array( + 'DISALLOWED_AFTER' => '(?=\()' + ) + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/nsis.php b/examples/includes/geshi/geshi/nsis.php new file mode 100644 index 0000000..9f3e1cc --- /dev/null +++ b/examples/includes/geshi/geshi/nsis.php @@ -0,0 +1,351 @@ + 'NSIS', + 'COMMENT_SINGLE' => array(1 => ';', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'",'"','`'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + '!appendfile', '!addIncludeDir', '!addplugindir', '!cd', '!define', '!delfile', '!echo', '!else', + '!endif', '!error', '!execute', '!ifdef', '!ifmacrodef', '!ifmacrondef', '!ifndef', '!include', + '!insertmacro', '!macro', '!macroend', '!packhdr', '!tempfile', '!system', '!undef', '!verbose', + '!warning' + ), + 2 => array( + 'AddBrandingImage', 'AllowRootDirInstall', 'AutoCloseWindow', 'BGFont', + 'BGGradient', 'BrandingText', 'Caption', 'ChangeUI', 'CheckBitmap', 'CompletedText', 'ComponentText', + 'CRCCheck', 'DetailsButtonText', 'DirShow', 'DirText', 'DirVar', 'DirVerify', 'FileErrorText', + 'Function', 'FunctionEnd', 'Icon', 'InstallButtonText', 'InstallColors', 'InstallDir', + 'InstallDirRegKey', 'InstProgressFlags', 'InstType', 'LangString', 'LangStringUP', 'LicenseBkColor', + 'LicenseData', 'LicenseForceSelection', 'LicenseLangString', 'LicenseText', 'LoadLanguageFile', + 'MiscButtonText', 'Name', 'OutFile', 'Page', 'PageEx', 'PageExEnd', 'Section', + 'SectionEnd', 'SectionGroup', 'SectionGroupEnd', 'SetCompressor', 'SetFont', 'ShowInstDetails', + 'ShowUninstDetails', 'SilentInstall', 'SilentUnInstall', 'SpaceTexts', 'SubCaption', 'SubSection', + 'SubSectionEnd', 'UninstallButtonText', 'UninstallCaption', 'UninstallIcon', 'UninstallSubCaption', + 'UninstallText', 'UninstPage', 'Var', 'VIAddVersionKey', 'VIProductVersion', 'WindowIcon', 'XPStyle' + ), + 3 => array( + 'AddSize', 'AllowSkipFiles', 'FileBufSize', 'GetInstDirError', 'PageCallbacks', + 'SectionIn', 'SetCompress', 'SetCompressionLevel', 'SetCompressorDictSize', + 'SetDatablockOptimize', 'SetDateSave', 'SetOverwrite', 'SetPluginUnload' + ), + 4 => array( + 'Abort', 'BringToFront', 'Call', 'CallInstDLL', 'ClearErrors', 'CopyFiles','CreateDirectory', + 'CreateFont', 'CreateShortCut', 'Delete', 'DeleteINISec', 'DeleteINIStr', 'DeleteRegKey', + 'DeleteRegValue', 'DetailPrint', 'EnableWindow', 'EnumRegKey', 'EnumRegValue', 'Exch', 'Exec', + 'ExecShell', 'ExecWait', 'ExpandEnvStrings', 'File', 'FileClose', 'FileOpen', 'FileRead', + 'FileReadByte', 'FileSeek', 'FileWrite', 'FileWriteByte', 'FindClose', 'FindFirst', 'FindNext', + 'FindWindow', 'FlushINI', 'GetCurInstType', 'GetCurrentAddress', 'GetDlgItem', 'GetDLLVersion', + 'GetDLLVersionLocal', 'GetErrorLevel', 'GetFileTime', 'GetFileTimeLocal', 'GetFullPathName', + 'GetFunctionAddress', 'GetLabelAddress', 'GetTempFileName', 'GetWindowText', 'Goto', 'HideWindow', + 'IfAbort', 'IfErrors', 'IfFileExists', 'IfRebootFlag', 'IfSilent', 'InitPluginsDir', 'InstTypeGetText', + 'InstTypeSetText', 'IntCmp', 'IntCmpU', 'IntFmt', 'IntOp', 'IsWindow', 'LockWindow', 'LogSet', 'LogText', + 'MessageBox', 'Nop', 'Pop', 'Push', 'Quit', 'ReadEnvStr', 'ReadIniStr', 'ReadRegDWORD', 'ReadRegStr', + 'Reboot', 'RegDLL', 'Rename', 'ReserveFile', 'Return', 'RMDir', 'SearchPath', 'SectionGetFlags', + 'SectionGetInstTypes', 'SectionGetSize', 'SectionGetText', 'SectionSetFlags', 'SectionSetInstTypes', + 'SectionSetSize', 'SectionSetText', 'SendMessage', 'SetAutoClose', 'SetBrandingImage', 'SetCtlColors', + 'SetCurInstType', 'SetDetailsPrint', 'SetDetailsView', 'SetErrorLevel', 'SetErrors', 'SetFileAttributes', + 'SetOutPath', 'SetRebootFlag', 'SetShellVarContext', 'SetSilent', 'ShowWindow', 'Sleep', 'StrCmp', + 'StrCpy', 'StrLen', 'UnRegDLL', 'WriteINIStr', 'WriteRegBin', 'WriteRegDWORD', 'WriteRegExpandStr', + 'WriteRegStr', 'WriteUninstaller' + ), + 5 => array( + 'all', 'alwaysoff', 'ARCHIVE', 'auto', 'both', 'bzip2', 'checkbox', 'components', 'current', + 'custom', 'directory', 'false', 'FILE_ATTRIBUTE_ARCHIVE', 'FILE_ATTRIBUTE_HIDDEN', 'FILE_ATTRIBUTE_NORMAL', + 'FILE_ATTRIBUTE_OFFLINE', 'FILE_ATTRIBUTE_READONLY', 'FILE_ATTRIBUTE_SYSTEM,TEMPORARY', + 'FILE_ATTRIBUTE_TEMPORARY', 'force', 'HIDDEN', 'hide', 'HKCC', 'HKCR', 'HKCU', 'HKDD', 'HKEY_CLASSES_ROOT', + 'HKEY_CURRENT_CONFIG', 'HKEY_CURRENT_USER', 'HKEY_DYN_DATA', 'HKEY_LOCAL_MACHINE', 'HKEY_PERFORMANCE_DATA', + 'HKEY_USERS', 'HKLM', 'HKPD', 'HKU', 'IDABORT', 'IDCANCEL', 'IDIGNORE', 'IDNO', 'IDOK', 'IDRETRY', 'IDYES', + 'ifdiff', 'ifnewer', 'instfiles', 'lastused', 'leave', 'license', 'listonly', 'lzma', 'manual', + 'MB_ABORTRETRYIGNORE', 'MB_DEFBUTTON1', 'MB_DEFBUTTON2', 'MB_DEFBUTTON3', 'MB_DEFBUTTON4', + 'MB_ICONEXCLAMATION', 'MB_ICONINFORMATION', 'MB_ICONQUESTION', 'MB_ICONSTOP', 'MB_OK', 'MB_OKCANCEL', + 'MB_RETRYCANCEL', 'MB_RIGHT', 'MB_SETFOREGROUND', 'MB_TOPMOST', 'MB_YESNO', 'MB_YESNOCANCEL', 'nevershow', + 'none', 'normal', 'off', 'OFFLINE', 'on', 'radiobuttons', 'READONLY', 'RO', 'SHCTX', 'SHELL_CONTEXT', 'show', + 'silent', 'silentlog', 'SW_HIDE', 'SW_SHOWMAXIMIZED', 'SW_SHOWMINIMIZED', 'SW_SHOWNORMAL', 'SYSTEM', + 'textonly', 'true', 'try', 'uninstConfirm', 'zlib' + ), + 6 => array( + '/a', '/components', '/COMPONENTSONLYONCUSTOM', '/CUSTOMSTRING', '/e', '/FILESONLY', '/FINAL', '/gray', '/GLOBAL', + '/ifempty', '/IMGID', '/ITALIC', '/lang', '/NOCUSTOM', '/nonfatal', '/NOUNLOAD', '/oname', '/r', '/REBOOTOK', + '/RESIZETOFIT', '/SOLID', '/SD', '/SHORT', '/silent', '/STRIKE', '/TIMEOUT', '/TRIMCENTER', '/TRIMLEFT', + '/TRIMRIGHT', '/UNDERLINE', '/windows', '/x' + ), + 7 => array( + '.onGUIEnd', '.onGUIInit', '.onInit', '.onInstFailed', '.onInstSuccess', '.onMouseOverSection', + '.onRebootFailed', '.onSelChange', '.onUserAbort', '.onVerifyInstDir', 'un.onGUIEnd', 'un.onGUIInit', + 'un.onInit', 'un.onRebootFailed', 'un.onUninstFailed', 'un.onUninstSuccess', 'un.onUserAbort' + ), + 8 => array( + 'MUI.nsh', '"${NSISDIR}\Contrib\Modern UI\System.nsh"', 'MUI_SYSVERSION', 'MUI_ICON', 'MUI_UNICON', + 'MUI_HEADERIMAGE', 'MUI_HEADERIMAGE_BITMAP', 'MUI_HEADERIMAGE_BITMAP_NOSTRETCH', 'MUI_HEADERIMAGE_BITMAP_RTL', + 'MUI_HEADERIMAGE_BITMAP_RTL_NOSTRETCH', 'MUI_HEADERIMAGE_UNBITMAP', 'MUI_HEADERIMAGE_UNBITMAP_NOSTRETCH', + 'MUI_HEADERIMAGE_UNBITMAP_RTL', 'MUI_HEADERIMAGE_UNBITMAP_RTL_NOSTRETCH', 'MUI_HEADERIMAGE_RIGHT', 'MUI_BGCOLOR', + 'MUI_UI', 'MUI_UI_HEADERIMAGE', 'MUI_UI_HEADERIMAGE_RIGHT', 'MUI_UI_COMPONENTSPAGE_SMALLDESC', + 'MUI_UI_COMPONENTSPAGE_NODESC', 'MUI_WELCOMEFINISHPAGE_BITMAP', 'MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH', + 'MUI_WELCOMEFINISHPAGE_INI', 'MUI_UNWELCOMEFINISHPAGE_BITMAP', 'MUI_UNWELCOMEFINISHPAGE_BITMAP_NOSTRETCH', + 'MUI_UNWELCOMEFINISHPAGE_INI', 'MUI_LICENSEPAGE_BGCOLOR', 'MUI_COMPONENTSPAGE_CHECKBITMAP', + 'MUI_COMPONENTSPAGE_SMALLDESC', 'MUI_COMPONENTSPAGE_NODESC', 'MUI_INSTFILESPAGE_COLORS', + 'MUI_INSTFILESPAGE_PROGRESSBAR', 'MUI_FINISHPAGE_NOAUTOCLOSE', 'MUI_UNFINISHPAGE_NOAUTOCLOSE', + 'MUI_ABORTWARNING', 'MUI_ABORTWARNING_TEXT', 'MUI_UNABORTWARNING', 'MUI_UNABORTWARNING_TEXT', + 'MUI_PAGE_WELCOME', 'MUI_PAGE_LICENSE', 'MUI_PAGE_COMPONENTS', 'MUI_PAGE_DIRECTORY', + 'MUI_PAGE_STARTMENU', 'MUI_PAGE_INSTFILES', 'MUI_PAGE_FINISH', 'MUI_UNPAGE_WELCOME', + 'MUI_UNPAGE_CONFIRM', 'MUI_UNPAGE_LICENSE', 'MUI_UNPAGE_COMPONENTS', 'MUI_UNPAGE_DIRECTORY', + 'MUI_UNPAGE_INSTFILES', 'MUI_UNPAGE_FINISH', 'MUI_PAGE_HEADER_TEXT', 'MUI_PAGE_HEADER_SUBTEXT', + 'MUI_WELCOMEPAGE_TITLE', 'MUI_WELCOMEPAGE_TITLE_3LINES', 'MUI_WELCOMEPAGE_TEXT', + 'MUI_LICENSEPAGE_TEXT_TOP', 'MUI_LICENSEPAGE_TEXT_BOTTOM', 'MUI_LICENSEPAGE_BUTTON', + 'MUI_LICENSEPAGE_CHECKBOX', 'MUI_LICENSEPAGE_CHECKBOX_TEXT', 'MUI_LICENSEPAGE_RADIOBUTTONS', + 'MUI_LICENSEPAGE_RADIOBUTTONS_TEXT_ACCEPT', 'MUI_LICENSEPAGE_RADIOBUTTONS_TEXT_DECLINE', + 'MUI_COMPONENTSPAGE_TEXT_TOP', 'MUI_COMPONENTSPAGE_TEXT_COMPLIST', 'MUI_COMPONENTSPAGE_TEXT_INSTTYPE', + 'MUI_COMPONENTSPAGE_TEXT_DESCRIPTION_TITLE', 'MUI_COMPONENTSPAGE_TEXT_DESCRIPTION_INFO', + 'MUI_DIRECTORYPAGE_TEXT_TOP', 'MUI_DIRECTORYPAGE_TEXT_DESTINATION', 'MUI_DIRECTORYPAGE_VARIABLE', + 'MUI_DIRECTORYPAGE_VERIFYONLEAVE', 'MUI_STARTMENU_WRITE_BEGIN', 'MUI_STARTMENU_WRITE_END', + 'MUI_STARTMENUPAGE_TEXT_TOP', 'MUI_STARTMENUPAGE_TEXT_CHECKBOX', 'MUI_STARTMENUPAGE_DEFAULTFOLDER', + 'MUI_STARTMENUPAGE_NODISABLE', 'MUI_STARTMENUPAGE_REGISTRY_ROOT', 'MUI_STARTMENUPAGE_REGISTRY_KEY', + 'MUI_STARTMENUPAGE_REGISTRY_VALUENAME', 'MUI_INSTFILESPAGE_FINISHHEADER_TEXT', + 'MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT', 'MUI_INSTFILESPAGE_ABORTHEADER_TEXT', + 'MUI_INSTFILESPAGE_ABORTHEADER_SUBTEXT', 'MUI_FINISHPAGE_TITLE', 'MUI_FINISHPAGE_TITLE_3LINES', + 'MUI_FINISHPAGE_TEXT', 'MUI_FINISHPAGE_TEXT_LARGE', 'MUI_FINISHPAGE_BUTTON', + 'MUI_FINISHPAGE_TEXT_REBOOT', 'MUI_FINISHPAGE_TEXT_REBOOTNOW', 'MUI_FINISHPAGE_TEXT_REBOOTLATER', + 'MUI_FINISHPAGE_RUN', 'MUI_FINISHPAGE_RUN_TEXT', 'MUI_FINISHPAGE_RUN_PARAMETERS', + 'MUI_FINISHPAGE_RUN_NOTCHECKED', 'MUI_FINISHPAGE_RUN_FUNCTION', 'MUI_FINISHPAGE_SHOWREADME', + 'MUI_FINISHPAGE_SHOWREADME_TEXT', 'MUI_FINISHPAGE_SHOWREADME_NOTCHECKED', + 'MUI_FINISHPAGE_SHOWREADME_FUNCTION', 'MUI_FINISHPAGE_LINK', 'MUI_FINISHPAGE_LINK_LOCATION', + 'MUI_FINISHPAGE_LINK_COLOR', 'MUI_FINISHPAGE_NOREBOOTSUPPORT', 'MUI_UNCONFIRMPAGE_TEXT_TOP', + 'MUI_UNCONFIRMPAGE_TEXT_LOCATION', 'MUI_LANGUAGE', 'MUI_LANGDLL_DISPLAY', + 'MUI_LANGDLL_REGISTRY_ROOT', 'MUI_LANGDLL_REGISTRY_KEY', 'MUI_LANGDLL_REGISTRY_VALUENAME', + 'MUI_LANGDLL_WINDOWTITLE', 'MUI_LANGDLL_INFO', 'MUI_LANGDLL_ALWAYSSHOW', + 'MUI_RESERVEFILE_INSTALLOPTIONS', 'MUI_RESERVEFILE_LANGDLL', 'MUI_FUNCTION_DESCRIPTION_BEGIN', + 'MUI_DESCRIPTION_TEXT', 'MUI_FUNCTION_DESCRIPTION_END', 'MUI_INSTALLOPTIONS_EXTRACT', + 'MUI_INSTALLOPTIONS_EXTRACT_AS', 'MUI_HEADER_TEXT', 'MUI_INSTALLOPTIONS_DISPLAY', + 'MUI_INSTALLOPTIONS_INITDIALOG', 'MUI_INSTALLOPTIONS_SHOW', + 'MUI_INSTALLOPTIONS_DISPLAY_RETURN', 'MUI_INSTALLOPTIONS_SHOW_RETURN', + 'MUI_INSTALLOPTIONS_READ', 'MUI_INSTALLOPTIONS_WRITE', + 'MUI_CUSTOMFUNCTION_GUIINIT', 'MUI_CUSTOMFUNCTION_UNGUIINIT', + 'MUI_CUSTOMFUNCTION_ABORT', 'MUI_CUSTOMFUNCTION_UNABORT', + 'MUI_PAGE_CUSTOMFUNCTION_PRE', 'MUI_PAGE_CUSTOMFUNCTION_SHOW', 'MUI_PAGE_CUSTOMFUNCTION_LEAVE', + 'MUI_WELCOMEFINISHPAGE_CUSTOMFUNCTION_INIT' + ), + 9 => array( + 'LogicLib.nsh', '${LOGICLIB}', 'LOGICLIB_STRCMP', 'LOGICLIB_INT64CMP', 'LOGICLIB_SECTIONCMP', '${If}', '${Unless}', + '${ElseIf}', '${ElseUnless}', '${Else}', '${EndIf}', '${EndUnless}', '${AndIf}', '${AndUnless}', + '${OrIf}', '${OrUnless}', '${IfThen}', '${IfCmd}', '${Select}', '${Case2}', '${Case3}', + '${Case4}', '${Case5}', '${CaseElse}', '${Default}', '${EndSelect}', '${Switch}', + '${Case}', '${EndSwitch}', '${Do}', '${DoWhile}', '${UntilWhile}', '${Continue}', '${Break}', + '${Loop}', '${LoopWhile}', '${LoopUntil}', '${While}', '${ExitWhile}', '${EndWhile}', '${For}', + '${ForEach}', '${ExitFor}', '${Next}', '${Abort}', '${Errors}', '${RebootFlag}', '${Silent}', + '${FileExists}', '${Cmd}', '${SectionIsSelected}', '${SectionIsSectionGroup}', + '${SectionIsSectionGroupEnd}', '${SectionIsBold}', '${SectionIsReadOnly}', + '${SectionIsExpanded}', '${SectionIsPartiallySelected}' + ), + 10 => array( + 'StrFunc.nsh', '${STRFUNC}', '${StrCase}', '${StrClb}', '${StrIOToNSIS}', '${StrLoc}', '${StrNSISToIO}', '${StrRep}', + '${StrSort}', '${StrStr}', '${StrStrAdv}', '${StrTok}', '${StrTrimNewLines}' + ), + 11 => array( + 'UpgradeDLL.nsh', 'UPGRADEDLL_INCLUDED', 'UpgradeDLL' + ), + 12 => array( + 'Sections.nsh', 'SECTIONS_INCLUDED', '${SF_SELECTED}', '${SF_SECGRP}', '${SF_SUBSEC}', '${SF_SECGRPEND}', + '${SF_SUBSECEND}', '${SF_BOLD}', '${SF_RO}', '${SF_EXPAND}', '${SF_PSELECTED}', '${SF_TOGGLED}', + '${SF_NAMECHG}', '${SECTION_OFF}', 'SelectSection', 'UnselectSection', 'ReverseSection', + 'StartRadioButtons', 'RadioButton', 'EndRadioButtons', '${INSTTYPE_0}', '${INSTTYPE_1}', '${INSTTYPE_2}', + '${INSTTYPE_3}', '${INSTTYPE_4}', '${INSTTYPE_5}', '${INSTTYPE_6}', '${INSTTYPE_7}', '${INSTTYPE_8}', + '${INSTTYPE_9}', '${INSTTYPE_10}', '${INSTTYPE_11}', '${INSTTYPE_12}', '${INSTTYPE_13}', '${INSTTYPE_14}', + '${INSTTYPE_15}', '${INSTTYPE_16}', '${INSTTYPE_17}', '${INSTTYPE_18}', '${INSTTYPE_19}', '${INSTTYPE_20}', + '${INSTTYPE_21}', '${INSTTYPE_22}', '${INSTTYPE_23}', '${INSTTYPE_24}', '${INSTTYPE_25}', '${INSTTYPE_26}', + '${INSTTYPE_27}', '${INSTTYPE_28}', '${INSTTYPE_29}', '${INSTTYPE_30}', '${INSTTYPE_31}', '${INSTTYPE_32}', + 'SetSectionInInstType', 'ClearSectionInInstType', 'SetSectionFlag', 'ClearSectionFlag', 'SectionFlagIsSet' + ), + 13 => array( + 'Colors.nsh', 'WHITE', 'BLACK', 'YELLOW', 'RED', 'GREEN', 'BLUE', 'MAGENTA', 'CYAN', 'rgb2hex' + ), + 14 => array( + 'FileFunc.nsh', '${Locate}', '${GetSize}', '${DriveSpace}', '${GetDrives}', '${GetTime}', '${GetFileAttributes}', '${GetFileVersion}', '${GetExeName}', '${GetExePath}', '${GetParameters}', '${GetOptions}', '${GetRoot}', '${GetParent}', '${GetFileName}', '${GetBaseName}', '${GetFileExt}', '${BannerTrimPath}', '${DirState}', '${RefreshShellIcons}' + ), + 15 => array( + 'TextFunc.nsh', '${LineFind}', '${LineRead}', '${FileReadFromEnd}', '${LineSum}', '${FileJoin}', '${TextCompare}', '${ConfigRead}', '${ConfigWrite}', '${FileRecode}', '${TrimNewLines}' + ), + 16 => array( + 'WordFunc.nsh', '${WordFind}', '${WordFind2X}', '${WordFind3X}', '${WordReplace}', '${WordAdd}', '${WordInsert}', '${StrFilter}', '${VersionCompare}', '${VersionConvert}' + ) + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false, + 8 => false, + 9 => false, + 10 => false, + 11 => false, + 12 => false, + 13 => false, + 14 => false, + 15 => false, + 16 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000066; font-weight:bold;', + 2 => 'color: #000066;', + 3 => 'color: #003366;', + 4 => 'color: #000099;', + 5 => 'color: #ff6600;', + 6 => 'color: #ff6600;', + 7 => 'color: #006600;', + 8 => 'color: #006600;', + 9 => 'color: #006600;', + 10 => 'color: #006600;', + 11 => 'color: #006600;', + 12 => 'color: #006600;', + 13 => 'color: #006600;', + 14 => 'color: #006600;', + 15 => 'color: #006600;', + 16 => 'color: #006600;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #666666; font-style: italic;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #660066; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => '' + ), + 'STRINGS' => array( + 0 => 'color: #660066;' + ), + 'NUMBERS' => array( + 0 => '' + ), + 'METHODS' => array( + 0 => '' + ), + 'SYMBOLS' => array( + 0 => '' + ), + 'REGEXPS' => array( + 0 => 'color: #660000;', + 1 => 'color: #660000;', + 2 => 'color: #660000;', + 3 => 'color: #660000;', + 4 => 'color: #660000;', + 5 => 'color: #660000;', + 6 => 'color: #660000;', + 7 => 'color: #000099;', + 8 => 'color: #003399;' + ), + 'SCRIPT' => array( + 0 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '', + 8 => '', + 9 => '', + 10 => '', + 11 => '', + 12 => '', + 13 => '', + 14 => '', + 15 => '', + 16 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 0 => '\$\$', + 1 => '\$\\r', + 2 => '\$\\n', + 3 => '\$\\t', + 4 => '\$[a-zA-Z0-9_]+', + 5 => '\$\{.{1,256}\}', + 6 => '\$\\\(.{1,256}\\\)', + 7 => array( + GESHI_SEARCH => '([^:\/\\\*\?\"\<\>(?:)\s]*?)(::)([^:\/\\\*\?\"\<\>(?:)\s]*?)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '\\2\\3' + ), + 8 => array( + GESHI_SEARCH => '([^:\/\\\*\?\"\<\>(?:)\s]*?)(::)([^:\/\\\*\?\"\<\>(?:)]*?\s)', + GESHI_REPLACE => '\\3', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1\\2', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/objc.php b/examples/includes/geshi/geshi/objc.php new file mode 100644 index 0000000..668f14b --- /dev/null +++ b/examples/includes/geshi/geshi/objc.php @@ -0,0 +1,358 @@ + 'Objective-C', + 'COMMENT_SINGLE' => array( + //Compiler directives + 1 => '#', + //Single line C-Comments + 2 => '//' + ), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + //Multiline Continuation for single-line comment + 2 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m', + //Pseudo-Highlighting of the @-sign before strings + 3 => "/@(?=\")/" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', "'"), + 'ESCAPE_CHAR' => '\\', + + 'KEYWORDS' => array( + // Objective-C keywords + 1 => array( + 'while', 'switch', 'return', 'in', 'if', 'goto', 'foreach', 'for', + 'else', 'do', 'default', 'continue', 'case', '@try', '@throw', + '@synthesize', '@synchronized', '@selector', '@public', '@protocol', + '@protected', '@property', '@private', '@interface', + '@implementation', '@finally', '@end', '@encode', '@defs', '@class', + '@catch' + ), + // Macros and constants + 2 => array( + 'YES', 'USHRT_MAX', 'ULONG_MAX', 'UINT_MAX', 'UCHAR_MAX', 'true', + 'TMP_MAX', 'stdout', 'stdin', 'stderr', 'SIGTERM', 'SIGSEGV', + 'SIGINT', 'SIGILL', 'SIG_IGN', 'SIGFPE', 'SIG_ERR', 'SIG_DFL', + 'SIGABRT', 'SHRT_MIN', 'SHRT_MAX', 'SEEK_SET', 'SEEK_END', + 'SEEK_CUR', 'SCHAR_MIN', 'SCHAR_MAX', 'RAND_MAX', 'NULL', + 'NO', 'nil', 'Nil', 'L_tmpnam', 'LONG_MIN', 'LONG_MAX', + 'LDBL_MIN_EXP', 'LDBL_MIN', 'LDBL_MAX_EXP', 'LDBL_MAX', + 'LDBL_MANT_DIG', 'LDBL_EPSILON', 'LDBL_DIG', 'INT_MIN', 'INT_MAX', + 'HUGE_VAL', 'FOPEN_MAX', 'FLT_ROUNDS', 'FLT_RADIX', 'FLT_MIN_EXP', + 'FLT_MIN', 'FLT_MAX_EXP', 'FLT_MAX', 'FLT_MANT_DIG', 'FLT_EPSILON', + 'FLT_DIG', 'FILENAME_MAX', 'false', 'EXIT_SUCCESS', 'EXIT_FAILURE', + 'errno', 'ERANGE', 'EOF', 'enum', 'EDOM', 'DBL_MIN_EXP', 'DBL_MIN', + 'DBL_MAX_EXP', 'DBL_MAX', 'DBL_MANT_DIG', 'DBL_EPSILON', 'DBL_DIG', + 'CLOCKS_PER_SEC', 'CHAR_MIN', 'CHAR_MAX', 'CHAR_BIT', 'BUFSIZ', + 'break' + ), + // C standard library functions + 3 => array( + 'vsprintf', 'vprintf', 'vfprintf', 'va_start', 'va_end', 'va_arg', + 'ungetc', 'toupper', 'tolower', 'tmpname', 'tmpfile', 'time', + 'tanh', 'tan', 'system', 'strxfrm', 'strtoul', 'strtol', 'strtok', + 'strtod', 'strstr', 'strspn', 'strrchr', 'strpbrk', 'strncpy', + 'strncmp', 'strncat', 'strlen', 'strftime', 'strerror', 'strcspn', + 'strcpy', 'strcoll', 'strcmp', 'strchr', 'strcat', 'sscanf', + 'srand', 'sqrt', 'sprintf', 'snprintf', 'sizeof', 'sinh', 'sin', + 'setvbuf', 'setjmp', 'setbuf', 'scanf', 'rewind', 'rename', + 'remove', 'realloc', 'rand', 'qsort', 'puts', 'putchar', 'putc', + 'printf', 'pow', 'perror', 'offsetof', 'modf', 'mktime', 'memset', + 'memmove', 'memcpy', 'memcmp', 'memchr', 'malloc', 'longjmp', + 'log10', 'log', 'localtime', 'ldiv', 'ldexp', 'labs', 'isxdigit', + 'isupper', 'isspace', 'ispunct', 'isprint', 'islower', + 'isgraph', 'isdigit', 'iscntrl', 'isalpha', 'isalnum', 'gmtime', + 'gets', 'getenv', 'getchar', 'getc', 'fwrite', 'ftell', 'fsetpos', + 'fseek', 'fscanf', 'frexp', 'freopen', 'free', 'fread', 'fputs', + 'fputc', 'fprintf', 'fopen', 'fmod', 'floor', 'fgets', 'fgetpos', + 'fgetc', 'fflush', 'ferror', 'feof', 'fclose', 'fabs', 'exp', + 'exit', 'div', 'difftime', 'ctime', 'cosh', 'cos', 'clock', + 'clearerr', 'ceil', 'calloc', 'bsearch', 'atol', 'atoi', 'atof', + 'atexit', 'atan2', 'atan', 'assert', 'asin', 'asctime', 'acos', + 'abs', 'abort' + ), + // Data types (C, Objective-C, Cocoa) + 4 => array( + 'volatile', 'void', 'va_list', 'unsigned', 'union', 'typedef', 'tm', + 'time_t', 'struct', 'string', 'static', 'size_t', + 'signed', 'signal', 'short', 'SEL', 'register', 'raise', + 'ptrdiff_t', 'NSZone', 'NSRect', 'NSRange', 'NSPoint', 'long', + 'ldiv_t', 'jmp_buf', 'int', 'IMP', 'id', 'fpos_t', 'float', 'FILE', + 'extern', 'double', 'div_t', 'const', 'clock_t', 'Class', 'char', + 'BOOL', 'auto' + ), + // Foundation classes + 5 => array( + 'NSXMLParser', 'NSXMLNode', 'NSXMLElement', 'NSXMLDTDNode', + 'NSXMLDTD', 'NSXMLDocument', 'NSWhoseSpecifier', + 'NSValueTransformer', 'NSValue', 'NSUserDefaults', 'NSURLResponse', + 'NSURLRequest', 'NSURLProtocol', 'NSURLProtectionSpace', + 'NSURLHandle', 'NSURLDownload', 'NSURLCredentialStorage', + 'NSURLCredential', 'NSURLConnection', 'NSURLCache', + 'NSURLAuthenticationChallenge', 'NSURL', 'NSUniqueIDSpecifier', + 'NSUndoManager', 'NSUnarchiver', 'NSTimeZone', 'NSTimer', + 'NSThread', 'NSTask', 'NSString', 'NSStream', 'NSSpellServer', + 'NSSpecifierTest', 'NSSortDescriptor', 'NSSocketPortNameServer', + 'NSSocketPort', 'NSSetCommand', 'NSSet', 'NSSerializer', + 'NSScriptWhoseTest', 'NSScriptSuiteRegistry', + 'NSScriptObjectSpecifier', 'NSScriptExecutionContext', + 'NSScriptCommandDescription', 'NSScriptCommand', + 'NSScriptCoercionHandler', 'NSScriptClassDescription', 'NSScanner', + 'NSRunLoop', 'NSRelativeSpecifier', 'NSRecursiveLock', + 'NSRangeSpecifier', 'NSRandomSpecifier', 'NSQuitCommand', 'NSProxy', + 'NSProtocolChecker', 'NSPropertySpecifier', + 'NSPropertyListSerialization', 'NSProcessInfo', 'NSPredicate', + 'NSPositionalSpecifier', 'NSPortNameServer', 'NSPortMessage', + 'NSPortCoder', 'NSPort', 'NSPointerFunctions', 'NSPointerArray', + 'NSPipe', 'NSOutputStream', 'NSOperationQueue', 'NSOperation', + 'NSObject', 'NSNumberFormatter', 'NSNumber', 'NSNull', + 'NSNotificationQueue', 'NSNotificationCenter', 'NSNotification', + 'NSNetServiceBrowser', 'NSNetService', 'NSNameSpecifier', + 'NSMutableURLRequest', 'NSMutableString', 'NSMutableSet', + 'NSMutableIndexSet', 'NSMutableDictionary', 'NSMutableData', + 'NSMutableCharacterSet', 'NSMutableAttributedString', + 'NSMutableArray', 'NSMoveCommand', 'NSMiddleSpecifier', + 'NSMethodSignature', 'NSMetadataQueryResultGroup', + 'NSMetadataQueryAttributeValueTuple', 'NSMetadataQuery', + 'NSMetadataItem', 'NSMessagePortNameServer', 'NSMessagePort', + 'NSMapTable', 'NSMachPort', 'NSMachBootstrapServer', + 'NSLogicalTest', 'NSLock', 'NSLocale', 'NSKeyedUnarchiver', + 'NSKeyedArchiver', 'NSInvocationOperation', 'NSInvocation', + 'NSInputStream', 'NSIndexSpecifier', 'NSIndexSet', 'NSIndexPath', + 'NSHTTPURLResponse', 'NSHTTPCookieStorage', 'NSHTTPCookie', + 'NSHost', 'NSHashTable', 'NSGetCommand', 'NSGarbageCollector', + 'NSFormatter', 'NSFileManager', 'NSFileHandle', 'NSExpression', + 'NSExistsCommand', 'NSException', 'NSError', 'NSEnumerator', + 'NSDistributedNotificationCenter', 'NSDistributedLock', + 'NSDistantObjectRequest', 'NSDistantObject', + 'NSDirectoryEnumerator', 'NSDictionary', 'NSDeserializer', + 'NSDeleteCommand', 'NSDecimalNumberHandler', 'NSDecimalNumber', + 'NSDateFormatter', 'NSDateComponents', 'NSDate', 'NSData', + 'NSCreateCommand', 'NSCountedSet', 'NSCountCommand', 'NSConnection', + 'NSConditionLock', 'NSCondition', 'NSCompoundPredicate', + 'NSComparisonPredicate', 'NSCoder', 'NSCloseCommand', + 'NSCloneCommand', 'NSClassDescription', 'NSCharacterSet', + 'NSCalendarDate', 'NSCalendar', 'NSCachedURLResponse', 'NSBundle', + 'NSAutoreleasePool', 'NSAttributedString', 'NSAssertionHandler', + 'NSArray', 'NSArchiver', 'NSAppleScript', 'NSAppleEventManager', + 'NSAppleEventDescriptor', 'NSAffineTransform' + ), + // Foundation protocols + 6 => array( + 'NSURLProtocolClient', 'NSURLHandleClient', 'NSURLClient', + 'NSURLAuthenticationChallengeSender', 'NSScriptObjectSpecifiers', + 'NSScriptKeyValueCoding', 'NSScriptingComparisonMethods', + 'NSObjCTypeSerializationCallBack', 'NSMutableCopying', + 'NSLocking', 'NSKeyValueObserving', 'NSKeyValueCoding', + 'NSFastEnumeration', 'NSErrorRecoveryAttempting', + 'NSDecimalNumberBehaviors', 'NSCopying', 'NSComparisonMethods', + 'NSCoding' + ), + // AppKit classes + 7 => array( + 'NSWorkspace', 'NSWindowController', 'NSWindow', 'NSViewController', + 'NSViewAnimation', 'NSView', 'NSUserDefaultsController', + 'NSTypesetter', 'NSTreeNode', 'NSTreeController', 'NSTrackingArea', + 'NSToolbarItemGroup', 'NSToolbarItem', 'NSToolbar', + 'NSTokenFieldCell', 'NSTokenField', 'NSTextView', + 'NSTextTableBlock', 'NSTextTable', 'NSTextTab', 'NSTextStorage', + 'NSTextList', 'NSTextFieldCell', 'NSTextField', 'NSTextContainer', + 'NSTextBlock', 'NSTextAttachmentCell', 'NSTextAttachment', 'NSText', + 'NSTabViewItem', 'NSTabView', 'NSTableView', 'NSTableHeaderView', + 'NSTableHeaderCell', 'NSTableColumn', 'NSStepperCell', 'NSStepper', + 'NSStatusItem', 'NSStatusBar', 'NSSplitView', 'NSSpellChecker', + 'NSSpeechSynthesizer', 'NSSpeechRecognizer', 'NSSound', + 'NSSliderCell', 'NSSlider', 'NSSimpleHorizontalTypesetter', + 'NSShadow', 'NSSegmentedControl', 'NSSegmentedCell', + 'NSSecureTextFieldCell', 'NSSecureTextField', 'NSSearchFieldCell', + 'NSSearchField', 'NSScrollView', 'NSScroller', 'NSScreen', + 'NSSavePanel', 'NSRulerView', 'NSRulerMarker', 'NSRuleEditor', + 'NSResponder', 'NSQuickDrawView', 'NSProgressIndicator', + 'NSPrintPanel', 'NSPrintOperation', 'NSPrintInfo', 'NSPrinter', + 'NSPredicateEditorRowTemplate', 'NSPredicateEditor', + 'NSPopUpButtonCell', 'NSPopUpButton', 'NSPICTImageRep', + 'NSPersistentDocument', 'NSPDFImageRep', 'NSPathControl', + 'NSPathComponentCell', 'NSPathCell', 'NSPasteboard', + 'NSParagraphStyle', 'NSPanel', 'NSPageLayout', 'NSOutlineView', + 'NSOpenPanel', 'NSOpenGLView', 'NSOpenGLPixelFormat', + 'NSOpenGLPixelBuffer', 'NSOpenGLContext', 'NSObjectController', + 'NSNibOutletConnector', 'NSNibControlConnector', 'NSNibConnector', + 'NSNib', 'NSMutableParagraphStyle', 'NSMovieView', 'NSMovie', + 'NSMenuView', 'NSMenuItemCell', 'NSMenuItem', 'NSMenu', 'NSMatrix', + 'NSLevelIndicatorCell', 'NSLevelIndicator', 'NSLayoutManager', + 'NSInputServer', 'NSInputManager', 'NSImageView', 'NSImageRep', + 'NSImageCell', 'NSImage', 'NSHelpManager', 'NSGraphicsContext', + 'NSGradient', 'NSGlyphInfo', 'NSGlyphGenerator', 'NSFormCell', + 'NSForm', 'NSFontPanel', 'NSFontManager', 'NSFontDescriptor', + 'NSFont', 'NSFileWrapper', 'NSEvent', 'NSEPSImageRep', 'NSDrawer', + 'NSDocumentController', 'NSDocument', 'NSDockTile', + 'NSDictionaryController', 'NSDatePickerCell', 'NSDatePicker', + 'NSCustomImageRep', 'NSCursor', 'NSController', 'NSControl', + 'NSComboBoxCell', 'NSComboBox', 'NSColorWell', 'NSColorSpace', + 'NSColorPicker', 'NSColorPanel', 'NSColorList', 'NSColor', + 'NSCollectionViewItem', 'NSCollectionView', 'NSClipView', + 'NSCIImageRep', 'NSCell', 'NSCachedImageRep', 'NSButtonCell', + 'NSButton', 'NSBrowserCell', 'NSBrowser', 'NSBox', + 'NSBitmapImageRep', 'NSBezierPath', 'NSATSTypesetter', + 'NSArrayController', 'NSApplication', 'NSAnimationContext', + 'NSAnimation', 'NSAlert', 'NSActionCell' + ), + // AppKit protocols + 8 => array( + 'NSWindowScripting', 'NSValidatedUserInterfaceItem', + 'NSUserInterfaceValidations', 'NSToolTipOwner', + 'NSToolbarItemValidation', 'NSTextInput', + 'NSTableDataSource', 'NSServicesRequests', + 'NSPrintPanelAccessorizing', 'NSPlaceholders', + 'NSPathControlDelegate', 'NSPathCellDelegate', + 'NSOutlineViewDataSource', 'NSNibAwaking', 'NSMenuValidation', + 'NSKeyValueBindingCreation', 'NSInputServiceProvider', + 'NSInputServerMouseTracker', 'NSIgnoreMisspelledWords', + 'NSGlyphStorage', 'NSFontPanelValidation', 'NSEditorRegistration', + 'NSEditor', 'NSDraggingSource', 'NSDraggingInfo', + 'NSDraggingDestination', 'NSDictionaryControllerKeyValuePair', + 'NSComboBoxDataSource', 'NSComboBoxCellDataSource', + 'NSColorPickingDefault', 'NSColorPickingCustom', 'NSChangeSpelling', + 'NSAnimatablePropertyContainer', 'NSAccessibility' + ), + // CoreData classes + 9 => array( + 'NSRelationshipDescription', 'NSPropertyMapping', + 'NSPropertyDescription', 'NSPersistentStoreCoordinator', + 'NSPersistentStore', 'NSMigrationManager', 'NSMappingModel', + 'NSManagedObjectModel', 'NSManagedObjectID', + 'NSManagedObjectContext', 'NSManagedObject', + 'NSFetchRequestExpression', 'NSFetchRequest', + 'NSFetchedPropertyDescription', 'NSEntityMigrationPolicy', + 'NSEntityMapping', 'NSEntityDescription', 'NSAttributeDescription', + 'NSAtomicStoreCacheNode', 'NSAtomicStore' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', '&', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => true, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true + ), + // Define the colors for the groups listed above + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #a61390;', // Objective-C keywords + 2 => 'color: #a61390;', // Macros and constants + 3 => 'color: #a61390;', // C standard library functions + 4 => 'color: #a61390;', // data types + 5 => 'color: #400080;', // Foundation classes + 6 => 'color: #2a6f76;', // Foundation protocols + 7 => 'color: #400080;', // AppKit classes + 8 => 'color: #2a6f76;', // AppKit protocols + 9 => 'color: #400080;' // CoreData classes + ), + 'COMMENTS' => array( + 1 => 'color: #6e371a;', // Preprocessor directives + 2 => 'color: #11740a; font-style: italic;', // Normal C single-line comments + 3 => 'color: #bf1d1a;', // Q-sign in front of Strings + 'MULTI' => 'color: #11740a; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #2400d9;' + ), + 'BRACKETS' => array( + 0 => 'color: #002200;' + ), + 'STRINGS' => array( + 0 => 'color: #bf1d1a;' + ), + 'NUMBERS' => array( + 0 => 'color: #2400d9;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #002200;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.opengroup.org/onlinepubs/009695399/functions/{FNAME}.html', + 4 => '', + 5 => 'http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/{FNAME}_Class/', + 6 => 'http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Protocols/{FNAME}_Protocol/', + 7 => 'http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/{FNAME}_Class/', + 8 => 'http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Protocols/{FNAME}_Protocol/', + 9 => 'http://developer.apple.com/documentation/Cocoa/Reference/CoreDataFramework/Classes/{FNAME}_Class/' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/ocaml-brief.php b/examples/includes/geshi/geshi/ocaml-brief.php new file mode 100644 index 0000000..8c15519 --- /dev/null +++ b/examples/includes/geshi/geshi/ocaml-brief.php @@ -0,0 +1,112 @@ + 'OCaml (brief)', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('(*' => '*)'), + 'CASE_KEYWORDS' => 0, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => "", + 'KEYWORDS' => array( + /* main OCaml keywords */ + 1 => array( + 'and', 'as', 'asr', 'begin', 'class', 'closed', 'constraint', 'do', 'done', 'downto', 'else', + 'end', 'exception', 'external', 'failwith', 'false', 'flush', 'for', 'fun', 'function', 'functor', + 'if', 'in', 'include', 'inherit', 'incr', 'land', 'let', 'load', 'los', 'lsl', 'lsr', 'lxor', + 'match', 'method', 'mod', 'module', 'mutable', 'new', 'not', 'of', 'open', 'option', 'or', 'parser', + 'private', 'ref', 'rec', 'raise', 'regexp', 'sig', 'struct', 'stdout', 'stdin', 'stderr', 'then', + 'to', 'true', 'try', 'type', 'val', 'virtual', 'when', 'while', 'with' + ) + ), + /* highlighting symbols is really important in OCaml */ + 'SYMBOLS' => array( + ';', '!', ':', '.', '=', '%', '^', '*', '-', '/', '+', + '>', '<', '(', ')', '[', ']', '&', '|', '#', "'" + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #06c; font-weight: bold;' /* nice blue */ + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #5d478b; font-style: italic;' /* light purple */ + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #6c6;' + ), + 'STRINGS' => array( + 0 => 'color: #3cb371;' /* nice green */ + ), + 'NUMBERS' => array( + 0 => 'color: #c6c;' /* pink */ + ), + 'METHODS' => array( + 1 => 'color: #060;' /* dark green */ + ), + 'REGEXPS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #a52a2a;' /* maroon */ + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/ocaml.php b/examples/includes/geshi/geshi/ocaml.php new file mode 100644 index 0000000..e21ca7f --- /dev/null +++ b/examples/includes/geshi/geshi/ocaml.php @@ -0,0 +1,174 @@ + 'OCaml', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('(*' => '*)'), + 'CASE_KEYWORDS' => 0, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => "", + 'KEYWORDS' => array( + /* main OCaml keywords */ + 1 => array( + 'and', 'as', 'asr', 'begin', 'class', 'closed', 'constraint', 'do', 'done', 'downto', 'else', + 'end', 'exception', 'external', 'failwith', 'false', 'for', 'fun', 'function', 'functor', + 'if', 'in', 'include', 'inherit', 'incr', 'land', 'let', 'load', 'los', 'lsl', 'lsr', 'lxor', + 'match', 'method', 'mod', 'module', 'mutable', 'new', 'not', 'of', 'open', 'option', 'or', 'parser', + 'private', 'ref', 'rec', 'raise', 'regexp', 'sig', 'struct', 'stdout', 'stdin', 'stderr', 'then', + 'to', 'true', 'try', 'type', 'val', 'virtual', 'when', 'while', 'with' + ), + /* define names of main librarys, so we can link to it */ + 2 => array( + 'Arg', 'Arith_status', 'Array', 'ArrayLabels', 'Big_int', 'Bigarray', 'Buffer', 'Callback', + 'CamlinternalOO', 'Char', 'Complex', 'Condition', 'Dbm', 'Digest', 'Dynlink', 'Event', + 'Filename', 'Format', 'Gc', 'Genlex', 'Graphics', 'GraphicsX11', 'Hashtbl', 'Int32', 'Int64', + 'Lazy', 'Lexing', 'List', 'ListLabels', 'Map', 'Marshal', 'MoreLabels', 'Mutex', 'Nativeint', + 'Num', 'Obj', 'Oo', 'Parsing', 'Pervasives', 'Printexc', 'Printf', 'Queue', 'Random', 'Scanf', + 'Set', 'Sort', 'Stack', 'StdLabels', 'Str', 'Stream', 'String', 'StringLabels', 'Sys', 'Thread', + 'ThreadUnix', 'Tk' + ), + /* just link to the Pervasives functions library, cause it's the default opened library when starting OCaml */ + 3 => array( + 'abs', 'abs_float', 'acos', 'asin', 'at_exit', 'atan', 'atan2', + 'bool_of_string', 'ceil', 'char_of_int', 'classify_float', + 'close_in', 'close_in_noerr', 'close_out', 'close_out_noerr', + 'compare', 'cos', 'cosh', 'decr', 'epsilon_float', 'exit', 'exp', + 'float', 'float_of_int', 'float_of_string', 'floor', 'flush', + 'flush_all', 'format_of_string', 'frexp', 'fst', 'ignore', + 'in_channel_length', 'infinity', 'input', 'input_binary_int', + 'input_byte', 'input_char', 'input_line', 'input_value', + 'int_of_char', 'int_of_float', 'int_of_string', 'invalid_arg', + 'ldexp', 'log', 'log10', 'max', 'max_float', 'max_int', 'min', + 'min_float', 'min_int', 'mod_float', 'modf', 'nan', 'open_in', + 'open_in_bin', 'open_in_gen', 'open_out', 'open_out_bin', + 'open_out_gen', 'out_channel_length', 'output', 'output_binary_int', + 'output_byte', 'output_char', 'output_string', 'output_value', + 'pos_in', 'pos_out', 'pred', 'prerr_char', 'prerr_endline', + 'prerr_float', 'prerr_int', 'prerr_newline', 'prerr_string', + 'print_char', 'print_endline', 'print_float', 'print_int', + 'print_newline', 'print_string', 'read_float', 'read_int', + 'read_line', 'really_input', 'seek_in', 'seek_out', + 'set_binary_mode_in', 'set_binary_mode_out', 'sin', 'sinh', 'snd', + 'sqrt', 'string_of_bool', 'string_of_float', 'string_of_format', + 'string_of_int', 'succ', 'tan', 'tanh', 'truncate' + ), + /* here Pervasives Types */ + 4 => array ( + 'fpclass', 'in_channel', 'out_channel', 'open_flag', 'Sys_error', 'format' + ), + /* finally Pervasives Exceptions */ + 5 => array ( + 'Exit', 'Invalid_Argument', 'Failure', 'Division_by_zero' + ) + ), + /* highlighting symbols is really important in OCaml */ + 'SYMBOLS' => array( + ';', '!', ':', '.', '=', '%', '^', '*', '-', '/', '+', + '>', '<', '(', ')', '[', ']', '&', '|', '#', "'" + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => true, /* functions name are case sensitive */ + 3 => true, /* types name too */ + 4 => true, /* pervasives types */ + 5 => true /* pervasives exceptions */ + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #06c; font-weight: bold;', /* nice blue */ + 2 => 'color: #06c; font-weight: bold;', /* nice blue */ + 3 => 'color: #06c; font-weight: bold;', /* nice blue */ + 4 => 'color: #06c; font-weight: bold;', /* nice blue */ + 5 => 'color: #06c; font-weight: bold;' /* nice blue */ + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #5d478b; font-style: italic;' /* light purple */ + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #6c6;' + ), + 'STRINGS' => array( + 0 => 'color: #3cb371;' /* nice green */ + ), + 'NUMBERS' => array( + 0 => 'color: #c6c;' /* pink */ + ), + 'METHODS' => array( + 1 => 'color: #060;' /* dark green */ + ), + 'REGEXPS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #a52a2a;' /* maroon */ + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + /* some of keywords are Pervasives functions (land, lxor, asr, ...) */ + 1 => '', + /* link to the wanted library */ + 2 => 'http://caml.inria.fr/pub/docs/manual-ocaml/libref/{FNAME}.html', + /* link to Pervasives functions */ + 3 => 'http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#VAL{FNAME}', + /* link to Pervasives type */ + 4 => 'http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#TYPE{FNAME}', + /* link to Pervasives exceptions */ + 5 => 'http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#EXCEPTION{FNAME}' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/oobas.php b/examples/includes/geshi/geshi/oobas.php new file mode 100644 index 0000000..5ca65cd --- /dev/null +++ b/examples/includes/geshi/geshi/oobas.php @@ -0,0 +1,135 @@ + 'OpenOffice.org Basic', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array(), + //Single-Line comments using REM keyword + 'COMMENT_REGEXP' => array(2 => '/\bREM.*?$/i'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'dim','private','public','global','as','if','redim','true','set','byval', + 'false','bool','double','integer','long','object','single','variant', + 'msgbox','print','inputbox','green','blue','red','qbcolor', + 'rgb','open','close','reset','freefile','get','input','line', + 'put','write','loc','seek','eof','lof','chdir','chdrive', + 'curdir','dir','fileattr','filecopy','filedatetime','fileexists', + 'filelen','getattr','kill','mkdir','name','rmdir','setattr', + 'dateserial','datevalue','day','month','weekday','year','cdatetoiso', + 'cdatefromiso','hour','minute','second','timeserial','timevalue', + 'date','now','time','timer','erl','err','error','on','goto','resume', + 'and','eqv','imp','not','or','xor','mod','atn','cos','sin','tan','log', + 'exp','rnd','randomize','sqr','fix','int','abs','sgn','hex','oct', + 'it','then','else','select','case','iif','do','loop','for','next','to', + 'while','wend','gosub','return','call','choose','declare', + 'end','exit','freelibrary','function','rem','stop','sub','switch','with', + 'cbool','cdate','cdbl','cint','clng','const','csng','cstr','defbool', + 'defdate','defdbl','defint','deflng','asc','chr','str','val','cbyte', + 'space','string','format','lcase','left','lset','ltrim','mid','right', + 'rset','rtrim','trim','ucase','split','join','converttourl','convertfromurl', + 'instr','len','strcomp','beep','shell','wait','getsystemticks','environ', + 'getsolarversion','getguitype','twipsperpixelx','twipsperpixely', + 'createunostruct','createunoservice','getprocessservicemanager', + 'createunodialog','createunolistener','createunovalue','thiscomponent', + 'globalscope' + ) + ), + 'SYMBOLS' => array( + '(', ')', '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080;', + 2 => 'color: #808080;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/oracle11.php b/examples/includes/geshi/geshi/oracle11.php new file mode 100644 index 0000000..7d267b1 --- /dev/null +++ b/examples/includes/geshi/geshi/oracle11.php @@ -0,0 +1,614 @@ + 'Oracle 11 SQL', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array("'", '"', '`'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( +//Put your package names here - e.g. select distinct ''''|| lower(name) || ''',' from user_source; +// 6 => array( +// ), + +//Put your table names here - e.g. select distinct ''''|| lower(table_name) || ''',' from user_tables; +// 5 => array( +// ), + +//Put your view names here - e.g. select distinct ''''|| lower(view_name) || ''',' from user_views; +// 4 => array( +// ), + +//Put your table field names here - e.g. select distinct ''''|| lower(column_name) || ''',' from user_tab_columns; +// 3 => array( +// ), + + //Put ORACLE reserved keywords here (11i). I like mine uppercase. + 1 => array( + 'ABS', + 'ACCESS', + 'ACOS', + 'ADD', + 'ADD_MONTHS', + 'ALL', + 'ALTER', + 'ANALYZE', + 'AND', + 'ANY', + 'APPENDCHILDXML', + 'ARRAY', + 'AS', + 'ASC', + 'ASCII', + 'ASCIISTR', + 'ASIN', + 'ASSOCIATE', + 'AT', + 'ATAN', + 'ATAN2', + 'AUDIT', + 'AUTHID', + 'AVG', + 'BEGIN', + 'BETWEEN', + 'BFILENAME', + 'BIN_TO_NUM', + 'BINARY_INTEGER', + 'BITAND', + 'BODY', + 'BOOLEAN', + 'BULK', + 'BY', + 'CALL', + 'CARDINALITY', + 'CASCADE', + 'CASE', + 'CAST', + 'CEIL', + 'CHAR', + 'CHAR_BASE', + 'CHARTOROWID', + 'CHECK', + 'CHR', + 'CLOSE', + 'CLUSTER', + 'CLUSTER_ID', + 'CLUSTER_PROBABILITY', + 'CLUSTER_SET', + 'COALESCE', + 'COLLECT', + 'COLUMN', + 'COMMENT', + 'COMMIT', + 'COMPOSE', + 'COMPRESS', + 'CONCAT', + 'CONNECT', + 'CONSTANT', + 'CONSTRAINT', + 'CONSTRAINTS', + 'CONTEXT', + 'CONTROLFILE', + 'CONVERT', + 'CORR', + 'CORR_K', + 'CORR_S', + 'COS', + 'COSH', + 'COST', + 'COUNT', + 'COVAR_POP', + 'COVAR_SAMP', + 'CREATE', + 'CUBE_TABLE', + 'CUME_DIST', + 'CURRENT', + 'CURRENT_DATE', + 'CURRENT_TIMESTAMP', + 'CURRVAL', + 'CURSOR', + 'CV', + 'DATABASE', + 'DATAOBJ_TO_PARTITION', + 'DATE', + 'DAY', + 'DBTIMEZONE', + 'DECIMAL', + 'DECLARE', + 'DECODE', + 'DECOMPOSE', + 'DEFAULT', + 'DELETE', + 'DELETEXML', + 'DENSE_RANK', + 'DEPTH', + 'DEREF', + 'DESC', + 'DIMENSION', + 'DIRECTORY', + 'DISASSOCIATE', + 'DISTINCT', + 'DO', + 'DROP', + 'DUMP', + 'ELSE', + 'ELSIF', + 'EMPTY_BLOB', + 'EMPTY_CLOB', + 'END', + 'EXCEPTION', + 'EXCLUSIVE', + 'EXEC', + 'EXECUTE', + 'EXISTS', + 'EXISTSNODE', + 'EXIT', + 'EXP', + 'EXPLAIN', + 'EXTENDS', + 'EXTRACT', + 'EXTRACTVALUE', + 'FALSE', + 'FEATURE_ID', + 'FEATURE_SET', + 'FEATURE_VALUE', + 'FETCH', + 'FILE', + 'FIRST', + 'FIRST_VALUE', + 'FLOAT', + 'FLOOR', + 'FOR', + 'FORALL', + 'FROM', + 'FROM_TZ', + 'FUNCTION', + 'GOTO', + 'GRANT', + 'GREATEST', + 'GROUP', + 'GROUP_ID', + 'GROUPING', + 'GROUPING_ID', + 'HAVING', + 'HEAP', + 'HEXTORAW', + 'HOUR', + 'IDENTIFIED', + 'IF', + 'IMMEDIATE', + 'IN', + 'INCREMENT', + 'INDEX', + 'INDEXTYPE', + 'INDICATOR', + 'INITCAP', + 'INITIAL', + 'INSERT', + 'INSERTCHILDXML', + 'INSERTXMLBEFORE', + 'INSTR', + 'INSTRB', + 'INTEGER', + 'INTERFACE', + 'INTERSECT', + 'INTERVAL', + 'INTO', + 'IS', + 'ISOLATION', + 'ITERATION_NUMBER', + 'JAVA', + 'KEY', + 'LAG', + 'LAST', + 'LAST_DAY', + 'LAST_VALUE', + 'LEAD', + 'LEAST', + 'LENGTH', + 'LENGTHB', + 'LEVEL', + 'LIBRARY', + 'LIKE', + 'LIMITED', + 'LINK', + 'LN', + 'LNNVL', + 'LOCALTIMESTAMP', + 'LOCK', + 'LOG', + 'LONG', + 'LOOP', + 'LOWER', + 'LPAD', + 'LTRIM', + 'MAKE_REF', + 'MATERIALIZED', + 'MAX', + 'MAXEXTENTS', + 'MEDIAN', + 'MIN', + 'MINUS', + 'MINUTE', + 'MLSLABEL', + 'MOD', + 'MODE', + 'MODIFY', + 'MONTH', + 'MONTHS_BETWEEN', + 'NANVL', + 'NATURAL', + 'NATURALN', + 'NCHR', + 'NEW', + 'NEW_TIME', + 'NEXT_DAY', + 'NEXTVAL', + 'NLS_CHARSET_DECL_LEN', + 'NLS_CHARSET_ID', + 'NLS_CHARSET_NAME', + 'NLS_INITCAP', + 'NLS_LOWER', + 'NLS_UPPER', + 'NLSSORT', + 'NOAUDIT', + 'NOCOMPRESS', + 'NOCOPY', + 'NOT', + 'NOWAIT', + 'NTILE', + 'NULL', + 'NULLIF', + 'NUMBER', + 'NUMBER_BASE', + 'NUMTODSINTERVAL', + 'NUMTOYMINTERVAL', + 'NVL', + 'NVL2', + 'OCIROWID', + 'OF', + 'OFFLINE', + 'ON', + 'ONLINE', + 'OPAQUE', + 'OPEN', + 'OPERATOR', + 'OPTION', + 'OR', + 'ORA_HASH', + 'ORDER', + 'ORGANIZATION', + 'OTHERS', + 'OUT', + 'OUTLINE', + 'PACKAGE', + 'PARTITION', + 'PATH', + 'PCTFREE', + 'PERCENT_RANK', + 'PERCENTILE_CONT', + 'PERCENTILE_DISC', + 'PLAN', + 'PLS_INTEGER', + 'POSITIVE', + 'POSITIVEN', + 'POWER', + 'POWERMULTISET', + 'POWERMULTISET_BY_CARDINALITY', + 'PRAGMA', + 'PREDICTION', + 'PREDICTION_BOUNDS', + 'PREDICTION_COST', + 'PREDICTION_DETAILS', + 'PREDICTION_PROBABILITY', + 'PREDICTION_SET', + 'PRESENTNNV', + 'PRESENTV', + 'PREVIOUS', + 'PRIMARY', + 'PRIOR', + 'PRIVATE', + 'PRIVILEGES', + 'PROCEDURE', + 'PROFILE', + 'PUBLIC', + 'RAISE', + 'RANGE', + 'RANK', + 'RATIO_TO_REPORT', + 'RAW', + 'RAWTOHEX', + 'RAWTONHEX', + 'REAL', + 'RECORD', + 'REF', + 'REFTOHEX', + 'REGEXP_COUNT', + 'REGEXP_INSTR', + 'REGEXP_REPLACE', + 'REGEXP_SUBSTR', + 'REGR_AVGX', + 'REGR_AVGY', + 'REGR_COUNT', + 'REGR_INTERCEPT', + 'REGR_R2', + 'REGR_SLOPE', + 'REGR_SXX', + 'REGR_SXY', + 'REGR_SYY', + 'RELEASE', + 'REMAINDER', + 'RENAME', + 'REPLACE', + 'RESOURCE', + 'RETURN', + 'RETURNING', + 'REVERSE', + 'REVOKE', + 'ROLE', + 'ROLLBACK', + 'ROUND', + 'ROW', + 'ROW_NUMBER', + 'ROWID', + 'ROWIDTOCHAR', + 'ROWIDTONCHAR', + 'ROWNUM', + 'ROWS', + 'ROWTYPE', + 'RPAD', + 'RTRIM', + 'SAVEPOINT', + 'SCHEMA', + 'SCN_TO_TIMESTAMP', + 'SECOND', + 'SEGMENT', + 'SELECT', + 'SEPERATE', + 'SEQUENCE', + 'SESSION', + 'SESSIONTIMEZONE', + 'SET', + 'SHARE', + 'SIGN', + 'SIN', + 'SINH', + 'SIZE', + 'SMALLINT', + 'SOUNDEX', + 'SPACE', + 'SQL', + 'SQLCODE', + 'SQLERRM', + 'SQRT', + 'START', + 'STATISTICS', + 'STATS_BINOMIAL_TEST', + 'STATS_CROSSTAB', + 'STATS_F_TEST', + 'STATS_KS_TEST', + 'STATS_MODE', + 'STATS_MW_TEST', + 'STATS_ONE_WAY_ANOVA', + 'STATS_T_TEST_INDEP', + 'STATS_T_TEST_INDEPU', + 'STATS_T_TEST_ONE', + 'STATS_T_TEST_PAIRED', + 'STATS_WSR_TEST', + 'STDDEV', + 'STDDEV_POP', + 'STDDEV_SAMP', + 'STOP', + 'SUBSTR', + 'SUBSTRB', + 'SUBTYPE', + 'SUCCESSFUL', + 'SUM', + 'SYNONYM', + 'SYS_CONNECT_BY_PATH', + 'SYS_CONTEXT', + 'SYS_DBURIGEN', + 'SYS_EXTRACT_UTC', + 'SYS_GUID', + 'SYS_TYPEID', + 'SYS_XMLAGG', + 'SYS_XMLGEN', + 'SYSDATE', + 'SYSTEM', + 'SYSTIMESTAMP', + 'TABLE', + 'TABLESPACE', + 'TAN', + 'TANH', + 'TEMPORARY', + 'THEN', + 'TIME', + 'TIMESTAMP', + 'TIMESTAMP_TO_SCN', + 'TIMEZONE_ABBR', + 'TIMEZONE_HOUR', + 'TIMEZONE_MINUTE', + 'TIMEZONE_REGION', + 'TIMING', + 'TO', + 'TO_BINARY_DOUBLE', + 'TO_BINARY_FLOAT', + 'TO_CHAR', + 'TO_CLOB', + 'TO_DATE', + 'TO_DSINTERVAL', + 'TO_LOB', + 'TO_MULTI_BYTE', + 'TO_NCHAR', + 'TO_NCLOB', + 'TO_NUMBER', + 'TO_SINGLE_BYTE', + 'TO_TIMESTAMP', + 'TO_TIMESTAMP_TZ', + 'TO_YMINTERVAL', + 'TRANSACTION', + 'TRANSLATE', + 'TREAT', + 'TRIGGER', + 'TRIM', + 'TRUE', + 'TRUNC', + 'TRUNCATE', + 'TYPE', + 'TZ_OFFSET', + 'UI', + 'UID', + 'UNION', + 'UNIQUE', + 'UNISTR', + 'UPDATE', + 'UPDATEXML', + 'UPPER', + 'USE', + 'USER', + 'USERENV', + 'USING', + 'VALIDATE', + 'VALUE', + 'VALUES', + 'VAR_POP', + 'VAR_SAMP', + 'VARCHAR', + 'VARCHAR2', + 'VARIANCE', + 'VIEW', + 'VSIZE', + 'WHEN', + 'WHENEVER', + 'WHERE', + 'WHILE', + 'WIDTH_BUCKET', + 'WITH', + 'WORK', + 'WRITE', + 'XMLAGG', + 'XMLCAST', + 'XMLCDATA', + 'XMLCOLATTVAL', + 'XMLCOMMENT', + 'XMLCONCAT', + 'XMLDIFF', + 'XMLELEMENT', + 'XMLEXISTS', + 'XMLFOREST', + 'XMLPARSE', + 'XMLPATCH', + 'XMLPI', + 'XMLQUERY', + 'XMLROOT', + 'XMLSEQUENCE', + 'XMLSERIALIZE', + 'XMLTABLE', + 'XMLTRANSFORM', + 'YEAR', + 'ZONE' + ) + ), + 'SYMBOLS' => array( + '(', ')', '=', '<', '>', '|', '+', '-', '*', '/', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, +// 3 => false, +// 4 => false, +// 5 => false, +// 6 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #993333; font-weight: bold; text-transform: uppercase;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #ff0000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', +// 3 => '', +// 4 => '', +// 5 => '', +// 6 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/oracle8.php b/examples/includes/geshi/geshi/oracle8.php new file mode 100644 index 0000000..d54b1e3 --- /dev/null +++ b/examples/includes/geshi/geshi/oracle8.php @@ -0,0 +1,496 @@ + 'Oracle 8 SQL', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array("'", '"', '`'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( +//Put your package names here - e.g. select distinct ''''|| lower(name) || ''',' from user_source; +// 6 => array( +// ), + +//Put your table names here - e.g. select distinct ''''|| lower(table_name) || ''',' from user_tables; +// 5 => array( +// ), + +//Put your view names here - e.g. select distinct ''''|| lower(view_name) || ''',' from user_views; +// 4 => array( +// ), + +//Put your table field names here - e.g. select distinct ''''|| lower(column_name) || ''',' from user_tab_columns; +// 3 => array( +// ), + +//Put ORACLE reserved keywords here (8.1.7). I like mine uppercase. + 1 => array( + 'ABS', + 'ACCESS', + 'ACOS', + 'ADD', + 'ADD_MONTHS', + 'ALL', + 'ALTER', + 'ANALYZE', + 'AND', + 'ANY', + 'ARRAY', + 'AS', + 'ASC', + 'ASCII', + 'ASIN', + 'ASSOCIATE', + 'AT', + 'ATAN', + 'ATAN2', + 'AUDIT', + 'AUTHID', + 'AVG', + 'BEGIN', + 'BETWEEN', + 'BFILENAME', + 'BINARY_INTEGER', + 'BITAND', + 'BODY', + 'BOOLEAN', + 'BULK', + 'BY', + 'CALL', + 'CASCADE', + 'CASE', + 'CEIL', + 'CHAR', + 'CHAR_BASE', + 'CHARTOROWID', + 'CHECK', + 'CHR', + 'CLOSE', + 'CLUSTER', + 'COALESCE', + 'COLLECT', + 'COLUMN', + 'COMMENT', + 'COMMIT', + 'COMPRESS', + 'CONCAT', + 'CONNECT', + 'CONSTANT', + 'CONSTRAINT', + 'CONSTRAINTS', + 'CONTEXT', + 'CONTROLFILE', + 'CONVERT', + 'CORR', + 'COS', + 'COSH', + 'COST', + 'COUNT', + 'COVAR_POP', + 'COVAR_SAMP', + 'CREATE', + 'CUME_DIST', + 'CURRENT', + 'CURRVAL', + 'CURSOR', + 'DATABASE', + 'DATE', + 'DAY', + 'DECIMAL', + 'DECLARE', + 'DECODE', + 'DEFAULT', + 'DELETE', + 'DENSE_RANK', + 'DEREF', + 'DESC', + 'DIMENSION', + 'DIRECTORY', + 'DISASSOCIATE', + 'DISTINCT', + 'DO', + 'DROP', + 'DUMP', + 'ELSE', + 'ELSIF', + 'EMPTY_BLOB', + 'EMPTY_CLOB', + 'END', + 'EXCEPTION', + 'EXCLUSIVE', + 'EXEC', + 'EXECUTE', + 'EXISTS', + 'EXIT', + 'EXP', + 'EXPLAIN', + 'EXTENDS', + 'EXTRACT', + 'FALSE', + 'FETCH', + 'FILE', + 'FIRST_VALUE', + 'FLOAT', + 'FLOOR', + 'FOR', + 'FORALL', + 'FROM', + 'FUNCTION', + 'GOTO', + 'GRANT', + 'GREATEST', + 'GROUP', + 'GROUPING', + 'HAVING', + 'HEAP', + 'HEXTORAW', + 'HOUR', + 'IDENTIFIED', + 'IF', + 'IMMEDIATE', + 'IN', + 'INCREMENT', + 'INDEX', + 'INDEXTYPE', + 'INDICATOR', + 'INITCAP', + 'INITIAL', + 'INSERT', + 'INSTR', + 'INSTRB', + 'INTEGER', + 'INTERFACE', + 'INTERSECT', + 'INTERVAL', + 'INTO', + 'IS', + 'ISOLATION', + 'JAVA', + 'KEY', + 'LAG', + 'LAST_DAY', + 'LAST_VALUE', + 'LEAD', + 'LEAST', + 'LENGTH', + 'LENGTHB', + 'LEVEL', + 'LIBRARY', + 'LIKE', + 'LIMITED', + 'LINK', + 'LN', + 'LOCK', + 'LOG', + 'LONG', + 'LOOP', + 'LOWER', + 'LPAD', + 'LTRIM', + 'MAKE_REF', + 'MATERIALIZED', + 'MAX', + 'MAXEXTENTS', + 'MIN', + 'MINUS', + 'MINUTE', + 'MLSLABEL', + 'MOD', + 'MODE', + 'MODIFY', + 'MONTH', + 'MONTHS_BETWEEN', + 'NATURAL', + 'NATURALN', + 'NEW', + 'NEW_TIME', + 'NEXT_DAY', + 'NEXTVAL', + 'NLS_CHARSET_DECL_LEN', + 'NLS_CHARSET_ID', + 'NLS_CHARSET_NAME', + 'NLS_INITCAP', + 'NLS_LOWER', + 'NLS_UPPER', + 'NLSSORT', + 'NOAUDIT', + 'NOCOMPRESS', + 'NOCOPY', + 'NOT', + 'NOWAIT', + 'NTILE', + 'NULL', + 'NULLIF', + 'NUMBER', + 'NUMBER_BASE', + 'NUMTODSINTERVAL', + 'NUMTOYMINTERVAL', + 'NVL', + 'NVL2', + 'OCIROWID', + 'OF', + 'OFFLINE', + 'ON', + 'ONLINE', + 'OPAQUE', + 'OPEN', + 'OPERATOR', + 'OPTION', + 'OR', + 'ORDER', + 'ORGANIZATION', + 'OTHERS', + 'OUT', + 'OUTLINE', + 'PACKAGE', + 'PARTITION', + 'PCTFREE', + 'PERCENT_RANK', + 'PLAN', + 'PLS_INTEGER', + 'POSITIVE', + 'POSITIVEN', + 'POWER', + 'PRAGMA', + 'PRIMARY', + 'PRIOR', + 'PRIVATE', + 'PRIVILEGES', + 'PROCEDURE', + 'PROFILE', + 'PUBLIC', + 'RAISE', + 'RANGE', + 'RANK', + 'RATIO_TO_REPORT', + 'RAW', + 'RAWTOHEX', + 'REAL', + 'RECORD', + 'REF', + 'REFTOHEX', + 'REGR_AVGX', + 'REGR_AVGY', + 'REGR_COUNT', + 'REGR_INTERCEPT', + 'REGR_R2', + 'REGR_SLOPE', + 'REGR_SXX', + 'REGR_SXY', + 'REGR_SYY', + 'RELEASE', + 'RENAME', + 'REPLACE', + 'RESOURCE', + 'RETURN', + 'RETURNING', + 'REVERSE', + 'REVOKE', + 'ROLE', + 'ROLLBACK', + 'ROUND', + 'ROW', + 'ROW_NUMBER', + 'ROWID', + 'ROWIDTOCHAR', + 'ROWNUM', + 'ROWS', + 'ROWTYPE', + 'RPAD', + 'RTRIM', + 'SAVEPOINT', + 'SCHEMA', + 'SECOND', + 'SEGMENT', + 'SELECT', + 'SEPERATE', + 'SEQUENCE', + 'SESSION', + 'SET', + 'SHARE', + 'SIGN', + 'SIN', + 'SINH', + 'SIZE', + 'SMALLINT', + 'SOUNDEX', + 'SPACE', + 'SQL', + 'SQLCODE', + 'SQLERRM', + 'SQRT', + 'START', + 'STATISTICS', + 'STDDEV', + 'STDDEV_POP', + 'STDDEV_SAMP', + 'STOP', + 'SUBSTR', + 'SUBSTRB', + 'SUBTYPE', + 'SUCCESSFUL', + 'SUM', + 'SYNONYM', + 'SYS_CONTEXT', + 'SYS_GUID', + 'SYSDATE', + 'SYSTEM', + 'TABLE', + 'TABLESPACE', + 'TAN', + 'TANH', + 'TEMPORARY', + 'THEN', + 'TIME', + 'TIMESTAMP', + 'TIMEZONE_ABBR', + 'TIMEZONE_HOUR', + 'TIMEZONE_MINUTE', + 'TIMEZONE_REGION', + 'TIMING', + 'TO', + 'TO_CHAR', + 'TO_DATE', + 'TO_LOB', + 'TO_MULTI_BYTE', + 'TO_NUMBER', + 'TO_SINGLE_BYTE', + 'TRANSACTION', + 'TRANSLATE', + 'TRIGGER', + 'TRIM', + 'TRUE', + 'TRUNC', + 'TRUNCATE', + 'TYPE', + 'UI', + 'UID', + 'UNION', + 'UNIQUE', + 'UPDATE', + 'UPPER', + 'USE', + 'USER', + 'USERENV', + 'USING', + 'VALIDATE', + 'VALUE', + 'VALUES', + 'VAR_POP', + 'VAR_SAMP', + 'VARCHAR', + 'VARCHAR2', + 'VARIANCE', + 'VIEW', + 'VSIZE', + 'WHEN', + 'WHENEVER', + 'WHERE', + 'WHILE', + 'WITH', + 'WORK', + 'WRITE', + 'YEAR', + 'ZONE' + ) + ), + 'SYMBOLS' => array( + '(', ')', '=', '<', '>', '|', '+', '-', '*', '/', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, +// 3 => false, +// 4 => false, +// 5 => false, +// 6 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #993333; font-weight: bold; text-transform: uppercase;' +//Add the styles for groups 3-6 here when used + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #ff0000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', +// 3 => '', +// 4 => '', +// 5 => '', +// 6 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/pascal.php b/examples/includes/geshi/geshi/pascal.php new file mode 100644 index 0000000..d2acd0f --- /dev/null +++ b/examples/includes/geshi/geshi/pascal.php @@ -0,0 +1,152 @@ + 'Pascal', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('{' => '}','(*' => '*)'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array("''"), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'absolute','asm','assembler','begin','break','case','catch','cdecl', + 'const','constructor','default','destructor','div','do','downto', + 'else','end','except','export','exports','external','far', + 'finalization','finally','for','forward','function','goto','if', + 'implementation','in','index','inherited','initialization','inline', + 'interface','interrupt','label','library','mod','name','not','of', + 'or','overload','override','private','procedure','program', + 'property','protected','public','published','raise','repeat', + 'resourcestring','shl','shr','stdcall','stored','switch','then', + 'to','try','type','unit','until','uses','var','while','xor' + ), + 2 => array( + 'nil', 'false', 'true', + ), + 3 => array( + 'abs','and','arc','arctan','blockread','blockwrite','chr','dispose', + 'cos','eof','eoln','exp','get','ln','new','odd','ord','ordinal', + 'pred','read','readln','sin','sqrt','succ','write','writeln' + ), + 4 => array( + 'ansistring','array','boolean','byte','bytebool','char','file', + 'integer','longbool','longint','object','packed','pointer','real', + 'record','set','shortint','smallint','string','union','word' + ), + ), + 'SYMBOLS' => array( + ',', ':', '=', '+', '-', '*', '/' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;', + 4 => 'color: #000066; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;', + 'HARD' => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #0066ee;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/per.php b/examples/includes/geshi/geshi/per.php new file mode 100644 index 0000000..092aae0 --- /dev/null +++ b/examples/includes/geshi/geshi/per.php @@ -0,0 +1,302 @@ + 'per', + 'COMMENT_SINGLE' => array(1 => '--', 2 => '#'), + 'COMMENT_MULTI' => array('{' => '}'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + "ACCELERATOR", + "ACCELERATOR2", + "ACTION", + "ALT", + "AND", + "AUTO", + "AUTONEXT", + "AUTOSCALE", + "BETWEEN", + "BOTH", + "BUTTON", + "BUTTONEDIT", + "BUTTONTEXTHIDDEN", + "BY", + "BYTE", + "CANVAS", + "CENTER", + "CHECKBOX", + "CLASS", + "COLOR", + "COLUMNS", + "COMBOBOX", + "COMMAND", + "COMMENT", + "COMMENTS", + "COMPACT", + "COMPRESS", + "CONFIG", + "CONTROL", + "CURRENT", + "DATABASE", + "DATEEDIT", + "DEC", + "DEFAULT", + "DEFAULTS", + "DELIMITERS", + "DISPLAY", + "DISPLAYONLY", + "DOWNSHIFT", + "DYNAMIC", + "EDIT", + "FIXED", + "FOLDER", + "FONTPITCH", + "FORMAT", + "FORMONLY", + "GRID", + "GRIDCHILDRENINPARENT", + "GROUP", + "HBOX", + "HEIGHT", + "HIDDEN", + "HORIZONTAL", + "INCLUDE", + "INITIAL", + "INITIALIZER", + "INPUT", + "INSTRUCTIONS", + "INTERVAL", + "INVISIBLE", + "IS", + "ITEM", + "ITEMS", + "JUSTIFY", + "KEY", + "KEYS", + "LABEL", + "LEFT", + "LIKE", + "LINES", + "MATCHES", + "NAME", + "NOENTRY", + "NONCOMPRESS", + "NORMAL", + "NOT", + "NOUPDATE", + "OPTIONS", + "OR", + "ORIENTATION", + "PACKED", + "PAGE", + "PICTURE", + "PIXELHEIGHT", + "PIXELS", + "PIXELWIDTH", + "POINTS", + "PROGRAM", + "PROGRESSBAR", + "QUERYCLEAR", + "QUERYEDITABLE", + "RADIOGROUP", + "RECORD", + "REQUIRED", + "REVERSE", + "RIGHT", + "SAMPLE", + "SCREEN", + "SCROLL", + "SCROLLBARS", + "SCROLLGRID", + "SECOND", + "SEPARATOR", + "SHIFT", + "SIZE", + "SIZEPOLICY", + "SMALLFLOAT", + "SMALLINT", + "SPACING", + "STRETCH", + "STYLE", + "TABINDEX", + "TABLE", + "TAG", + "TEXT", + "TEXTEDIT", + "THROUGH", + "THRU", + "TITLE", + "TO", + "TOOLBAR", + "TOPMENU", + "TYPE", + "UNHIDABLE", + "UNHIDABLECOLUMNS", + "UNMOVABLE", + "UNMOVABLECOLUMNS", + "UNSIZABLE", + "UNSIZABLECOLUMNS", + "UNSORTABLE", + "UNSORTABLECOLUMNS", + "UPSHIFT", + "USER", + "VALIDATE", + "VALUECHECKED", + "VALUEMAX", + "VALUEMIN", + "VALUEUNCHECKED", + "VARCHAR", + "VARIABLE", + "VBOX", + "VERIFY", + "VERSION", + "VERTICAL", + "TIMESTAMP", + "WANTCOLUMNSANCHORED", /* to be removed! */ + "WANTFIXEDPAGESIZE", + "WANTNORETURNS", + "WANTTABS", + "WHERE", + "WIDGET", + "WIDTH", + "WINDOWSTYLE", + "WITHOUT", + "WORDWRAP", + "X", + "Y", + "ZEROFILL", + "SCHEMA", + "ATTRIBUTES", + "TABLES", + "LAYOUT", + "END" + ), + 2 => array( + "YEAR", + "BLACK", + "BLINK", + "BLUE", + "YELLOW", + "WHITE", + "UNDERLINE", + "CENTURY", + "FRACTION", + "CHAR", + "CHARACTER", + "CHARACTERS", + "CYAN", + "DATE", + "DATETIME", + "DAY", + "DECIMAL", + "FALSE", + "FLOAT", + "GREEN", + "HOUR", + "INT", + "INTEGER", + "MAGENTA", + "MINUTE", + "MONEY", + "NONE", + "NULL", + "REAL", + "RED", + "TRUE", + "TODAY", + "MONTH", + "IMAGE" + ), + ), + 'SYMBOLS' => array( + '+', '-', '*', '?', '=', '/', '%', '>', '<', '^', '!', '|', ':', + '(', ')', '[', ']' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0600FF;', + 2 => 'color: #0000FF; font-weight: bold;', + ), + 'COMMENTS' => array( + 1 => 'color: #008080; font-style: italic;', + 2 => 'color: #008080;', + 'MULTI' => 'color: green' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008080; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #808080;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF0000;' + ), + 'METHODS' => array( + 1 => 'color: #0000FF;', + 2 => 'color: #0000FF;' + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/perl.php b/examples/includes/geshi/geshi/perl.php new file mode 100644 index 0000000..f8ac096 --- /dev/null +++ b/examples/includes/geshi/geshi/perl.php @@ -0,0 +1,213 @@ + 'Perl', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array( + '=back' => '=cut', + '=head' => '=cut', + '=item' => '=cut', + '=over' => '=cut', + '=begin' => '=cut', + '=end' => '=cut', + '=for' => '=cut', + '=encoding' => '=cut', + '=pod' => '=cut' + ), + 'COMMENT_REGEXP' => array( + //Regular expressions + 2 => "/(?<=[\\s^])(s|tr|y)\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/(?:\\\\.|(?!\n)[^\\/\\\\])*\\/[msixpogcde]*(?=[\\s$\\.\\;])|(?<=[\\s^(=])(m|q[qrwx]?)?\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[msixpogc]*(?=[\\s$\\.\\,\\;\\)])/iU", + //Regular expression match variables + 3 => '/\$\d+/', + //Heredoc + 4 => '/<<\s*?([\'"]?)([a-zA-Z0-9]+)\1;[^\n]*?\\n.*\\n\\2(?![a-zA-Z0-9])/siU', + //Predefined variables + 5 => '/\$(\^[a-zA-Z]?|[\*\$`\'&_\.,+\-~:;\\\\\/"\|%=\?!@#<>\(\)\[\]])(?!\w)|@[_+\-]|%[!]|\$(?=\{)/', + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"','`'), + 'HARDQUOTE' => array("'", "'"), // An optional 2-element array defining the beginning and end of a hard-quoted string + 'HARDESCAPE' => array('\\\'',), + // Things that must still be escaped inside a hard-quoted string + // If HARDQUOTE is defined, HARDESCAPE must be defined + // This will not work unless the first character of each element is either in the + // QUOTEMARKS array or is the ESCAPE_CHAR + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'case', 'do', 'else', 'elsif', 'for', 'if', 'then', 'until', 'while', 'foreach', 'my', + 'xor', 'or', 'and', 'unless', 'next', 'last', 'redo', 'not', 'our', + 'reset', 'continue', 'cmp', 'ne', 'eq', 'lt', 'gt', 'le', 'ge', + ), + 2 => array( + 'use', 'sub', 'new', '__END__', '__DATA__', '__DIE__', '__WARN__', 'BEGIN', + 'STDIN', 'STDOUT', 'STDERR', 'ARGV', 'ARGVOUT' + ), + 3 => array( + 'abs', 'accept', 'alarm', 'atan2', 'bind', 'binmode', 'bless', + 'caller', 'chdir', 'chmod', 'chomp', 'chop', 'chown', 'chr', + 'chroot', 'close', 'closedir', 'connect', 'cos', + 'crypt', 'dbmclose', 'dbmopen', 'defined', 'delete', 'die', + 'dump', 'each', 'endgrent', 'endhostent', 'endnetent', 'endprotoent', + 'endpwent', 'endservent', 'eof', 'eval', 'exec', 'exists', 'exit', + 'exp', 'fcntl', 'fileno', 'flock', 'fork', 'format', 'formline', + 'getc', 'getgrent', 'getgrgid', 'getgrnam', 'gethostbyaddr', + 'gethostbyname', 'gethostent', 'getlogin', 'getnetbyaddr', 'getnetbyname', + 'getnetent', 'getpeername', 'getpgrp', 'getppid', 'getpriority', + 'getprotobyname', 'getprotobynumber', 'getprotoent', 'getpwent', + 'getpwnam', 'getpwuid', 'getservbyname', 'getservbyport', 'getservent', + 'getsockname', 'getsockopt', 'glob', 'gmtime', 'goto', 'grep', + 'hex', 'import', 'index', 'int', 'ioctl', 'join', 'keys', 'kill', + 'lc', 'lcfirst', 'length', 'link', 'listen', 'local', + 'localtime', 'log', 'lstat', 'm', 'map', 'mkdir', 'msgctl', 'msgget', + 'msgrcv', 'msgsnd', 'no', 'oct', 'open', 'opendir', + 'ord', 'pack', 'package', 'pipe', 'pop', 'pos', 'print', + 'printf', 'prototype', 'push', 'qq', 'qr', 'quotemeta', 'qw', + 'qx', 'q', 'rand', 'read', 'readdir', 'readline', 'readlink', 'readpipe', + 'recv', 'ref', 'rename', 'require', 'return', + 'reverse', 'rewinddir', 'rindex', 'rmdir', 's', 'scalar', 'seek', + 'seekdir', 'select', 'semctl', 'semget', 'semop', 'send', 'setgrent', + 'sethostent', 'setnetent', 'setpgrp', 'setpriority', 'setprotoent', + 'setpwent', 'setservent', 'setsockopt', 'shift', 'shmctl', 'shmget', + 'shmread', 'shmwrite', 'shutdown', 'sin', 'sleep', 'socket', 'socketpair', + 'sort', 'splice', 'split', 'sprintf', 'sqrt', 'srand', 'stat', + 'study', 'substr', 'symlink', 'syscall', 'sysopen', 'sysread', + 'sysseek', 'system', 'syswrite', 'tell', 'telldir', 'tie', 'tied', + 'time', 'times', 'tr', 'truncate', 'uc', 'ucfirst', 'umask', 'undef', + 'unlink', 'unpack', 'unshift', 'untie', 'utime', 'values', + 'vec', 'wait', 'waitpid', 'wantarray', 'warn', 'write', 'y' + ) + ), + 'SYMBOLS' => array( + '<', '>', '=', + '!', '@', '~', '&', '|', '^', + '+','-', '*', '/', '%', + ',', ';', '?', '.', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #009966; font-style: italic;', + 3 => 'color: #0000ff;', + 4 => 'color: #cc0000; font-style: italic;', + 5 => 'color: #0000ff;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;', + 'HARD' => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;', + 4 => 'color: #009999;', + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://perldoc.perl.org/functions/{FNAMEL}.html' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '->', + 2 => '::' + ), + 'REGEXPS' => array( + //Variable + 0 => '(?:\$[\$#]?|\\\\(?:[@%*]?|\\\\*\$|&)|%[$]?|@[$]?|\*[$]?|&[$]?)[a-zA-Z_][a-zA-Z0-9_]*', + //File Descriptor + 4 => '<[a-zA-Z_][a-zA-Z0-9_]*>', + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'COMMENTS' => array( + 'DISALLOWED_BEFORE' => '$' + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/php-brief.php b/examples/includes/geshi/geshi/php-brief.php new file mode 100644 index 0000000..dd6781d --- /dev/null +++ b/examples/includes/geshi/geshi/php-brief.php @@ -0,0 +1,202 @@ + 'PHP (brief)', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + //Heredoc and Nowdoc syntax + 'COMMENT_REGEXP' => array(3 => '/<<<\s*?(\'?)([a-zA-Z0-9]+)\1[^\n]*?\\n.*\\n\\2(?![a-zA-Z0-9])/siU'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array("\'"), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | + GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'include', 'require', 'include_once', 'require_once', + 'for', 'as', 'foreach', 'if', 'elseif', 'else', 'while', 'do', 'endwhile', 'endif', 'switch', 'case', 'endswitch', + 'return', 'break' + ), + 2 => array( + 'null', '__LINE__', '__FILE__', + 'false', '<?php', + 'true', 'var', 'default', + 'function', 'class', 'new', '&new', 'public', 'private', 'interface', 'extends', + 'const', 'self' + ), + 3 => array( + 'func_num_args', 'func_get_arg', 'func_get_args', 'strlen', 'strcmp', 'strncmp', 'strcasecmp', 'strncasecmp', 'each', 'error_reporting', 'define', 'defined', + 'trigger_error', 'user_error', 'set_error_handler', 'restore_error_handler', 'get_declared_classes', 'get_loaded_extensions', + 'extension_loaded', 'get_extension_funcs', 'debug_backtrace', + 'constant', 'bin2hex', 'sleep', 'usleep', 'time', 'mktime', 'gmmktime', 'strftime', 'gmstrftime', 'strtotime', 'date', 'gmdate', 'getdate', 'localtime', 'checkdate', 'flush', 'wordwrap', 'htmlspecialchars', 'htmlentities', 'html_entity_decode', 'md5', 'md5_file', 'crc32', 'getimagesize', 'image_type_to_mime_type', 'phpinfo', 'phpversion', 'phpcredits', 'strnatcmp', 'strnatcasecmp', 'substr_count', 'strspn', 'strcspn', 'strtok', 'strtoupper', 'strtolower', 'strpos', 'strrpos', 'strrev', 'hebrev', 'hebrevc', 'nl2br', 'basename', 'dirname', 'pathinfo', 'stripslashes', 'stripcslashes', 'strstr', 'stristr', 'strrchr', 'str_shuffle', 'str_word_count', 'strcoll', 'substr', 'substr_replace', 'quotemeta', 'ucfirst', 'ucwords', 'strtr', 'addslashes', 'addcslashes', 'rtrim', 'str_replace', 'str_repeat', 'count_chars', 'chunk_split', 'trim', 'ltrim', 'strip_tags', 'similar_text', 'explode', 'implode', 'setlocale', 'localeconv', + 'parse_str', 'str_pad', 'chop', 'strchr', 'sprintf', 'printf', 'vprintf', 'vsprintf', 'sscanf', 'fscanf', 'parse_url', 'urlencode', 'urldecode', 'rawurlencode', 'rawurldecode', 'readlink', 'linkinfo', 'link', 'unlink', 'exec', 'system', 'escapeshellcmd', 'escapeshellarg', 'passthru', 'shell_exec', 'proc_open', 'proc_close', 'rand', 'srand', 'getrandmax', 'mt_rand', 'mt_srand', 'mt_getrandmax', 'base64_decode', 'base64_encode', 'abs', 'ceil', 'floor', 'round', 'is_finite', 'is_nan', 'is_infinite', 'bindec', 'hexdec', 'octdec', 'decbin', 'decoct', 'dechex', 'base_convert', 'number_format', 'fmod', 'ip2long', 'long2ip', 'getenv', 'putenv', 'getopt', 'microtime', 'gettimeofday', 'getrusage', 'uniqid', 'quoted_printable_decode', 'set_time_limit', 'get_cfg_var', 'magic_quotes_runtime', 'set_magic_quotes_runtime', 'get_magic_quotes_gpc', 'get_magic_quotes_runtime', + 'import_request_variables', 'error_log', 'serialize', 'unserialize', 'memory_get_usage', 'var_dump', 'var_export', 'debug_zval_dump', 'print_r','highlight_file', 'show_source', 'highlight_string', 'ini_get', 'ini_get_all', 'ini_set', 'ini_alter', 'ini_restore', 'get_include_path', 'set_include_path', 'restore_include_path', 'setcookie', 'header', 'headers_sent', 'connection_aborted', 'connection_status', 'ignore_user_abort', 'parse_ini_file', 'is_uploaded_file', 'move_uploaded_file', 'intval', 'floatval', 'doubleval', 'strval', 'gettype', 'settype', 'is_null', 'is_resource', 'is_bool', 'is_long', 'is_float', 'is_int', 'is_integer', 'is_double', 'is_real', 'is_numeric', 'is_string', 'is_array', 'is_object', 'is_scalar', + 'ereg', 'ereg_replace', 'eregi', 'eregi_replace', 'split', 'spliti', 'join', 'sql_regcase', 'dl', 'pclose', 'popen', 'readfile', 'rewind', 'rmdir', 'umask', 'fclose', 'feof', 'fgetc', 'fgets', 'fgetss', 'fread', 'fopen', 'fpassthru', 'ftruncate', 'fstat', 'fseek', 'ftell', 'fflush', 'fwrite', 'fputs', 'mkdir', 'rename', 'copy', 'tempnam', 'tmpfile', 'file', 'file_get_contents', 'stream_select', 'stream_context_create', 'stream_context_set_params', 'stream_context_set_option', 'stream_context_get_options', 'stream_filter_prepend', 'stream_filter_append', 'fgetcsv', 'flock', 'get_meta_tags', 'stream_set_write_buffer', 'set_file_buffer', 'set_socket_blocking', 'stream_set_blocking', 'socket_set_blocking', 'stream_get_meta_data', 'stream_register_wrapper', 'stream_wrapper_register', 'stream_set_timeout', 'socket_set_timeout', 'socket_get_status', 'realpath', 'fnmatch', 'fsockopen', 'pfsockopen', 'pack', 'unpack', 'get_browser', 'crypt', 'opendir', 'closedir', 'chdir', 'getcwd', 'rewinddir', 'readdir', 'dir', 'glob', 'fileatime', 'filectime', 'filegroup', 'fileinode', 'filemtime', 'fileowner', 'fileperms', 'filesize', 'filetype', 'file_exists', 'is_writable', 'is_writeable', 'is_readable', 'is_executable', 'is_file', 'is_dir', 'is_link', 'stat', 'lstat', 'chown', + 'touch', 'clearstatcache', 'mail', 'ob_start', 'ob_flush', 'ob_clean', 'ob_end_flush', 'ob_end_clean', 'ob_get_flush', 'ob_get_clean', 'ob_get_length', 'ob_get_level', 'ob_get_status', 'ob_get_contents', 'ob_implicit_flush', 'ob_list_handlers', 'ksort', 'krsort', 'natsort', 'natcasesort', 'asort', 'arsort', 'sort', 'rsort', 'usort', 'uasort', 'uksort', 'shuffle', 'array_walk', 'count', 'end', 'prev', 'next', 'reset', 'current', 'key', 'min', 'max', 'in_array', 'array_search', 'extract', 'compact', 'array_fill', 'range', 'array_multisort', 'array_push', 'array_pop', 'array_shift', 'array_unshift', 'array_splice', 'array_slice', 'array_merge', 'array_merge_recursive', 'array_keys', 'array_values', 'array_count_values', 'array_reverse', 'array_reduce', 'array_pad', 'array_flip', 'array_change_key_case', 'array_rand', 'array_unique', 'array_intersect', 'array_intersect_assoc', 'array_diff', 'array_diff_assoc', 'array_sum', 'array_filter', 'array_map', 'array_chunk', 'array_key_exists', 'pos', 'sizeof', 'key_exists', 'assert', 'assert_options', 'version_compare', 'ftok', 'str_rot13', 'aggregate', + 'session_name', 'session_module_name', 'session_save_path', 'session_id', 'session_regenerate_id', 'session_decode', 'session_register', 'session_unregister', 'session_is_registered', 'session_encode', + 'session_start', 'session_destroy', 'session_unset', 'session_set_save_handler', 'session_cache_limiter', 'session_cache_expire', 'session_set_cookie_params', 'session_get_cookie_params', 'session_write_close', 'preg_match', 'preg_match_all', 'preg_replace', 'preg_replace_callback', 'preg_split', 'preg_quote', 'preg_grep', 'overload', 'ctype_alnum', 'ctype_alpha', 'ctype_cntrl', 'ctype_digit', 'ctype_lower', 'ctype_graph', 'ctype_print', 'ctype_punct', 'ctype_space', 'ctype_upper', 'ctype_xdigit', 'virtual', 'apache_request_headers', 'apache_note', 'apache_lookup_uri', 'apache_child_terminate', 'apache_setenv', 'apache_response_headers', 'apache_get_version', 'getallheaders', 'mysql_connect', 'mysql_pconnect', 'mysql_close', 'mysql_select_db', 'mysql_create_db', 'mysql_drop_db', 'mysql_query', 'mysql_unbuffered_query', 'mysql_db_query', 'mysql_list_dbs', 'mysql_list_tables', 'mysql_list_fields', 'mysql_list_processes', 'mysql_error', 'mysql_errno', 'mysql_affected_rows', 'mysql_insert_id', 'mysql_result', 'mysql_num_rows', 'mysql_num_fields', 'mysql_fetch_row', 'mysql_fetch_array', 'mysql_fetch_assoc', 'mysql_fetch_object', 'mysql_data_seek', 'mysql_fetch_lengths', 'mysql_fetch_field', 'mysql_field_seek', 'mysql_free_result', 'mysql_field_name', 'mysql_field_table', 'mysql_field_len', 'mysql_field_type', 'mysql_field_flags', 'mysql_escape_string', 'mysql_real_escape_string', 'mysql_stat', + 'mysql_thread_id', 'mysql_client_encoding', 'mysql_get_client_info', 'mysql_get_host_info', 'mysql_get_proto_info', 'mysql_get_server_info', 'mysql_info', 'mysql', 'mysql_fieldname', 'mysql_fieldtable', 'mysql_fieldlen', 'mysql_fieldtype', 'mysql_fieldflags', 'mysql_selectdb', 'mysql_createdb', 'mysql_dropdb', 'mysql_freeresult', 'mysql_numfields', 'mysql_numrows', 'mysql_listdbs', 'mysql_listtables', 'mysql_listfields', 'mysql_db_name', 'mysql_dbname', 'mysql_tablename', 'mysql_table_name', 'pg_connect', 'pg_pconnect', 'pg_close', 'pg_connection_status', 'pg_connection_busy', 'pg_connection_reset', 'pg_host', 'pg_dbname', 'pg_port', 'pg_tty', 'pg_options', 'pg_ping', 'pg_query', 'pg_send_query', 'pg_cancel_query', 'pg_fetch_result', 'pg_fetch_row', 'pg_fetch_assoc', 'pg_fetch_array', 'pg_fetch_object', 'pg_fetch_all', 'pg_affected_rows', 'pg_get_result', 'pg_result_seek', 'pg_result_status', 'pg_free_result', 'pg_last_oid', 'pg_num_rows', 'pg_num_fields', 'pg_field_name', 'pg_field_num', 'pg_field_size', 'pg_field_type', 'pg_field_prtlen', 'pg_field_is_null', 'pg_get_notify', 'pg_get_pid', 'pg_result_error', 'pg_last_error', 'pg_last_notice', 'pg_put_line', 'pg_end_copy', 'pg_copy_to', 'pg_copy_from', + 'pg_trace', 'pg_untrace', 'pg_lo_create', 'pg_lo_unlink', 'pg_lo_open', 'pg_lo_close', 'pg_lo_read', 'pg_lo_write', 'pg_lo_read_all', 'pg_lo_import', 'pg_lo_export', 'pg_lo_seek', 'pg_lo_tell', 'pg_escape_string', 'pg_escape_bytea', 'pg_unescape_bytea', 'pg_client_encoding', 'pg_set_client_encoding', 'pg_meta_data', 'pg_convert', 'pg_insert', 'pg_update', 'pg_delete', 'pg_select', 'pg_exec', 'pg_getlastoid', 'pg_cmdtuples', 'pg_errormessage', 'pg_numrows', 'pg_numfields', 'pg_fieldname', 'pg_fieldsize', 'pg_fieldtype', 'pg_fieldnum', 'pg_fieldprtlen', 'pg_fieldisnull', 'pg_freeresult', 'pg_result', 'pg_loreadall', 'pg_locreate', 'pg_lounlink', 'pg_loopen', 'pg_loclose', 'pg_loread', 'pg_lowrite', 'pg_loimport', 'pg_loexport', + 'echo', 'print', 'global', 'static', 'exit', 'array', 'empty', 'eval', 'isset', 'unset', 'die' + ) + ), + 'SYMBOLS' => array( + 1 => array( + '<%', '<%=', '%>', '' + ), + 0 => array( + '(', ')', '[', ']', '{', '}', + '!', '@', '%', '&', '|', '/', + '<', '>', + '=', '-', '+', '*', + '.', ':', ',', ';' + ) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #990000;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #666666; font-style: italic;', + 3 => 'color: #0000cc; font-style: italic;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;', + 'HARD' => 'color: #0000ff;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + ), + 'METHODS' => array( + 1 => 'color: #004000;', + 2 => 'color: #004000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;', + 1 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.php.net/{FNAMEL}' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '->', + 2 => '::' + ), + 'REGEXPS' => array( + //Variables + 0 => "[\\$]{1,2}[a-zA-Z_][a-zA-Z0-9_]*" + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + ' '?>' + ), + 1 => array( + ' '?>' + ), + 2 => array( + '<%' => '%>' + ), + 3 => array( + '' + ), + 4 => "/(<\?(?:php)?)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(\?>|\Z)/sm", + 5 => "/(<%)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(%>|\Z)/sm" + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/php.php b/examples/includes/geshi/geshi/php.php new file mode 100644 index 0000000..fc6be6c --- /dev/null +++ b/examples/includes/geshi/geshi/php.php @@ -0,0 +1,1094 @@ + 'PHP', + 'COMMENT_SINGLE' => array(1 => '//', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array("'", "\\"), + 'HARDCHAR' => "\\", + 'COMMENT_REGEXP' => array( + //Heredoc and Nowdoc syntax + 3 => '/<<<\s*?(\'?)([a-zA-Z0-9]+?)\1[^\n]*?\\n.*\\n\\2(?![a-zA-Z0-9])/siU', + // phpdoc comments + 4 => '#/\*\*(?![\*\/]).*\*/#sU', + // Advanced # handling + 2 => "/#.*?(?:(?=\?\>)|^)/smi" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'ESCAPE_REGEXP' => array( + //Simple Single Char Escapes + 1 => "#\\\\[nfrtv\$\"\n\\\\]#i", + //Hexadecimal Char Specs + 2 => "#\\\\x[\da-fA-F]{1,2}#i", + //Octal Char Specs + 3 => "#\\\\[0-7]{1,3}#", + //String Parsing of Variable Names + 4 => "#\\$[a-z0-9_]+(?:\\[[a-z0-9_]+\\]|->[a-z0-9_]+)?|(?:\\{\\$|\\$\\{)[a-z0-9_]+(?:\\[('?)[a-z0-9_]*\\1\\]|->[a-z0-9_]+)*\\}#i", + //Experimental extension supporting cascaded {${$var}} syntax + 5 => "#\$[a-z0-9_]+(?:\[[a-z0-9_]+\]|->[a-z0-9_]+)?|(?:\{\$|\$\{)[a-z0-9_]+(?:\[('?)[a-z0-9_]*\\1\]|->[a-z0-9_]+)*\}|\{\$(?R)\}#i", + //Format String support in ""-Strings + 6 => "#%(?:%|(?:\d+\\\\\\\$)?\\+?(?:\x20|0|'.)?-?(?:\d+|\\*)?(?:\.\d+)?[bcdefFosuxX])#" + ), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX | + GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'as','break','case','continue','default','do','else','elseif', + 'endfor','endforeach','endif','endswitch','endwhile','for', + 'foreach','if','include','include_once','require','require_once', + 'return','switch','while', + + 'echo','print' + ), + 2 => array( + '&new','</script>','<?php','<script language', + 'class','const','declare','extends','function','global','interface', + 'namespace','new','private','public','self','var' + ), + 3 => array( + 'abs','acos','acosh','addcslashes','addslashes','aggregate', + 'aggregate_methods','aggregate_methods_by_list', + 'aggregate_methods_by_regexp','aggregate_properties', + 'aggregate_properties_by_list','aggregate_properties_by_regexp', + 'aggregation_info','apache_child_terminate','apache_get_modules', + 'apache_get_version','apache_getenv','apache_lookup_uri', + 'apache_note','apache_request_headers','apache_response_headers', + 'apache_setenv','array','array_change_key_case','array_chunk', + 'array_combine','array_count_values','array_diff', + 'array_diff_assoc','array_diff_key','array_diff_uassoc', + 'array_diff_ukey','array_fill','array_fill_keys','array_filter', + 'array_flip','array_intersect','array_intersect_assoc', + 'array_intersect_key','array_intersect_uassoc', + 'array_intersect_ukey','array_key_exists','array_keys','array_map', + 'array_merge','array_merge_recursive','array_multisort','array_pad', + 'array_pop','array_product','array_push','array_rand', + 'array_reduce','array_reverse','array_search','array_shift', + 'array_slice','array_splice','array_sum','array_udiff', + 'array_udiff_assoc','array_udiff_uassoc','array_uintersect', + 'array_uintersect_assoc','array_uintersect_uassoc','array_unique', + 'array_unshift','array_values','array_walk','array_walk_recursive', + 'arsort','asin','asinh','asort','assert','assert_options','atan', + 'atan2','atanh','base_convert','base64_decode','base64_encode', + 'basename','bcadd','bccomp','bcdiv','bcmod','bcmul', + 'bcompiler_load','bcompiler_load_exe','bcompiler_parse_class', + 'bcompiler_read','bcompiler_write_class','bcompiler_write_constant', + 'bcompiler_write_exe_footer','bcompiler_write_file', + 'bcompiler_write_footer','bcompiler_write_function', + 'bcompiler_write_functions_from_file','bcompiler_write_header', + 'bcompiler_write_included_filename','bcpow','bcpowmod','bcscale', + 'bcsqrt','bcsub','bin2hex','bindec','bindtextdomain', + 'bind_textdomain_codeset','bitset_empty','bitset_equal', + 'bitset_excl','bitset_fill','bitset_from_array','bitset_from_hash', + 'bitset_from_string','bitset_in','bitset_incl', + 'bitset_intersection','bitset_invert','bitset_is_empty', + 'bitset_subset','bitset_to_array','bitset_to_hash', + 'bitset_to_string','bitset_union','blenc_encrypt','bzclose', + 'bzcompress','bzdecompress','bzerrno','bzerror','bzerrstr', + 'bzflush','bzopen','bzread','bzwrite','cal_days_in_month', + 'cal_from_jd','cal_info','cal_to_jd','call_user_func', + 'call_user_func_array','call_user_method','call_user_method_array', + 'ceil','chdir','checkdate','checkdnsrr','chgrp','chmod','chop', + 'chown','chr','chunk_split','class_exists','class_implements', + 'class_parents','classkit_aggregate_methods', + 'classkit_doc_comments','classkit_import','classkit_method_add', + 'classkit_method_copy','classkit_method_redefine', + 'classkit_method_remove','classkit_method_rename','clearstatcache', + 'closedir','closelog','com_create_guid','com_event_sink', + 'com_get_active_object','com_load_typelib','com_message_pump', + 'com_print_typeinfo','compact','confirm_phpdoc_compiled', + 'connection_aborted','connection_status','constant', + 'convert_cyr_string','convert_uudecode','convert_uuencode','copy', + 'cos','cosh','count','count_chars','cpdf_add_annotation', + 'cpdf_add_outline','cpdf_arc','cpdf_begin_text','cpdf_circle', + 'cpdf_clip','cpdf_close','cpdf_closepath', + 'cpdf_closepath_fill_stroke','cpdf_closepath_stroke', + 'cpdf_continue_text','cpdf_curveto','cpdf_end_text','cpdf_fill', + 'cpdf_fill_stroke','cpdf_finalize','cpdf_finalize_page', + 'cpdf_global_set_document_limits','cpdf_import_jpeg','cpdf_lineto', + 'cpdf_moveto','cpdf_newpath','cpdf_open','cpdf_output_buffer', + 'cpdf_page_init','cpdf_rect','cpdf_restore','cpdf_rlineto', + 'cpdf_rmoveto','cpdf_rotate','cpdf_rotate_text','cpdf_save', + 'cpdf_save_to_file','cpdf_scale','cpdf_set_action_url', + 'cpdf_set_char_spacing','cpdf_set_creator','cpdf_set_current_page', + 'cpdf_set_font','cpdf_set_font_directories', + 'cpdf_set_font_map_file','cpdf_set_horiz_scaling', + 'cpdf_set_keywords','cpdf_set_leading','cpdf_set_page_animation', + 'cpdf_set_subject','cpdf_set_text_matrix','cpdf_set_text_pos', + 'cpdf_set_text_rendering','cpdf_set_text_rise','cpdf_set_title', + 'cpdf_set_viewer_preferences','cpdf_set_word_spacing', + 'cpdf_setdash','cpdf_setflat','cpdf_setgray','cpdf_setgray_fill', + 'cpdf_setgray_stroke','cpdf_setlinecap','cpdf_setlinejoin', + 'cpdf_setlinewidth','cpdf_setmiterlimit','cpdf_setrgbcolor', + 'cpdf_setrgbcolor_fill','cpdf_setrgbcolor_stroke','cpdf_show', + 'cpdf_show_xy','cpdf_stringwidth','cpdf_stroke','cpdf_text', + 'cpdf_translate','crack_check','crack_closedict', + 'crack_getlastmessage','crack_opendict','crc32','create_function', + 'crypt','ctype_alnum','ctype_alpha','ctype_cntrl','ctype_digit', + 'ctype_graph','ctype_lower','ctype_print','ctype_punct', + 'ctype_space','ctype_upper','ctype_xdigit','curl_close', + 'curl_copy_handle','curl_errno','curl_error','curl_exec', + 'curl_getinfo','curl_init','curl_multi_add_handle', + 'curl_multi_close','curl_multi_exec','curl_multi_getcontent', + 'curl_multi_info_read','curl_multi_init','curl_multi_remove_handle', + 'curl_multi_select','curl_setopt','curl_setopt_array', + 'curl_version','current','cvsclient_connect','cvsclient_log', + 'cvsclient_login','cvsclient_retrieve','date','date_create', + 'date_date_set','date_default_timezone_get', + 'date_default_timezone_set','date_format','date_isodate_set', + 'date_modify','date_offset_get','date_parse','date_sun_info', + 'date_sunrise','date_sunset','date_time_set','date_timezone_get', + 'date_timezone_set','db_id_list','dba_close','dba_delete', + 'dba_exists','dba_fetch','dba_firstkey','dba_handlers','dba_insert', + 'dba_key_split','dba_list','dba_nextkey','dba_open','dba_optimize', + 'dba_popen','dba_replace','dba_sync','dbase_add_record', + 'dbase_close','dbase_create','dbase_delete_record', + 'dbase_get_header_info','dbase_get_record', + 'dbase_get_record_with_names','dbase_numfields','dbase_numrecords', + 'dbase_open','dbase_pack','dbase_replace_record', + 'dbg_get_all_contexts','dbg_get_all_module_names', + 'dbg_get_all_source_lines','dbg_get_context_name', + 'dbg_get_module_name','dbg_get_profiler_results', + 'dbg_get_source_context','dblist','dbmclose','dbmdelete', + 'dbmexists','dbmfetch','dbmfirstkey','dbminsert','dbmnextkey', + 'dbmopen','dbmreplace','dbx_close','dbx_compare','dbx_connect', + 'dbx_error','dbx_escape_string','dbx_fetch_row','dbx_query', + 'dbx_sort','dcgettext','dcngettext','deaggregate','debug_backtrace', + 'debug_zval_dump','debugbreak','decbin','dechex','decoct','define', + 'defined','define_syslog_variables','deg2rad','dgettext','die', + 'dio_close','dio_open','dio_read','dio_seek','dio_stat','dio_write', + 'dir','dirname','disk_free_space','disk_total_space', + 'diskfreespace','dl','dngettext','docblock_token_name', + 'docblock_tokenize','dom_import_simplexml','domxml_add_root', + 'domxml_attributes','domxml_children','domxml_doc_add_root', + 'domxml_doc_document_element','domxml_doc_get_element_by_id', + 'domxml_doc_get_elements_by_tagname','domxml_doc_get_root', + 'domxml_doc_set_root','domxml_doc_validate','domxml_doc_xinclude', + 'domxml_dump_mem','domxml_dump_mem_file','domxml_dump_node', + 'domxml_dumpmem','domxml_elem_get_attribute', + 'domxml_elem_set_attribute','domxml_get_attribute','domxml_getattr', + 'domxml_html_dump_mem','domxml_new_child','domxml_new_doc', + 'domxml_new_xmldoc','domxml_node','domxml_node_add_namespace', + 'domxml_node_attributes','domxml_node_children', + 'domxml_node_get_content','domxml_node_has_attributes', + 'domxml_node_new_child','domxml_node_set_content', + 'domxml_node_set_namespace','domxml_node_unlink_node', + 'domxml_open_file','domxml_open_mem','domxml_parser', + 'domxml_parser_add_chunk','domxml_parser_cdata_section', + 'domxml_parser_characters','domxml_parser_comment', + 'domxml_parser_end','domxml_parser_end_document', + 'domxml_parser_end_element','domxml_parser_entity_reference', + 'domxml_parser_get_document','domxml_parser_namespace_decl', + 'domxml_parser_processing_instruction', + 'domxml_parser_start_document','domxml_parser_start_element', + 'domxml_root','domxml_set_attribute','domxml_setattr', + 'domxml_substitute_entities_default','domxml_unlink_node', + 'domxml_version','domxml_xmltree','doubleval','each','easter_date', + 'easter_days','empty','end','ereg','ereg_replace','eregi', + 'eregi_replace','error_get_last','error_log','error_reporting', + 'escapeshellarg','escapeshellcmd','eval','event_deschedule', + 'event_dispatch','event_free','event_handle_signal', + 'event_have_events','event_init','event_new','event_pending', + 'event_priority_set','event_schedule','event_set','event_timeout', + 'exec','exif_imagetype','exif_read_data','exif_tagname', + 'exif_thumbnail','exit','exp','explode','expm1','extension_loaded', + 'extract','ezmlm_hash','fbird_add_user','fbird_affected_rows', + 'fbird_backup','fbird_blob_add','fbird_blob_cancel', + 'fbird_blob_close','fbird_blob_create','fbird_blob_echo', + 'fbird_blob_get','fbird_blob_import','fbird_blob_info', + 'fbird_blob_open','fbird_close','fbird_commit','fbird_commit_ret', + 'fbird_connect','fbird_db_info','fbird_delete_user','fbird_drop_db', + 'fbird_errcode','fbird_errmsg','fbird_execute','fbird_fetch_assoc', + 'fbird_fetch_object','fbird_fetch_row','fbird_field_info', + 'fbird_free_event_handler','fbird_free_query','fbird_free_result', + 'fbird_gen_id','fbird_maintain_db','fbird_modify_user', + 'fbird_name_result','fbird_num_fields','fbird_num_params', + 'fbird_param_info','fbird_pconnect','fbird_prepare','fbird_query', + 'fbird_restore','fbird_rollback','fbird_rollback_ret', + 'fbird_server_info','fbird_service_attach','fbird_service_detach', + 'fbird_set_event_handler','fbird_trans','fbird_wait_event','fclose', + 'fdf_add_doc_javascript','fdf_add_template','fdf_close', + 'fdf_create','fdf_enum_values','fdf_errno','fdf_error','fdf_get_ap', + 'fdf_get_attachment','fdf_get_encoding','fdf_get_file', + 'fdf_get_flags','fdf_get_opt','fdf_get_status','fdf_get_value', + 'fdf_get_version','fdf_header','fdf_next_field_name','fdf_open', + 'fdf_open_string','fdf_remove_item','fdf_save','fdf_save_string', + 'fdf_set_ap','fdf_set_encoding','fdf_set_file','fdf_set_flags', + 'fdf_set_javascript_action','fdf_set_on_import_javascript', + 'fdf_set_opt','fdf_set_status','fdf_set_submit_form_action', + 'fdf_set_target_frame','fdf_set_value','fdf_set_version','feof', + 'fflush','fgetc','fgetcsv','fgets','fgetss','file','file_exists', + 'file_get_contents','file_put_contents','fileatime','filectime', + 'filegroup','fileinode','filemtime','fileowner','fileperms', + 'filepro','filepro_fieldcount','filepro_fieldname', + 'filepro_fieldtype','filepro_fieldwidth','filepro_retrieve', + 'filepro_rowcount','filesize','filetype','filter_has_var', + 'filter_id','filter_input','filter_input_array','filter_list', + 'filter_var','filter_var_array','finfo_buffer','finfo_close', + 'finfo_file','finfo_open','finfo_set_flags','floatval','flock', + 'floor','flush','fmod','fnmatch','fopen','fpassthru','fprintf', + 'fputcsv','fputs','fread','frenchtojd','fribidi_charset_info', + 'fribidi_get_charsets','fribidi_log2vis','fscanf','fseek', + 'fsockopen','fstat','ftell','ftok','ftp_alloc','ftp_cdup', + 'ftp_chdir','ftp_chmod','ftp_close','ftp_connect','ftp_delete', + 'ftp_exec','ftp_fget','ftp_fput','ftp_get','ftp_get_option', + 'ftp_login','ftp_mdtm','ftp_mkdir','ftp_nb_continue','ftp_nb_fget', + 'ftp_nb_fput','ftp_nb_get','ftp_nb_put','ftp_nlist','ftp_pasv', + 'ftp_put','ftp_pwd','ftp_quit','ftp_raw','ftp_rawlist','ftp_rename', + 'ftp_rmdir','ftp_set_option','ftp_site','ftp_size', + 'ftp_ssl_connect','ftp_systype','ftruncate','function_exists', + 'func_get_arg','func_get_args','func_num_args','fwrite','gd_info', + 'getallheaders','getcwd','getdate','getenv','gethostbyaddr', + 'gethostbyname','gethostbynamel','getimagesize','getlastmod', + 'getmxrr','getmygid','getmyinode','getmypid','getmyuid','getopt', + 'getprotobyname','getprotobynumber','getrandmax','getrusage', + 'getservbyname','getservbyport','gettext','gettimeofday','gettype', + 'get_browser','get_cfg_var','get_class','get_class_methods', + 'get_class_vars','get_current_user','get_declared_classes', + 'get_defined_constants','get_defined_functions','get_defined_vars', + 'get_extension_funcs','get_headers','get_html_translation_table', + 'get_included_files','get_include_path','get_loaded_extensions', + 'get_magic_quotes_gpc','get_magic_quotes_runtime','get_meta_tags', + 'get_object_vars','get_parent_class','get_required_files', + 'get_resource_type','glob','gmdate','gmmktime','gmp_abs','gmp_add', + 'gmp_and','gmp_clrbit','gmp_cmp','gmp_com','gmp_div','gmp_div_q', + 'gmp_div_qr','gmp_div_r','gmp_divexact','gmp_fact','gmp_gcd', + 'gmp_gcdext','gmp_hamdist','gmp_init','gmp_intval','gmp_invert', + 'gmp_jacobi','gmp_legendre','gmp_mod','gmp_mul','gmp_neg', + 'gmp_nextprime','gmp_or','gmp_perfect_square','gmp_popcount', + 'gmp_pow','gmp_powm','gmp_prob_prime','gmp_random','gmp_scan0', + 'gmp_scan1','gmp_setbit','gmp_sign','gmp_sqrt','gmp_sqrtrem', + 'gmp_strval','gmp_sub','gmp_xor','gmstrftime','gopher_parsedir', + 'gregoriantojd','gzclose','gzcompress','gzdeflate','gzencode', + 'gzeof','gzfile','gzgetc','gzgets','gzgetss','gzinflate','gzopen', + 'gzpassthru','gzputs','gzread','gzrewind','gzseek','gztell', + 'gzuncompress','gzwrite','hash','hash_algos','hash_file', + 'hash_final','hash_hmac','hash_hmac_file','hash_init','hash_update', + 'hash_update_file','hash_update_stream','header','headers_list', + 'headers_sent','hebrev','hebrevc','hexdec','highlight_file', + 'highlight_string','html_doc','html_doc_file','html_entity_decode', + 'htmlentities','htmlspecialchars','htmlspecialchars_decode', + 'http_build_cookie','http_build_query','http_build_str', + 'http_build_url','http_cache_etag','http_cache_last_modified', + 'http_chunked_decode','http_date','http_deflate','http_get', + 'http_get_request_body','http_get_request_body_stream', + 'http_get_request_headers','http_head','http_inflate', + 'http_match_etag','http_match_modified','http_match_request_header', + 'http_negotiate_charset','http_negotiate_content_type', + 'http_negotiate_language','http_parse_cookie','http_parse_headers', + 'http_parse_message','http_parse_params', + 'http_persistent_handles_clean','http_persistent_handles_count', + 'http_persistent_handles_ident','http_post_data','http_post_fields', + 'http_put_data','http_put_file','http_put_stream','http_redirect', + 'http_request','http_request_body_encode', + 'http_request_method_exists','http_request_method_name', + 'http_request_method_register','http_request_method_unregister', + 'http_send_content_disposition','http_send_content_type', + 'http_send_data','http_send_file','http_send_last_modified', + 'http_send_status','http_send_stream','http_support', + 'http_throttle','hypot','i18n_convert','i18n_discover_encoding', + 'i18n_http_input','i18n_http_output','i18n_internal_encoding', + 'i18n_ja_jp_hantozen','i18n_mime_header_decode', + 'i18n_mime_header_encode','ibase_add_user','ibase_affected_rows', + 'ibase_backup','ibase_blob_add','ibase_blob_cancel', + 'ibase_blob_close','ibase_blob_create','ibase_blob_echo', + 'ibase_blob_get','ibase_blob_import','ibase_blob_info', + 'ibase_blob_open','ibase_close','ibase_commit','ibase_commit_ret', + 'ibase_connect','ibase_db_info','ibase_delete_user','ibase_drop_db', + 'ibase_errcode','ibase_errmsg','ibase_execute','ibase_fetch_assoc', + 'ibase_fetch_object','ibase_fetch_row','ibase_field_info', + 'ibase_free_event_handler','ibase_free_query','ibase_free_result', + 'ibase_gen_id','ibase_maintain_db','ibase_modify_user', + 'ibase_name_result','ibase_num_fields','ibase_num_params', + 'ibase_param_info','ibase_pconnect','ibase_prepare','ibase_query', + 'ibase_restore','ibase_rollback','ibase_rollback_ret', + 'ibase_server_info','ibase_service_attach','ibase_service_detach', + 'ibase_set_event_handler','ibase_trans','ibase_wait_event','iconv', + 'iconv_get_encoding','iconv_mime_decode', + 'iconv_mime_decode_headers','iconv_mime_encode', + 'iconv_set_encoding','iconv_strlen','iconv_strpos','iconv_strrpos', + 'iconv_substr','id3_get_frame_long_name','id3_get_frame_short_name', + 'id3_get_genre_id','id3_get_genre_list','id3_get_genre_name', + 'id3_get_tag','id3_get_version','id3_remove_tag','id3_set_tag', + 'idate','ignore_user_abort','image_type_to_extension', + 'image_type_to_mime_type','image2wbmp','imagealphablending', + 'imageantialias','imagearc','imagechar','imagecharup', + 'imagecolorallocate','imagecolorallocatealpha','imagecolorat', + 'imagecolorclosest','imagecolorclosestalpha','imagecolordeallocate', + 'imagecolorexact','imagecolorexactalpha','imagecolormatch', + 'imagecolorresolve','imagecolorresolvealpha','imagecolorset', + 'imagecolorsforindex','imagecolorstotal','imagecolortransparent', + 'imageconvolution','imagecopy','imagecopymerge', + 'imagecopymergegray','imagecopyresampled','imagecopyresized', + 'imagecreate','imagecreatefromgd','imagecreatefromgd2', + 'imagecreatefromgd2part','imagecreatefromgif','imagecreatefromjpeg', + 'imagecreatefrompng','imagecreatefromstring','imagecreatefromwbmp', + 'imagecreatefromxbm','imagecreatetruecolor','imagedashedline', + 'imagedestroy','imageellipse','imagefill','imagefilledarc', + 'imagefilledellipse','imagefilledpolygon','imagefilledrectangle', + 'imagefilltoborder','imagefilter','imagefontheight', + 'imagefontwidth','imageftbbox','imagefttext','imagegammacorrect', + 'imagegd','imagegd2','imagegif','imagegrabscreen','imagegrabwindow', + 'imageinterlace','imageistruecolor','imagejpeg','imagelayereffect', + 'imageline','imageloadfont','imagepalettecopy','imagepng', + 'imagepolygon','imagepsbbox','imagepsencodefont', + 'imagepsextendfont','imagepsfreefont','imagepsloadfont', + 'imagepsslantfont','imagepstext','imagerectangle','imagerotate', + 'imagesavealpha','imagesetbrush','imagesetpixel','imagesetstyle', + 'imagesetthickness','imagesettile','imagestring','imagestringup', + 'imagesx','imagesy','imagetruecolortopalette','imagettfbbox', + 'imagettftext','imagetypes','imagewbmp','imagexbm','imap_8bit', + 'imap_alerts','imap_append','imap_base64','imap_binary','imap_body', + 'imap_bodystruct','imap_check','imap_clearflag_full','imap_close', + 'imap_create','imap_createmailbox','imap_delete', + 'imap_deletemailbox','imap_errors','imap_expunge', + 'imap_fetch_overview','imap_fetchbody','imap_fetchheader', + 'imap_fetchstructure','imap_fetchtext','imap_get_quota', + 'imap_get_quotaroot','imap_getacl','imap_getmailboxes', + 'imap_getsubscribed','imap_header','imap_headerinfo','imap_headers', + 'imap_last_error','imap_list','imap_listmailbox', + 'imap_listsubscribed','imap_lsub','imap_mail','imap_mail_compose', + 'imap_mail_copy','imap_mail_move','imap_mailboxmsginfo', + 'imap_mime_header_decode','imap_msgno','imap_num_msg', + 'imap_num_recent','imap_open','imap_ping','imap_qprint', + 'imap_rename','imap_renamemailbox','imap_reopen', + 'imap_rfc822_parse_adrlist','imap_rfc822_parse_headers', + 'imap_rfc822_write_address','imap_savebody','imap_scan', + 'imap_scanmailbox','imap_search','imap_set_quota','imap_setacl', + 'imap_setflag_full','imap_sort','imap_status','imap_subscribe', + 'imap_thread','imap_timeout','imap_uid','imap_undelete', + 'imap_unsubscribe','imap_utf7_decode','imap_utf7_encode', + 'imap_utf8','implode','import_request_variables','in_array', + 'ini_alter','ini_get','ini_get_all','ini_restore','ini_set', + 'intval','ip2long','iptcembed','iptcparse','isset','is_a', + 'is_array','is_bool','is_callable','is_dir','is_double', + 'is_executable','is_file','is_finite','is_float','is_infinite', + 'is_int','is_integer','is_link','is_long','is_nan','is_null', + 'is_numeric','is_object','is_readable','is_real','is_resource', + 'is_scalar','is_soap_fault','is_string','is_subclass_of', + 'is_uploaded_file','is_writable','is_writeable','iterator_apply', + 'iterator_count','iterator_to_array','java_last_exception_clear', + 'java_last_exception_get','jddayofweek','jdmonthname','jdtofrench', + 'jdtogregorian','jdtojewish','jdtojulian','jdtounix','jewishtojd', + 'join','jpeg2wbmp','json_decode','json_encode','juliantojd','key', + 'key_exists','krsort','ksort','lcg_value','ldap_add','ldap_bind', + 'ldap_close','ldap_compare','ldap_connect','ldap_count_entries', + 'ldap_delete','ldap_dn2ufn','ldap_err2str','ldap_errno', + 'ldap_error','ldap_explode_dn','ldap_first_attribute', + 'ldap_first_entry','ldap_first_reference','ldap_free_result', + 'ldap_get_attributes','ldap_get_dn','ldap_get_entries', + 'ldap_get_option','ldap_get_values','ldap_get_values_len', + 'ldap_list','ldap_mod_add','ldap_mod_del','ldap_mod_replace', + 'ldap_modify','ldap_next_attribute','ldap_next_entry', + 'ldap_next_reference','ldap_parse_reference','ldap_parse_result', + 'ldap_read','ldap_rename','ldap_search','ldap_set_option', + 'ldap_sort','ldap_start_tls','ldap_unbind','levenshtein', + 'libxml_clear_errors','libxml_get_errors','libxml_get_last_error', + 'libxml_set_streams_context','libxml_use_internal_errors','link', + 'linkinfo','list','localeconv','localtime','log','log1p','log10', + 'long2ip','lstat','ltrim','lzf_compress','lzf_decompress', + 'lzf_optimized_for','magic_quotes_runtime','mail','max','mbereg', + 'mberegi','mberegi_replace','mbereg_match','mbereg_replace', + 'mbereg_search','mbereg_search_getpos','mbereg_search_getregs', + 'mbereg_search_init','mbereg_search_pos','mbereg_search_regs', + 'mbereg_search_setpos','mbregex_encoding','mbsplit','mbstrcut', + 'mbstrlen','mbstrpos','mbstrrpos','mbsubstr','mb_check_encoding', + 'mb_convert_case','mb_convert_encoding','mb_convert_kana', + 'mb_convert_variables','mb_decode_mimeheader', + 'mb_decode_numericentity','mb_detect_encoding','mb_detect_order', + 'mb_encode_mimeheader','mb_encode_numericentity','mb_ereg', + 'mb_eregi','mb_eregi_replace','mb_ereg_match','mb_ereg_replace', + 'mb_ereg_search','mb_ereg_search_getpos','mb_ereg_search_getregs', + 'mb_ereg_search_init','mb_ereg_search_pos','mb_ereg_search_regs', + 'mb_ereg_search_setpos','mb_get_info','mb_http_input', + 'mb_http_output','mb_internal_encoding','mb_language', + 'mb_list_encodings','mb_output_handler','mb_parse_str', + 'mb_preferred_mime_name','mb_regex_encoding','mb_regex_set_options', + 'mb_send_mail','mb_split','mb_strcut','mb_strimwidth','mb_stripos', + 'mb_stristr','mb_strlen','mb_strpos','mb_strrchr','mb_strrichr', + 'mb_strripos','mb_strrpos','mb_strstr','mb_strtolower', + 'mb_strtoupper','mb_strwidth','mb_substitute_character','mb_substr', + 'mb_substr_count','mcrypt_cbc','mcrypt_cfb','mcrypt_create_iv', + 'mcrypt_decrypt','mcrypt_ecb','mcrypt_enc_get_algorithms_name', + 'mcrypt_enc_get_block_size','mcrypt_enc_get_iv_size', + 'mcrypt_enc_get_key_size','mcrypt_enc_get_modes_name', + 'mcrypt_enc_get_supported_key_sizes', + 'mcrypt_enc_is_block_algorithm', + 'mcrypt_enc_is_block_algorithm_mode','mcrypt_enc_is_block_mode', + 'mcrypt_enc_self_test','mcrypt_encrypt','mcrypt_generic', + 'mcrypt_generic_deinit','mcrypt_generic_end','mcrypt_generic_init', + 'mcrypt_get_block_size','mcrypt_get_cipher_name', + 'mcrypt_get_iv_size','mcrypt_get_key_size','mcrypt_list_algorithms', + 'mcrypt_list_modes','mcrypt_module_close', + 'mcrypt_module_get_algo_block_size', + 'mcrypt_module_get_algo_key_size', + 'mcrypt_module_get_supported_key_sizes', + 'mcrypt_module_is_block_algorithm', + 'mcrypt_module_is_block_algorithm_mode', + 'mcrypt_module_is_block_mode','mcrypt_module_open', + 'mcrypt_module_self_test','mcrypt_ofb','md5','md5_file', + 'mdecrypt_generic','memcache_add','memcache_add_server', + 'memcache_close','memcache_connect','memcache_debug', + 'memcache_decrement','memcache_delete','memcache_flush', + 'memcache_get','memcache_get_extended_stats', + 'memcache_get_server_status','memcache_get_stats', + 'memcache_get_version','memcache_increment','memcache_pconnect', + 'memcache_replace','memcache_set','memcache_set_compress_threshold', + 'memcache_set_server_params','memory_get_peak_usage', + 'memory_get_usage','metaphone','mhash','mhash_count', + 'mhash_get_block_size','mhash_get_hash_name','mhash_keygen_s2k', + 'method_exists','microtime','mime_content_type','min', + 'ming_keypress','ming_setcubicthreshold','ming_setscale', + 'ming_useconstants','ming_useswfversion','mkdir','mktime', + 'money_format','move_uploaded_file','msql','msql_affected_rows', + 'msql_close','msql_connect','msql_create_db','msql_createdb', + 'msql_data_seek','msql_db_query','msql_dbname','msql_drop_db', + 'msql_dropdb','msql_error','msql_fetch_array','msql_fetch_field', + 'msql_fetch_object','msql_fetch_row','msql_field_flags', + 'msql_field_len','msql_field_name','msql_field_seek', + 'msql_field_table','msql_field_type','msql_fieldflags', + 'msql_fieldlen','msql_fieldname','msql_fieldtable','msql_fieldtype', + 'msql_free_result','msql_freeresult','msql_list_dbs', + 'msql_list_fields','msql_list_tables','msql_listdbs', + 'msql_listfields','msql_listtables','msql_num_fields', + 'msql_num_rows','msql_numfields','msql_numrows','msql_pconnect', + 'msql_query','msql_regcase','msql_result','msql_select_db', + 'msql_selectdb','msql_tablename','mssql_bind','mssql_close', + 'mssql_connect','mssql_data_seek','mssql_execute', + 'mssql_fetch_array','mssql_fetch_assoc','mssql_fetch_batch', + 'mssql_fetch_field','mssql_fetch_object','mssql_fetch_row', + 'mssql_field_length','mssql_field_name','mssql_field_seek', + 'mssql_field_type','mssql_free_result','mssql_free_statement', + 'mssql_get_last_message','mssql_guid_string','mssql_init', + 'mssql_min_error_severity','mssql_min_message_severity', + 'mssql_next_result','mssql_num_fields','mssql_num_rows', + 'mssql_pconnect','mssql_query','mssql_result','mssql_rows_affected', + 'mssql_select_db','mt_getrandmax','mt_rand','mt_srand','mysql', + 'mysql_affected_rows','mysql_client_encoding','mysql_close', + 'mysql_connect','mysql_createdb','mysql_create_db', + 'mysql_data_seek','mysql_dbname','mysql_db_name','mysql_db_query', + 'mysql_dropdb','mysql_drop_db','mysql_errno','mysql_error', + 'mysql_escape_string','mysql_fetch_array','mysql_fetch_assoc', + 'mysql_fetch_field','mysql_fetch_lengths','mysql_fetch_object', + 'mysql_fetch_row','mysql_fieldflags','mysql_fieldlen', + 'mysql_fieldname','mysql_fieldtable','mysql_fieldtype', + 'mysql_field_flags','mysql_field_len','mysql_field_name', + 'mysql_field_seek','mysql_field_table','mysql_field_type', + 'mysql_freeresult','mysql_free_result','mysql_get_client_info', + 'mysql_get_host_info','mysql_get_proto_info', + 'mysql_get_server_info','mysql_info','mysql_insert_id', + 'mysql_listdbs','mysql_listfields','mysql_listtables', + 'mysql_list_dbs','mysql_list_fields','mysql_list_processes', + 'mysql_list_tables','mysql_numfields','mysql_numrows', + 'mysql_num_fields','mysql_num_rows','mysql_pconnect','mysql_ping', + 'mysql_query','mysql_real_escape_string','mysql_result', + 'mysql_selectdb','mysql_select_db','mysql_set_charset','mysql_stat', + 'mysql_tablename','mysql_table_name','mysql_thread_id', + 'mysql_unbuffered_query','mysqli_affected_rows','mysqli_autocommit', + 'mysqli_bind_param','mysqli_bind_result','mysqli_change_user', + 'mysqli_character_set_name','mysqli_client_encoding','mysqli_close', + 'mysqli_commit','mysqli_connect','mysqli_connect_errno', + 'mysqli_connect_error','mysqli_data_seek','mysqli_debug', + 'mysqli_disable_reads_from_master','mysqli_disable_rpl_parse', + 'mysqli_dump_debug_info','mysqli_embedded_server_end', + 'mysqli_embedded_server_start','mysqli_enable_reads_from_master', + 'mysqli_enable_rpl_parse','mysqli_errno','mysqli_error', + 'mysqli_escape_string','mysqli_execute','mysqli_fetch', + 'mysqli_fetch_array','mysqli_fetch_assoc','mysqli_fetch_field', + 'mysqli_fetch_field_direct','mysqli_fetch_fields', + 'mysqli_fetch_lengths','mysqli_fetch_object','mysqli_fetch_row', + 'mysqli_field_count','mysqli_field_seek','mysqli_field_tell', + 'mysqli_free_result','mysqli_get_charset','mysqli_get_client_info', + 'mysqli_get_client_version','mysqli_get_host_info', + 'mysqli_get_metadata','mysqli_get_proto_info', + 'mysqli_get_server_info','mysqli_get_server_version', + 'mysqli_get_warnings','mysqli_info','mysqli_init', + 'mysqli_insert_id','mysqli_kill','mysqli_master_query', + 'mysqli_more_results','mysqli_multi_query','mysqli_next_result', + 'mysqli_num_fields','mysqli_num_rows','mysqli_options', + 'mysqli_param_count','mysqli_ping','mysqli_prepare','mysqli_query', + 'mysqli_real_connect','mysqli_real_escape_string', + 'mysqli_real_query','mysqli_report','mysqli_rollback', + 'mysqli_rpl_parse_enabled','mysqli_rpl_probe', + 'mysqli_rpl_query_type','mysqli_select_db','mysqli_send_long_data', + 'mysqli_send_query','mysqli_set_charset', + 'mysqli_set_local_infile_default','mysqli_set_local_infile_handler', + 'mysqli_set_opt','mysqli_slave_query','mysqli_sqlstate', + 'mysqli_ssl_set','mysqli_stat','mysqli_stmt_affected_rows', + 'mysqli_stmt_attr_get','mysqli_stmt_attr_set', + 'mysqli_stmt_bind_param','mysqli_stmt_bind_result', + 'mysqli_stmt_close','mysqli_stmt_data_seek','mysqli_stmt_errno', + 'mysqli_stmt_error','mysqli_stmt_execute','mysqli_stmt_fetch', + 'mysqli_stmt_field_count','mysqli_stmt_free_result', + 'mysqli_stmt_get_warnings','mysqli_stmt_init', + 'mysqli_stmt_insert_id','mysqli_stmt_num_rows', + 'mysqli_stmt_param_count','mysqli_stmt_prepare','mysqli_stmt_reset', + 'mysqli_stmt_result_metadata','mysqli_stmt_send_long_data', + 'mysqli_stmt_sqlstate','mysqli_stmt_store_result', + 'mysqli_store_result','mysqli_thread_id','mysqli_thread_safe', + 'mysqli_use_result','mysqli_warning_count','natcasesort','natsort', + 'new_xmldoc','next','ngettext','nl2br','nl_langinfo', + 'ntuser_getdomaincontroller','ntuser_getusergroups', + 'ntuser_getuserinfo','ntuser_getuserlist','number_format', + 'ob_clean','ob_deflatehandler','ob_end_clean','ob_end_flush', + 'ob_etaghandler','ob_flush','ob_get_clean','ob_get_contents', + 'ob_get_flush','ob_get_length','ob_get_level','ob_get_status', + 'ob_gzhandler','ob_iconv_handler','ob_implicit_flush', + 'ob_inflatehandler','ob_list_handlers','ob_start','ob_tidyhandler', + 'octdec','odbc_autocommit','odbc_binmode','odbc_close', + 'odbc_close_all','odbc_columnprivileges','odbc_columns', + 'odbc_commit','odbc_connect','odbc_cursor','odbc_data_source', + 'odbc_do','odbc_error','odbc_errormsg','odbc_exec','odbc_execute', + 'odbc_fetch_array','odbc_fetch_into','odbc_fetch_object', + 'odbc_fetch_row','odbc_field_len','odbc_field_name', + 'odbc_field_num','odbc_field_precision','odbc_field_scale', + 'odbc_field_type','odbc_foreignkeys','odbc_free_result', + 'odbc_gettypeinfo','odbc_longreadlen','odbc_next_result', + 'odbc_num_fields','odbc_num_rows','odbc_pconnect','odbc_prepare', + 'odbc_primarykeys','odbc_procedurecolumns','odbc_procedures', + 'odbc_result','odbc_result_all','odbc_rollback','odbc_setoption', + 'odbc_specialcolumns','odbc_statistics','odbc_tableprivileges', + 'odbc_tables','opendir','openlog','openssl_csr_export', + 'openssl_csr_export_to_file','openssl_csr_get_public_key', + 'openssl_csr_get_subject','openssl_csr_new','openssl_csr_sign', + 'openssl_error_string','openssl_free_key','openssl_get_privatekey', + 'openssl_get_publickey','openssl_open','openssl_pkcs12_export', + 'openssl_pkcs12_export_to_file','openssl_pkcs12_read', + 'openssl_pkcs7_decrypt','openssl_pkcs7_encrypt', + 'openssl_pkcs7_sign','openssl_pkcs7_verify','openssl_pkey_export', + 'openssl_pkey_export_to_file','openssl_pkey_free', + 'openssl_pkey_get_details','openssl_pkey_get_private', + 'openssl_pkey_get_public','openssl_pkey_new', + 'openssl_private_decrypt','openssl_private_encrypt', + 'openssl_public_decrypt','openssl_public_encrypt','openssl_seal', + 'openssl_sign','openssl_verify','openssl_x509_checkpurpose', + 'openssl_x509_check_private_key','openssl_x509_export', + 'openssl_x509_export_to_file','openssl_x509_free', + 'openssl_x509_parse','openssl_x509_read','ord', + 'output_add_rewrite_var','output_reset_rewrite_vars','overload', + 'outputdebugstring','pack','parse_ini_file','parse_str','parse_url', + 'parsekit_compile_file','parsekit_compile_string', + 'parsekit_func_arginfo','parsekit_opcode_flags', + 'parsekit_opcode_name','passthru','pathinfo','pclose', + 'pdf_add_bookmark','pdf_add_launchlink','pdf_add_locallink', + 'pdf_add_nameddest','pdf_add_note','pdf_add_pdflink', + 'pdf_add_thumbnail','pdf_add_weblink','pdf_arc','pdf_arcn', + 'pdf_attach_file','pdf_begin_font','pdf_begin_glyph', + 'pdf_begin_page','pdf_begin_pattern','pdf_begin_template', + 'pdf_circle','pdf_clip','pdf_close','pdf_close_image', + 'pdf_close_pdi','pdf_close_pdi_page','pdf_closepath', + 'pdf_closepath_fill_stroke','pdf_closepath_stroke','pdf_concat', + 'pdf_continue_text','pdf_create_gstate','pdf_create_pvf', + 'pdf_curveto','pdf_delete','pdf_delete_pvf','pdf_encoding_set_char', + 'pdf_end_font','pdf_end_glyph','pdf_end_page','pdf_end_pattern', + 'pdf_end_template','pdf_endpath','pdf_fill','pdf_fill_imageblock', + 'pdf_fill_pdfblock','pdf_fill_stroke','pdf_fill_textblock', + 'pdf_findfont','pdf_fit_image','pdf_fit_pdi_page', + 'pdf_fit_textline','pdf_get_apiname','pdf_get_buffer', + 'pdf_get_errmsg','pdf_get_errnum','pdf_get_parameter', + 'pdf_get_pdi_parameter','pdf_get_pdi_value','pdf_get_value', + 'pdf_initgraphics','pdf_lineto','pdf_load_font', + 'pdf_load_iccprofile','pdf_load_image','pdf_makespotcolor', + 'pdf_moveto','pdf_new','pdf_open_ccitt','pdf_open_file', + 'pdf_open_image','pdf_open_image_file','pdf_open_pdi', + 'pdf_open_pdi_page','pdf_place_image','pdf_place_pdi_page', + 'pdf_process_pdi','pdf_rect','pdf_restore','pdf_rotate','pdf_save', + 'pdf_scale','pdf_set_border_color','pdf_set_border_dash', + 'pdf_set_border_style','pdf_set_gstate','pdf_set_info', + 'pdf_set_parameter','pdf_set_text_pos','pdf_set_value', + 'pdf_setcolor','pdf_setdash','pdf_setdashpattern','pdf_setflat', + 'pdf_setfont','pdf_setlinecap','pdf_setlinejoin','pdf_setlinewidth', + 'pdf_setmatrix','pdf_setmiterlimit','pdf_setpolydash','pdf_shading', + 'pdf_shading_pattern','pdf_shfill','pdf_show','pdf_show_boxed', + 'pdf_show_xy','pdf_skew','pdf_stringwidth','pdf_stroke', + 'pdf_translate','pdo_drivers','pfsockopen','pg_affected_rows', + 'pg_cancel_query','pg_clientencoding','pg_client_encoding', + 'pg_close','pg_cmdtuples','pg_connect','pg_connection_busy', + 'pg_connection_reset','pg_connection_status','pg_convert', + 'pg_copy_from','pg_copy_to','pg_dbname','pg_delete','pg_end_copy', + 'pg_errormessage','pg_escape_bytea','pg_escape_string','pg_exec', + 'pg_execute','pg_fetch_all','pg_fetch_all_columns','pg_fetch_array', + 'pg_fetch_assoc','pg_fetch_object','pg_fetch_result','pg_fetch_row', + 'pg_fieldisnull','pg_fieldname','pg_fieldnum','pg_fieldprtlen', + 'pg_fieldsize','pg_fieldtype','pg_field_is_null','pg_field_name', + 'pg_field_num','pg_field_prtlen','pg_field_size','pg_field_table', + 'pg_field_type','pg_field_type_oid','pg_free_result', + 'pg_freeresult','pg_get_notify','pg_get_pid','pg_get_result', + 'pg_getlastoid','pg_host','pg_insert','pg_last_error', + 'pg_last_notice','pg_last_oid','pg_loclose','pg_locreate', + 'pg_loexport','pg_loimport','pg_loopen','pg_loread','pg_loreadall', + 'pg_lounlink','pg_lowrite','pg_lo_close','pg_lo_create', + 'pg_lo_export','pg_lo_import','pg_lo_open','pg_lo_read', + 'pg_lo_read_all','pg_lo_seek','pg_lo_tell','pg_lo_unlink', + 'pg_lo_write','pg_meta_data','pg_numfields','pg_numrows', + 'pg_num_fields','pg_num_rows','pg_options','pg_parameter_status', + 'pg_pconnect','pg_ping','pg_port','pg_prepare','pg_put_line', + 'pg_query','pg_query_params','pg_result','pg_result_error', + 'pg_result_error_field','pg_result_seek','pg_result_status', + 'pg_select','pg_send_execute','pg_send_prepare','pg_send_query', + 'pg_send_query_params','pg_set_client_encoding', + 'pg_set_error_verbosity','pg_setclientencoding','pg_trace', + 'pg_transaction_status','pg_tty','pg_unescape_bytea','pg_untrace', + 'pg_update','pg_version','php_egg_logo_guid','php_ini_loaded_file', + 'php_ini_scanned_files','php_logo_guid','php_real_logo_guid', + 'php_sapi_name','php_strip_whitespace','php_uname','phpcredits', + 'phpdoc_xml_from_string','phpinfo','phpversion','pi','png2wbmp', + 'pop3_close','pop3_delete_message','pop3_get_account_size', + 'pop3_get_message','pop3_get_message_count', + 'pop3_get_message_header','pop3_get_message_ids', + 'pop3_get_message_size','pop3_get_message_sizes','pop3_open', + 'pop3_undelete','popen','pos','posix_ctermid','posix_errno', + 'posix_getcwd','posix_getegid','posix_geteuid','posix_getgid', + 'posix_getgrgid','posix_getgrnam','posix_getgroups', + 'posix_getlogin','posix_getpgid','posix_getpgrp','posix_getpid', + 'posix_getppid','posix_getpwnam','posix_getpwuid','posix_getrlimit', + 'posix_getsid','posix_getuid','posix_get_last_error','posix_isatty', + 'posix_kill','posix_mkfifo','posix_setegid','posix_seteuid', + 'posix_setgid','posix_setpgid','posix_setsid','posix_setuid', + 'posix_strerror','posix_times','posix_ttyname','posix_uname','pow', + 'preg_grep','preg_last_error','preg_match','preg_match_all', + 'preg_quote','preg_replace','preg_replace_callback','preg_split', + 'prev','print_r','printf','proc_close','proc_get_status', + 'proc_open','proc_terminate','putenv','quoted_printable_decode', + 'quotemeta','rad2deg','radius_acct_open','radius_add_server', + 'radius_auth_open','radius_close','radius_config', + 'radius_create_request','radius_cvt_addr','radius_cvt_int', + 'radius_cvt_string','radius_demangle','radius_demangle_mppe_key', + 'radius_get_attr','radius_get_vendor_attr','radius_put_addr', + 'radius_put_attr','radius_put_int','radius_put_string', + 'radius_put_vendor_addr','radius_put_vendor_attr', + 'radius_put_vendor_int','radius_put_vendor_string', + 'radius_request_authenticator','radius_send_request', + 'radius_server_secret','radius_strerror','rand','range', + 'rawurldecode','rawurlencode','read_exif_data','readdir','readfile', + 'readgzfile','readlink','realpath','reg_close_key','reg_create_key', + 'reg_enum_key','reg_enum_value','reg_get_value','reg_open_key', + 'reg_set_value','register_shutdown_function', + 'register_tick_function','rename','res_close','res_get','res_list', + 'res_list_type','res_open','res_set','reset', + 'restore_error_handler','restore_include_path','rewind','rewinddir', + 'rmdir','round','rsort','rtrim','runkit_class_adopt', + 'runkit_class_emancipate','runkit_constant_add', + 'runkit_constant_redefine','runkit_constant_remove', + 'runkit_default_property_add','runkit_function_add', + 'runkit_function_copy','runkit_function_redefine', + 'runkit_function_remove','runkit_function_rename','runkit_import', + 'runkit_lint','runkit_lint_file','runkit_method_add', + 'runkit_method_copy','runkit_method_redefine', + 'runkit_method_remove','runkit_method_rename','runkit_object_id', + 'runkit_return_value_used','runkit_sandbox_output_handler', + 'runkit_superglobals','runkit_zval_inspect','scandir','sem_acquire', + 'sem_get','sem_release','sem_remove','serialize', + 'session_cache_expire','session_cache_limiter','session_commit', + 'session_decode','session_destroy','session_encode', + 'session_get_cookie_params','session_id','session_is_registered', + 'session_module_name','session_name','session_regenerate_id', + 'session_register','session_save_path','session_set_cookie_params', + 'session_set_save_handler','session_start','session_unregister', + 'session_unset','session_write_close','set_content', + 'set_error_handler','set_file_buffer','set_include_path', + 'set_magic_quotes_runtime','set_socket_blocking','set_time_limit', + 'setcookie','setlocale','setrawcookie','settype','sha1','sha1_file', + 'shell_exec','shmop_close','shmop_delete','shmop_open','shmop_read', + 'shmop_size','shmop_write','shm_attach','shm_detach','shm_get_var', + 'shm_put_var','shm_remove','shm_remove_var','show_source','shuffle', + 'similar_text','simplexml_import_dom','simplexml_load_file', + 'simplexml_load_string','sin','sinh','sizeof','sleep','smtp_close', + 'smtp_cmd_data','smtp_cmd_mail','smtp_cmd_rcpt','smtp_connect', + 'snmp_get_quick_print','snmp_get_valueretrieval','snmp_read_mib', + 'snmp_set_quick_print','snmp_set_valueretrieval','snmp2_get', + 'snmp2_getnext','snmp2_real_walk','snmp2_set','snmp2_walk', + 'snmp3_get','snmp3_getnext','snmp3_real_walk','snmp3_set', + 'snmp3_walk','snmpget','snmpgetnext','snmprealwalk','snmpset', + 'snmpwalk','snmpwalkoid','socket_accept','socket_bind', + 'socket_clear_error','socket_close','socket_connect', + 'socket_create','socket_create_listen','socket_create_pair', + 'socket_getopt','socket_getpeername','socket_getsockname', + 'socket_get_option','socket_get_status','socket_iovec_add', + 'socket_iovec_alloc','socket_iovec_delete','socket_iovec_fetch', + 'socket_iovec_free','socket_iovec_set','socket_last_error', + 'socket_listen','socket_read','socket_readv','socket_recv', + 'socket_recvfrom','socket_recvmsg','socket_select','socket_send', + 'socket_sendmsg','socket_sendto','socket_setopt','socket_set_block', + 'socket_set_blocking','socket_set_nonblock','socket_set_option', + 'socket_set_timeout','socket_shutdown','socket_strerror', + 'socket_write','socket_writev','sort','soundex','spl_autoload', + 'spl_autoload_call','spl_autoload_extensions', + 'spl_autoload_functions','spl_autoload_register', + 'spl_autoload_unregister','spl_classes','spl_object_hash','split', + 'spliti','sprintf','sql_regcase','sqlite_array_query', + 'sqlite_busy_timeout','sqlite_changes','sqlite_close', + 'sqlite_column','sqlite_create_aggregate','sqlite_create_function', + 'sqlite_current','sqlite_error_string','sqlite_escape_string', + 'sqlite_exec','sqlite_factory','sqlite_fetch_all', + 'sqlite_fetch_array','sqlite_fetch_column_types', + 'sqlite_fetch_object','sqlite_fetch_single','sqlite_fetch_string', + 'sqlite_field_name','sqlite_has_more','sqlite_has_prev', + 'sqlite_last_error','sqlite_last_insert_rowid','sqlite_libencoding', + 'sqlite_libversion','sqlite_next','sqlite_num_fields', + 'sqlite_num_rows','sqlite_open','sqlite_popen','sqlite_prev', + 'sqlite_query','sqlite_rewind','sqlite_seek','sqlite_single_query', + 'sqlite_udf_decode_binary','sqlite_udf_encode_binary', + 'sqlite_unbuffered_query','sqlite_valid','sqrt','srand','sscanf', + 'ssh2_auth_hostbased_file','ssh2_auth_none','ssh2_auth_password', + 'ssh2_auth_pubkey_file','ssh2_connect','ssh2_exec', + 'ssh2_fetch_stream','ssh2_fingerprint','ssh2_forward_accept', + 'ssh2_forward_listen','ssh2_methods_negotiated','ssh2_poll', + 'ssh2_publickey_add','ssh2_publickey_init','ssh2_publickey_list', + 'ssh2_publickey_remove','ssh2_scp_recv','ssh2_scp_send','ssh2_sftp', + 'ssh2_sftp_lstat','ssh2_sftp_mkdir','ssh2_sftp_readlink', + 'ssh2_sftp_realpath','ssh2_sftp_rename','ssh2_sftp_rmdir', + 'ssh2_sftp_stat','ssh2_sftp_symlink','ssh2_sftp_unlink', + 'ssh2_shell','ssh2_tunnel','stat','stats_absolute_deviation', + 'stats_cdf_beta','stats_cdf_binomial','stats_cdf_cauchy', + 'stats_cdf_chisquare','stats_cdf_exponential','stats_cdf_f', + 'stats_cdf_gamma','stats_cdf_laplace','stats_cdf_logistic', + 'stats_cdf_negative_binomial','stats_cdf_noncentral_chisquare', + 'stats_cdf_noncentral_f','stats_cdf_noncentral_t', + 'stats_cdf_normal','stats_cdf_poisson','stats_cdf_t', + 'stats_cdf_uniform','stats_cdf_weibull','stats_covariance', + 'stats_dens_beta','stats_dens_cauchy','stats_dens_chisquare', + 'stats_dens_exponential','stats_dens_f','stats_dens_gamma', + 'stats_dens_laplace','stats_dens_logistic','stats_dens_normal', + 'stats_dens_pmf_binomial','stats_dens_pmf_hypergeometric', + 'stats_dens_pmf_negative_binomial','stats_dens_pmf_poisson', + 'stats_dens_t','stats_dens_uniform','stats_dens_weibull', + 'stats_harmonic_mean','stats_kurtosis','stats_rand_gen_beta', + 'stats_rand_gen_chisquare','stats_rand_gen_exponential', + 'stats_rand_gen_f','stats_rand_gen_funiform','stats_rand_gen_gamma', + 'stats_rand_gen_ipoisson','stats_rand_gen_iuniform', + 'stats_rand_gen_noncenral_f','stats_rand_gen_noncentral_chisquare', + 'stats_rand_gen_noncentral_t','stats_rand_gen_normal', + 'stats_rand_gen_t','stats_rand_getsd','stats_rand_ibinomial', + 'stats_rand_ibinomial_negative','stats_rand_ignlgi', + 'stats_rand_phrase_to_seeds','stats_rand_ranf','stats_rand_setall', + 'stats_skew','stats_standard_deviation','stats_stat_binomial_coef', + 'stats_stat_correlation','stats_stat_factorial', + 'stats_stat_independent_t','stats_stat_innerproduct', + 'stats_stat_paired_t','stats_stat_percentile','stats_stat_powersum', + 'stats_variance','strcasecmp','strchr','strcmp','strcoll','strcspn', + 'stream_bucket_append','stream_bucket_make_writeable', + 'stream_bucket_new','stream_bucket_prepend','stream_context_create', + 'stream_context_get_default','stream_context_get_options', + 'stream_context_set_default','stream_context_set_option', + 'stream_context_set_params','stream_copy_to_stream', + 'stream_encoding','stream_filter_append','stream_filter_prepend', + 'stream_filter_register','stream_filter_remove', + 'stream_get_contents','stream_get_filters','stream_get_line', + 'stream_get_meta_data','stream_get_transports', + 'stream_get_wrappers','stream_is_local', + 'stream_notification_callback','stream_register_wrapper', + 'stream_resolve_include_path','stream_select','stream_set_blocking', + 'stream_set_timeout','stream_set_write_buffer', + 'stream_socket_accept','stream_socket_client', + 'stream_socket_enable_crypto','stream_socket_get_name', + 'stream_socket_pair','stream_socket_recvfrom', + 'stream_socket_sendto','stream_socket_server', + 'stream_socket_shutdown','stream_supports_lock', + 'stream_wrapper_register','stream_wrapper_restore', + 'stream_wrapper_unregister','strftime','stripcslashes','stripos', + 'stripslashes','strip_tags','stristr','strlen','strnatcasecmp', + 'strnatcmp','strpbrk','strncasecmp','strncmp','strpos','strrchr', + 'strrev','strripos','strrpos','strspn','strstr','strtok', + 'strtolower','strtotime','strtoupper','strtr','strval', + 'str_ireplace','str_pad','str_repeat','str_replace','str_rot13', + 'str_split','str_shuffle','str_word_count','substr', + 'substr_compare','substr_count','substr_replace','svn_add', + 'svn_auth_get_parameter','svn_auth_set_parameter','svn_cat', + 'svn_checkout','svn_cleanup','svn_client_version','svn_commit', + 'svn_diff','svn_export','svn_fs_abort_txn','svn_fs_apply_text', + 'svn_fs_begin_txn2','svn_fs_change_node_prop','svn_fs_check_path', + 'svn_fs_contents_changed','svn_fs_copy','svn_fs_delete', + 'svn_fs_dir_entries','svn_fs_file_contents','svn_fs_file_length', + 'svn_fs_is_dir','svn_fs_is_file','svn_fs_make_dir', + 'svn_fs_make_file','svn_fs_node_created_rev','svn_fs_node_prop', + 'svn_fs_props_changed','svn_fs_revision_prop', + 'svn_fs_revision_root','svn_fs_txn_root','svn_fs_youngest_rev', + 'svn_import','svn_info','svn_log','svn_ls','svn_repos_create', + 'svn_repos_fs','svn_repos_fs_begin_txn_for_commit', + 'svn_repos_fs_commit_txn','svn_repos_hotcopy','svn_repos_open', + 'svn_repos_recover','svn_status','svn_update','symlink', + 'sys_get_temp_dir','syslog','system','tan','tanh','tempnam', + 'textdomain','thread_get','thread_include','thread_lock', + 'thread_lock_try','thread_mutex_destroy','thread_mutex_init', + 'thread_set','thread_start','thread_unlock','tidy_access_count', + 'tidy_clean_repair','tidy_config_count','tidy_diagnose', + 'tidy_error_count','tidy_get_body','tidy_get_config', + 'tidy_get_error_buffer','tidy_get_head','tidy_get_html', + 'tidy_get_html_ver','tidy_get_output','tidy_get_release', + 'tidy_get_root','tidy_get_status','tidy_getopt','tidy_is_xhtml', + 'tidy_is_xml','tidy_parse_file','tidy_parse_string', + 'tidy_repair_file','tidy_repair_string','tidy_warning_count','time', + 'timezone_abbreviations_list','timezone_identifiers_list', + 'timezone_name_from_abbr','timezone_name_get','timezone_offset_get', + 'timezone_open','timezone_transitions_get','tmpfile', + 'token_get_all','token_name','touch','trigger_error', + 'transliterate','transliterate_filters_get','trim','uasort', + 'ucfirst','ucwords','uksort','umask','uniqid','unixtojd','unlink', + 'unpack','unregister_tick_function','unserialize','unset', + 'urldecode','urlencode','user_error','use_soap_error_handler', + 'usleep','usort','utf8_decode','utf8_encode','var_dump', + 'var_export','variant_abs','variant_add','variant_and', + 'variant_cast','variant_cat','variant_cmp', + 'variant_date_from_timestamp','variant_date_to_timestamp', + 'variant_div','variant_eqv','variant_fix','variant_get_type', + 'variant_idiv','variant_imp','variant_int','variant_mod', + 'variant_mul','variant_neg','variant_not','variant_or', + 'variant_pow','variant_round','variant_set','variant_set_type', + 'variant_sub','variant_xor','version_compare','virtual','vfprintf', + 'vprintf','vsprintf','wddx_add_vars','wddx_deserialize', + 'wddx_packet_end','wddx_packet_start','wddx_serialize_value', + 'wddx_serialize_vars','win_beep','win_browse_file', + 'win_browse_folder','win_create_link','win_message_box', + 'win_play_wav','win_shell_execute','win32_create_service', + 'win32_delete_service','win32_get_last_control_message', + 'win32_ps_list_procs','win32_ps_stat_mem','win32_ps_stat_proc', + 'win32_query_service_status','win32_scheduler_delete_task', + 'win32_scheduler_enum_tasks','win32_scheduler_get_task_info', + 'win32_scheduler_run','win32_scheduler_set_task_info', + 'win32_set_service_status','win32_start_service', + 'win32_start_service_ctrl_dispatcher','win32_stop_service', + 'wordwrap','xml_error_string','xml_get_current_byte_index', + 'xml_get_current_column_number','xml_get_current_line_number', + 'xml_get_error_code','xml_parse','xml_parser_create', + 'xml_parser_create_ns','xml_parser_free','xml_parser_get_option', + 'xml_parser_set_option','xml_parse_into_struct', + 'xml_set_character_data_handler','xml_set_default_handler', + 'xml_set_element_handler','xml_set_end_namespace_decl_handler', + 'xml_set_external_entity_ref_handler', + 'xml_set_notation_decl_handler','xml_set_object', + 'xml_set_processing_instruction_handler', + 'xml_set_start_namespace_decl_handler', + 'xml_set_unparsed_entity_decl_handler','xmldoc','xmldocfile', + 'xmlrpc_decode','xmlrpc_decode_request','xmlrpc_encode', + 'xmlrpc_encode_request','xmlrpc_get_type','xmlrpc_is_fault', + 'xmlrpc_parse_method_descriptions', + 'xmlrpc_server_add_introspection_data','xmlrpc_server_call_method', + 'xmlrpc_server_create','xmlrpc_server_destroy', + 'xmlrpc_server_register_introspection_callback', + 'xmlrpc_server_register_method','xmlrpc_set_type','xmltree', + 'xmlwriter_end_attribute','xmlwriter_end_cdata', + 'xmlwriter_end_comment','xmlwriter_end_document', + 'xmlwriter_end_dtd','xmlwriter_end_dtd_attlist', + 'xmlwriter_end_dtd_element','xmlwriter_end_dtd_entity', + 'xmlwriter_end_element','xmlwriter_end_pi','xmlwriter_flush', + 'xmlwriter_full_end_element','xmlwriter_open_memory', + 'xmlwriter_open_uri','xmlwriter_output_memory', + 'xmlwriter_set_indent','xmlwriter_set_indent_string', + 'xmlwriter_start_attribute','xmlwriter_start_attribute_ns', + 'xmlwriter_start_cdata','xmlwriter_start_comment', + 'xmlwriter_start_document','xmlwriter_start_dtd', + 'xmlwriter_start_dtd_attlist','xmlwriter_start_dtd_element', + 'xmlwriter_start_dtd_entity','xmlwriter_start_element', + 'xmlwriter_start_element_ns','xmlwriter_start_pi','xmlwriter_text', + 'xmlwriter_write_attribute','xmlwriter_write_attribute_ns', + 'xmlwriter_write_cdata','xmlwriter_write_comment', + 'xmlwriter_write_dtd','xmlwriter_write_dtd_attlist', + 'xmlwriter_write_dtd_element','xmlwriter_write_dtd_entity', + 'xmlwriter_write_element','xmlwriter_write_element_ns', + 'xmlwriter_write_pi','xmlwriter_write_raw','xpath_eval', + 'xpath_eval_expression','xpath_new_context','xpath_register_ns', + 'xpath_register_ns_auto','xptr_eval','xptr_new_context','yp_all', + 'yp_cat','yp_errno','yp_err_string','yp_first', + 'yp_get_default_domain','yp_master','yp_match','yp_next','yp_order', + 'zend_current_obfuscation_level','zend_get_cfg_var','zend_get_id', + 'zend_loader_current_file','zend_loader_enabled', + 'zend_loader_file_encoded','zend_loader_file_licensed', + 'zend_loader_install_license','zend_loader_version', + 'zend_logo_guid','zend_match_hostmasks','zend_obfuscate_class_name', + 'zend_obfuscate_function_name','zend_optimizer_version', + 'zend_runtime_obfuscate','zend_version','zip_close', + 'zip_entry_close','zip_entry_compressedsize', + 'zip_entry_compressionmethod','zip_entry_filesize','zip_entry_name', + 'zip_entry_open','zip_entry_read','zip_open','zip_read', + 'zlib_get_coding_type' + ), + 4 => array( + 'DEFAULT_INCLUDE_PATH', 'DIRECTORY_SEPARATOR', 'E_ALL', + 'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_CORE_ERROR', + 'E_CORE_WARNING', 'E_ERROR', 'E_NOTICE', 'E_PARSE', 'E_STRICT', + 'E_USER_ERROR', 'E_USER_NOTICE', 'E_USER_WARNING', 'E_WARNING', + 'ENT_COMPAT','ENT_QUOTES','ENT_NOQUOTES', + 'false', 'null', 'PEAR_EXTENSION_DIR', 'PEAR_INSTALL_DIR', + 'PHP_BINDIR', 'PHP_CONFIG_FILE_PATH', 'PHP_DATADIR', + 'PHP_EXTENSION_DIR', 'PHP_LIBDIR', + 'PHP_LOCALSTATEDIR', 'PHP_OS', + 'PHP_OUTPUT_HANDLER_CONT', 'PHP_OUTPUT_HANDLER_END', + 'PHP_OUTPUT_HANDLER_START', 'PHP_SYSCONFDIR', + 'PHP_VERSION', 'true', '__CLASS__', '__FILE__', '__FUNCTION__', + '__LINE__', '__METHOD__' + ) + ), + 'SYMBOLS' => array( + 1 => array( + '<%', '<%=', '%>', '' + ), + 0 => array( + '(', ')', '[', ']', '{', '}', + '!', '@', '%', '&', '|', '/', + '<', '>', + '=', '-', '+', '*', + '.', ':', ',', ';' + ) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #990000;', + 4 => 'color: #009900; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => 'color: #666666; font-style: italic;', + 3 => 'color: #0000cc; font-style: italic;', + 4 => 'color: #009933; font-style: italic;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 1 => 'color: #000099; font-weight: bold;', + 2 => 'color: #660099; font-weight: bold;', + 3 => 'color: #660099; font-weight: bold;', + 4 => 'color: #006699; font-weight: bold;', + 5 => 'color: #006699; font-weight: bold; font-style: italic;', + 6 => 'color: #009933; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;', + 'HARD' => 'color: #0000ff;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;', + GESHI_NUMBER_OCT_PREFIX => 'color: #208080;', + GESHI_NUMBER_HEX_PREFIX => 'color: #208080;', + GESHI_NUMBER_FLT_SCI_ZERO => 'color:#800080;', + ), + 'METHODS' => array( + 1 => 'color: #004000;', + 2 => 'color: #004000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;', + 1 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #000088;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.php.net/{FNAMEL}', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '->', + 2 => '::' + ), + 'REGEXPS' => array( + //Variables + 0 => "[\\$]{1,2}[a-zA-Z_][a-zA-Z0-9_]*" + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + ' '?>' + ), + 1 => array( + ' '?>' + ), + 2 => array( + '<%' => '%>' + ), + 3 => array( + '' + ), + 4 => "/(<\?(?:php)?)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(\?>|\Z)/sm", + 5 => "/(<%)(?:'(?:[^'\\\\]|\\\\.)*?'|\"(?:[^\"\\\\]|\\\\.)*?\"|\/\*(?!\*\/).*?\*\/|.)*?(%>|\Z)/sm" + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true + ), + 'TAB_WIDTH' => 4 +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/pic16.php b/examples/includes/geshi/geshi/pic16.php new file mode 100644 index 0000000..2679788 --- /dev/null +++ b/examples/includes/geshi/geshi/pic16.php @@ -0,0 +1,141 @@ + 'PIC16', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + /*Instructions*/ + 1 => array( + 'addcf','adddcf','addlw','addwf','andlw','andwf','bc','bcf','bdc', + 'bnc','bndc','bnz','bsf','btfsc','btfss','bz','call','clrc','clrdc', + 'clrf','clrw','clrwdt','clrz','comf','decf','goto','incf','incfsz', + 'iorlw','iorwf','lcall','lgoto','movf','movfw','movlw','movwf', + 'option','negf','nop','retfie','retlw','return','rlf','rrf','setc', + 'setdc','setz','skpc','skpdc','skpnc','skpndc','skpnz','skpz', + 'sleep','subcf','subdcf','sublw','subwf','swapf','tris','tstf', + 'xorlw','xorwf' + ), + /*Registers*/ + 2 => array( + 'INDF','TMR0','OPTION','PCL','STATUS','FSR','PORTA','PORTB','PORTC', + 'PORTD','PORTE','PORTF','TRISA','TRISB','TRISC','TRISD','TRISE', + 'TRISF','PCLATH','INTCON','PIR1','PIE1','PCON','CMCON','VRCON', + 'F','W' + ), + /*Directives*/ + 3 => array( + '_BADRAM','BANKISEL','BANKSEL','CBLOCK','CODE','_CONFIG','CONSTANT', + 'DA','DATA','DB','DE','#DEFINE','DT','DW','ELSE','END','ENDC', + 'ENDIF','ENDM','ENDW','EQU','ERROR','ERRORLEVEL','EXITM','EXPAND', + 'EXTERN','FILL','GLOBAL','IDATA','_IDLOCS','IF','IFDEF','IFNDEF', + 'INCLUDE','#INCLUDE','LIST','LOCAL','MACRO','_MAXRAM','MESSG', + 'NOEXPAND','NOLIST','ORG','PAGE','PAGESEL','PROCESSOR','RADIX', + 'RES','SET','SPACE','SUBTITLE','TITLE','UDATA','UDATA_ACS', + 'UDATA_OVR','UDATA_SHR','#UNDEFINE','VARIABLE','WHILE', + 'D','H','O','B','A' + ), + ), + 'SYMBOLS' => array('=','.',',',':'), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000a0; font-weight: bold;', + 2 => 'color: #aa3300; font-weight: bold;', + 3 => 'color: #0000ff;', + ), + 'COMMENTS' => array( + 1 => 'color: #00a000;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #ff0000;' + ), + 'BRACKETS' => array( + 0 => 'color: #0000ff;' + ), + 'STRINGS' => array( + 0 => 'color: #ff7700;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff7700;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #7777ff;' + ), + 'REGEXPS' => array(), + 'SCRIPT' => array() + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | + GESHI_NUMBER_BIN_SUFFIX | + GESHI_NUMBER_HEX_PREFIX | + GESHI_NUMBER_HEX_SUFFIX, + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array(), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "a-zA-Z0-9\$_\|\#>|^", + 'DISALLOWED_AFTER' => "a-zA-Z0-9_<\|%" + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/pixelbender.php b/examples/includes/geshi/geshi/pixelbender.php new file mode 100644 index 0000000..93da0df --- /dev/null +++ b/examples/includes/geshi/geshi/pixelbender.php @@ -0,0 +1,176 @@ + 'Pixel Bender 1.0', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'languageVersion', 'kernel' + ), + 2 => array( + 'import', 'parameter', 'dependent', 'const', 'input', 'output', + 'evaluatePixel', 'evaluateDependents', 'needed', 'changed', 'generated' + ), + 3 => array( + 'bool', 'bool2', 'bool3', 'bool4', 'int', 'int2', 'int3', 'int4', + 'float', 'float2', 'float3', 'float4', 'float2x2', 'float3x3', 'float4x4', + 'pixel2', 'pixel3', 'pixel4', 'region', 'image1', 'image2', 'image3', 'image4', + 'imageRef', 'void' + ), + 4 => array( + 'in', 'out', 'inout', 'if', 'else', 'for', 'while', 'do', 'break', + 'continue', 'return' + ), + 5 => array( + 'radians', 'degrees', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'pow', + 'exp', 'exp2', 'log', 'log2', 'sqrt', 'inverseSqrt', 'abs', 'sign', 'floor', + 'ceil', 'fract', 'mod', 'min', 'max', 'step', 'clamp', 'mix', 'smoothStep', + 'length', 'distance', 'dot', 'cross', 'normalize', 'matrixCompMult', 'lessThan', + 'lessThanEqual', 'greaterThan', 'greaterThanEqual', 'equal', 'notEqual', 'any', + 'all', 'not', 'nowhere', 'everywhere', 'transform', 'union', 'intersect', + 'outset', 'inset', 'bounds', 'isEmpty', 'sample', 'sampleLinear', 'sampleNearest', + 'outCoord', 'dod', 'pixelSize', 'pixelAspectRatio' + ), + 6 => array( + 'namespace', 'vendor', 'version', 'minValue', 'maxValue', 'defaultValue', 'description' + ), + 7 => array( + '#if', '#endif', '#ifdef', '#elif', 'defined', '#define', + 'AIF_ATI', 'AIF_NVIDIA', 'AIF_FLASH_TARGET' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '%', '&', '|', '+', '-', '*', '/', '=', '<', '>', '?', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0033ff;', + 2 => 'color: #0033ff; font-weight: bold;', + 3 => 'color: #0033ff;', + 4 => 'color: #9900cc; font-weight: bold;', + 5 => 'color: #333333;', + 6 => 'color: #666666;', + 7 => 'color: #990000;', + ), + 'COMMENTS' => array( + 1 => 'color: #009900;', + 'MULTI' => 'color: #3f5fbf;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #990000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000; font-weight:bold;' + ), + 'METHODS' => array( + 0 => 'color: #000000;', + ), + 'SYMBOLS' => array( + 0 => 'color: #000000; font-weight: bold;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array('.'), + 'REGEXPS' => array(), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array() +); + + +?> diff --git a/examples/includes/geshi/geshi/plsql.php b/examples/includes/geshi/geshi/plsql.php new file mode 100644 index 0000000..2f3a2b6 --- /dev/null +++ b/examples/includes/geshi/geshi/plsql.php @@ -0,0 +1,256 @@ + + * Copyright: (c) 2006 Victor Engmark (http://l0b0.net/) + * Release Version: 1.0.8.3 + * Date Started: 2006/10/26 + * + * Oracle 9.2 PL/SQL language file for GeSHi. + * Formatting is based on the default setup of TOAD 8.6. + * + * CHANGES + * ------- + * 2006/10/27 (1.0.0) + * - First Release + * + * TODO (updated 2006/10/27) + * ------------------------- + * * Add < and > to brackets + * * Remove symbols which are also comment delimiters / quote marks? + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'PL/SQL', + 'COMMENT_SINGLE' => array(1 =>'--'), //http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96624/02_funds.htm#2930 + 'COMMENT_MULTI' => array('/*' => '*/'), //http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96624/02_funds.htm#2950 + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array("'", '"'), //http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96624/02_funds.htm + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + //PL/SQL reserved keywords (http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96624/f_words.htm#LNPLS019) + 1 => array('ZONE', 'YEAR', 'WRITE', 'WORK', 'WITH', 'WHILE', 'WHERE', + 'WHENEVER', 'WHEN', 'VIEW', 'VARCHAR2', 'VARCHAR', 'VALUES', + 'VALIDATE', 'USE', 'UPDATE', 'UNIQUE', 'UNION', 'TYPE', 'TRUE', + 'TRIGGER', 'TO', 'TIMEZONE_REGION', 'TIMEZONE_MINUTE', 'TIMEZONE_HOUR', + 'TIMEZONE_ABBR', 'TIMESTAMP', 'TIME', 'THEN', 'TABLE', 'SYNONYM', + 'SUCCESSFUL', 'SUBTYPE', 'START', 'SQLERRM', 'SQLCODE', 'SQL', 'SPACE', + 'SMALLINT', 'SHARE', 'SET', 'SEPARATE', 'SELECT', 'SECOND', + 'SAVEPOINT', 'ROWTYPE', 'ROWNUM', 'ROWID', 'ROW', 'ROLLBACK', + 'REVERSE', 'RETURN', 'RELEASE', 'RECORD', 'REAL', 'RAW', 'RANGE', + 'RAISE', 'PUBLIC', 'PROCEDURE', 'PRIVATE', 'PRIOR', 'PRAGMA', + 'POSITIVEN', 'POSITIVE', 'PLS_INTEGER', 'PCTFREE', 'PARTITION', + 'PACKAGE', 'OUT', 'OTHERS', 'ORGANIZATION', 'ORDER', 'OR', 'OPTION', + 'OPERATOR', 'OPEN', 'OPAQUE', 'ON', 'OF', 'OCIROWID', 'NUMBER_BASE', + 'NUMBER', 'NULL', 'NOWAIT', 'NOT', 'NOCOPY', 'NEXTVAL', 'NEW', + 'NATURALN', 'NATURAL', 'MONTH', 'MODE', 'MLSLABEL', 'MINUTE', 'MINUS', + 'LOOP', 'LONG', 'LOCK', 'LIMITED', 'LIKE', 'LEVEL', 'JAVA', + 'ISOLATION', 'IS', 'INTO', 'INTERVAL', 'INTERSECT', 'INTERFACE', + 'INTEGER', 'INSERT', 'INDICATOR', 'INDEX', 'IN', 'IMMEDIATE', 'IF', + 'HOUR', 'HEAP', 'HAVING', 'GROUP', 'GOTO', 'FUNCTION', 'FROM', + 'FORALL', 'FOR', 'FLOAT', 'FETCH', 'FALSE', 'EXTENDS', 'EXIT', + 'EXISTS', 'EXECUTE', 'EXCLUSIVE', 'EXCEPTION', 'END', 'ELSIF', 'ELSE', + 'DROP', 'DO', 'DISTINCT', 'DESC', 'DELETE', 'DEFAULT', 'DECLARE', + 'DECIMAL', 'DAY', 'DATE', 'CURSOR', 'CURRVAL', 'CURRENT', 'CREATE', + 'CONSTANT', 'CONNECT', 'COMPRESS', 'COMMIT', 'COMMENT', 'COLLECT', + 'CLUSTER', 'CLOSE', 'CHECK', 'CHAR_BASE', 'CHAR', 'CASE', 'BY', 'BULK', + 'BOOLEAN', 'BODY', 'BINARY_INTEGER', 'BETWEEN', 'BEGIN', 'AUTHID', + 'AT', 'ASC', 'AS', 'ARRAY', 'ANY', 'AND', 'ALTER', 'ALL'), + //SQL functions (http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/toc.htm & http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/functions101a.htm#85925) + 2 => array('XMLTRANSFORM', 'XMLSEQUENCE', 'XMLFOREST', 'XMLELEMENT', + 'XMLCONCAT', 'XMLCOLATTVAL', 'XMLAGG', 'WIDTH_BUCKET', 'VSIZE', + 'VARIANCE', 'VAR_SAMP', 'VAR_POP', 'VALUE', 'USERENV', 'USER', 'UPPER', + 'UPDATEXML', 'UNISTR', 'UID', 'TZ_OFFSET', 'TRUNC', 'TRIM', 'TREAT', + 'TRANSLATE', 'TO_YMINTERVAL', 'TO_TIMESTAMP_TZ', 'TO_TIMESTAMP', + 'TO_SINGLE_BYTE', 'TO_NUMBER', 'TO_NCLOB', 'TO_NCHAR', 'TO_MULTI_BYTE', + 'TO_LOB', 'TO_DSINTERVAL', 'TO_DATE', 'TO_CLOB', 'TO_CHAR', 'TANH', + 'TAN', 'SYSTIMESTAMP', 'SYSDATE', 'SYS_XMLGEN', 'SYS_XMLAGG', + 'SYS_TYPEID', 'SYS_GUID', 'SYS_EXTRACT_UTC', 'SYS_DBURIGEN', + 'SYS_CONTEXT', 'SYS_CONNECT_BY_PATH', 'SUM', 'SUBSTR', 'STDDEV_SAMP', + 'STDDEV_POP', 'STDDEV', 'SQRT', 'SOUNDEX', 'SINH', 'SIN', 'SIGN', + 'SESSIONTIMEZONE', 'RTRIM', 'RPAD', 'ROWIDTONCHAR', 'ROWIDTOCHAR', + 'ROW_NUMBER', 'ROUND', 'REPLACE', 'REGR_SYY', 'REGR_SXY', 'REGR_SXX', + 'REGR_SLOPE', 'REGR_R2', 'REGR_INTERCEPT', 'REGR_COUNT', 'REGR_AVGY', + 'REGR_AVGX', 'REFTOHEX', 'REF', 'RAWTONHEX', 'RAWTOHEX', + 'RATIO_TO_REPORT', 'RANK', 'POWER', 'PERCENTILE_DISC', + 'PERCENTILE_CONT', 'PERCENT_RANK', 'PATH', 'NVL2', 'NVL', + 'NUMTOYMINTERVAL', 'NUMTODSINTERVAL', 'NULLIF', 'NTILE', 'NLSSORT', + 'NLS_UPPER', 'NLS_LOWER', 'NLS_INITCAP', 'NLS_CHARSET_NAME', + 'NLS_CHARSET_ID', 'NLS_CHARSET_DECL_LEN', 'NEXT_DAY', 'NEW_TIME', + 'NCHR', 'MONTHS_BETWEEN', 'MOD', 'MIN', 'MAX', 'MAKE_REF', 'LTRIM', + 'LPAD', 'LOWER', 'LOG', 'LOCALTIMESTAMP', 'LN', 'LENGTH', 'LEAST', + 'LEAD', 'LAST_VALUE', 'LAST_DAY', 'LAST', 'LAG', 'INSTR', 'INITCAP', + 'HEXTORAW', 'GROUPING_ID', 'GROUPING', 'GROUP_ID', 'GREATEST', + 'FROM_TZ', 'FLOOR', 'FIRST_VALUE', 'FIRST', 'EXTRACTVALUE', 'EXTRACT', + 'EXP', 'EXISTSNODE', 'EMPTY_CLOB', 'EMPTY_BLOB', 'DUMP', 'DEREF', + 'DEPTH', 'DENSE_RANK', 'DECOMPOSE', 'DECODE', 'DBTIMEZONE', + 'CURRENT_TIMESTAMP', 'CURRENT_DATE', 'CUME_DIST', 'COVAR_SAMP', + 'COVAR_POP', 'COUNT', 'COSH', 'COS', 'CORR', 'CONVERT', 'CONCAT', + 'COMPOSE', 'COALESCE', 'CHR', 'CHARTOROWID', 'CEIL', 'CAST', 'BITAND', + 'BIN_TO_NUM', 'BFILENAME', 'AVG', 'ATAN2', 'ATAN', 'ASIN', 'ASCIISTR', + 'ASCII', 'ADD_MONTHS', 'ACOS', 'ABS'), + //PL/SQL packages (http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96612/intro2.htm#1025672) + 3 => array('UTL_URL', 'UTL_TCP', 'UTL_SMTP', 'UTL_REF', 'UTL_RAW', + 'UTL_PG', 'UTL_INADDR', 'UTL_HTTP', 'UTL_FILE', 'UTL_ENCODE', + 'UTL_COLL', 'SDO_UTIL', 'SDO_TUNE', 'SDO_MIGRATE', 'SDO_LRS', + 'SDO_GEOM', 'SDO_CS', 'DMBS_XMLQUERY', 'DMBS_FLASHBACK', + 'DMBS_DEFER_SYS', 'DEBUG_EXTPROC', 'DBMS_XSLPROCESSOR', 'DBMS_XPLAN', + 'DBMS_XMLSCHEMA', 'DBMS_XMLSAVE', 'DBMS_XMLPARSER', 'DBMS_XMLGEN', + 'DBMS_XMLDOM', 'DBMS_XDBT', 'DBMS_XDB_VERSION', 'DBMS_XDB', 'DBMS_WM', + 'DBMS_UTILITY', 'DBMS_TYPES', 'DBMS_TTS', 'DBMS_TRANSFORM', + 'DBMS_TRANSACTION', 'DBMS_TRACE', 'DBMS_STRM_A', 'DBMS_STRM', + 'DBMS_STORAGE_MAP', 'DBMS_STATS', 'DBMS_SQL', 'DBMS_SPACE_ADMIN', + 'DBMS_SPACE', 'DBMS_SHARED_POOL', 'DBMS_SESSION', 'DBMS_RULE_ADM', + 'DBMS_RULE', 'DBMS_ROWID', 'DBMS_RLS', 'DBMS_RESUMABLE', + 'DBMS_RESOURCE_MANAGER_PRIVS', 'DBMS_RESOURCE_MANAGER', 'DBMS_REPUTIL', + 'DBMS_REPCAT_RGT', 'DBMS_REPCAT_INSTATIATE', 'DBMS_REPCAT_ADMIN', + 'DBMS_REPCAT', 'DBMS_REPAIR', 'DBMS_REFRESH', 'DBMS_REDEFINITION', + 'DBMS_RECTIFIER_DIFF', 'DBMS_RANDOM', 'DBMS_PROPAGATION_ADM', + 'DBMS_PROFILER', 'DBMS_PIPE', 'DBMS_PCLXUTIL', 'DBMS_OUTPUT', + 'DBMS_OUTLN_EDIT', 'DBMS_OUTLN', 'DBMS_ORACLE_TRACE_USER', + 'DBMS_ORACLE_TRACE_AGENT', 'DBMS_OLAP', 'DBMS_OFFLINE_SNAPSHOT', + 'DBMS_OFFLINE_OG', 'DBMS_ODCI', 'DBMS_OBFUSCATION_TOOLKIT', + 'DBMS_MVIEW', 'DBMS_MGWMSG', 'DBMS_MGWADM', 'DBMS_METADATA', + 'DBMS_LOGSTDBY', 'DBMS_LOGMNR_D', 'DBMS_LOGMNR_CDC_SUBSCRIBE', + 'DBMS_LOGMNR_CDC_PUBLISH', 'DBMS_LOGMNR', 'DBMS_LOCK', 'DBMS_LOB', + 'DBMS_LIBCACHE', 'DBMS_LDAP', 'DBMS_JOB', 'DBMS_IOT', + 'DBMS_HS_PASSTHROUGH', 'DBMS_FGA', 'DBMS_DISTRIBUTED_TRUST_ADMIN', + 'DBMS_DESCRIBE', 'DBMS_DEFER_QUERY', 'DBMS_DEFER', 'DBMS_DEBUG', + 'DBMS_DDL', 'DBMS_CAPTURE_ADM', 'DBMS_AW', 'DBMS_AQELM', 'DBMS_AQADM', + 'DBMS_AQ', 'DBMS_APPLY_ADM', 'DBMS_APPLICATION_INFO', 'DBMS_ALERT', + 'CWM2_OLAP_AW_ACCESS'), + //PL/SQL predefined exceptions (http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96624/07_errs.htm#784) + 4 => array('ZERO_DIVIDE', 'VALUE_ERROR', 'TOO_MANY_ROWS', + 'TIMEOUT_ON_RESOURCE', 'SYS_INVALID_ROWID', 'SUBSCRIPT_OUTSIDE_LIMIT', + 'SUBSCRIPT_BEYOND_COUNT', 'STORAGE_ERROR', 'SELF_IS_NULL', + 'ROWTYPE_MISMATCH', 'PROGRAM_ERROR', 'NOT_LOGGED_ON', 'NO_DATA_FOUND', + 'LOGIN_DENIED', 'INVALID_NUMBER', 'INVALID_CURSOR', 'DUP_VAL_ON_INDEX', + 'CURSOR_ALREADY_OPEN', 'COLLECTION_IS_NULL', 'CASE_NOT_FOUND', + 'ACCESS_INTO_NULL'), + //Static data dictionary views (http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96536/ch2.htm) + 5 => array('USER_REPSITES', 'USER_REPSCHEMA', + 'USER_REPRESOLUTION_STATISTICS', 'USER_REPRESOLUTION_METHOD', + 'USER_REPRESOLUTION', 'USER_REPRESOL_STATS_CONTROL', 'USER_REPPROP', + 'USER_REPPRIORITY_GROUP', 'USER_REPPRIORITY', + 'USER_REPPARAMETER_COLUMN', 'USER_REPOBJECT', 'USER_REPKEY_COLUMNS', + 'USER_REPGROUPED_COLUMN', 'USER_REPGROUP_PRIVILEGES', 'USER_REPGROUP', + 'USER_REPGENOBJECTS', 'USER_REPGENERATED', 'USER_REPFLAVORS', + 'USER_REPFLAVOR_OBJECTS', 'USER_REPFLAVOR_COLUMNS', 'USER_REPDDL', + 'USER_REPCONFLICT', 'USER_REPCOLUMN_GROUP', 'USER_REPCOLUMN', + 'USER_REPCATLOG', 'USER_REPCAT_USER_PARM_VALUES', + 'USER_REPCAT_USER_AUTHORIZATIONS', 'USER_REPCAT_TEMPLATE_SITES', + 'USER_REPCAT_TEMPLATE_PARMS', 'USER_REPCAT_TEMPLATE_OBJECTS', + 'USER_REPCAT_REFRESH_TEMPLATES', 'USER_REPCAT', 'USER_REPAUDIT_COLUMN', + 'USER_REPAUDIT_ATTRIBUTE', 'DBA_REPSITES_NEW', 'DBA_REPSITES', + 'DBA_REPSCHEMA', 'DBA_REPRESOLUTION_STATISTICS', + 'DBA_REPRESOLUTION_METHOD', 'DBA_REPRESOLUTION', + 'DBA_REPRESOL_STATS_CONTROL', 'DBA_REPPROP', 'DBA_REPPRIORITY_GROUP', + 'DBA_REPPRIORITY', 'DBA_REPPARAMETER_COLUMN', 'DBA_REPOBJECT', + 'DBA_REPKEY_COLUMNS', 'DBA_REPGROUPED_COLUMN', + 'DBA_REPGROUP_PRIVILEGES', 'DBA_REPGROUP', 'DBA_REPGENOBJECTS', + 'DBA_REPGENERATED', 'DBA_REPFLAVORS', 'DBA_REPFLAVOR_OBJECTS', + 'DBA_REPFLAVOR_COLUMNS', 'DBA_REPEXTENSIONS', 'DBA_REPDDL', + 'DBA_REPCONFLICT', 'DBA_REPCOLUMN_GROUP', 'DBA_REPCOLUMN', + 'DBA_REPCATLOG', 'DBA_REPCAT_USER_PARM_VALUES', + 'DBA_REPCAT_USER_AUTHORIZATIONS', 'DBA_REPCAT_TEMPLATE_SITES', + 'DBA_REPCAT_TEMPLATE_PARMS', 'DBA_REPCAT_TEMPLATE_OBJECTS', + 'DBA_REPCAT_REFRESH_TEMPLATES', 'DBA_REPCAT_EXCEPTIONS', 'DBA_REPCAT', + 'DBA_REPAUDIT_COLUMN', 'DBA_REPAUDIT_ATTRIBUTE', 'ALL_REPSITES', + 'ALL_REPSCHEMA', 'ALL_REPRESOLUTION_STATISTICS', + 'ALL_REPRESOLUTION_METHOD', 'ALL_REPRESOLUTION', + 'ALL_REPRESOL_STATS_CONTROL', 'ALL_REPPROP', 'ALL_REPPRIORITY_GROUP', + 'ALL_REPPRIORITY', 'ALL_REPPARAMETER_COLUMN', 'ALL_REPOBJECT', + 'ALL_REPKEY_COLUMNS', 'ALL_REPGROUPED_COLUMN', + 'ALL_REPGROUP_PRIVILEGES', 'ALL_REPGROUP', 'ALL_REPGENOBJECTS', + 'ALL_REPGENERATED', 'ALL_REPFLAVORS', 'ALL_REPFLAVOR_OBJECTS', + 'ALL_REPFLAVOR_COLUMNS', 'ALL_REPDDL', 'ALL_REPCONFLICT', + 'ALL_REPCOLUMN_GROUP', 'ALL_REPCOLUMN', 'ALL_REPCATLOG', + 'ALL_REPCAT_USER_PARM_VALUES', 'ALL_REPCAT_USER_AUTHORIZATIONS', + 'ALL_REPCAT_TEMPLATE_SITES', 'ALL_REPCAT_TEMPLATE_PARMS', + 'ALL_REPCAT_TEMPLATE_OBJECTS', 'ALL_REPCAT_REFRESH_TEMPLATES', + 'ALL_REPCAT', 'ALL_REPAUDIT_COLUMN', 'ALL_REPAUDIT_ATTRIBUTE') + ), + 'SYMBOLS' => array( + //PL/SQL delimiters (http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96624/02_funds.htm#2732) + '+', '%', "'", '.', '/', '(', ')', ':', ',', '*', '"', '=', '<', '>', '@', ';', '-', ':=', '=>', '||', '**', '<<', '>>', '/*', '*/', '..', '<>', '!=', '~=', '^=', '<=', '>=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #00F;', + 2 => 'color: #000;', + 3 => 'color: #00F;', + 4 => 'color: #F00;', + 5 => 'color: #800;' + ), + 'COMMENTS' => array( + 1 => 'color: #080; font-style: italic;', + 'MULTI' => 'color: #080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #00F;' + ), + 'STRINGS' => array( + 0 => 'color: #F00;' + ), + 'NUMBERS' => array( + 0 => 'color: #800;' + ), + 'METHODS' => array( + 0 => 'color: #0F0;' + ), + 'SYMBOLS' => array( + 0 => 'color: #00F;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + 0 => 'color: #0F0;' + ) + ), + 'URLS' => array( + 1 => 'http://www.oracle.com/pls/db92/db92.drilldown?word={FNAMEU}', + 2 => 'http://www.oracle.com/pls/db92/db92.drilldown?word={FNAMEU}', + 3 => 'http://www.oracle.com/pls/db92/db92.drilldown?word={FNAMEU}', + 4 => 'http://www.oracle.com/pls/db92/db92.drilldown?word={FNAMEU}', + 5 => 'http://www.oracle.com/pls/db92/db92.drilldown?word={FNAMEU}' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array(), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array() +); + +?> diff --git a/examples/includes/geshi/geshi/povray.php b/examples/includes/geshi/geshi/povray.php new file mode 100644 index 0000000..09a8b01 --- /dev/null +++ b/examples/includes/geshi/geshi/povray.php @@ -0,0 +1,199 @@ + 'POVRAY', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'yes', 'wrinkles', 'wood', 'width', 'waves', 'water_level', 'warp', 'vturbulence', + 'vstr', 'vrotate', 'vnormalize', 'vlength', 'vcross', 'vaxis_rotate', 'variance', 'v_steps', + 'uv_mapping', 'utf8', 'use_index', 'use_colour', 'use_color', 'use_alpha', 'up', 'undef', + 'ultra_wide_angle', 'u_steps', 'type', 'turbulence', 'turb_depth', 'ttf', 'true', 'triangle_wave', + 'translate', 'transform', 'trace', 'toroidal', 'tolerance', 'tiles', 'tile2', 'tightness', + 'tiff', 'threshold', 'thickness', 'tga', 'texture_map', 'target', 'sys', 'sum', + 'substr', 'sturm', 'strupr', 'strlwr', 'strength', 'str', 'statistics', 'sqr', + 'spotted', 'spotlight', 'split_union', 'spline', 'spiral2', 'spiral1', 'spherical', 'specular', + 'spacing', 'solid', 'smooth', 'slope', 'slice', 'sky', 'size', 'sine_wave', + 'shadowless', 'scattering', 'scallop_wave', 'scale', 'save_file', 'samples', 'roughness', 'rotate', + 'ripples', 'right', 'rgbt', 'rgbft', 'rgbf', 'rgb', 'repeat', 'render', + 'refraction', 'reflection_exponent', 'recursion_limit', 'reciprocal', 'ratio', 'ramp_wave', 'radius', 'radial', + 'quilted', 'quick_colour', 'quick_color', 'quaternion', 'quadratic_spline', 'pwr', 'projected_through', 'prod', + 'pretrace_start', 'pretrace_end', 'precompute', 'precision', 'ppm', 'pow', 'pot', 'poly_wave', + 'point_at', 'png', 'planar', 'pigment_pattern', 'pi', 'phong_size', 'phong', 'phase', + 'pgm', 'perspective', 'pattern', 'pass_through', 'parallel', 'panoramic', 'orthographic', 'orientation', + 'orient', 'open', 'onion', 'once', 'on', 'omnimax', 'omega', 'offset', + 'off', 'octaves', 'number_of_waves', 'noise_generator', 'no_shadow', 'no_reflection', 'no_image', 'no_bump_scale', + 'no', 'nearest_count', 'natural_spline', 'mortar', 'minimum_reuse', 'min_extent', 'metric', 'method', + 'metallic', 'media_interaction', 'media_attenuation', 'media', 'max_trace_level', 'max_trace', 'max_sample', 'max_iteration', + 'max_intersections', 'max_gradient', 'max_extent', 'matrix', 'material_map', 'marble', 'map_type', 'mandel', + 'major_radius', 'magnet', 'low_error_factor', 'look_at', 'location', 'load_file', 'linear_sweep', 'linear_spline', + 'leopard', 'lambda', 'julia', 'jpeg', 'jitter', 'irid_wavelength', 'ior', 'inverse', + 'intervals', 'interpolate', 'internal', 'inside_vector', 'inside', 'initial_frame', 'initial_clock', 'image_width', + 'image_pattern', 'image_height', 'iff', 'hypercomplex', 'hollow', 'hierarchy', 'hf_gray_16', 'hexagon', + 'gray_threshold', 'granite', 'gradient', 'global_lights', 'gif', 'gather', 'fresnel', 'frequency', + 'frame_number', 'form', 'fog_type', 'fog_offset', 'fog_alt', 'focal_point', 'flip', 'flatness', + 'fisheye', 'final_frame', 'final_clock', 'false', 'falloff_angle', 'falloff', 'fade_power', 'fade_distance', + 'fade_colour', 'fade_color', 'facets', 'extinction', 'exterior', 'exponent', 'expand_thresholds', 'evaluate', + 'error_bound', 'emission', 'eccentricity', 'double_illuminate', 'distance', 'dist_exp', 'dispersion_samples', 'dispersion', + 'direction', 'diffuse', 'df3', 'dents', 'density_map', 'density_file', 'density', 'cylindrical', + 'cutaway_textures', 'cubic_wave', 'cubic_spline', 'cube', 'crand', 'crackle', 'count', 'coords', + 'control1', 'control0', 'conserve_energy', 'conic_sweep', 'confidence', 'concat', 'composite', 'component', + 'colour_map', 'colour', 'color', 'collect', 'clock_on', 'clock_delta', 'clock', 'circular', + 'chr', 'checker', 'charset', 'cells', 'caustics', 'bumps', 'bump_size', 'brilliance', + 'brightness', 'brick_size', 'brick', 'bozo', 'boxed', 'blur_samples', 'black_hole', 'bezier_spline', + 'b_spline', 'average', 'autostop', 'assumed_gamma', 'ascii', 'array', 'area_light', 'arc_angle', + 'append', 'aperture', 'angle', 'ambient_light', 'ambient', 'always_sample', 'altitude', 'alpha', + 'all_intersections', 'all', 'agate_turb', 'agate', 'adc_bailout', 'adaptive', 'accuracy', 'absorption', + 'aa_threshold', 'aa_level', 'reflection' + ), + 2 => array( + 'abs', 'acos', 'acosh', 'asc', 'asin', 'asinh', 'atan', 'atanh', + 'atan2', 'ceil', 'cos', 'cosh', 'defined', 'degrees', 'dimensions', 'dimension_size', + 'div', 'exp', 'file_exists', 'floor', 'int', 'ln', 'log', 'max', + 'min', 'mod', 'pov', 'radians', 'rand', 'seed', 'select', 'sin', + 'sinh', 'sqrt', 'strcmp', 'strlen', 'tan', 'tanh', 'val', 'vdot', + 'vlenght', + ), + 3 => array ( + 'x', 'y', 'z', 't', 'u', 'v', 'red', 'blue', + 'green', 'filter', 'transmit', 'gray', 'e', + ), + 4 => array ( + 'camera', 'background', 'fog', 'sky_sphere', 'rainbow', 'global_settings', 'radiosity', 'photon', + 'object', 'blob', 'sphere', 'cylinder', 'box', 'cone', 'height_field', 'julia_fractal', + 'lathe', 'prism', 'sphere_sweep', 'superellipsoid', 'sor', 'text', 'torus', 'bicubic_patch', + 'disc', 'mesh', 'triangle', 'smooth_triangle', 'mesh2', 'vertex_vectors', 'normal_vectors', 'uv_vectors', + 'texture_list', 'face_indices', 'normal_indices', 'uv_indices', 'texture', 'polygon', 'plane', 'poly', + 'cubic', 'quartic', 'quadric', 'isosurface', 'function', 'contained_by', 'parametric', 'pigment', + 'union', 'intersection', 'difference', 'merge', 'light_source', 'looks_like', 'light_group', 'clipped_by', + 'bounded_by', 'interior', 'material', 'interior_texture', 'normal', 'finish', 'color_map', 'pigment_map', + 'image_map', 'bump_map', 'slope_map', 'normal_map', 'irid', 'photons', + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', + '@', '%', '&', '*', '|', '/', '<', + '>', '+', '-', '.', '=', '<=', '>=', + '!=', + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #a63123;', + 2 => 'color: #2312bc;', + 3 => 'color: #cc1122; font-weight: bold;', + 4 => 'color: #116688; font-weight: bold;', + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', +// 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66aa;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + 0 => 'color: #6666cc; font-weight: bold;', + 1 => 'color: #66cc66; font-weight: bold;', + 2 => 'color: #66cc66; font-weight: bold;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + # normal hash lines + 0 => '\#(?!(include|declare|local|fopen|fclose|read|write|default|version|if|else|end|ifdef|ifndef|switch|case|range|break|while|debug|error|warning|macro) )[[:word:]]*', + # syntax functions hash thingis + 1 => "\#(include|declare|local|fopen|fclose|read|write|default|version|if|else|end|ifdef|ifndef|switch|case|range|break|while|debug|error|warning|macro)", + 2 => array( + GESHI_SEARCH => "([a-zA-Z]+)(\n)(.*)(\n)(\\1;?)", + GESHI_REPLACE => '\3', + GESHI_BEFORE => '\1\2', + GESHI_AFTER => '\4\5', + GESHI_MODIFIERS => 'siU' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true + ), + 'TAB_WIDTH' => 4 +); +?> diff --git a/examples/includes/geshi/geshi/powershell.php b/examples/includes/geshi/geshi/powershell.php new file mode 100644 index 0000000..5b9e16b --- /dev/null +++ b/examples/includes/geshi/geshi/powershell.php @@ -0,0 +1,279 @@ + 'posh', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '`', + 'KEYWORDS' => array( + 1 => array( + // Cmdlets + 'Add-Content', 'Add-History', 'Add-Member', 'Add-PSSnapin', 'Clear-Content', 'Clear-Item', + 'Clear-ItemProperty', 'Clear-Variable', 'Compare-Object', 'ConvertFrom-SecureString', + 'Convert-Path', 'ConvertTo-Html', 'ConvertTo-SecureString', 'Copy-Item', 'Copy-ItemProperty', + 'Export-Alias', 'Export-Clixml', 'Export-Console', 'Export-Csv', 'ForEach-Object', + 'Format-Custom', 'Format-List', 'Format-Table', 'Format-Wide', 'Get-Acl', 'Get-Alias', + 'Get-AuthenticodeSignature', 'Get-ChildItem', 'Get-Command', 'Get-Content', 'Get-Credential', + 'Get-Culture', 'Get-Date', 'Get-EventLog', 'Get-ExecutionPolicy', 'Get-Help', 'Get-History', + 'Get-Host', 'Get-Item', 'Get-ItemProperty', 'Get-Location', 'Get-Member', + 'Get-PfxCertificate', 'Get-Process', 'Get-PSDrive', 'Get-PSProvider', 'Get-PSSnapin', + 'Get-Service', 'Get-TraceSource', 'Get-UICulture', 'Get-Unique', 'Get-Variable', + 'Get-WmiObject', 'Group-Object', 'Import-Alias', 'Import-Clixml', 'Import-Csv', + 'Invoke-Expression', 'Invoke-History', 'Invoke-Item', 'Join-Path', 'Measure-Command', + 'Measure-Object', 'Move-Item', 'Move-ItemProperty', 'New-Alias', 'New-Item', + 'New-ItemProperty', 'New-Object', 'New-PSDrive', 'New-Service', 'New-TimeSpan', + 'New-Variable', 'Out-Default', 'Out-File', 'Out-Host', 'Out-Null', 'Out-Printer', + 'Out-String', 'Pop-Location', 'Push-Location', 'Read-Host', 'Remove-Item', + 'Remove-ItemProperty', 'Remove-PSDrive', 'Remove-PSSnapin', 'Remove-Variable', 'Rename-Item', + 'Rename-ItemProperty', 'Resolve-Path', 'Restart-Service', 'Resume-Service', 'Select-Object', + 'Select-String', 'Set-Acl', 'Set-Alias', 'Set-AuthenticodeSignature', 'Set-Content', + 'Set-Date', 'Set-ExecutionPolicy', 'Set-Item', 'Set-ItemProperty', 'Set-Location', + 'Set-PSDebug', 'Set-Service', 'Set-TraceSource', 'Set-Variable', 'Sort-Object', 'Split-Path', + 'Start-Service', 'Start-Sleep', 'Start-Transcript', 'Stop-Process', 'Stop-Service', + 'Stop-Transcript', 'Suspend-Service', 'Tee-Object', 'Test-Path', 'Trace-Command', + 'Update-FormatData', 'Update-TypeData', 'Where-Object', 'Write-Debug', 'Write-Error', + 'Write-Host', 'Write-Output', 'Write-Progress', 'Write-Verbose', 'Write-Warning' + ), + 2 => array( + // Aliases + 'ac', 'asnp', 'clc', 'cli', 'clp', 'clv', 'cpi', 'cpp', 'cvpa', 'diff', 'epal', 'epcsv', 'fc', + 'fl', 'ft', 'fw', 'gal', 'gc', 'gci', 'gcm', 'gdr', 'ghy', 'gi', 'gl', 'gm', + 'gp', 'gps', 'group', 'gsv', 'gsnp', 'gu', 'gv', 'gwmi', 'iex', 'ihy', 'ii', 'ipal', 'ipcsv', + 'mi', 'mp', 'nal', 'ndr', 'ni', 'nv', 'oh', 'rdr', 'ri', 'rni', 'rnp', 'rp', 'rsnp', 'rv', + 'rvpa', 'sal', 'sasv', 'sc', 'select', 'si', 'sl', 'sleep', 'sort', 'sp', 'spps', 'spsv', 'sv', + 'tee', 'write', 'cat', 'cd', 'clear', 'cp', 'h', 'history', 'kill', 'lp', 'ls', + 'mount', 'mv', 'popd', 'ps', 'pushd', 'pwd', 'r', 'rm', 'rmdir', 'echo', 'cls', 'chdir', + 'copy', 'del', 'dir', 'erase', 'move', 'rd', 'ren', 'set', 'type' + ), + 3 => array( + // Reserved words + 'break', 'continue', 'do', 'for', 'foreach', 'while', 'if', 'switch', 'until', 'where', + 'function', 'filter', 'else', 'elseif', 'in', 'return', 'param', 'throw', 'trap' + ), + 4 => array( + // Operators + '-eq', '-ne', '-gt', '-ge', '-lt', '-le', '-ieq', '-ine', '-igt', '-ige', '-ilt', '-ile', + '-ceq', '-cne', '-cgt', '-cge', '-clt', '-cle', '-like', '-notlike', '-match', '-notmatch', + '-ilike', '-inotlike', '-imatch', '-inotmatch', '-clike', '-cnotlike', '-cmatch', '-cnotmatch', + '-contains', '-notcontains', '-icontains', '-inotcontains', '-ccontains', '-cnotcontains', + '-isnot', '-is', '-as', '-replace', '-ireplace', '-creplace', '-and', '-or', '-band', '-bor', + '-not', '-bnot', '-f', '-casesensitive', '-exact', '-file', '-regex', '-wildcard' + ), + 5 => array( + // Options + '-Year', '-Wrap', '-Word', '-Width', '-WhatIf', '-Wait', '-View', '-Verbose', '-Verb', + '-Variable', '-ValueOnly', '-Value', '-Unique', '-UFormat', '-TypeName', '-Trace', '-TotalCount', + '-Title', '-TimestampServer', '-TargetObject', '-Syntax', '-SyncWindow', '-Sum', '-String', + '-Strict', '-Stream', '-Step', '-Status', '-Static', '-StartupType', '-Start', '-StackName', + '-Stack', '-SourceId', '-SimpleMatch', '-ShowError', '-Separator', '-SecureString', '-SecureKey', + '-SecondValue', '-SecondsRemaining', '-Seconds', '-Second', '-Scope', '-Root', '-Role', + '-Resolve', '-RemoveListener', '-RemoveFileListener', '-Registered', '-ReferenceObject', + '-Recurse', '-RecommendedAction', '-ReadCount', '-Quiet', '-Query', '-Qualifier', '-PSSnapin', + '-PSProvider', '-PSHost', '-PSDrive', '-PropertyType', '-Property', '-Prompt', '-Process', + '-PrependPath', '-PercentComplete', '-Pattern', '-PathType', '-Path', '-PassThru', '-ParentId', + '-Parent', '-Parameter', '-Paging', '-OutVariable', '-OutBuffer', '-Option', '-OnType', '-Off', + '-Object', '-Noun', '-NoTypeInformation', '-NoQualifier', '-NoNewline', '-NoElement', + '-NoClobber', '-NewName', '-Newest', '-Namespace', '-Name', '-Month', '-Minutes', '-Minute', + '-Minimum', '-Milliseconds', '-Message', '-MemberType', '-Maximum', '-LogName', '-LiteralPath', + '-LiteralName', '-ListenerOption', '-List', '-Line', '-Leaf', '-Last', '-Key', '-ItemType', + '-IsValid', '-IsAbsolute', '-InputObject', '-IncludeEqual', '-IncludeChain', '-Include', + '-IgnoreWhiteSpace', '-Id', '-Hours', '-Hour', '-HideTableHeaders', '-Head', '-GroupBy', + '-Functionality', '-Full', '-Format', '-ForegroundColor', '-Force', '-First', '-FilterScript', + '-Filter', '-FilePath', '-Expression', '-ExpandProperty', '-Expand', '-ExecutionPolicy', + '-ExcludeProperty', '-ExcludeDifferent', '-Exclude', '-Exception', '-Examples', '-ErrorVariable', + '-ErrorRecord', '-ErrorId', '-ErrorAction', '-End', '-Encoding', '-DisplayName', '-DisplayHint', + '-DisplayError', '-DifferenceObject', '-Detailed', '-Destination', '-Description', '-Descending', + '-Depth', '-DependsOn', '-Delimiter', '-Debugger', '-Debug', '-Days', '-Day', '-Date', + '-CurrentOperation', '-Culture', '-Credential', '-Count', '-Container', '-Confirm', + '-ComputerName', '-Component', '-Completed', '-ComObject', '-CommandType', '-Command', + '-Column', '-Class', '-ChildPath', '-Character', '-Certificate', '-CategoryTargetType', + '-CategoryTargetName', '-CategoryReason', '-CategoryActivity', '-Category', '-CaseSensitive', + '-Body', '-BinaryPathName', '-Begin', '-BackgroundColor', '-Average', '-AutoSize', '-Audit', + '-AsString', '-AsSecureString', '-AsPlainText', '-As', '-ArgumentList', '-AppendPath', '-Append', + '-Adjust', '-Activity', '-AclObject' + ), + 6 => array( + '_','args','DebugPreference','Error','ErrorActionPreference', + 'foreach','Home','Host','Input','LASTEXITCODE','MaximumAliasCount', + 'MaximumDriveCount','MaximumFunctionCount','MaximumHistoryCount', + 'MaximumVariableCount','OFS','PsHome', + 'ReportErrorShowExceptionClass','ReportErrorShowInnerException', + 'ReportErrorShowSource','ReportErrorShowStackTrace', + 'ShouldProcessPreference','ShouldProcessReturnPreference', + 'StackTrace','VerbosePreference','WarningPreference','PWD' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '=', '<', '>', '@', '|', '&', ',', '?', + '+=', '-=', '*=', '/=', '%=', '*', '/', '%', '!', '+', '-', '++', '--' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #008080; font-weight: bold;', + 2 => 'color: #008080; font-weight: bold;', + 3 => 'color: #0000FF;', + 4 => 'color: #FF0000;', + 5 => 'color: #008080; font-style: italic;', + 6 => 'color: #000080;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000;', + 'MULTI' => 'color: #008000;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008080; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #800000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000;' + ), + 'METHODS' => array( + 0 => 'color: pink;' + ), + 'SYMBOLS' => array( + 0 => 'color: pink;' + ), + 'REGEXPS' => array( + 0 => 'color: #800080;', + 3 => 'color: #008080;', + 4 => 'color: #008080;', + 5 => 'color: #800000;', + 6 => 'color: #000080;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + // special after pipe + 3 => array( + GESHI_SEARCH => '(\[)(int|long|string|char|bool|byte|double|decimal|float|single|regex|array|xml|scriptblock|switch|hashtable|type|ref|psobject|wmi|wmisearcher|wmiclass|object)((\[.*\])?\])', + GESHI_REPLACE => '\2', + GESHI_MODIFIERS => 'si', + GESHI_BEFORE => '\1', + GESHI_AFTER => '\3' + ), + // Classes + 4 => array( + GESHI_SEARCH => '(\[)(System\.Reflection\.Assembly|System\.Net\.CredentialCache|Microsoft\.SharePoint\.SPFileLevel|Microsoft\.SharePoint\.Publishing\.PublishingWeb|Microsoft\.SharePoint\.Publishing|Microsoft\.SharePoint\.SPWeb)(\])', + GESHI_REPLACE => '\2', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '\1', + GESHI_AFTER => '\3' + ), + // Members + // There's about a hundred million of these, add the ones you need as you need them + 5 => array ( + GESHI_SEARCH => '(::)(ReflectionOnlyLoadFrom|ReflectionOnlyLoad|ReferenceEquals|LoadWithPartialName|LoadFrom|LoadFile|Load|GetExecutingAssembly|GetEntryAssembly|GetCallingAssembly|GetAssembly|Equals|DefaultNetworkCredentials|DefaultCredentials|CreateQualifiedName|Checkout|Draft|Published|IsPublishingWeb)', + GESHI_REPLACE => '\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\1', + GESHI_AFTER => '' + ), + // Special variables + 6 => array( + GESHI_SEARCH => '(\$)(\$[_\^]?|\?)(?!\w)', + GESHI_REPLACE => '\1\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + // variables + //BenBE: Please note that changes here and in Keyword group 6 have to be synchronized in order to work properly. + //This Regexp must only match, if keyword group 6 doesn't. If this assumption fails + //Highlighting of the keywords will be incomplete or incorrect! + 0 => "(?)[\\\$](?!(?:DebugPreference|Error(?:ActionPreference)?|". + "Ho(?:me|st)|Input|LASTEXITCODE|Maximum(?:AliasCount|DriveCount|". + "FunctionCount|HistoryCount|VariableCount)|OFS|P(?:WD|sHome)|". + "ReportErrorShow(?:ExceptionClass|InnerException|S(?:ource|". + "tackTrace))|S(?:houldProcess(?:Preference|ReturnPreference)|". + "tackTrace)|VerbosePreference|WarningPreference|_|args|foreach)\W)". + "(\w+)(?=[^|\w])", + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 6 => array( + 'DISALLOWED_BEFORE' => '(? \ No newline at end of file diff --git a/examples/includes/geshi/geshi/progress.php b/examples/includes/geshi/geshi/progress.php new file mode 100644 index 0000000..abd5bcb --- /dev/null +++ b/examples/includes/geshi/geshi/progress.php @@ -0,0 +1,479 @@ + 'Progress', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array ( + 1 => array( + 'ACCUMULATE','APPLY','ASSIGN','BELL','QUERY', + 'BUFFER-COMPARE','BUFFER-COPY','CALL','CASE', + 'CHOOSE','CLASS','CLEAR','CLOSE QUERY','each','WHERE', + 'CLOSE STORED-PROCEDURE','COLOR','COMPILE','CONNECT', + 'CONSTRUCTOR','COPY-LOB','CREATE','CREATE ALIAS', + 'CREATE BROWSE','CREATE BUFFER','CREATE CALL','CREATE CLIENT-PRINCIPAL', + 'CREATE DATABASE','CREATE DATASET','CREATE DATA-SOURCE','CREATE QUERY', + 'CREATE SAX-attributeS','CREATE SAX-READER','CREATE SAX-WRITER','CREATE SERVER', + 'CREATE SERVER-SOCKET','CREATE SOAP-HEADER','CREATE SOAP-HEADER-ENTRYREF','CREATE SOCKET', + 'CREATE TEMP-TABLE','CREATE WIDGET','CREATE widget-POOL','CREATE X-DOCUMENT', + 'CREATE X-NODEREF','CURRENT-LANGUAGE','CURRENT-VALUE','DDE ADVISE', + 'DDE EXECUTE','DDE GET','DDE INITIATE','DDE REQUEST', + 'DDE SEND','DDE TERMINATE','DEFINE BROWSE','DEFINE BUFFER','DEFINE', + 'DEFINE BUTTON','DEFINE DATASET','DEFINE DATA-SOURCE','DEFINE FRAME','DEF','VAR', + 'DEFINE IMAGE','DEFINE MENU','DEFINE PARAMETER','DEFINE property','PARAM', + 'DEFINE QUERY','DEFINE RECTANGLE','DEFINE STREAM','DEFINE SUB-MENU', + 'DEFINE TEMP-TABLE','DEFINE WORKFILE','DEFINE WORK-TABLE', + 'DELETE','DELETE ALIAS','DELETE object','DELETE PROCEDURE', + 'DELETE widget','DELETE widget-POOL','DESTRUCTOR','DICTIONARY', + 'DISABLE','DISABLE TRIGGERS','DISCONNECT','DISPLAY', + 'DO','DOS','DOWN','DYNAMIC-CURRENT-VALUE', + 'ELSE','EMPTY TEMP-TABLE','ENABLE','END', + 'ENTRY','EXPORT','FIND','AND', + 'FIX-CODEPAGE','FOR','FORM','FRAME-VALUE', + 'GET','GET-KEY-VALUE','HIDE','IF', + 'IMPORT','INPUT CLEAR','INPUT CLOSE','INPUT FROM','input', + 'INPUT THROUGH','INPUT-OUTPUT CLOSE','INPUT-OUTPUT THROUGH','INSERT', + 'INTERFACE','LEAVE','LOAD','BREAK', + 'LOAD-PICTURE','MESSAGE','method','NEXT','prev', + 'NEXT-PROMPT','ON','OPEN QUERY','OS-APPEND', + 'OS-COMMAND','OS-COPY','OS-CREATE-DIR','OS-DELETE', + 'OS-RENAME','OUTPUT CLOSE','OUTPUT THROUGH','OUTPUT TO', + 'OVERLAY','PAGE','PAUSE','PROCEDURE', + 'PROCESS EVENTS','PROMPT-FOR','PROMSGS','PROPATH', + 'PUBLISH','PUT','PUT CURSOR','PUT SCREEN', + 'PUT-BITS','PUT-BYTE','PUT-BYTES','PUT-DOUBLE', + 'PUT-FLOAT','PUT-INT64','PUT-KEY-VALUE','PUT-LONG', + 'PUT-SHORT','PUT-STRING','PUT-UNSIGNED-LONG','PUT-UNSIGNED-SHORT', + 'QUIT','RAW-TRANSFER','READKEY','RELEASE', + 'RELEASE EXTERNAL','RELEASE object','REPEAT','REPOSITION', + 'RUN','RUN STORED-PROCEDURE','RUN SUPER', + 'SAVE CACHE','SCROLL','SEEK','SET', + 'SET-BYTE-ORDER','SET-POINTER-VALUE','SET-SIZE','SHOW-STATS', + 'STATUS','STOP','SUBSCRIBE','SUBSTRING', + 'system-DIALOG COLOR','system-DIALOG FONT','system-DIALOG GET-DIR','system-DIALOG GET-FILE', + 'system-DIALOG PRINTER-SETUP','system-HELP','THEN','THIS-object', + 'TRANSACTION-MODE AUTOMATIC','TRIGGER PROCEDURE','UNDERLINE','UNDO', + 'UNIX','UNLOAD','UNSUBSCRIBE','UP','STRING', + 'UPDATE','USE','USING','VALIDATE','substr','SKIP','CLOSE', + 'VIEW','WAIT-FOR','MODULO','NE','AVAIL', + 'NOT','OR','&GLOBAL-DEFINE','&IF','UNFORMATTED','NO-PAUSE', + '&THEN','&ELSEIF','&ELSE','&ENDIF','OPEN','NO-WAIT', + '&MESSAGE','&SCOPED-DEFINE','&UNDEFINE','DEFINED', + 'BROWSE','BUTTON','COMBO-BOX','CONTROL-FRAME', + 'DIALOG-BOX','EDITOR','FIELD-GROUP','FILL-IN', + 'FRAME','IMAGE','LITERAL','MENU', + 'MENU-ITEM','RADIO-SET','RECTANGLE','SELECTION-LIST', + 'SLIDER','SUB-MENU','TEXT','TOGGLE-BOX', + 'WINDOW','WITH','AT','OF','EDITING','ON ENDKEY','output', + 'ON ERROR','ON QUIT','ON STOP','PRESELECT', + 'QUERY-TUNING','SIZE','Trigger','VIEW-AS','ALERT-BOX', + 'Buffer','Data-relation','ProDataSet','SAX-attributes', + 'SAX-reader','SAX-writer','Server socket','SOAP-fault', + 'SOAP-header','SOAP-header-entryref','Socket','Temp-table', + 'X-noderef','Height','Left','Top','TO', + 'Width','ACTIVE-WINDOW','AUDIT-CONTROL','FIRST','LAST', + 'AUDIT-POLICY','CLIPBOARD','CODEBASE-LOCATOR','COLOR-TABLE', + 'COMPILER','COM-SELF','DEBUGGER','DEFAULT-WINDOW', + 'ERROR-STATUS','FILE-INFO','FOCUS','FONT-TABLE', + 'LAST-EVENT','LOG-MANAGER','RCODE-INFO','SECURITY-POLICY', + 'SELF','SESSION','SOURCE-PROCEDURE','TARGET-PROCEDURE','NO-LOCK','NO-error', + 'THIS-PROCEDURE','WEB-CONTEXT','FUNCTION','RETURNS','NO-UNDO' + ), + 2 => array( + 'ACCEPT-CHANGES','ACCEPT-ROW-CHANGES','ADD-BUFFER','ADD-CALC-COLUMN', + 'ADD-COLUMNS-FROM','ADD-EVENTS-PROCEDURE','ADD-FIELDS-FROM','ADD-FIRST', + 'ADD-HEADER-ENTRY','ADD-INDEX-FIELD','ADD-LAST','ADD-LIKE-COLUMN', + 'ADD-LIKE-FIELD','ADD-LIKE-INDEX','ADD-NEW-FIELD','ADD-NEW-INDEX', + 'ADD-RELATION','ADD-SCHEMA-LOCATION','ADD-SOURCE-BUFFER','ADD-SUPER-PROCEDURE', + 'APPEND-CHILD','APPLY-CALLBACK','ATTACH-DATA-SOURCE','AUTHENTICATION-FAILED', + 'BEGIN-EVENT-GROUP','BUFFER-COMPARE','BUFFER-COPY','BUFFER-CREATE', + 'BUFFER-DELETE','BUFFER-FIELD','BUFFER-RELEASE','BUFFER-VALIDATE', + 'CANCEL-BREAK','CANCEL-REQUESTS','CLEAR','CLEAR-APPL-CONTEXT', + 'CLEAR-LOG','CLEAR-SELECTION','CLEAR-SORT-ARROWS','CLONE-NODE', + 'CLOSE-LOG','CONNECT','CONNECTED','CONVERT-TO-OFFSET', + 'COPY-DATASET','COPY-SAX-attributeS','COPY-TEMP-TABLE','CREATE-LIKE', + 'CREATE-NODE','CREATE-NODE-NAMESPACE','CREATE-RESULT-LIST-ENTRY','DEBUG', + 'DECLARE-NAMESPACE','DELETE-CHAR','DELETE-CURRENT-ROW', + 'DELETE-HEADER-ENTRY','DELETE-LINE','DELETE-NODE','DELETE-RESULT-LIST-ENTRY', + 'DELETE-SELECTED-ROW','DELETE-SELECTED-ROWS','DESELECT-FOCUSED-ROW','DESELECT-ROWS', + 'DESELECT-SELECTED-ROW','DETACH-DATA-SOURCE','DISABLE','DISABLE-CONNECTIONS', + 'DISABLE-DUMP-TRIGGERS','DISABLE-LOAD-TRIGGERS','DISCONNECT','DISPLAY-MESSAGE', + 'DUMP-LOGGING-NOW','EDIT-CLEAR','EDIT-COPY','EDIT-CUT', + 'EDIT-PASTE','EDIT-UNDO','EMPTY-DATASET','EMPTY-TEMP-TABLE', + 'ENABLE','ENABLE-CONNECTIONS','ENABLE-EVENTS','ENCRYPT-AUDIT-MAC-KEY', + 'END-DOCUMENT','END-ELEMENT','END-EVENT-GROUP','END-FILE-DROP', + 'EXPORT','EXPORT-PRINCIPAL','FETCH-SELECTED-ROW', + 'FILL','FIND-BY-ROWID','FIND-CURRENT','FIND-FIRST', + 'FIND-LAST','FIND-UNIQUE','GET-attribute','GET-attribute-NODE', + 'GET-BINARY-DATA','GET-BLUE-VALUE','GET-BROWSE-COLUMN','GET-BUFFER-HANDLE', + 'GET-BYTES-AVAILABLE','GET-CALLBACK-PROC-CONTEXT','GET-CALLBACK-PROC-NAME','GET-CGI-LIST', + 'GET-CGI-LONG-VALUE','GET-CGI-VALUE','GET-CHANGES','GET-CHILD', + 'GET-CHILD-RELATION','GET-CONFIG-VALUE','GET-CURRENT','GET-DATASET-BUFFER', + 'GET-DOCUMENT-ELEMENT','GET-DROPPED-FILE','GET-DYNAMIC','GET-ERROR-COLUMN ', + 'GET-ERROR-ROW ','GET-FILE-NAME ','GET-FILE-OFFSET ','GET-FIRST', + 'GET-GREEN-VALUE','GET-HEADER-ENTRY','GET-INDEX-BY-NAMESPACE-NAME','GET-INDEX-BY-QNAME', + 'GET-ITERATION','GET-LAST','GET-LOCALNAME-BY-INDEX','GET-MESSAGE', + 'GET-NEXT','GET-NODE','GET-NUMBER','GET-PARENT', + 'GET-PREV','GET-PRINTERS','GET-property','GET-QNAME-BY-INDEX', + 'GET-RED-VALUE','GET-RELATION','GET-REPOSITIONED-ROW','GET-RGB-VALUE', + 'GET-SELECTED-widget','GET-SERIALIZED','GET-SIGNATURE','GET-SOCKET-OPTION', + 'GET-SOURCE-BUFFER','GET-TAB-ITEM','GET-TEXT-HEIGHT-CHARS','GET-TEXT-HEIGHT-PIXELS', + 'GET-TEXT-WIDTH-CHARS','GET-TEXT-WIDTH-PIXELS','GET-TOP-BUFFER','GET-TYPE-BY-INDEX', + 'GET-TYPE-BY-NAMESPACE-NAME','GET-TYPE-BY-QNAME','GET-URI-BY-INDEX','GET-VALUE-BY-INDEX', + 'GET-VALUE-BY-NAMESPACE-NAME','GET-VALUE-BY-QNAME','GET-WAIT-STATE','IMPORT-NODE', + 'IMPORT-PRINCIPAL','INCREMENT-EXCLUSIVE-ID','INDEX-INFORMATION','INITIALIZE-DOCUMENT-TYPE', + 'INITIATE','INSERT','INSERT-attribute','INSERT-BACKTAB', + 'INSERT-BEFORE','INSERT-FILE','INSERT-ROW','INSERT-STRING', + 'INSERT-TAB','INVOKE','IS-ROW-SELECTED','IS-SELECTED', + 'LIST-property-NAMES','LOAD','LoadControls','LOAD-DOMAINS', + 'LOAD-ICON','LOAD-IMAGE','LOAD-IMAGE-DOWN','LOAD-IMAGE-INSENSITIVE', + 'LOAD-IMAGE-UP','LOAD-MOUSE-POINTER','LOAD-SMALL-ICON','LOCK-REGISTRATION', + 'LOG-AUDIT-EVENT','LOGOUT','LONGCHAR-TO-NODE-VALUE','LOOKUP', + 'MEMPTR-TO-NODE-VALUE','MERGE-CHANGES','MERGE-ROW-CHANGES','MOVE-AFTER-TAB-ITEM', + 'MOVE-BEFORE-TAB-ITEM','MOVE-COLUMN','MOVE-TO-BOTTOM','MOVE-TO-EOF', + 'MOVE-TO-TOP','NODE-VALUE-TO-LONGCHAR','NODE-VALUE-TO-MEMPTR','NORMALIZE', + 'QUERY-CLOSE','QUERY-OPEN','QUERY-PREPARE','RAW-TRANSFER', + 'READ','READ-FILE','READ-XML','READ-XMLSCHEMA', + 'REFRESH','REFRESH-AUDIT-POLICY','REGISTER-DOMAIN','REJECT-CHANGES', + 'REJECT-ROW-CHANGES','REMOVE-attribute','REMOVE-CHILD','REMOVE-EVENTS-PROCEDURE', + 'REMOVE-SUPER-PROCEDURE','REPLACE','REPLACE-CHILD','REPLACE-SELECTION-TEXT', + 'REPOSITION-BACKWARD','REPOSITION-FORWARD','REPOSITION-TO-ROW','REPOSITION-TO-ROWID', + 'RESET','SAVE','SAVE-FILE','SAVE-ROW-CHANGES', + 'SAX-PARSE','SAX-PARSE-FIRST','SAX-PARSE-NEXT','SCROLL-TO-CURRENT-ROW', + 'SCROLL-TO-ITEM','SCROLL-TO-SELECTED-ROW','SEAL','SEARCH', + 'SELECT-ALL','SELECT-FOCUSED-ROW','SELECT-NEXT-ROW','SELECT-PREV-ROW', + 'SELECT-ROW','SET-ACTOR','SET-APPL-CONTEXT','SET-attribute', + 'SET-attribute-NODE','SET-BLUE-VALUE','SET-BREAK','SET-BUFFERS', + 'SET-CALLBACK','SET-CALLBACK-PROCEDURE','SET-CLIENT','SET-COMMIT', + 'SET-CONNECT-PROCEDURE','SET-DYNAMIC','SET-GREEN-VALUE','SET-INPUT-SOURCE', + 'SET-MUST-UNDERSTAND','SET-NODE','SET-NUMERIC-FORMAT','SET-OUTPUT-DESTINATION', + 'SET-PARAMETER','SET-property','SET-READ-RESPONSE-PROCEDURE','SET-RED-VALUE', + 'SET-REPOSITIONED-ROW','SET-RGB-VALUE','SET-ROLLBACK','SET-SELECTION', + 'SET-SERIALIZED','SET-SOCKET-OPTION','SET-SORT-ARROW','SET-WAIT-STATE', + 'START-DOCUMENT','START-ELEMENT','STOP-PARSING','SYNCHRONIZE', + 'TEMP-TABLE-PREPARE','UPDATE-attribute','URL-DECODE','URL-ENCODE', + 'VALIDATE','VALIDATE-SEAL','WRITE','WRITE-CDATA','USE-INDEX', + 'WRITE-CHARACTERS','WRITE-COMMENT','WRITE-DATA-ELEMENT','WRITE-EMPTY-ELEMENT', + 'WRITE-ENTITY-REF','WRITE-EXTERNAL-DTD','WRITE-FRAGMENT','WRITE-MESSAGE', + 'WRITE-PROCESSING-INSTRUCTION','WRITE-XML','WRITE-XMLSCHEMA','FALSE','true' + ), + 3 => array( + 'ABSOLUTE','ACCUM','ADD-INTERVAL','ALIAS','mod', + 'AMBIGUOUS','ASC','AUDIT-ENABLED','AVAILABLE', + 'BASE64-DECODE','BASE64-ENCODE','CAN-DO','CAN-FIND', + 'CAN-QUERY','CAN-SET','CAPS','CAST','OS-DIR', + 'CHR','CODEPAGE-CONVERT','COMPARE','CONNECTED', + 'COUNT-OF','CURRENT-CHANGED','CURRENT-RESULT-ROW','DATASERVERS', + 'DATA-SOURCE-MODIFIED','DATETIME','DATETIME-TZ', + 'DAY','DBCODEPAGE','DBCOLLATION','DBNAME', + 'DBPARAM','DBRESTRICTIONS','DBTASKID','DBTYPE', + 'DBVERSION','DECIMAL','DECRYPT','DYNAMIC-function', + 'DYNAMIC-NEXT-VALUE','ENCODE','ENCRYPT','ENTERED', + 'ERROR','ETIME','EXP','FILL','ENDKEY','END-error', + 'FIRST-OF','FRAME-DB','FRAME-DOWN', + 'FRAME-FIELD','FRAME-FILE','FRAME-INDEX','FRAME-LINE', + 'GATEWAYS','GENERATE-PBE-KEY','GENERATE-PBE-SALT','GENERATE-RANDOM-KEY', + 'GENERATE-UUID','GET-BITS','GET-BYTE','GET-BYTE-ORDER', + 'GET-BYTES','GET-CODEPAGE','GET-CODEPAGES','GET-COLLATION', + 'GET-COLLATIONS','GET-DOUBLE','GET-FLOAT','GET-INT64', + 'GET-LONG','GET-POINTER-VALUE','GET-SHORT','GET-SIZE', + 'GET-STRING','GET-UNSIGNED-LONG','GET-UNSIGNED-SHORT','GO-PENDING', + 'GUID','HEX-DECODE','INDEX', + 'INT64','INTEGER','INTERVAL','IS-ATTR-SPACE', + 'IS-CODEPAGE-FIXED','IS-COLUMN-CODEPAGE','IS-LEAD-BYTE','ISO-DATE', + 'KBLABEL','KEYCODE','KEYFUNCTION','KEYLABEL', + 'KEYWORD','KEYWORD-ALL','LASTKEY', + 'LAST-OF','LC','LDBNAME','LEFT-TRIM', + 'LIBRARY','LINE-COUNTER','LIST-EVENTS','LIST-QUERY-ATTRS', + 'LIST-SET-ATTRS','LIST-widgetS','LOCKED','LOG', + 'LOGICAL','LOOKUP','MAXIMUM','MD5-DIGEST', + 'MEMBER','MESSAGE-LINES','MINIMUM','MONTH', + 'MTIME','NEW','NEXT-VALUE','NORMALIZE','SHARED', + 'NOT ENTERED','NOW','NUM-ALIASES','NUM-DBS', + 'NUM-ENTRIES','NUM-RESULTS','OPSYS','OS-DRIVES', + 'OS-ERROR','OS-GETENV','PAGE-NUMBER','PAGE-SIZE', + 'PDBNAME','PROC-HANDLE','PROC-STATUS','PROGRAM-NAME', + 'PROGRESS','PROVERSION','QUERY-OFF-END','QUOTER', + 'RANDOM','RAW','RECID','REJECTED', + 'REPLACE','RETRY','RETURN-VALUE','RGB-VALUE', + 'RIGHT-TRIM','R-INDEX','ROUND','ROWID','LENGTH', + 'SDBNAME','SEARCH','SET-DB-CLIENT','SETUSERID', + 'SHA1-DIGEST','SQRT','SUBSTITUTE','VARIABLE', + 'SUPER','TERMINAL','TIME','TIMEZONE','external','ENTRY', + 'TODAY','TO-ROWID','TRIM','TRUNCATE','return', + 'TYPE-OF','USERID','VALID-EVENT','VALID-HANDLE', + 'VALID-object','WEEKDAY','YEAR','BEGINS','VALUE', + 'EQ','GE','GT','LE','LT','MATCHES','AS','BY','LIKE' + ), + 4 => array( + 'ACCELERATOR','ACTIVE','ACTOR','ADM-DATA', + 'AFTER-BUFFER','AFTER-ROWID','AFTER-TABLE','ALLOW-COLUMN-SEARCHING', + 'ALWAYS-ON-TOP','APPL-ALERT-BOXES','APPL-CONTEXT-ID','APPSERVER-INFO', + 'APPSERVER-PASSWORD','APPSERVER-USERID','ASYNCHRONOUS','ASYNC-REQUEST-COUNT', + 'ASYNC-REQUEST-HANDLE','ATTACHED-PAIRLIST','attribute-NAMES','ATTR-SPACE', + 'AUDIT-EVENT-CONTEXT','AUTO-COMPLETION','AUTO-DELETE','AUTO-DELETE-XML', + 'AUTO-END-KEY','AUTO-GO','AUTO-INDENT','AUTO-RESIZE', + 'AUTO-RETURN','AUTO-SYNCHRONIZE','AUTO-VALIDATE','AUTO-ZAP', + 'AVAILABLE-FORMATS','BACKGROUND','BASE-ADE','BASIC-LOGGING', + 'BATCH-MODE','BATCH-SIZE','BEFORE-BUFFER','BEFORE-ROWID', + 'BEFORE-TABLE','BGCOLOR','BLANK','BLOCK-ITERATION-DISPLAY', + 'BORDER-BOTTOM-CHARS','BORDER-BOTTOM-PIXELS','BORDER-LEFT-CHARS','BORDER-LEFT-PIXELS', + 'BORDER-RIGHT-CHARS','BORDER-RIGHT-PIXELS','BORDER-TOP-CHARS','BORDER-TOP-PIXELS', + 'BOX','BOX-SELECTABLE','BUFFER-CHARS','BUFFER-FIELD', + 'BUFFER-HANDLE','BUFFER-LINES','BUFFER-NAME','BUFFER-VALUE', + 'BYTES-READ','BYTES-WRITTEN','CACHE','CALL-NAME', + 'CALL-TYPE','CANCEL-BUTTON','CANCELLED','CAN-CREATE', + 'CAN-DELETE','CAN-READ','CAN-WRITE','CAREFUL-PAINT', + 'CASE-SENSITIVE','CENTERED','CHARSET','CHECKED', + 'CHILD-BUFFER','CHILD-NUM','CLASS-TYPE','CLIENT-CONNECTION-ID', + 'CLIENT-TTY','CLIENT-TYPE','CLIENT-WORKSTATION','CODE', + 'CODEPAGE','COLUMN','COLUMN-BGCOLOR','COLUMN-DCOLOR', + 'COLUMN-FGCOLOR','COLUMN-FONT','COLUMN-LABEL','COLUMN-MOVABLE', + 'COLUMN-PFCOLOR','COLUMN-READ-ONLY','COLUMN-RESIZABLE','COLUMN-SCROLLING', + 'COM-HANDLE','COMPLETE','CONFIG-NAME','CONTEXT-HELP', + 'CONTEXT-HELP-FILE','CONTEXT-HELP-ID','CONTROL-BOX','CONVERT-3D-COLORS', + 'CPCASE','CPCOLL','CPINTERNAL','CPLOG', + 'CPPRINT','CPRCODEIN','CPRCODEOUT','CPSTREAM', + 'CPTERM','CRC-VALUE','CURRENT-COLUMN','CURRENT-ENVIRONMENT', + 'CURRENT-ITERATION','CURRENT-ROW-MODIFIED','CURRENT-WINDOW','CURSOR-CHAR', + 'CURSOR-LINE','CURSOR-OFFSET','DATA-ENTRY-RETURN','DATASET', + 'DATA-SOURCE','DATA-SOURCE-COMPLETE-MAP','DATA-TYPE','DATE-FORMAT', + 'DB-REFERENCES','DCOLOR','DDE-ERROR','DDE-ID', + 'DDE-ITEM','DDE-NAME','DDE-TOPIC','DEBLANK', + 'DEBUG-ALERT','DECIMALS','DEFAULT','DEFAULT-BUFFER-HANDLE', + 'DEFAULT-BUTTON','DEFAULT-COMMIT','DELIMITER','DISABLE-AUTO-ZAP', + 'DISPLAY-TIMEZONE','DISPLAY-TYPE','DOMAIN-DESCRIPTION','DOMAIN-NAME', + 'DOMAIN-TYPE','DRAG-ENABLED','DROP-TARGET','DYNAMIC', + 'EDGE-CHARS','EDGE-PIXELS','EDIT-CAN-PASTE','EDIT-CAN-UNDO', + 'EMPTY','ENCODING','ENCRYPTION-SALT','END-USER-PROMPT', + 'ENTRY-TYPES-LIST','ERROR-COLUMN','ERROR-object-DETAIL','ERROR-ROW', + 'ERROR-STRING','EVENT-GROUP-ID','EVENT-PROCEDURE','EVENT-PROCEDURE-CONTEXT', + 'EVENT-TYPE','EXCLUSIVE-ID','EXECUTION-LOG','EXPAND', + 'EXPANDABLE','FGCOLOR','FILE-CREATE-DATE','FILE-CREATE-TIME', + 'FILE-MOD-DATE','FILE-MOD-TIME','FILE-NAME','FILE-OFFSET', + 'FILE-SIZE','FILE-TYPE','FILLED','FILL-MODE', + 'FILL-WHERE-STRING','FIRST-ASYNC-REQUEST','FIRST-BUFFER','FIRST-CHILD', + 'FIRST-COLUMN','FIRST-DATASET','FIRST-DATA-SOURCE','FIRST-object', + 'FIRST-PROCEDURE','FIRST-QUERY','FIRST-SERVER','FIRST-SERVER-SOCKET', + 'FIRST-SOCKET','FIRST-TAB-ITEM','FIT-LAST-COLUMN','FLAT-BUTTON', + 'FOCUSED-ROW','FOCUSED-ROW-SELECTED','FONT','FOREGROUND', + 'FORMAT','FORMATTED','FORM-INPUT','FORM-LONG-INPUT', + 'FORWARD-ONLY','FRAGMENT','FRAME-COL','FRAME-NAME', + 'FRAME-ROW','FRAME-SPACING','FRAME-X','FRAME-Y', + 'FREQUENCY','FULL-HEIGHT-CHARS','FULL-HEIGHT-PIXELS','FULL-PATHNAME', + 'FULL-WIDTH-CHARS','FULL-WIDTH-PIXELS','GRAPHIC-EDGE', + 'GRID-FACTOR-HORIZONTAL','GRID-FACTOR-VERTICAL','GRID-SNAP','GRID-UNIT-HEIGHT-CHARS', + 'GRID-UNIT-HEIGHT-PIXELS','GRID-UNIT-WIDTH-CHARS','GRID-UNIT-WIDTH-PIXELS','GRID-VISIBLE', + 'GROUP-BOX','HANDLE','HANDLER','HAS-LOBS', + 'HAS-RECORDS','HEIGHT-CHARS','HEIGHT-PIXELS','HELP', + 'HIDDEN','HORIZONTAL','HTML-CHARSET','HTML-END-OF-LINE', + 'HTML-END-OF-PAGE','HTML-FRAME-BEGIN','HTML-FRAME-END','HTML-HEADER-BEGIN', + 'HTML-HEADER-END','HTML-TITLE-BEGIN','HTML-TITLE-END','HWND', + 'ICFPARAMETER','ICON','IGNORE-CURRENT-MODIFIED','IMAGE-DOWN', + 'IMAGE-INSENSITIVE','IMAGE-UP','IMMEDIATE-DISPLAY','INDEX-INFORMATION', + 'IN-HANDLE','INHERIT-BGCOLOR','INHERIT-FGCOLOR','INITIAL','INIT', + 'INNER-CHARS','INNER-LINES','INPUT-VALUE','INSTANTIATING-PROCEDURE', + 'INTERNAL-ENTRIES','IS-CLASS','IS-OPEN','IS-PARAMETER-SET', + 'IS-XML','ITEMS-PER-ROW','KEEP-CONNECTION-OPEN','KEEP-FRAME-Z-ORDER', + 'KEEP-SECURITY-CACHE','KEY','KEYS','LABEL', + 'LABEL-BGCOLOR','LABEL-DCOLOR','LABEL-FGCOLOR','LABEL-FONT', + 'LABELS','LANGUAGES','LARGE','LARGE-TO-SMALL', + 'LAST-ASYNC-REQUEST','LAST-BATCH','LAST-CHILD','LAST-object', + 'LAST-PROCEDURE','LAST-SERVER','LAST-SERVER-SOCKET','LAST-SOCKET', + 'LAST-TAB-ITEM','LINE','LIST-ITEM-PAIRS','LIST-ITEMS', + 'LITERAL-QUESTION','LOCAL-HOST','LOCAL-NAME','LOCAL-PORT', + 'LOCATOR-COLUMN-NUMBER','LOCATOR-LINE-NUMBER','LOCATOR-PUBLIC-ID','LOCATOR-system-ID', + 'LOCATOR-TYPE','LOG-ENTRY-TYPES','LOGFILE-NAME','LOGGING-LEVEL', + 'LOGIN-EXPIRATION-TIMESTAMP','LOGIN-HOST','LOGIN-STATE','LOG-THRESHOLD', + 'MANDATORY','MANUAL-HIGHLIGHT','MAX-BUTTON','MAX-CHARS', + 'MAX-DATA-GUESS','MAX-HEIGHT-CHARS','MAX-HEIGHT-PIXELS','MAX-VALUE', + 'MAX-WIDTH-CHARS','MAX-WIDTH-PIXELS','MD5-VALUE','MENU-BAR', + 'MENU-KEY','MENU-MOUSE','MERGE-BY-FIELD','MESSAGE-AREA', + 'MESSAGE-AREA-FONT','MIN-BUTTON','MIN-COLUMN-WIDTH-CHARS','MIN-COLUMN-WIDTH-PIXELS', + 'MIN-HEIGHT-CHARS','MIN-HEIGHT-PIXELS','MIN-SCHEMA-MARSHAL','MIN-VALUE', + 'MIN-WIDTH-CHARS','MIN-WIDTH-PIXELS','MODIFIED','MOUSE-POINTER', + 'MOVABLE','MULTI-COMPILE','MULTIPLE','MULTITASKING-INTERVAL', + 'MUST-UNDERSTAND','NAME','NAMESPACE-PREFIX','NAMESPACE-URI', + 'NEEDS-APPSERVER-PROMPT','NEEDS-PROMPT','NESTED','NEW-ROW', + 'NEXT-COLUMN','NEXT-ROWID','NEXT-SIBLING','NEXT-TAB-ITEM', 'NO-BOX', + 'NO-CURRENT-VALUE','NODE-VALUE','NO-EMPTY-SPACE','NO-FOCUS', + 'NONAMESPACE-SCHEMA-LOCATION','NO-SCHEMA-MARSHAL','NO-VALIDATE','NUM-BUFFERS', + 'NUM-BUTTONS','NUM-CHILD-RELATIONS','NUM-CHILDREN','NUM-COLUMNS', + 'NUM-DROPPED-FILES','NUMERIC-DECIMAL-POINT','NUMERIC-FORMAT','NUMERIC-SEPARATOR', + 'NUM-FIELDS','NUM-FORMATS','NUM-HEADER-ENTRIES','NUM-ITEMS', + 'NUM-ITERATIONS','NUM-LINES','NUM-LOCKED-COLUMNS','NUM-LOG-FILES', + 'NUM-MESSAGES','NUM-PARAMETERS','NUM-REFERENCES','NUM-RELATIONS', + 'NUM-REPLACED','NUM-SELECTED-ROWS','NUM-SELECTED-WIDGETS','NUM-SOURCE-BUFFERS', + 'NUM-TABS','NUM-TOP-BUFFERS','NUM-TO-RETAIN','NUM-VISIBLE-COLUMNS', + 'ON-FRAME-BORDER','ORIGIN-HANDLE','ORIGIN-ROWID','OWNER', + 'OWNER-DOCUMENT','PAGE-BOTTOM','PAGE-TOP','PARAMETER', + 'PARENT','PARENT-BUFFER','PARENT-RELATION','PARSE-STATUS', + 'PASSWORD-FIELD','PATHNAME','PBE-HASH-ALGORITHM','PBE-KEY-ROUNDS', + 'PERSISTENT','PERSISTENT-CACHE-DISABLED','PERSISTENT-PROCEDURE','PFCOLOR', + 'PIXELS-PER-COLUMN','PIXELS-PER-ROW','POPUP-MENU','POPUP-ONLY', + 'POSITION','PREFER-DATASET','PREPARED','PREPARE-STRING', + 'PREV-COLUMN','PREV-SIBLING','PREV-TAB-ITEM','PRIMARY', + 'PRINTER-CONTROL-HANDLE','PRINTER-HDC','PRINTER-NAME','PRINTER-PORT', + 'PRIVATE-DATA','PROCEDURE-NAME','PROGRESS-SOURCE','PROXY', + 'PROXY-PASSWORD','PROXY-USERID','PUBLIC-ID','PUBLISHED-EVENTS', + 'RADIO-BUTTONS','READ-ONLY','RECORD-LENGTH', + 'REFRESHABLE','RELATION-FIELDS','RELATIONS-ACTIVE','REMOTE', + 'REMOTE-HOST','REMOTE-PORT','RESIZABLE','RESIZE', + 'RESTART-ROWID','RETAIN-SHAPE','RETURN-INSERTED','RETURN-VALUE-DATA-TYPE', + 'ROLES','ROUNDED','COL','ROW','ROW-HEIGHT-CHARS', + 'ROW-HEIGHT-PIXELS','ROW-MARKERS','ROW-RESIZABLE','ROW-STATE', + 'SAVE-WHERE-STRING','SCHEMA-CHANGE','SCHEMA-LOCATION','SCHEMA-MARSHAL', + 'SCHEMA-PATH','SCREEN-LINES','SCREEN-VALUE','SCROLLABLE', + 'SCROLLBAR-HORIZONTAL','SCROLL-BARS','SCROLLBAR-VERTICAL','SEAL-TIMESTAMP', + 'SELECTABLE','SELECTED','SELECTION-END','SELECTION-START', + 'SELECTION-TEXT','SENSITIVE','SEPARATOR-FGCOLOR','SEPARATORS', + 'SERVER','SERVER-CONNECTION-BOUND','SERVER-CONNECTION-BOUND-REQUEST','SERVER-CONNECTION-CONTEXT', + 'SERVER-CONNECTION-ID','SERVER-OPERATING-MODE','SESSION-END','SESSION-ID', + 'SHOW-IN-TASKBAR','SIDE-LABEL-HANDLE','SIDE-LABELS','SKIP-DELETED-RECORD', + 'SMALL-ICON','SMALL-TITLE','SOAP-FAULT-ACTOR','SOAP-FAULT-CODE', + 'SOAP-FAULT-DETAIL','SOAP-FAULT-STRING','SORT','SORT-ASCENDING', + 'SORT-NUMBER','SSL-SERVER-NAME','STANDALONE','STARTUP-PARAMETERS', + 'STATE-DETAIL','STATUS-AREA','STATUS-AREA-FONT','STOPPED', + 'STREAM','STRETCH-TO-FIT','STRICT','STRING-VALUE', + 'SUBTYPE','SUPER-PROCEDURES','SUPPRESS-NAMESPACE-PROCESSING','SUPPRESS-WARNINGS', + 'SYMMETRIC-ENCRYPTION-ALGORITHM','SYMMETRIC-ENCRYPTION-IV','SYMMETRIC-ENCRYPTION-KEY','SYMMETRIC-SUPPORT', + 'system-ALERT-BOXES','system-ID','TABLE','TABLE-CRC-LIST', + 'TABLE-HANDLE','TABLE-LIST','TABLE-NUMBER','TAB-POSITION', + 'TAB-STOP','TEMP-DIRECTORY','TEXT-SELECTED','THREE-D', + 'TIC-MARKS','TIME-SOURCE','TITLE','TITLE-BGCOLOR','FIELD', + 'TITLE-DCOLOR','TITLE-FGCOLOR','TITLE-FONT','TOOLTIP', + 'TOOLTIPS','TOP-ONLY','TRACKING-CHANGES','TRANSACTION', + 'TRANS-INIT-PROCEDURE','TRANSPARENT','TYPE','UNIQUE-ID', + 'UNIQUE-MATCH','URL','URL-PASSWORD','URL-USERID','EXTENT', + 'USER-ID','V6DISPLAY','VALIDATE-EXPRESSION','VALIDATE-MESSAGE', + 'VALIDATE-XML','VALIDATION-ENABLED','VIEW-FIRST-COLUMN-ON-REOPEN', + 'VIRTUAL-HEIGHT-CHARS','VIRTUAL-HEIGHT-PIXELS','VIRTUAL-WIDTH-CHARS','VIRTUAL-WIDTH-PIXELS', + 'VISIBLE','WARNING','WHERE-STRING','widget-ENTER','DATE', + 'widget-LEAVE','WIDTH-CHARS','WIDTH-PIXELS','WINDOW-STATE', + 'WINDOW-system','WORD-WRAP','WORK-AREA-HEIGHT-PIXELS','WORK-AREA-WIDTH-PIXELS', + 'WORK-AREA-X','WORK-AREA-Y','WRITE-STATUS','X','widget-Handle', + 'X-DOCUMENT','XML-DATA-TYPE','XML-NODE-TYPE','XML-SCHEMA-PATH', + 'XML-SUPPRESS-NAMESPACE-PROCESSING','Y','YEAR-OFFSET','CHARACTER','INTEGER','LOGICAL', + 'LONGCHAR','MEMPTR','DECIMAL','CHAR','DEC','INT','LOG','DECI','INTE','LOGI','long' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', + '<', '>', '=', + '+', '-', '*', '/', + '!', '@', '%', '|', '$', + ':', '.', ';', ',', + '?', '<=','<>','>=', '\\' + ), + 'CASE_SENSITIVE' => array ( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array ( + 'KEYWORDS' => array ( + 1 => 'color: #0000ff; font-weight: bold;', + 2 => 'color: #1D16B2;', + 3 => 'color: #993333;', + 4 => 'color: #0000ff;' + ), + 'COMMENTS' => array ( +// 1 => 'color: #808080; font-style: italic;', +// 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array ( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array ( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array ( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array ( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array ( + 0 => 'color: #006600;' + ), + 'SYMBOLS' => array ( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array ( + ), + 'SCRIPT' => array ( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 0 => ':' + ), + 'REGEXPS' => array ( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array ( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array ( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(? "(?![\-a-zA-Z0-9_%])" + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/prolog.php b/examples/includes/geshi/geshi/prolog.php new file mode 100644 index 0000000..e3a07c1 --- /dev/null +++ b/examples/includes/geshi/geshi/prolog.php @@ -0,0 +1,143 @@ + 'Prolog', + 'COMMENT_SINGLE' => array(1 => '%'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array("\'"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'NUMBERS' => + GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_FLT_SCI_ZERO, + 'KEYWORDS' => array( + 1 => array( + 'abolish','abs','arg','asserta','assertz','at_end_of_stream','atan', + 'atom','atom_chars','atom_codes','atom_concat','atom_length', + 'atomic','bagof','call','catch','ceiling','char_code', + 'char_conversion','clause','close','compound','consult','copy_term', + 'cos','current_char_conversion','current_input','current_op', + 'current_output','current_predicate','current_prolog_flag', + 'discontiguous','dynamic','ensure_loaded','exp','fail','findall', + 'float','float_fractional_part','float_integer_part','floor', + 'flush_output','functor','get_byte','get_char','get_code','halt', + 'include','initialization','integer','is','listing','log','mod', + 'multifile','nl','nonvar','notrace','number','number_chars', + 'number_codes','once','op','open','peek_byte','peek_char', + 'peek_code','put_byte','put_char','put_code','read','read_term', + 'rem','repeat','retract','round','set_input','set_output', + 'set_prolog_flag','set_stream_position','setof','sign','sin','sqrt', + 'stream_property','sub_atom','throw','trace','true','truncate', + 'unify_with_occurs_check','univ','var','write','write_canonical', + 'write_term','writeq' + ) + ), + 'SYMBOLS' => array( + 0 => array('(', ')', '[', ']', '{', '}',), + 1 => array('?-', ':-', '=:='), + 2 => array('\-', '\+', '\*', '\/'), + 3 => array('-', '+', '*', '/'), + 4 => array('.', ':', ',', ';'), + 5 => array('!', '@', '&', '|'), + 6 => array('<', '>', '=') + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #990000;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;', + 'HARD' => 'color: #0000ff;' + ), + 'NUMBERS' => array( + 0 => 'color: #800080;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;', + 1 => 'color: #339933;', + 2 => 'color: #339933;', + 3 => 'color: #339933;', + 4 => 'color: #339933;', + 5 => 'color: #339933;', + 6 => 'color: #339933;' + ), + 'REGEXPS' => array( + 0 => 'color: #008080;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://pauillac.inria.fr/~deransar/prolog/bips.html' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Variables + 0 => "(? GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/providex.php b/examples/includes/geshi/geshi/providex.php new file mode 100644 index 0000000..d8b918e --- /dev/null +++ b/examples/includes/geshi/geshi/providex.php @@ -0,0 +1,299 @@ + 'ProvideX', + 'COMMENT_SINGLE' => array(1 => '!'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array( + // Single-Line Comments using REM command + 2 => "/\bREM\b.*?$/i" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + // Directives + '*break', '*continue', '*end', '*escape', '*next', '*proceed', + '*retry', '*return', '*same', 'accept', 'add index', 'addr', + 'auto', 'begin', 'break', 'button', 'bye', 'call', 'case', + 'chart', 'check_box', 'class', 'clear', 'clip_board', 'close', + 'continue', 'control', 'create required', 'create table', + 'cwdir', 'data', 'day_format', 'def', 'default', 'defctl', + 'defprt', 'deftty', 'delete required', 'dictionary', 'dim', 'direct', + 'directory', 'disable', 'drop', 'drop_box', 'dump', 'edit', + 'else', 'enable', 'end switch', 'end', 'end_if', 'endtrace', + 'enter', 'erase', 'error_handler', 'escape', 'event', 'execute', + 'exit', 'exitto', 'extract', 'file', 'find', 'floating point', + 'for', 'function', 'get_file_box', 'gosub', 'goto', 'grid', + 'h_scrollbar', 'hide', 'if', 'index', 'indexed', 'input', + 'insert', 'invoke', 'iolist', 'keyed', 'let', 'like', + 'line_switch', 'list', 'list_box', 'load', 'local', 'lock', + 'long_form', 'menu_bar', 'merge', 'message_lib', 'mnemonic', + 'msgbox', 'multi_line', 'multi_media', 'next', 'object', 'obtain', + 'on', 'open', 'password', 'perform', 'pop', 'popup_menu', + 'precision', 'prefix', 'preinput', 'print', 'process', 'program', + 'property', 'purge', 'quit', 'radio_button', 'randomize', + 'read', 'record', 'redim', 'refile', 'release', 'rem', 'remove', + 'rename', 'renumber', 'repeat', 'reset', 'restore', 'retry', + 'return', 'round', 'run', 'save', 'select', 'serial', 'server', + 'set_focus', 'set_nbf', 'set_param', 'setctl', 'setday', 'setdev', + 'setdrive', 'seterr', 'setesc', 'setfid', 'setmouse', 'settime', + 'settrace', 'short_form', 'show', 'sort', 'start', 'static', + 'step', 'stop', 'switch', 'system_help', 'system_jrnl', 'table', + 'then', 'to', 'translate', 'tristate_box', 'unlock', 'until', + 'update', 'user_lex', 'v_scrollbar', 'vardrop_box', 'varlist_box', + 'via', 'video_palette', 'wait', 'wend', 'while', 'winprt_setup', + 'with', 'write' + ), + 2 => array( + // System Functions + '@x', '@y', 'abs', 'acs', 'and', 'arg', 'asc', 'asn', 'ath', + 'atn', 'bin', 'bsz', 'chg', 'chr', 'cmp', 'cos', 'cpl', + 'crc', 'cse', 'ctl', 'cvs', 'dec', 'dir', 'dll', 'dsk', + 'dte', 'env', 'ept', 'err', 'evn', 'evs', 'exp', 'ffn', + 'fib', 'fid', 'fin', 'fpt', 'gap', 'gbl', 'gep', 'hsa', + 'hsh', 'hta', 'hwn', 'i3e', 'ind', 'int', 'iol', 'ior', + 'jul', 'jst', 'kec', 'kef', 'kel', 'ken', 'kep', 'key', + 'kgn', 'lcs', 'len', 'lno', 'log', 'lrc', 'lst', 'max', + 'mem', 'mid', 'min', 'mnm', 'mod', 'msg', 'msk', 'mxc', + 'mxl', 'new', 'not', 'nul', 'num', 'obj', 'opt', 'pad', + 'pck', 'pfx', 'pgm', 'pos', 'prc', 'prm', 'pth', 'pub', + 'rcd', 'rdx', 'rec', 'ref', 'rnd', 'rno', 'sep', 'sgn', + 'sin', 'sqr', 'srt', 'ssz', 'stk', 'stp', 'str', 'sub', + 'swp', 'sys', 'tan', 'tbl', 'tcb', 'tmr', 'trx', 'tsk', + 'txh', 'txw', 'ucp', 'ucs', 'upk', 'vin', 'vis', 'xeq', + 'xfa', 'xor', '_obj' + ), + 3 => array( + // System Variables + // Vars that are duplicates of functions + // 'ctl', 'err', 'pfx', 'prm', 'rnd', 'sep', 'sys', + 'bkg', 'chn', 'day', 'dlm', 'dsz', 'eom', 'ers', 'esc', + 'gfn', 'gid', 'hfn', 'hlp', 'hwd', 'lfa', 'lfo', 'lip', + 'lpg', 'lwd', 'mse', 'msl', 'nar', 'nid', 'pgn', 'psz', + 'quo', 'ret', 'sid', 'ssn', 'tim', 'tme', 'tms', 'tsm', + 'uid', 'unt', 'who' + + ), + 4 => array( + // Nomads Variables + '%Flmaint_Lib$', '%Flmaint_Msg$', '%Nomads_Activation_Ok', + '%Nomads_Auto_Qry', '%Nomads_Disable_Debug', + '%Nomads_Disable_Trace', '%Nomads_Fkey_Handler$', + '%Nomads_Fkey_Tbl$', '%Nomads_Notest', '%Nomads_Onexit$', + '%Nomads_Post_Display', '%Nomads_Pre_Display$', + '%Nomads_Process$', '%Nomads_Trace_File$', + '%Nomad_Actv_Folder_Colors$', '%Nomad_Automation_Enabled', + '%Nomad_Auto_Close', '%Nomad_Center_Wdw', '%Nomad_Concurrent_Wdw', + '%Nomad_Custom_Define', '%Nomad_Custom_Dir$', + '%Nomad_Custom_Genmtc', '%Nomad_Custom_Skip_Definition', + '%Nomad_Def_Sfx$', '%Nomad_Enter_Tab', '%Nomad_Esc_Sel', + '%Nomad_Isjavx', '%Nomad_Iswindx', '%Nomad_Iswindx$', + '%Nomad_Menu$', '%Nomad_Menu_Leftedge_Clr$', + '%Nomad_Menu_Textbackground_Clr$', '%Nomad_Mln_Sep$', + '%Nomad_Msgmnt$', '%Nomad_Noplusw', '%Nomad_No_Customize', + '%Nomad_Object_Persistence', '%Nomad_Object_Resize', + '%Nomad_Open_Load', '%Nomad_Override_Font$', + '%Nomad_Palette_Loaded', '%Nomad_Panel_Info_Force', + '%Nomad_Panel_Info_Prog$', '%Nomad_Pnl_Def_Colour$', + '%Nomad_Pnl_Def_Font$', '%Nomad_Prg_Cache', '%Nomad_Qry_Attr$', + '%Nomad_Qry_Btn$', '%Nomad_Qry_Clear_Start', '%Nomad_Qry_Tip$', + '%Nomad_Qry_Wide', '%Nomad_Query_Clear_Status', '%Nomad_Query_Kno', + '%Nomad_Query_No_Gray', '%Nomad_Query_Odb_Ignore', + '%Nomad_Query_Retkno', '%Nomad_Query_Sbar_Max', + '%Nomad_Relative_Wdw', '%Nomad_Save_Qry_Path', '%Nomad_Script_Fn', + '%Nomad_Script_Log', '%Nomad_Script_Wdw', + '%Nomad_Skip_Change_Logic', '%Nomad_Skip_Onselect_Logic', + '%Nomad_Stk$', '%Nomad_Tab_Dir', '%Nomad_Timeout', + '%Nomad_Turbo_Off', '%Nomad_Visual_Effect', + '%Nomad_Visual_Override', '%Nomad_Win_Ver', '%Nomad_Xchar', + '%Nomad_Xmax', '%Nomad_Ychar', '%Nomad_Ymax', '%Scr_Def_Attr$', + '%Scr_Def_H_Fl$', '%Scr_Def_H_Id$', '%Scr_Lib', '%Scr_Lib$', + '%Z__Usr_Sec$', 'Alternate_Panel$', 'Alternate_Panel_Type$', + 'Arg_1$', 'Arg_10$', 'Arg_11$', 'Arg_12$', 'Arg_13$', 'Arg_14$', + 'Arg_15$', 'Arg_16$', 'Arg_17$', 'Arg_18$', 'Arg_19$', 'Arg_2$', + 'Arg_20$', 'Arg_3$', 'Arg_4$', 'Arg_5$', 'Arg_6$', 'Arg_7$', + 'Arg_8$', 'Arg_9$', 'Change_Flg', 'Cmd_Str$', 'Default_Prog$', + 'Disp_Cmd$', 'Entire_Record$', 'Exit_Cmd$', 'Fldr_Default_Prog$', + 'Folder_Id$', 'Id', 'Id$', 'Ignore_Exit', 'Initialize_Flg', + 'Init_Text$', 'Init_Val$', 'Main_Scrn_K$', 'Mnu_Ln$', + 'Next_Folder', 'Next_Id', 'Next_Id$', 'No_Flush', 'Prime_Key$', + 'Prior_Val', 'Prior_Val$', 'Qry_Val$', 'Refresh_Flg', + 'Replacement_Folder$', 'Replacement_Lib$', 'Replacement_Scrn$', + 'Scrn_Id$', 'Scrn_K$', 'Scrn_Lib$', 'Tab_Table$', '_Eom$' + ), + 5 => array( + // Mnemonics + "'!w'", "'*c'", "'*h'", "'*i'", "'*o'", "'*r'", "'*x'", + "'+b'", "'+d'", "'+e'", "'+f'", "'+i'", "'+n'", + "'+p'", "'+s'", "'+t'", "'+u'", "'+v'", "'+w'", "'+x'", + "'+z'", "'-b'", "'-d'", "'-e'", "'-f'", "'-i'", + "'-n'", "'-p'", "'-s'", "'-t'", "'-u'", "'-v'", "'-w'", + "'-x'", "'-z'", "'2d'", "'3d'", "'4d'", "'@@'", "'ab'", + "'arc'", "'at'", "'backgr'", "'bb'", "'be'", "'beep'", + "'bg'", "'bi'", "'bj'", "'bk'", "'black'", "'blue'", + "'bm'", "'bo'", "'box'", "'br'", "'bs'", "'bt'", "'bu'", + "'bw'", "'bx'", "'caption'", "'ce'", "'cf'", "'ch'", + "'ci'", "'circle'", "'cl'", "'colour'", "'cp'", "'cpi'", + "'cr'", "'cs'", "'cursor'", "'cyan''_cyan'", "'dc'", + "'default'", "'df'", "'dialogue'", "'dn'", "'do'", + "'drop'", "'eb'", "'ee'", "'ef'", "'eg'", "'ei'", "'ej'", + "'el'", "'em'", "'eo'", "'ep'", "'er'", "'es'", "'et'", + "'eu'", "'ew'", "'ff'", "'fill'", "'fl'", "'font'", + "'frame'", "'gd'", "'ge'", "'gf'", "'goto'", "'green'", + "'gs'", "'hide'", "'ic'", "'image'", "'jc'", + "'jd'", "'jl'", "'jn'", "'jr'", "'js'", "'l6'", "'l8'", + "'lc'", "'ld'", "'lf'", "'li'", "'line'", "'lm'", + "'lpi'", "'lt'", "'magenta'", "'maxsize'", "'me'", + "'message'", "'minsize'", "'mn'", "'mode'", + "'move'", "'mp'", "'ms'", "'ni'", "'offset'", "'option'", + "'pe'", "'pen'", "'picture'", "'pie'", "'pm'", "'polygon'", + "'pop'", "'ps'", "'push'", "'rb'", "'rc'", "'rectangle'", + "'red'", "'rl'", "'rm'", "'rp'", "'rs'", "'rt'", "'sb'", + "'scroll'", "'sd'", "'se'", "'sf'", "'show'", "'size'", + "'sl'", "'sn'", "'sp'", "'sr'", "'swap'", "'sx'", "'text'", + "'textwdw'", "'tr'", "'tw'", "'uc'", "'up'", "'vt'", "'wa'", + "'wc'", "'wd'", "'wg'", "'white'", "'window'", "'wm'", + "'wp'", "'wr'", "'wrap'", "'ws'", "'wx'", "'xp'", "'yellow'", + "'zx'", "'_black'", "'_blue'", "'_colour'", "'_green'", + "'_magenta'", "'_red'", "'_white'", "'_yellow'" + ), + ), + 'SYMBOLS' => array( + 0 => array('+', '-', '*', '/', '^', '|'), + 1 => array('++', '--', '+=', '-=', '*=', '/=', '^=', '|='), + 2 => array('<', '>', '='), + 3 => array('(', ')', '[', ']', '{', '}'), + 4 => array(',', '@', ';', '\\') + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: navy;', // Directives + 2 => 'color: blue;', // System Functions + 3 => 'color: blue;', // System Variables + 4 => 'color: #6A5ACD; font-style: italic;', // Nomads Global Variables + 5 => 'color: #BDB76B;', // Mnemonics + ), + 'COMMENTS' => array( + 1 => 'color: #008080; font-style: italic;', + 2 => 'color: #008080;', + 'MULTI' => 'color: #008080; font-style: italic;' + ), + 'BRACKETS' => array( + 0 => 'color: #000066;' + ), + 'STRINGS' => array( + 0 => 'color: green;' + ), + 'NUMBERS' => array( + 0 => 'color: #00008B;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;', + 1 => 'color: #000099;', + 2 => 'color: #000099;', + 3 => 'color: #0000C9;', + 4 => 'color: #000099;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 1 => 'color: #006400; font-weight: bold', + 2 => 'color: #6A5ACD;' + ) + ), + 'URLS' => array( + 1 => 'http://www.allbasic.info./wiki/index.php/PX:Directive_{FNAME}', + 2 => 'http://www.allbasic.info./wiki/index.php/PX:System_function_{FNAME}', + 3 => 'http://www.allbasic.info./wiki/index.php/PX:System_variable_{FNAME}', + 4 => 'http://www.allbasic.info./wiki/index.php/PX:Nomads_{FNAME}', + 5 => 'http://www.allbasic.info./wiki/index.php/PX:Mnemonic_{FNAMEU}' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => "'" + ), + 'REGEXPS' => array( + 1 => array( + // Line Labels + GESHI_SEARCH => '([[:space:]])([a-zA-Z_][a-zA-Z0-9_]+)(:)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + 2 => array( + // Global String Variables + GESHI_SEARCH => '(\%)([a-zA-Z_][a-zA-Z0-9_]+)(\$)', + GESHI_REPLACE => '\\1\\2\\3', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'NUMBERS' => GESHI_NEVER + ) + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/python.php b/examples/includes/geshi/geshi/python.php new file mode 100644 index 0000000..fbc6cab --- /dev/null +++ b/examples/includes/geshi/geshi/python.php @@ -0,0 +1,237 @@ + 'Python', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + //Longest quotemarks ALWAYS first + 'QUOTEMARKS' => array('"""', '"', "'"), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + + /* + ** Set 1: reserved words + ** http://python.org/doc/current/ref/keywords.html + */ + 1 => array( + 'and', 'del', 'for', 'is', 'raise', 'assert', 'elif', 'from', 'lambda', 'return', 'break', + 'else', 'global', 'not', 'try', 'class', 'except', 'if', 'or', 'while', 'continue', 'exec', + 'import', 'pass', 'yield', 'def', 'finally', 'in', 'print', 'with', 'as' + ), + + /* + ** Set 2: builtins + ** http://python.org/doc/current/lib/built-in-funcs.html + */ + 2 => array( + '__import__', 'abs', 'basestring', 'bool', 'callable', 'chr', 'classmethod', 'cmp', + 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', + 'file', 'filter', 'float', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', + 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'list', 'locals', + 'long', 'map', 'max', 'min', 'object', 'oct', 'open', 'ord', 'pow', 'property', 'range', + 'raw_input', 'reduce', 'reload', 'reversed', 'round', 'set', 'setattr', 'slice', + 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', + 'vars', 'xrange', 'zip', + // Built-in constants: http://python.org/doc/current/lib/node35.html + 'False', 'True', 'None', 'NotImplemented', 'Ellipsis', + // Built-in Exceptions: http://python.org/doc/current/lib/module-exceptions.html + 'Exception', 'StandardError', 'ArithmeticError', 'LookupError', 'EnvironmentError', + 'AssertionError', 'AttributeError', 'EOFError', 'FloatingPointError', 'IOError', + 'ImportError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'MemoryError', 'NameError', + 'NotImplementedError', 'OSError', 'OverflowError', 'ReferenceError', 'RuntimeError', + 'StopIteration', 'SyntaxError', 'SystemError', 'SystemExit', 'TypeError', + 'UnboundlocalError', 'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', + 'UnicodeTranslateError', 'ValueError', 'WindowsError', 'ZeroDivisionError', 'Warning', + 'UserWarning', 'DeprecationWarning', 'PendingDeprecationWarning', 'SyntaxWarning', + 'RuntimeWarning', 'FutureWarning', + // self: this is a common python convention (but not a reserved word) + 'self', + // other + 'any', 'all' + ), + + /* + ** Set 3: standard library + ** http://python.org/doc/current/lib/modindex.html + */ + 3 => array( + '__builtin__', '__future__', '__main__', '_winreg', 'aifc', 'AL', 'al', 'anydbm', + 'array', 'asynchat', 'asyncore', 'atexit', 'audioop', 'base64', 'BaseHTTPServer', + 'Bastion', 'binascii', 'binhex', 'bisect', 'bsddb', 'bz2', 'calendar', 'cd', 'cgi', + 'CGIHTTPServer', 'cgitb', 'chunk', 'cmath', 'cmd', 'code', 'codecs', 'codeop', + 'collections', 'colorsys', 'commands', 'compileall', 'compiler', + 'ConfigParser', 'Cookie', 'cookielib', 'copy', 'copy_reg', 'cPickle', 'crypt', + 'cStringIO', 'csv', 'curses', 'datetime', 'dbhash', 'dbm', 'decimal', 'DEVICE', + 'difflib', 'dircache', 'dis', 'distutils', 'dl', 'doctest', 'DocXMLRPCServer', 'dumbdbm', + 'dummy_thread', 'dummy_threading', 'email', 'encodings', 'errno', 'exceptions', 'fcntl', + 'filecmp', 'fileinput', 'FL', 'fl', 'flp', 'fm', 'fnmatch', 'formatter', 'fpectl', + 'fpformat', 'ftplib', 'gc', 'gdbm', 'getopt', 'getpass', 'gettext', 'GL', 'gl', 'glob', + 'gopherlib', 'grp', 'gzip', 'heapq', 'hmac', 'hotshot', 'htmlentitydefs', 'htmllib', + 'HTMLParser', 'httplib', 'imageop', 'imaplib', 'imgfile', 'imghdr', 'imp', 'inspect', + 'itertools', 'jpeg', 'keyword', 'linecache', 'locale', 'logging', 'mailbox', 'mailcap', + 'marshal', 'math', 'md5', 'mhlib', 'mimetools', 'mimetypes', 'MimeWriter', 'mimify', + 'mmap', 'msvcrt', 'multifile', 'mutex', 'netrc', 'new', 'nis', 'nntplib', 'operator', + 'optparse', 'os', 'ossaudiodev', 'parser', 'pdb', 'pickle', 'pickletools', 'pipes', + 'pkgutil', 'platform', 'popen2', 'poplib', 'posix', 'posixfile', 'pprint', 'profile', + 'pstats', 'pty', 'pwd', 'py_compile', 'pyclbr', 'pydoc', 'Queue', 'quopri', 'random', + 're', 'readline', 'repr', 'resource', 'rexec', 'rfc822', 'rgbimg', 'rlcompleter', + 'robotparser', 'sched', 'ScrolledText', 'select', 'sets', 'sgmllib', 'sha', 'shelve', + 'shlex', 'shutil', 'signal', 'SimpleHTTPServer', 'SimpleXMLRPCServer', 'site', 'smtpd', + 'smtplib', 'sndhdr', 'socket', 'SocketServer', 'stat', 'statcache', 'statvfs', 'string', + 'StringIO', 'stringprep', 'struct', 'subprocess', 'sunau', 'SUNAUDIODEV', 'sunaudiodev', + 'symbol', 'sys', 'syslog', 'tabnanny', 'tarfile', 'telnetlib', 'tempfile', 'termios', + 'test', 'textwrap', 'thread', 'threading', 'time', 'timeit', 'Tix', 'Tkinter', 'token', + 'tokenize', 'traceback', 'tty', 'turtle', 'types', 'unicodedata', 'unittest', 'urllib2', + 'urllib', 'urlparse', 'user', 'UserDict', 'UserList', 'UserString', 'uu', 'warnings', + 'wave', 'weakref', 'webbrowser', 'whichdb', 'whrandom', 'winsound', 'xdrlib', 'xml', + 'xmllib', 'xmlrpclib', 'zipfile', 'zipimport', 'zlib', + // Python 3.0 + 'bytes', 'bytearray' + ), + + /* + ** Set 4: special methods + ** http://python.org/doc/current/ref/specialnames.html + */ + 4 => array( + /* + // Iterator types: http://python.org/doc/current/lib/typeiter.html + '__iter__', 'next', + // String types: http://python.org/doc/current/lib/string-methods.html + 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', + 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', + 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', + 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', + 'translate', 'upper', 'zfill', + */ + // Basic customization: http://python.org/doc/current/ref/customization.html + '__new__', '__init__', '__del__', '__repr__', '__str__', + '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__cmp__', '__rcmp__', + '__hash__', '__nonzero__', '__unicode__', '__dict__', + // Attribute access: http://python.org/doc/current/ref/attribute-access.html + '__setattr__', '__delattr__', '__getattr__', '__getattribute__', '__get__', '__set__', + '__delete__', '__slots__', + // Class creation, callable objects + '__metaclass__', '__call__', + // Container types: http://python.org/doc/current/ref/sequence-types.html + '__len__', '__getitem__', '__setitem__', '__delitem__', '__iter__', '__contains__', + '__getslice__', '__setslice__', '__delslice__', + // Numeric types: http://python.org/doc/current/ref/numeric-types.html + '__abs__','__add__','__and__','__coerce__','__div__','__divmod__','__float__', + '__hex__','__iadd__','__isub__','__imod__','__idiv__','__ipow__','__iand__', + '__ior__','__ixor__', '__ilshift__','__irshift__','__invert__','__int__', + '__long__','__lshift__', + '__mod__','__mul__','__neg__','__oct__','__or__','__pos__','__pow__', + '__radd__','__rdiv__','__rdivmod__','__rmod__','__rpow__','__rlshift__','__rrshift__', + '__rshift__','__rsub__','__rmul__','__rand__','__rxor__','__ror__', + '__sub__','__xor__' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '*', '&', '%', '!', ';', '<', '>', '?', '`' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #ff7700;font-weight:bold;', // Reserved + 2 => 'color: #008000;', // Built-ins + self + 3 => 'color: #dc143c;', // Standard lib + 4 => 'color: #0000cd;' // Special methods + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: black;' + ), + 'STRINGS' => array( + 0 => 'color: #483d8b;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff4500;' + ), + 'METHODS' => array( + 1 => 'color: black;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/qbasic.php b/examples/includes/geshi/geshi/qbasic.php new file mode 100644 index 0000000..f6531f7 --- /dev/null +++ b/examples/includes/geshi/geshi/qbasic.php @@ -0,0 +1,151 @@ + 'QBasic/QuickBASIC', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + //Single-Line Comments using REM command + 2 => "/\bREM.*?$/i" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'DO', 'LOOP', 'WHILE', 'WEND', 'THEN', 'ELSE', 'ELSEIF', 'IF', + 'FOR', 'TO', 'NEXT', 'STEP', 'GOTO', 'GOSUB', 'CALL', 'CALLS', + 'SUB', 'FUNCTION', 'RETURN', 'RESUME', 'SELECT', 'CASE', 'UNTIL' + ), + 3 => array( + 'ABS', 'ABSOLUTE', 'ACCESS', 'ALIAS', 'AND', 'ANY', 'APPEND', 'AS', 'ASC', 'ATN', + 'BASE', 'BEEP', 'BINARY', 'BLOAD', 'BSAVE', 'BYVAL', + 'CDBL', 'CDECL', 'CHAIN', 'CHDIR', 'CHR$', 'CINT', 'CIRCLE', 'CLEAR', + 'CLNG', 'CLOSE', 'CLS', 'COM', 'COMMAND$', 'COMMON', 'CONST', 'COS', 'CSNG', + 'CSRLIN', 'CVD', 'CVDMBF', 'CVI', 'CVL', 'CVS', 'CVSMDF', 'DATA', 'DATE$', + 'DECLARE', 'DEF', 'FN', 'SEG', 'DEFDBL', 'DEFINT', 'DEFLNG', 'DEFSNG', 'DEFSTR', + 'DIM', 'DOUBLE', 'DRAW', 'END', 'ENVIRON', 'ENVIRON$', 'EOF', 'EQV', 'ERASE', + 'ERDEV', 'ERDEV$', 'ERL', 'ERR', 'ERROR', 'EXIT', 'EXP', 'FIELD', 'FILEATTR', + 'FILES', 'FIX', 'FRE', 'FREEFILE', 'GET', 'HEX$', 'IMP', 'INKEY$', + 'INP', 'INPUT', 'INPUT$', 'INSTR', 'INT', 'INTEGER', 'IOCTL', 'IOCTL$', 'IS', + 'KEY', 'KILL', 'LBOUND', 'LCASE$', 'LEFT$', 'LEN', 'LET', 'LINE', 'LIST', 'LOC', + 'LOCAL', 'LOCATE', 'LOCK', 'LOF', 'LOG', 'LONG', 'LPOS', 'LPRINT', + 'LSET', 'LTRIM$', 'MID$', 'MKD$', 'MKDIR', 'MKDMBF$', 'MKI$', 'MKL$', + 'MKS$', 'MKSMBF$', 'MOD', 'NAME', 'NOT', 'OCT$', 'OFF', 'ON', 'PEN', 'PLAY', + 'OPEN', 'OPTION', 'OR', 'OUT', 'OUTPUT', + 'PAINT', 'PALETTE', 'PCOPY', 'PEEK', 'PMAP', 'POINT', 'POKE', 'POS', 'PRESET', + 'PRINT', 'PSET', 'PUT', 'RANDOM', 'RANDOMIZE', 'READ', 'REDIM', 'RESET', + 'RESTORE', 'RIGHT$', 'RMDIR', 'RND', 'RSET', 'RTRIM$', 'RUN', 'SADD', 'SCREEN', + 'SEEK', 'SETMEM', 'SGN', 'SHARED', 'SHELL', 'SIGNAL', 'SIN', 'SINGLE', 'SLEEP', + 'SOUND', 'SPACE$', 'SPC', 'SQR', 'STATIC', 'STICK', 'STOP', 'STR$', 'STRIG', + 'STRING', 'STRING$', 'SWAP', 'SYSTEM', 'TAB', 'TAN', 'TIME$', 'TIMER', + 'TROFF', 'TRON', 'TYPE', 'UBOUND', 'UCASE$', 'UEVENT', 'UNLOCK', 'USING', 'VAL', + 'VARPTR', 'VARPTR$', 'VARSEG', 'VIEW', 'WAIT', 'WIDTH', 'WINDOW', 'WRITE', 'XOR' + ) + ), + 'SYMBOLS' => array( + '(', ')', ',', '+', '-', '*', '/', '=', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #a1a100;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080;', + 2 => 'color: #808080;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 3 => 'http://www.qbasicnews.com/qboho/qck{FNAMEL}.shtml' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 8 +); + +?> diff --git a/examples/includes/geshi/geshi/rails.php b/examples/includes/geshi/geshi/rails.php new file mode 100644 index 0000000..52c70a6 --- /dev/null +++ b/examples/includes/geshi/geshi/rails.php @@ -0,0 +1,406 @@ + 'Rails', + 'COMMENT_SINGLE' => array(1 => "#"), + 'COMMENT_MULTI' => array("=begin" => "=end"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', '`','\''), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'alias', 'and', 'begin', 'break', 'case', 'class', + 'def', 'defined', 'do', 'else', 'elsif', 'end', + 'ensure', 'for', 'if', 'in', 'module', 'while', + 'next', 'not', 'or', 'redo', 'rescue', 'yield', + 'retry', 'super', 'then', 'undef', 'unless', + 'until', 'when', 'BEGIN', 'END', 'include' + ), + 2 => array( + '__FILE__', '__LINE__', 'false', 'nil', 'self', 'true', + 'return' + ), + 3 => array( + 'Array', 'Float', 'Integer', 'String', 'at_exit', + 'autoload', 'binding', 'caller', 'catch', 'chop', 'chop!', + 'chomp', 'chomp!', 'eval', 'exec', 'exit', 'exit!', 'fail', + 'fork', 'format', 'gets', 'global_variables', 'gsub', 'gsub!', + 'iterator?', 'lambda', 'load', 'local_variables', 'loop', + 'open', 'p', 'print', 'printf', 'proc', 'putc', 'puts', + 'raise', 'rand', 'readline', 'readlines', 'require', 'select', + 'sleep', 'split', 'sprintf', 'srand', 'sub', 'sub!', 'syscall', + 'system', 'trace_var', 'trap', 'untrace_var' + ), + 4 => array( + 'Abbrev', 'ArgumentError', 'Base64', 'Benchmark', + 'Benchmark::Tms', 'Bignum', 'Binding', 'CGI', 'CGI::Cookie', + 'CGI::HtmlExtension', 'CGI::QueryExtension', + 'CGI::Session', 'CGI::Session::FileStore', + 'CGI::Session::MemoryStore', 'Class', 'Comparable', 'Complex', + 'ConditionVariable', 'Continuation', 'Data', + 'Date', 'DateTime', 'Delegator', 'Dir', 'EOFError', 'ERB', + 'ERB::Util', 'Enumerable', 'Enumerable::Enumerator', 'Errno', + 'Exception', 'FalseClass', 'File', + 'File::Constants', 'File::Stat', 'FileTest', 'FileUtils', + 'FileUtils::DryRun', 'FileUtils::NoWrite', + 'FileUtils::StreamUtils_', 'FileUtils::Verbose', 'Find', + 'Fixnum', 'FloatDomainError', 'Forwardable', 'GC', 'Generator', + 'Hash', 'IO', 'IOError', 'Iconv', 'Iconv::BrokenLibrary', + 'Iconv::Failure', 'Iconv::IllegalSequence', + 'Iconv::InvalidCharacter', 'Iconv::InvalidEncoding', + 'Iconv::OutOfRange', 'IndexError', 'Interrupt', 'Kernel', + 'LoadError', 'LocalJumpError', 'Logger', 'Logger::Application', + 'Logger::Error', 'Logger::Formatter', 'Logger::LogDevice', + 'Logger::LogDevice::LogDeviceMutex', 'Logger::Severity', + 'Logger::ShiftingError', 'Marshal', 'MatchData', + 'Math', 'Matrix', 'Method', 'Module', 'Mutex', 'NameError', + 'NameError::message', 'NilClass', 'NoMemoryError', + 'NoMethodError', 'NotImplementedError', 'Numeric', 'Object', + 'ObjectSpace', 'Observable', 'PStore', 'PStore::Error', + 'Pathname', 'Precision', 'Proc', 'Process', 'Process::GID', + 'Process::Status', 'Process::Sys', 'Process::UID', 'Queue', + 'Range', 'RangeError', 'Rational', 'Regexp', 'RegexpError', + 'RuntimeError', 'ScriptError', 'SecurityError', 'Set', + 'Shellwords', 'Signal', 'SignalException', 'SimpleDelegator', + 'SingleForwardable', 'Singleton', 'SingletonClassMethods', + 'SizedQueue', 'SortedSet', 'StandardError', 'StringIO', + 'StringScanner', 'StringScanner::Error', 'Struct', 'Symbol', + 'SyncEnumerator', 'SyntaxError', 'SystemCallError', + 'SystemExit', 'SystemStackError', 'Tempfile', + 'Test::Unit::TestCase', 'Test::Unit', 'Test', 'Thread', + 'ThreadError', 'ThreadGroup', + 'ThreadsWait', 'Time', 'TrueClass', 'TypeError', 'URI', + 'URI::BadURIError', 'URI::Error', 'URI::Escape', 'URI::FTP', + 'URI::Generic', 'URI::HTTP', 'URI::HTTPS', + 'URI::InvalidComponentError', 'URI::InvalidURIError', + 'URI::LDAP', 'URI::MailTo', 'URI::REGEXP', + 'URI::REGEXP::PATTERN', 'UnboundMethod', 'Vector', 'YAML', + 'ZeroDivisionError', 'Zlib', + 'Zlib::BufError', 'Zlib::DataError', 'Zlib::Deflate', + 'Zlib::Error', 'Zlib::GzipFile', 'Zlib::GzipFile::CRCError', + 'Zlib::GzipFile::Error', 'Zlib::GzipFile::LengthError', + 'Zlib::GzipFile::NoFooter', 'Zlib::GzipReader', + 'Zlib::GzipWriter', 'Zlib::Inflate', 'Zlib::MemError', + 'Zlib::NeedDict', 'Zlib::StreamEnd', 'Zlib::StreamError', + 'Zlib::VersionError', + 'Zlib::ZStream', + 'ActionController::AbstractRequest', + 'ActionController::Assertions::DomAssertions', + 'ActionController::Assertions::ModelAssertions', + 'ActionController::Assertions::ResponseAssertions', + 'ActionController::Assertions::RoutingAssertions', + 'ActionController::Assertions::SelectorAssertions', + 'ActionController::Assertions::TagAssertions', + 'ActionController::Base', + 'ActionController::Benchmarking::ClassMethods', + 'ActionController::Caching', + 'ActionController::Caching::Actions', + 'ActionController::Caching::Actions::ActionCachePath', + 'ActionController::Caching::Fragments', + 'ActionController::Caching::Pages', + 'ActionController::Caching::Pages::ClassMethods', + 'ActionController::Caching::Sweeping', + 'ActionController::Components', + 'ActionController::Components::ClassMethods', + 'ActionController::Components::InstanceMethods', + 'ActionController::Cookies', + 'ActionController::Filters::ClassMethods', + 'ActionController::Flash', + 'ActionController::Flash::FlashHash', + 'ActionController::Helpers::ClassMethods', + 'ActionController::Integration::Session', + 'ActionController::IntegrationTest', + 'ActionController::Layout::ClassMethods', + 'ActionController::Macros', + 'ActionController::Macros::AutoComplete::ClassMethods', + 'ActionController::Macros::InPlaceEditing::ClassMethods', + 'ActionController::MimeResponds::InstanceMethods', + 'ActionController::Pagination', + 'ActionController::Pagination::ClassMethods', + 'ActionController::Pagination::Paginator', + 'ActionController::Pagination::Paginator::Page', + 'ActionController::Pagination::Paginator::Window', + 'ActionController::Rescue', 'ActionController::Resources', + 'ActionController::Routing', + 'ActionController::Scaffolding::ClassMethods', + 'ActionController::SessionManagement::ClassMethods', + 'ActionController::Streaming', 'ActionController::TestProcess', + 'ActionController::TestUploadedFile', + 'ActionController::UrlWriter', + 'ActionController::Verification::ClassMethods', + 'ActionMailer::Base', 'ActionView::Base', + 'ActionView::Helpers::ActiveRecordHelper', + 'ActionView::Helpers::AssetTagHelper', + 'ActionView::Helpers::BenchmarkHelper', + 'ActionView::Helpers::CacheHelper', + 'ActionView::Helpers::CaptureHelper', + 'ActionView::Helpers::DateHelper', + 'ActionView::Helpers::DebugHelper', + 'ActionView::Helpers::FormHelper', + 'ActionView::Helpers::FormOptionsHelper', + 'ActionView::Helpers::FormTagHelper', + 'ActionView::Helpers::JavaScriptHelper', + 'ActionView::Helpers::JavaScriptMacrosHelper', + 'ActionView::Helpers::NumberHelper', + 'ActionView::Helpers::PaginationHelper', + 'ActionView::Helpers::PrototypeHelper', + 'ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods', + 'ActionView::Helpers::ScriptaculousHelper', + 'ActionView::Helpers::TagHelper', + 'ActionView::Helpers::TextHelper', + 'ActionView::Helpers::UrlHelper', 'ActionView::Partials', + 'ActionWebService::API::Method', 'ActionWebService::Base', + 'ActionWebService::Client::Soap', + 'ActionWebService::Client::XmlRpc', + 'ActionWebService::Container::ActionController::ClassMethods', + 'ActionWebService::Container::Delegated::ClassMethods', + 'ActionWebService::Container::Direct::ClassMethods', + 'ActionWebService::Invocation::ClassMethods', + 'ActionWebService::Scaffolding::ClassMethods', + 'ActionWebService::SignatureTypes', 'ActionWebService::Struct', + 'ActiveRecord::Acts::List::ClassMethods', + 'ActiveRecord::Acts::List::InstanceMethods', + 'ActiveRecord::Acts::NestedSet::ClassMethods', + 'ActiveRecord::Acts::NestedSet::InstanceMethods', + 'ActiveRecord::Acts::Tree::ClassMethods', + 'ActiveRecord::Acts::Tree::InstanceMethods', + 'ActiveRecord::Aggregations::ClassMethods', + 'ActiveRecord::Associations::ClassMethods', + 'ActiveRecord::AttributeMethods::ClassMethods', + 'ActiveRecord::Base', + 'ActiveRecord::Calculations::ClassMethods', + 'ActiveRecord::Callbacks', + 'ActiveRecord::ConnectionAdapters::AbstractAdapter', + 'ActiveRecord::ConnectionAdapters::Column', + 'ActiveRecord::ConnectionAdapters::DB2Adapter', + 'ActiveRecord::ConnectionAdapters::DatabaseStatements', + 'ActiveRecord::ConnectionAdapters::FirebirdAdapter', + 'ActiveRecord::ConnectionAdapters::FrontBaseAdapter', + 'ActiveRecord::ConnectionAdapters::MysqlAdapter', + 'ActiveRecord::ConnectionAdapters::OpenBaseAdapter', + 'ActiveRecord::ConnectionAdapters::OracleAdapter', + 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter', + 'ActiveRecord::ConnectionAdapters::Quoting', + 'ActiveRecord::ConnectionAdapters::SQLServerAdapter', + 'ActiveRecord::ConnectionAdapters::SQLiteAdapter', + 'ActiveRecord::ConnectionAdapters::SchemaStatements', + 'ActiveRecord::ConnectionAdapters::SybaseAdapter::ColumnWithIdentity', + 'ActiveRecord::ConnectionAdapters::SybaseAdapterContext', + 'ActiveRecord::ConnectionAdapters::TableDefinition', + 'ActiveRecord::Errors', 'ActiveRecord::Locking', + 'ActiveRecord::Locking::Optimistic', + 'ActiveRecord::Locking::Optimistic::ClassMethods', + 'ActiveRecord::Locking::Pessimistic', + 'ActiveRecord::Migration', 'ActiveRecord::Observer', + 'ActiveRecord::Observing::ClassMethods', + 'ActiveRecord::Reflection::ClassMethods', + 'ActiveRecord::Reflection::MacroReflection', + 'ActiveRecord::Schema', 'ActiveRecord::Timestamp', + 'ActiveRecord::Transactions::ClassMethods', + 'ActiveRecord::Validations', + 'ActiveRecord::Validations::ClassMethods', + 'ActiveRecord::XmlSerialization', + 'ActiveSupport::CachingTools::HashCaching', + 'ActiveSupport::CoreExtensions::Array::Conversions', + 'ActiveSupport::CoreExtensions::Array::Grouping', + 'ActiveSupport::CoreExtensions::Date::Conversions', + 'ActiveSupport::CoreExtensions::Hash::Conversions', + 'ActiveSupport::CoreExtensions::Hash::Conversions::ClassMethods', + 'ActiveSupport::CoreExtensions::Hash::Diff', + 'ActiveSupport::CoreExtensions::Hash::Keys', + 'ActiveSupport::CoreExtensions::Hash::ReverseMerge', + 'ActiveSupport::CoreExtensions::Integer::EvenOdd', + 'ActiveSupport::CoreExtensions::Integer::Inflections', + 'ActiveSupport::CoreExtensions::Numeric::Bytes', + 'ActiveSupport::CoreExtensions::Numeric::Time', + 'ActiveSupport::CoreExtensions::Pathname::CleanWithin', + 'ActiveSupport::CoreExtensions::Range::Conversions', + 'ActiveSupport::CoreExtensions::String::Access', + 'ActiveSupport::CoreExtensions::String::Conversions', + 'ActiveSupport::CoreExtensions::String::Inflections', + 'ActiveSupport::CoreExtensions::String::Iterators', + 'ActiveSupport::CoreExtensions::String::StartsEndsWith', + 'ActiveSupport::CoreExtensions::String::Unicode', + 'ActiveSupport::CoreExtensions::Time::Calculations', + 'ActiveSupport::CoreExtensions::Time::Calculations::ClassMethods', + 'ActiveSupport::CoreExtensions::Time::Conversions', + 'ActiveSupport::Multibyte::Chars', + 'ActiveSupport::Multibyte::Handlers::UTF8Handler', + 'Breakpoint', 'Builder::BlankSlate', 'Builder::XmlMarkup', + 'Fixtures', + 'HTML::Selector', 'HashWithIndifferentAccess', 'Inflector', + 'Inflector::Inflections', 'Mime', 'Mime::Type', + 'OCI8AutoRecover', 'TimeZone', 'XmlSimple' + ), + 5 => array( + 'image_tag', 'link_to', 'link_to_remote', 'javascript_include_tag', + 'assert_equal', 'assert_not_equal', 'before_filter', + 'after_filter', 'render', 'redirect_to', 'hide_action', + 'render_to_string', 'url_for', 'controller_name', + 'controller_class_name', 'controller_path', 'session', + 'render_component', 'render_component_as_string', 'cookie', + 'layout', 'flash', 'auto_complete_for', 'in_place_editor_for', + 'respond_to', 'paginate', 'current_page', 'each', 'first', + 'first_page', 'last_page', 'last', 'length', 'new', 'page_count', + 'previous', 'scaffold', 'send_data', + 'send_file', 'deliver', 'receive', 'error_messages_for', + 'error_message_on', 'form', 'input', 'stylesheet_link_tag', + 'stylesheet_path', 'content_for', 'select_date', 'ago', + 'month', 'day', 'check_box', 'fields_for', 'file_field', + 'form_for', 'hidden_field', 'text_area', 'password_field', + 'collection_select', 'options_for_select', + 'options_from_collection_for_select', 'file_field_tag', + 'form_for_tag', 'hidden_field_tag', 'text_area_tag', + 'password_field_tag', 'link_to_function', 'javascript_tag', + 'human_size', 'number_to_currency', 'pagination_links', + 'form_remote_tag', 'form_remote_for', + 'submit_to_remote', 'remote_function', 'observe_form', + 'observe_field', 'remote_form_for', 'options_for_ajax', 'alert', + 'call', 'assign', 'show', 'hide', 'insert_html', 'sortable', + 'toggle', 'visual_effect', 'replace', 'replace_html', 'remove', + 'save', 'save!', 'draggable', 'drop_receiving', 'literal', + 'draggable_element', 'drop_receiving_element', 'sortable_element', + 'content_tag', 'tag', 'link_to_image', 'link_to_if', + 'link_to_unless', 'mail_to', 'link_image_to', 'button_to', + 'current_page?', 'act_as_list', 'act_as_nested', 'act_as_tree', + 'has_many', 'has_one', 'belongs_to', 'has_many_and_belogns_to', + 'delete', 'destroy', 'destroy_all', 'clone', 'deep_clone', 'copy', + 'update', 'table_name', 'primary_key', 'sum', 'maximun', 'minimum', + 'count', 'size', 'after_save', 'after_create', 'before_save', + 'before_create', 'add_to_base', 'errors', 'add', 'validate', + 'validates_presence_of', 'validates_numericality_of', + 'validates_uniqueness_of', 'validates_length_of', + 'validates_format_of', 'validates_size_of', 'to_a', 'to_s', + 'to_xml', 'to_i' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '%', '&', '*', '|', '/', '<', '>', + '+', '-', '=>', '<<' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color:#9966CC; font-weight:bold;', + 2 => 'color:#0000FF; font-weight:bold;', + 3 => 'color:#CC0066; font-weight:bold;', + 4 => 'color:#CC00FF; font-weight:bold;', + 5 => 'color:#5A0A0A; font-weight:bold;' + ), + 'COMMENTS' => array( + 1 => 'color:#008000; font-style:italic;', + 'MULTI' => 'color:#000080; font-style:italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color:#000099;' + ), + 'BRACKETS' => array( + 0 => 'color:#006600; font-weight:bold;' + ), + 'STRINGS' => array( + 0 => 'color:#996600;' + ), + 'NUMBERS' => array( + 0 => 'color:#006666;' + ), + 'METHODS' => array( + 1 => 'color:#9900CC;' + ), + 'SYMBOLS' => array( + 0 => 'color:#006600; font-weight:bold;' + ), + 'REGEXPS' => array( + 0 => 'color:#ff6633; font-weight:bold;', + 1 => 'color:#0066ff; font-weight:bold;', + 2 => 'color:#6666ff; font-weight:bold;', + 3 => 'color:#ff3333; font-weight:bold;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + 0 => array( + GESHI_SEARCH => "([[:space:]])(\\$[a-zA-Z_][a-zA-Z0-9_]*)", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 1 => array( + GESHI_SEARCH => "([[:space:]])(@[a-zA-Z_][a-zA-Z0-9_]*)", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 2 => "([A-Z][a-zA-Z0-9_]*::)+[A-Z][a-zA-Z0-9_]*", //Static OOP References + 3 => array( + GESHI_SEARCH => "([[:space:]]|\[|\()(:[a-zA-Z_][a-zA-Z0-9_]*)", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + '<%' => '%>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + ) +); + +?> diff --git a/examples/includes/geshi/geshi/rebol.php b/examples/includes/geshi/geshi/rebol.php new file mode 100644 index 0000000..6f57137 --- /dev/null +++ b/examples/includes/geshi/geshi/rebol.php @@ -0,0 +1,196 @@ + 'REBOL', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array('rebol [' => ']', 'comment [' => ']'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'binary!','block!','char!','date!','decimal!','email!','file!', + 'hash!','integer!','issue!','list!','logic!','money!','none!', + 'object!','paren!','pair!','path!','string!','tag!','time!', + 'tuple!','url!', + ), + 2 => array( + 'all','any','attempt','break','catch','compose','disarm','dispatch', + 'do','do-events','does','either','else','exit','for','forall', + 'foreach','forever','forskip','func','function','halt','has','if', + 'launch','loop','next','quit','reduce','remove-each','repeat', + 'return','secure','switch','throw','try','until','wait','while', + ), + 3 => array( + 'about','abs','absolute','add','alert','alias','alter','and', + 'any-block?','any-function?','any-string?','any-type?','any-word?', + 'append','arccosine','arcsine','arctangent','array','as-pair', + 'ask','at','back','binary?','bind','bitset?','block?','brightness?', + 'browse','build-tag','caret-to-offset','center-face','change', + 'change-dir','char?','charset','checksum','choose','clean-path', + 'clear','clear-fields','close','comment','complement','component?', + 'compress','confirm','connected?','construct','context','copy', + 'cosine','datatype?','date?','debase','decimal?','decode-cgi', + 'decompress','dehex','delete','detab','difference','dir?','dirize', + 'divide','dump-face','dump-obj','echo','email?','empty?','enbase', + 'entab','equal?','error?','even?','event?','exclude','exists?', + 'exp','extract','fifth','file?','find','first','flash','focus', + 'form','found?','fourth','free','function?','get','get-modes', + 'get-word?','greater-or-equal?','greater?','hash?','head','head?', + 'help','hide','hide-popup','image?','import-email','in', + 'in-window?','index?','info?','inform','input','input?','insert', + 'integer?','intersect','issue?','join','last','layout','length?', + 'lesser-or-equal?','lesser?','library?','license','link?', + 'list-dir','list?','lit-path?','lit-word?','load','load-image', + 'log-10','log-2','log-e','logic?','lowercase','make','make-dir', + 'make-face','max','maximum','maximum-of','min','minimum', + 'minimum-of','modified?','mold','money?','multiply','native?', + 'negate','negative?','none?','not','not-equal?','now','number?', + 'object?','odd?','offset-to-caret','offset?','op?','open','or', + 'pair?','paren?','parse','parse-xml','path?','pick','poke','port?', + 'positive?','power','prin','print','probe','protect', + 'protect-system','query','random','read','read-io','recycle', + 'refinement?','reform','rejoin','remainder','remold','remove', + 'rename', + //'repeat', + 'repend','replace','request','request-color','request-date', + 'request-download','request-file','request-list','request-pass', + 'request-text','resend','reverse','routine?','same?','save', + 'script?','second','select','send','series?','set','set-modes', + 'set-net','set-path?','set-word?','show','show-popup','sign?', + 'sine','size-text','size?','skip','sort','source','span?', + 'split-path','square-root','strict-equal?','strict-not-equal?', + 'string?','struct?','stylize','subtract','suffix?','tag?','tail', + 'tail?','tangent','third','time?','to','to-binary','to-bitset', + 'to-block','to-char','to-date','to-decimal','to-email','to-file', + 'to-get-word','to-hash','to-hex','to-idate','to-image','to-integer', + 'to-issue','to-list','to-lit-path','to-lit-word','to-local-file', + 'to-logic','to-money','to-pair','to-paren','to-path', + 'to-rebol-file','to-refinement','to-set-path','to-set-word', + 'to-string','to-tag','to-time','to-tuple','to-url','to-word', + 'trace','trim','tuple?','type?','unfocus','union','unique', + 'unprotect','unset','unset?','unview','update','upgrade', + 'uppercase','url?','usage','use','value?','view','viewed?','what', + 'what-dir','within?','word?','write','write-io','xor','zero?', + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '@', '%', '&', '*', '|', '/', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', +// 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' +// 2 => 'includes/dico_rebol.php?word={FNAME}', +// 3 => 'includes/dico_rebol.php?word={FNAME}' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 0 => "[\\$]{1,2}[a-zA-Z_][a-zA-Z0-9_]*", + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/reg.php b/examples/includes/geshi/geshi/reg.php new file mode 100644 index 0000000..9c85a15 --- /dev/null +++ b/examples/includes/geshi/geshi/reg.php @@ -0,0 +1,233 @@ + 'Microsoft Registry', + 'COMMENT_SINGLE' => array(1 =>';'), + 'COMMENT_MULTI' => array( ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( +// 1 => array(), +// 2 => array(), + /* Registry Key Constants Not Used */ + 3 => array( + 'HKEY_LOCAL_MACHINE', + 'HKEY_CLASSES_ROOT', + 'HKEY_CURRENT_USER', + 'HKEY_USERS', + 'HKEY_CURRENT_CONFIG', + 'HKEY_DYN_DATA', + 'HKLM', 'HKCR', 'HKCU', 'HKU', 'HKCC', 'HKDD' + ) + ), + 'SYMBOLS' => array( + '=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, +// 1 => false, +// 2 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( +// 1 => 'color: #00CCFF;', +// 2 => 'color: #0000FF;', + 3 => 'color: #800000;' + ), + 'COMMENTS' => array( + 1 => 'color: #009900;' + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #009900;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 0 => 'color: #00CCFF;', + 1 => 'color: #0000FF;', + 2 => '', + 3 => 'color: #0000FF;', + 4 => 'color: #0000FF;', + 5 => '', + 6 => '', + 7 => '', + 8 => 'color: #FF6600;', + ) + ), + 'URLS' => array( +// 1 => '', +// 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + // Highlight Key Delimiters + 0 => array( + GESHI_SEARCH => '((^|\\n)\\s*)(\\\\\\[(.*)\\\\\\])(\\s*(\\n|$))', + GESHI_REPLACE => '\\3', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\5' +// GESHI_CLASS => 'kw1' + ), + // Highlight File Format Header Version 5 + 1 => array( + GESHI_SEARCH => '(^\s*)(Windows Registry Editor Version \d+\.\d+)(\s*$)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3', + GESHI_CLASS => 'geshi_registry_header' + ), + // Highlight File Format Header Version 4 + 2 => array( + GESHI_SEARCH => '(^\\s*)(REGEDIT\s?\d+)(\s*$)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3', + GESHI_CLASS => 'geshi_registry_header' + ), + // Highlight dword: 32 bit integer values + 3 => array( + GESHI_SEARCH => '(=\s*)(dword:[0-9a-fA-F]{8})(\s*$)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' +// GESHI_CLASS => 'kw2' + ), + // Highlight variable names + 4 => array( + GESHI_SEARCH => '(^\s*)(\".*?\")(\s*=)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3', + GESHI_CLASS => 'geshi_variable' + ), + // Highlight String Values + 5 => array( + GESHI_SEARCH => '(=\s*)(\".*?\")(\s*$)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3', + GESHI_CLASS => 'st0' + ), + // Highlight Hexadecimal Values (Single-Line and Multi-Line) + 6 => array( + GESHI_SEARCH => '(=\s*\n?\s*)(hex:[0-9a-fA-F]{2}(,(\\\s*\n\s*)?[0-9a-fA-F]{2})*)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '', + GESHI_CLASS => 'kw2' + ), + // Highlight Default Variable + 7 => array( + GESHI_SEARCH => '(^\s*)(@)(\s*=)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'm', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3', + GESHI_CLASS => 'geshi_variable' + ), + // Highlight GUID's found anywhere. + 8 => array( + GESHI_SEARCH => '(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\})', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '', + GESHI_CLASS => 'geshi_guid' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'NUMBERS' => GESHI_NEVER, + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/robots.php b/examples/includes/geshi/geshi/robots.php new file mode 100644 index 0000000..7bb2b20 --- /dev/null +++ b/examples/includes/geshi/geshi/robots.php @@ -0,0 +1,98 @@ + 'robots.txt', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'User-agent', 'Disallow' + ) + ), + 'SYMBOLS' => array( + ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://www.robotstxt.org/wc/norobots.html' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/ruby.php b/examples/includes/geshi/geshi/ruby.php new file mode 100644 index 0000000..8928557 --- /dev/null +++ b/examples/includes/geshi/geshi/ruby.php @@ -0,0 +1,226 @@ + 'Ruby', + 'COMMENT_SINGLE' => array(1 => "#"), + 'COMMENT_MULTI' => array("=begin" => "=end"), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', '`','\''), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'alias', 'and', 'begin', 'break', 'case', 'class', + 'def', 'defined', 'do', 'else', 'elsif', 'end', + 'ensure', 'for', 'if', 'in', 'module', 'while', + 'next', 'not', 'or', 'redo', 'rescue', 'yield', + 'retry', 'super', 'then', 'undef', 'unless', + 'until', 'when', 'BEGIN', 'END', 'include' + ), + 2 => array( + '__FILE__', '__LINE__', 'false', 'nil', 'self', 'true', + 'return' + ), + 3 => array( + 'Array', 'Float', 'Integer', 'String', 'at_exit', + 'autoload', 'binding', 'caller', 'catch', 'chop', 'chop!', + 'chomp', 'chomp!', 'eval', 'exec', 'exit', 'exit!', 'fail', + 'fork', 'format', 'gets', 'global_variables', 'gsub', 'gsub!', + 'iterator?', 'lambda', 'load', 'local_variables', 'loop', + 'open', 'p', 'print', 'printf', 'proc', 'putc', 'puts', + 'raise', 'rand', 'readline', 'readlines', 'require', 'select', + 'sleep', 'split', 'sprintf', 'srand', 'sub', 'sub!', 'syscall', + 'system', 'trace_var', 'trap', 'untrace_var' + ), + 4 => array( + 'Abbrev', 'ArgumentError', 'Base64', 'Benchmark', + 'Benchmark::Tms', 'Bignum', 'Binding', 'CGI', 'CGI::Cookie', + 'CGI::HtmlExtension', 'CGI::QueryExtension', + 'CGI::Session', 'CGI::Session::FileStore', + 'CGI::Session::MemoryStore', 'Class', 'Comparable', 'Complex', + 'ConditionVariable', 'Continuation', 'Data', + 'Date', 'DateTime', 'Delegator', 'Dir', 'EOFError', 'ERB', + 'ERB::Util', 'Enumerable', 'Enumerable::Enumerator', 'Errno', + 'Exception', 'FalseClass', 'File', + 'File::Constants', 'File::Stat', 'FileTest', 'FileUtils', + 'FileUtils::DryRun', 'FileUtils::NoWrite', + 'FileUtils::StreamUtils_', 'FileUtils::Verbose', 'Find', + 'Fixnum', 'FloatDomainError', 'Forwardable', 'GC', 'Generator', + 'Hash', 'IO', 'IOError', 'Iconv', 'Iconv::BrokenLibrary', + 'Iconv::Failure', 'Iconv::IllegalSequence', + 'Iconv::InvalidCharacter', 'Iconv::InvalidEncoding', + 'Iconv::OutOfRange', 'IndexError', 'Interrupt', 'Kernel', + 'LoadError', 'LocalJumpError', 'Logger', 'Logger::Application', + 'Logger::Error', 'Logger::Formatter', 'Logger::LogDevice', + 'Logger::LogDevice::LogDeviceMutex', 'Logger::Severity', + 'Logger::ShiftingError', 'Marshal', 'MatchData', + 'Math', 'Matrix', 'Method', 'Module', 'Mutex', 'NameError', + 'NameError::message', 'NilClass', 'NoMemoryError', + 'NoMethodError', 'NotImplementedError', 'Numeric', 'Object', + 'ObjectSpace', 'Observable', 'PStore', 'PStore::Error', + 'Pathname', 'Precision', 'Proc', 'Process', 'Process::GID', + 'Process::Status', 'Process::Sys', 'Process::UID', 'Queue', + 'Range', 'RangeError', 'Rational', 'Regexp', 'RegexpError', + 'RuntimeError', 'ScriptError', 'SecurityError', 'Set', + 'Shellwords', 'Signal', 'SignalException', 'SimpleDelegator', + 'SingleForwardable', 'Singleton', 'SingletonClassMethods', + 'SizedQueue', 'SortedSet', 'StandardError', 'StringIO', + 'StringScanner', 'StringScanner::Error', 'Struct', 'Symbol', + 'SyncEnumerator', 'SyntaxError', 'SystemCallError', + 'SystemExit', 'SystemStackError', 'Tempfile', + 'Test::Unit::TestCase', 'Test::Unit', 'Test', 'Thread', + 'ThreadError', 'ThreadGroup', + 'ThreadsWait', 'Time', 'TrueClass', 'TypeError', 'URI', + 'URI::BadURIError', 'URI::Error', 'URI::Escape', 'URI::FTP', + 'URI::Generic', 'URI::HTTP', 'URI::HTTPS', + 'URI::InvalidComponentError', 'URI::InvalidURIError', + 'URI::LDAP', 'URI::MailTo', 'URI::REGEXP', + 'URI::REGEXP::PATTERN', 'UnboundMethod', 'Vector', 'YAML', + 'ZeroDivisionError', 'Zlib', + 'Zlib::BufError', 'Zlib::DataError', 'Zlib::Deflate', + 'Zlib::Error', 'Zlib::GzipFile', 'Zlib::GzipFile::CRCError', + 'Zlib::GzipFile::Error', 'Zlib::GzipFile::LengthError', + 'Zlib::GzipFile::NoFooter', 'Zlib::GzipReader', + 'Zlib::GzipWriter', 'Zlib::Inflate', 'Zlib::MemError', + 'Zlib::NeedDict', 'Zlib::StreamEnd', 'Zlib::StreamError', + 'Zlib::VersionError', + 'Zlib::ZStream', + 'HTML::Selector', 'HashWithIndifferentAccess', 'Inflector', + 'Inflector::Inflections', 'Mime', 'Mime::Type', + 'OCI8AutoRecover', 'TimeZone', 'XmlSimple' + ), + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '%', '&', '*', '|', '/', '<', '>', + '+', '-', '=>', '<<' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color:#9966CC; font-weight:bold;', + 2 => 'color:#0000FF; font-weight:bold;', + 3 => 'color:#CC0066; font-weight:bold;', + 4 => 'color:#CC00FF; font-weight:bold;', + ), + 'COMMENTS' => array( + 1 => 'color:#008000; font-style:italic;', + 'MULTI' => 'color:#000080; font-style:italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color:#000099;' + ), + 'BRACKETS' => array( + 0 => 'color:#006600; font-weight:bold;' + ), + 'STRINGS' => array( + 0 => 'color:#996600;' + ), + 'NUMBERS' => array( + 0 => 'color:#006666;' + ), + 'METHODS' => array( + 1 => 'color:#9900CC;' + ), + 'SYMBOLS' => array( + 0 => 'color:#006600; font-weight:bold;' + ), + 'REGEXPS' => array( + 0 => 'color:#ff6633; font-weight:bold;', + 1 => 'color:#0066ff; font-weight:bold;', + 2 => 'color:#6666ff; font-weight:bold;', + 3 => 'color:#ff3333; font-weight:bold;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + 0 => array(//Variables + GESHI_SEARCH => "([[:space:]])(\\$[a-zA-Z_][a-zA-Z0-9_]*)", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 1 => array(//Arrays + GESHI_SEARCH => "([[:space:]])(@[a-zA-Z_][a-zA-Z0-9_]*)", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 2 => "([A-Z][a-zA-Z0-9_]*::)+[A-Z][a-zA-Z0-9_]*",//Static OOP symbols + 3 => array( + GESHI_SEARCH => "([[:space:]]|\[|\()(:[a-zA-Z_][a-zA-Z0-9_]*)", + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + '<%' => '%>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + ), + 'TAB_WIDTH' => 2 +); + +?> diff --git a/examples/includes/geshi/geshi/sas.php b/examples/includes/geshi/geshi/sas.php new file mode 100644 index 0000000..d4ee828 --- /dev/null +++ b/examples/includes/geshi/geshi/sas.php @@ -0,0 +1,290 @@ + 'SAS', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + '_ALL_','_CHARACTER_','_INFILE_','_N_','_NULL_','_NUMERIC_', + '_WEBOUT_' + ), + 2 => array( + '%BQUOTE','%CMPRES','%COMPSTOR','%DATATYP','%DISPLAY','%DO','%ELSE', + '%END','%EVAL','%GLOBAL','%GOTO','%IF','%INDEX','%INPUT','%KEYDEF', + '%LABEL','%LEFT','%LENGTH','%LET','%LOCAL','%LOWCASE','%MACRO', + '%MEND','%NRBQUOTE','%NRQUOTE','%NRSTR','%PUT','%QCMPRES','%QLEFT', + '%QLOWCASE','%QSCAN','%QSUBSTR','%QSYSFUNC','%QTRIM','%QUOTE', + '%QUPCASE','%SCAN','%STR','%SUBSTR','%SUPERQ','%SYSCALL', + '%SYSEVALF','%SYSEXEC','%SYSFUNC','%SYSGET','%SYSLPUT','%SYSPROD', + '%SYSRC','%SYSRPUT','%THEN','%TO','%TRIM','%UNQUOTE','%UNTIL', + '%UPCASE','%VERIFY','%WHILE','%WINDOW' + ), + 3 => array( + 'ABS','ADDR','AIRY','ARCOS','ARSIN','ATAN','ATTRC','ATTRN','BAND', + 'BETAINV','BLSHIFT','BNOT','BOR','BRSHIFT','BXOR','BYTE','CDF', + 'CEIL','CEXIST','CINV','CLOSE','CNONCT','COLLATE','COMPBL', + 'COMPOUND','COMPRESS','COSH','COS','CSS','CUROBS','CV','DACCDBSL', + 'DACCDB','DACCSL','DACCSYD','DACCTAB','DAIRY','DATETIME','DATEJUL', + 'DATEPART','DATE','DAY','DCLOSE','DEPDBSL','DEPDB','DEPSL','DEPSYD', + 'DEPTAB','DEQUOTE','DHMS','DIF','DIGAMMA','DIM','DINFO','DNUM', + 'DOPEN','DOPTNAME','DOPTNUM','DREAD','DROPNOTE','DSNAME','ERFC', + 'ERF','EXIST','EXP','FAPPEND','FCLOSE','FCOL','FDELETE','FETCHOBS', + 'FETCH','FEXIST','FGET','FILEEXIST','FILENAME','FILEREF','FINFO', + 'FINV','FIPNAMEL','FIPNAME','FIPSTATE','FLOOR','FNONCT','FNOTE', + 'FOPEN','FOPTNAME','FOPTNUM','FPOINT','FPOS','FPUT','FREAD', + 'FREWIND','FRLEN','FSEP','FUZZ','FWRITE','GAMINV','GAMMA', + 'GETOPTION','GETVARC','GETVARN','HBOUND','HMS','HOSTHELP','HOUR', + 'IBESSEL','INDEXW','INDEXC','INDEX','INPUTN','INPUTC','INPUT', + 'INTRR','INTCK','INTNX','INT','IRR','JBESSEL','JULDATE','KURTOSIS', + 'LAG','LBOUND','LEFT','LENGTH','LGAMMA','LIBNAME','LIBREF','LOG10', + 'LOG2','LOGPDF','LOGPMF','LOGSDF','LOG','LOWCASE','MAX','MDY', + 'MEAN','MINUTE','MIN','MOD','MONTH','MOPEN','MORT','NETPV','NMISS', + 'NORMAL','NPV','N','OPEN','ORDINAL','PATHNAME','PDF','PEEKC','PEEK', + 'PMF','POINT','POISSON','POKE','PROBBETA','PROBBNML','PROBCHI', + 'PROBF','PROBGAM','PROBHYPR','PROBIT','PROBNEGB','PROBNORM','PROBT', + 'PUTN','PUTC','PUT','QTR','QUOTE','RANBIN','RANCAU','RANEXP', + 'RANGAM','RANGE','RANK','RANNOR','RANPOI','RANTBL','RANTRI', + 'RANUNI','REPEAT','RESOLVE','REVERSE','REWIND','RIGHT','ROUND', + 'SAVING','SCAN','SDF','SECOND','SIGN','SINH','SIN','SKEWNESS', + 'SOUNDEX','SPEDIS','SQRT','STDERR','STD','STFIPS','STNAME', + 'STNAMEL','SUBSTR','SUM','SYMGET','SYSGET','SYSMSG','SYSPROD', + 'SYSRC','SYSTEM','TANH','TAN','TIMEPART','TIME','TINV','TNONCT', + 'TODAY','TRANSLATE','TRANWRD','TRIGAMMA','TRIMN','TRIM','TRUNC', + 'UNIFORM','UPCASE','USS','VARFMT','VARINFMT','VARLABEL','VARLEN', + 'VARNAME','VARNUM','VARRAYX','VARRAY','VARTYPE','VAR','VERIFY', + 'VFORMATX','VFORMATDX','VFORMATD','VFORMATNX','VFORMATN', + 'VFORMATWX','VFORMATW','VFORMAT','VINARRAYX','VINARRAY', + 'VINFORMATX','VINFORMATDX','VINFORMATD','VINFORMATNX','VINFORMATN', + 'VINFORMATWX','VINFORMATW','VINFORMAT','VLABELX','VLABEL', + 'VLENGTHX','VLENGTH','VNAMEX','VNAME','VTYPEX','VTYPE','WEEKDAY', + 'YEAR','YYQ','ZIPFIPS','ZIPNAME','ZIPNAMEL','ZIPSTATE' + ), + 4 => array( + 'ABORT','ADD','ALTER','AND','ARRAY','AS','ATTRIB','BY','CALL', + 'CARDS4','CASCADE','CATNAME','CHECK','CONTINUE','CREATE', + 'DATALINES4','DELETE','DESCRIBE','DISPLAY','DISTINCT','DM','DROP', + 'ENDSAS','FILE','FOOTNOTE','FOREIGN','FORMAT','FROM', + 'GOTO','GROUP','HAVING','IN','INFILE','INFORMAT', + 'INSERT','INTO','KEEP','KEY','LABEL','LEAVE', + 'LIKE','LINK','LIST','LOSTCARD','MERGE','MESSAGE','MISSING', + 'MODIFY','MSGTYPE','NOT','NULL','ON','OPTIONS','OR','ORDER', + 'OUTPUT','PAGE','PRIMARY','REDIRECT','REFERENCES','REMOVE', + 'RENAME','REPLACE','RESET','RESTRICT','RETAIN','RETURN','SELECT', + 'SET','SKIP','STARTSAS','STOP','SYSTASK','TABLE','TITLE','UNIQUE', + 'UPDATE','VALIDATE','VIEW','WAITSAS','WHERE','WINDOW','X' + ), + 5 => array( + 'DO','ELSE','END','IF','THEN','UNTIL','WHILE' + ), + 6 => array( + 'RUN','QUIT','DATA' + ), + 7 => array( + 'ERROR' + ), + 8 => array( + 'WARNING' + ), + 9 => array( + 'NOTE' + ) + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false, + 8 => false, + 9 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff;', + 2 => 'color: #0000ff;', + 3 => 'color: #0000ff;', + 4 => 'color: #0000ff;', + 5 => 'color: #0000ff;', + 6 => 'color: #000080; font-weight: bold;', + 7 => 'color: #ff0000;', + 8 => 'color: #00ff00;', + 9 => 'color: #0000ff;' + ), + 'COMMENTS' => array( +// 1 => 'color: #006400; font-style: italic;', + 'MULTI' => 'color: #006400; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #a020f0;' + ), + 'NUMBERS' => array( + 0 => 'color: #2e8b57; font-weight: bold;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff; font-weight: bold;', + 1 => 'color: #000080; font-weight: bold;', + 2 => 'color: #006400; font-style: italic;', + 3 => 'color: #006400; font-style: italic;', + 4 => 'color: #006400; font-style: italic;', + 5 => 'color: #ff0000; font-weight: bold;', + 6 => 'color: #00ff00; font-style: italic;', + 7 => 'color: #0000ff; font-style: normal;', + 8 => 'color: #b218b2; font-weight: bold;', + 9 => 'color: #b218b2; font-weight: bold;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '', + 6 => '', + 7 => '', + 8 => '', + 9 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 0 => "&[a-zA-Z_][a-zA-Z0-9_]*", + 1 => array(//Procedures + GESHI_SEARCH => '(^\\s*)(PROC \\w+)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 2 => array( + GESHI_SEARCH => '(^\\s*)(\\*.*;)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 3 => array( + GESHI_SEARCH => '(.*;\\s*)(\\*.*;)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 4 => array( + GESHI_SEARCH => '(^\\s*)(%\\*.*;)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 5 => array(//Error messages + GESHI_SEARCH => '(^ERROR.*)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 6 => array(//Warning messages + GESHI_SEARCH => '(^WARNING.*)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 7 => array(//Notice messages + GESHI_SEARCH => '(^NOTE.*)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'im', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 8 => array( + GESHI_SEARCH => '(^\\s*)(CARDS.*)(^\\s*;\\s*$)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'sim', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + 9 => array( + GESHI_SEARCH => '(^\\s*)(DATALINES.*)(^\\s*;\\s*$)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'sim', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/scala.php b/examples/includes/geshi/geshi/scala.php new file mode 100644 index 0000000..c72de33 --- /dev/null +++ b/examples/includes/geshi/geshi/scala.php @@ -0,0 +1,122 @@ + 'Scala', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'abstract', 'case', 'catch', 'class', 'def', + 'do', 'else', 'extends', 'false', 'final', + 'finally', 'for', 'forSome', 'if', 'implicit', + 'import', 'match', 'new', 'null', 'object', + 'override', 'package', 'private', 'protected', 'requires', + 'return', 'sealed', 'super', 'this', 'throw', + 'trait', 'try', 'true', 'type', 'val', + 'var', 'while', 'with', 'yield' + ), + 2 => array( + 'void', 'double', 'int', 'boolean', 'byte', 'short', 'long', 'char', 'float' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '*', '&', '%', '!', ';', '<', '>', '?', + '_', ':', '=', '=>', '<<:', + '<%', '>:', '#', '@' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff; font-weight: bold;', + 2 => 'color: #9999cc; font-weight: bold;', + ), + 'COMMENTS' => array( + 1=> 'color: #008000; font-style: italic;', + 'MULTI' => 'color: #00ff00; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #0000ff; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #F78811;' + ), + 'STRINGS' => array( + 0 => 'color: #6666FF;' + ), + 'NUMBERS' => array( + 0 => 'color: #F78811;' + ), + 'METHODS' => array( + 1 => 'color: #000000;', + 2 => 'color: #000000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000080;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => 'http://scala-lang.org', + 2 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/scheme.php b/examples/includes/geshi/geshi/scheme.php new file mode 100644 index 0000000..1c85f80 --- /dev/null +++ b/examples/includes/geshi/geshi/scheme.php @@ -0,0 +1,170 @@ + 'Scheme', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array('#|' => '|#'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'abs', 'acos', 'and', 'angle', 'append', 'appply', 'approximate', + 'asin', 'assoc', 'assq', 'assv', 'atan', + + 'begin', 'boolean?', 'bound-identifier=?', + + 'caar', 'caddr', 'cadr', 'call-with-current-continuation', + 'call-with-input-file', 'call-with-output-file', 'call/cc', 'car', + 'case', 'catch', 'cdddar', 'cddddr', 'cdr', 'ceiling', 'char->integer', + 'char-alphabetic?', 'char-ci<=?', 'char-ci=?', + 'char-ci>?', 'char-ci=?', 'char-downcase', 'char-lower-case?', + 'char-numeric', 'char-ready', 'char-ready?', 'char-upcase', + 'char-upper-case?', 'char-whitespace?', 'char<=?', 'char=?', 'char>?', 'char?', 'close-input-port', 'close-output-port', + 'complex?', 'cond', 'cons', 'construct-identifier', 'cos', + 'current-input-port', 'current-output-port', + + 'd', 'define', 'define-syntax', 'delay', 'denominator', 'display', 'do', + + 'e', 'eof-object?', 'eq?', 'equal?', 'eqv?', 'even?', 'exact->inexact', + 'exact?', 'exp', 'expt', 'else', + + 'f', 'floor', 'for-each', 'force', 'free-identifer=?', + + 'gcd', 'gen-counter', 'gen-loser', 'generate-identifier', + + 'identifier->symbol', 'identifier', 'if', 'imag-part', 'inexact->exact', + 'inexact?', 'input-port?', 'integer->char', 'integer?', 'integrate-system', + + 'l', 'lambda', 'last-pair', 'lcm', 'length', 'let', 'let*', 'letrec', + 'list', 'list->string', 'list->vector', 'list-ref', 'list-tail', 'list?', + 'load', 'log', + + 'magnitude', 'make-polar', 'make-promise', 'make-rectangular', + 'make-string', 'make-vector', 'map', 'map-streams', 'max', 'member', + 'memq', 'memv', 'min', 'modulo', + + 'negative', 'newline', 'nil', 'not', 'null?', 'number->string', 'number?', + 'numerator', + + 'odd?', 'open-input-file', 'open-output-file', 'or', 'output-port', + + 'pair?', 'peek-char', 'positive?', 'procedure?', + + 'quasiquote', 'quote', 'quotient', + + 'rational', 'rationalize', 'read', 'read-char', 'real-part', 'real?', + 'remainder', 'return', 'reverse', + + 's', 'sequence', 'set!', 'set-char!', 'set-cdr!', 'sin', 'sqrt', 'string', + 'string->list', 'string->number', 'string->symbol', 'string-append', + 'string-ci<=?', 'string-ci=?', + 'string-ci>?', 'string-copy', 'string-fill!', 'string-length', + 'string-ref', 'string-set!', 'string<=?', 'string=?', 'string>?', 'string?', 'substring', 'symbol->string', + 'symbol?', 'syntax', 'syntax-rules', + + 't', 'tan', 'template', 'transcript-off', 'transcript-on', 'truncate', + + 'unquote', 'unquote-splicing', 'unwrap-syntax', + + 'vector', 'vector->list', 'vector-fill!', 'vector-length', 'vector-ref', + 'vector-set!', 'vector?', + + 'with-input-from-file', 'with-output-to-file', 'write', 'write-char', + + 'zero?' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '!', '%', '^', '&', '/','+','-','*','=','<','>',';','|' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/scilab.php b/examples/includes/geshi/geshi/scilab.php new file mode 100644 index 0000000..bfe72ad --- /dev/null +++ b/examples/includes/geshi/geshi/scilab.php @@ -0,0 +1,295 @@ + 'SciLab', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + 2 => "/\w+'/" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'HARDQUOTE' => array("'", "'"), + 'HARDESCAPE' => array(), + 'KEYWORDS' => array( + 1 => array( + 'if', 'else', 'elseif', 'end', 'select', 'case', 'for', 'while', 'break' + ), + 2 => array( + 'STDIN', 'STDOUT', 'STDERR', + '%i', '%pi', '%e', '%eps', '%nan', '%inf', '%s', '%t', '%f', + 'usual', 'polynomial', 'boolean', 'character', 'function', 'rational', 'state-space', + 'sparse', 'boolean sparse', 'list', 'tlist', 'library', 'endfunction' + ), + 3 => array( + '%asn', '%helps', '%k', '%sn', 'abcd', 'abinv', 'abort', 'about', 'About_M2SCI_tools', + 'abs', 'acos', 'acosh', 'acoshm', 'acosm', 'AdCommunications', 'add_demo', 'add_edge', + 'add_help_chapter', 'add_node', 'add_palette', 'addcolor', 'addf', 'addinter', 'addmenu', + 'adj_lists', 'adj2sp', 'aff2ab', 'alufunctions', 'amell', 'analpf', 'analyze', 'and', + 'ans', 'apropos', 'arc_graph', 'arc_number', 'arc_properties', 'argn', 'arhnk', 'arl2', + 'arma', 'arma2p', 'armac', 'armax', 'armax1', 'arsimul', 'artest', 'articul', 'ascii', + 'asciimat', 'asin', 'asinh', 'asinhm', 'asinm', 'assignation', 'atan', 'atanh', 'atanhm', + 'atanm', 'augment', 'auread', 'auwrite', 'axes_properties', 'axis_properties', 'backslash', + 'balanc', 'balreal', 'bandwr', 'banner','bar', 'barh', 'barhomogenize', 'basename', 'bdiag', + 'beep', 'besselh', 'besseli', 'besselj', 'besselk', 'bessely', 'best_match', 'beta','bezout', + 'bifish', 'bilin', 'binomial', 'black', 'bloc2exp', 'bloc2ss', 'bode', 'bool2s', + 'boucle', 'brackets', 'browsevar', 'bsplin3val', 'bstap', 'buttmag', 'buttondialog', + 'bvode', 'bvodeS', 'c_link', 'cainv', 'calendar', 'calerf', 'calfrq', 'call', 'canon', 'casc', + 'cat', 'catch', 'ccontrg', 'cd', 'cdfbet', 'cdfbin', 'cdfchi', 'cdfchn', 'cdff', 'cdffnc', + 'cdfgam', 'cdfnbn', 'cdfnor', 'cdfpoi', 'cdft', 'ceil', 'cell', 'cell2mat', 'cellstr', 'center', + 'cepstrum', 'chain_struct', 'chaintest', 'champ', 'champ_properties', 'champ1', 'char', 'chart', + 'chartooem', 'chdir', 'cheb1mag', 'cheb2mag', 'check_graph', 'chepol', 'chfact', 'chol', 'chsolve', + 'circuit', 'classmarkov', 'clc', 'clean', 'clear', 'clear_pixmap', 'clearfun', 'clearglobal','clf', + 'clipboard', 'close', 'cls2dls', 'cmb_lin', 'cmndred', 'cmoment', 'code2str', 'coeff', 'coff', 'coffg', + 'colcomp', 'colcompr', 'colinout', 'colon', 'color', 'color_list', 'colorbar', 'colordef', 'colormap', + 'colregul', 'comma', 'comments', 'comp', 'companion', 'comparison', 'Compound_properties', 'con_nodes', + 'cond', 'config', 'configure_msvc', 'conj', 'connex', 'console', 'cont_frm', 'cont_mat', 'Contents', + 'continue', 'contour', 'contour2d', 'contour2di', 'contourf', 'contr', 'contract_edge', 'contrss', + 'convex_hull', 'convol', 'convstr', 'copfac', 'copy', 'corr', 'correl', 'cos', 'cosh', 'coshm', + 'cosm', 'cotg', 'coth', 'cothm', 'covar', 'create_palette', 'cshep2d', 'csim', 'cspect', 'Cste', + 'ctr_gram', 'cumprod', 'cumsum', 'cycle_basis', 'czt', 'dasrt', 'dassl', 'datafit', 'date', 'datenum', + 'datevec', 'dbphi', 'dcf', 'ddp', 'debug', 'dec2hex', 'deff', 'definedfields', 'degree', 'delbpt', + 'delete', 'delete_arcs', 'delete_nodes', 'delip', 'delmenu', 'demoplay', 'denom', 'derivat', 'derivative', + 'des2ss', 'des2tf', 'det', 'determ', 'detr', 'detrend', 'dft', 'dhinf', 'dhnorm', 'diag', 'diary', + 'diff', 'diophant', 'dir', 'dirname', 'disp', 'dispbpt', 'dispfiles', 'dlgamma', 'dnaupd', 'do', 'dot', + 'double', 'dragrect', 'draw', 'drawaxis', 'drawlater', 'drawnow', 'driver', 'dsaupd', 'dscr', + 'dsearch', 'dsimul', 'dt_ility', 'dtsi', 'edge_number', 'edit', 'edit_curv', 'edit_error', + 'edit_graph', 'edit_graph_menus', 'editvar', 'eigenmarkov', 'ell1mag', + 'empty', 'emptystr', 'eqfir', 'eqiir', 'equal', 'Equal', 'equil', 'equil1', + 'ereduc', 'erf', 'erfc', 'erfcx', 'errbar', 'errcatch', 'errclear', 'error', 'error_table', 'etime', + 'eval', 'eval_cshep2d', 'eval3d', 'eval3dp', 'evans', 'evstr', 'excel2sci', 'exec', 'execstr', 'exists', + 'exit', 'exp', 'expm', 'external', 'extraction', 'eye', 'fac3d', 'factorial', 'factors', 'faurre', 'fchamp', + 'fcontour', 'fcontour2d', 'fec', 'fec_properties', 'feedback', 'feval', 'ffilt', 'fft', 'fft2', 'fftshift', + 'fgrayplot', 'figure', 'figure_properties', 'figure_style', 'file', 'fileinfo', 'fileparts', 'filter', 'find', + 'find_freq', 'find_path', 'findABCD', 'findAC', 'findBD', 'findBDK', 'findm', 'findmsvccompiler', 'findobj', + 'findR', 'findx0BD', 'firstnonsingleton', 'fit_dat', 'fix', 'floor', 'flts', 'foo', 'format', + 'formatman', 'fort', 'fourplan', 'fplot2d', 'fplot3d', 'fplot3d1', 'fprintf', 'fprintfMat', 'frep2tf', + 'freq', 'freson', 'frexp', 'frfit', 'frmag', 'fscanf', 'fscanfMat', 'fsfirlin', 'fsolve', 'fspecg', + 'fstabst', 'fstair', 'ftest', 'ftuneq', 'full', 'fullfile', 'fullrf', 'fullrfk', 'fun2string', 'Funcall', + 'funcprot', 'functions', 'funptr', 'fusee', 'G_make', 'g_margin', 'gainplot', 'gamitg', + 'gamma', 'gammaln', 'gca', 'gcare', 'gcd', 'gce', 'gcf', 'gda', 'gdf', 'gen_net', 'genfac3d', 'genlib', + 'genmarkov', 'geom3d', 'geomean', 'get', 'get_contents_infer', 'get_function_path', 'getcolor', 'getcwd', + 'getd', 'getdate', 'getenv', 'getf', 'getfield', 'getfont', 'gethistory', 'getio', 'getlinestyle', + 'getlongpathname', 'getmark', 'getmemory', 'getos', 'getpid', 'getscilabkeywords', 'getshell', + 'getshortpathname', 'getsymbol', 'getvalue', 'getversion', 'gfare', 'gfrancis', 'girth', 'givens', + 'glever', 'glist', 'global', 'GlobalProperty', 'glue', 'gmres', 'gpeche', 'gr_menu', 'graduate', 'grand', + 'graph_2_mat', 'graph_center', 'graph_complement', 'graph_diameter', 'graph_power', 'graph_simp', 'graph_sum', + 'graph_union', 'graphic', 'Graphics', 'graphics_entities', 'graph-list', 'graycolormap', 'grayplot', + 'grayplot_properties', 'graypolarplot', 'great', 'grep', 'group', 'gschur', 'gsort', 'gspec', 'gstacksize', + 'gtild', 'h_cl', 'h_inf', 'h_inf_st', 'h_norm', 'h2norm', 'halt', 'hamilton', 'hank', 'hankelsv', 'harmean', + 'hat', 'havewindow', 'head_comments', 'help', 'help_skeleton', 'hermit', 'hess', 'hex2dec', 'hilb', 'hinf', + 'hist3d', 'histplot', 'horner', 'host', 'hotcolormap', 'householder', 'hrmt', 'hsv2rgb', 'hsvcolormap', + 'htrianr', 'hypermat', 'hypermatrices', 'iconvert', 'ieee', 'ifft', 'iir', 'iirgroup', 'iirlp', + 'ilib_build', 'ilib_compile', 'ilib_for_link', 'ilib_gen_gateway', 'ilib_gen_loader', 'ilib_gen_Make', + 'im_inv', 'imag', 'impl', 'imrep2ss', 'imult', 'ind2sub', 'Infer', 'inistate', 'input', 'insertion', 'int', + 'int16', 'int2d', 'int32', 'int3d', 'int8', 'intc', 'intdec', 'integrate', 'interp', 'interp1', 'interp2d', + 'interp3d', 'interpln', 'intersci', 'intersect', 'intg', 'intl', 'intppty', 'intsplin', 'inttrap', 'inttype', + 'inv', 'inv_coeff', 'invr', 'invsyslin', 'iqr', 'is_connex', 'iscellstr', 'isdef', 'isdir', 'isempty', + 'isequal', 'isequalbitwise', 'iserror', 'isglobal', 'isinf', 'isnan', 'isoview', 'isreal', 'javasci', + 'jetcolormap', 'jmat', 'justify', 'kalm', 'karmarkar', 'kernel', 'keyboard', 'knapsack', 'kpure', 'krac2', + 'kron', 'kroneck', 'label_properties', 'labostat', 'LANGUAGE', 'lasterror', 'lattn', 'lattp', 'lcf', 'lcm', + 'lcmdiag', 'ldiv', 'ldivf', 'leastsq', 'left', 'legend', 'legend_properties', 'legendre', 'legends', 'length', + 'leqr', 'less', 'lev', 'levin', 'lex_sort', 'lft', 'lgfft', 'lib', 'lin', 'lin2mu', 'lindquist', + 'line_graph', 'linear_interpn', 'lines', 'LineSpec', 'linf', 'linfn', 'link', 'linmeq', 'linpro', 'linsolve', + 'linspace', 'listfiles', 'listvarinfile', 'lmisolver', 'lmitool', 'load', 'load_graph', 'loadhistory', + 'loadmatfile', 'loadplots', 'loadwave', 'locate', 'log', 'log10', 'log1p', 'log2', 'logm', 'logspace', + 'lotest', 'lqe', 'lqg', 'lqg_ltr', 'lqg2stan', 'lqr', 'ls', 'lsq', 'lsq_splin', 'lsqrsolve', 'lsslist', + 'lstcat', 'lstsize', 'ltitr', 'lu', 'ludel', 'lufact', 'luget', 'lusolve', 'lyap', 'm_circle', 'm2scideclare', + 'macglov', 'macr2lst', 'macr2tree', 'macro', 'macrovar', 'mad', 'make_graph', 'make_index', 'makecell', 'man', + 'manedit', 'mapsound', 'markp2ss', 'mat_2_graph', 'matfile2sci', 'Matlab-Scilab_character_strings', 'Matplot', + 'Matplot_properties', 'Matplot1', 'matrices', 'matrix', 'max', 'max_cap_path', 'max_clique', 'max_flow', + 'maxi', 'mcisendstring', 'mclearerr', 'mclose', 'mdelete', 'mean', 'meanf', 'median', 'menus', 'meof', + 'merror', 'mese', 'mesh', 'mesh2d', 'meshgrid', 'mfft', 'mfile2sci', 'mfprintf', 'mfscanf', 'mget', 'mgeti', + 'mgetl', 'mgetstr', 'milk_drop', 'min', 'min_lcost_cflow', 'min_lcost_flow1', 'min_lcost_flow2', + 'min_qcost_flow', 'min_weight_tree', 'mine', 'mini', 'minreal', 'minss', 'minus', 'mkdir', 'mlist', 'mode', + 'modulo', 'moment', 'mopen', 'move', 'mprintf', 'mps2linpro', 'mput', 'mputl', 'mputstr', 'mrfit', 'mscanf', + 'msd', 'mseek', 'msprintf', 'msscanf', 'mstr2sci', 'mtell', 'mtlb_0', 'mtlb_a', 'mtlb_all', 'mtlb_any', + 'mtlb_axis', 'mtlb_beta', 'mtlb_box', 'mtlb_close', 'mtlb_colordef', 'mtlb_conv', 'mtlb_cumprod', 'mtlb_cumsum', + 'mtlb_dec2hex', 'mtlb_delete', 'mtlb_diag', 'mtlb_diff', 'mtlb_dir', 'mtlb_double', 'mtlb_e', 'mtlb_echo', + 'mtlb_eig', 'mtlb_eval', 'mtlb_exist', 'mtlb_eye', 'mtlb_false', 'mtlb_fft', 'mtlb_fftshift', 'mtlb_find', + 'mtlb_findstr', 'mtlb_fliplr', 'mtlb_fopen', 'mtlb_format', 'mtlb_fprintf', 'mtlb_fread', 'mtlb_fscanf', + 'mtlb_full', 'mtlb_fwrite', 'mtlb_grid', 'mtlb_hold', 'mtlb_i', 'mtlb_ifft', 'mtlb_imp', 'mtlb_int16', + 'mtlb_int32', 'mtlb_int8', 'mtlb_is', 'mtlb_isa', 'mtlb_isfield', 'mtlb_isletter', 'mtlb_isspace', 'mtlb_l', + 'mtlb_legendre', 'mtlb_linspace', 'mtlb_load', 'mtlb_logic', 'mtlb_logical', 'mtlb_lower', 'mtlb_max', + 'mtlb_min', 'mtlb_mode', 'mtlb_more', 'mtlb_num2str', 'mtlb_ones', 'mtlb_plot', 'mtlb_prod', 'mtlb_rand', + 'mtlb_randn', 'mtlb_rcond', 'mtlb_realmax', 'mtlb_realmin', 'mtlb_repmat', 'mtlb_s', 'mtlb_save', + 'mtlb_setstr', 'mtlb_size', 'mtlb_sort', 'mtlb_sparse', 'mtlb_strcmp', 'mtlb_strcmpi', 'mtlb_strfind', + 'mtlb_strrep', 'mtlb_sum', 'mtlb_t', 'mtlb_toeplitz', 'mtlb_tril', 'mtlb_triu', 'mtlb_true', 'mtlb_uint16', + 'mtlb_uint32', 'mtlb_uint8', 'mtlb_upper', 'mtlb_zeros', 'mu2lin', 'mucomp', 'mulf', 'mvvacov', 'name2rgb', + 'names', 'nancumsum', 'nand2mean', 'nanmax', 'nanmean', 'nanmeanf', 'nanmedian', 'nanmin', 'nanstdev', + 'nansum', 'narsimul', 'NDcost', 'ndgrid', 'ndims', 'nearfloat', 'nehari', 'neighbors', 'netclose', 'netwindow', + 'netwindows', 'new', 'newaxes', 'newest', 'newfun', 'nextpow2', 'nf3d', 'nfreq', 'nlev', 'nnz', 'node_number', + 'nodes_2_path', 'nodes_degrees', 'noisegen', 'norm', 'not', 'null', 'number_properties', 'numdiff', 'numer', + 'nyquist', 'object_editor', 'obs_gram', 'obscont', 'obscont1', 'observer', 'obsv_mat', 'obsvss', 'ode', + 'ode_discrete', 'ode_optional_output', 'ode_root', 'odedc', 'odeoptions', 'oemtochar', 'old_style', + 'oldbesseli', 'oldbesselj', 'oldbesselk', 'oldbessely', 'oldload', 'oldplot', 'oldsave', 'ones', + 'Operation', 'optim', 'or', 'orth', 'overloading', 'p_margin', 'param3d', 'param3d_properties', + 'param3d1', 'paramfplot2d', 'parents', 'parrot', 'part', 'path_2_nodes', 'pathconvert', 'pause', 'pbig', + 'pca', 'pcg', 'pdiv', 'pen2ea', 'pencan', 'penlaur', 'percent', 'perctl', 'perfect_match', 'perl', + 'perms', 'permute', 'pertrans', 'pfss', 'phasemag', 'phc', 'pie', 'pinv', 'pipe_network', 'playsnd', 'plot', + 'plot_graph', 'plot2d', 'plot2d_old_version', 'plot2d1', 'plot2d2', 'plot2d3', 'plot2d4', 'plot3d', + 'plot3d_old_version', 'plot3d1', 'plot3d2', 'plot3d3', 'plotframe', 'plotprofile', 'plus', 'plzr', + 'pmodulo', 'pol2des', 'pol2str', 'pol2tex', 'polar', 'polarplot', 'polfact', 'poly', 'polyline_properties', + 'portr3d', 'portrait', 'power', 'ppol', 'prbs_a', 'predecessors', 'predef', 'print', 'printf', + 'printf_conversion', 'printing', 'printsetupbox', 'prod', 'profile', 'progressionbar', 'proj', 'projsl', + 'projspec', 'psmall', 'pspect', 'pvm', 'pvm_addhosts', 'pvm_barrier', 'pvm_bcast', 'pvm_bufinfo', 'pvm_config', + 'pvm_delhosts', 'pvm_error', 'pvm_exit', 'pvm_f772sci', 'pvm_get_timer', 'pvm_getinst', 'pvm_gettid', + 'pvm_gsize', 'pvm_halt', 'pvm_joingroup', 'pvm_kill', 'pvm_lvgroup', 'pvm_mytid', 'pvm_parent', 'pvm_probe', + 'pvm_recv', 'pvm_reduce', 'pvm_sci2f77', 'pvm_send', 'pvm_set_timer', 'pvm_spawn', 'pvm_spawn_independent', + 'pvm_start', 'pvm_tasks', 'pvm_tidtohost', 'pvmd3', 'pwd', 'qassign', 'qld', 'qmr', 'qr', 'quapro', 'quart', + 'quaskro', 'quit', 'quote', 'rand', 'randpencil', 'range', 'rank', 'rankqr', 'rat', 'rcond', + 'rdivf', 'read', 'read4b', 'readb', 'readc_', 'readmps', 'readxls', 'real', 'realtime', 'realtimeinit', + 'rectangle_properties', 'recur', 'reglin', 'regress', 'remez', 'remezb', 'repfreq', 'replot', 'resethistory', + 'residu', 'resume', 'return', 'rgb2name', 'ric_desc', 'ricc', 'riccati', 'rlist', 'rmdir', 'roots', 'rotate', + 'round', 'routh_t', 'rowcomp', 'rowcompr', 'rowinout', 'rowregul', 'rowshuff', 'rpem', 'rref', 'rtitr', + 'rubberbox', 'salesman', 'sample', 'samplef', 'samwr', 'save', 'save_format', 'save_graph', 'savehistory', + 'savematfile', 'savewave', 'sca', 'scaling', 'scanf', 'scanf_conversion', 'scf', 'schur', 'sci_files', + 'sci2exp', 'sci2for', 'sci2map', 'sciargs', 'SciComplex', 'SciComplexArray', 'SciDouble', 'SciDoubleArray', + 'scilab', 'Scilab', 'ScilabEval', 'scilink', 'scipad', 'SciString', 'SciStringArray', 'sd2sci', 'sda', 'sdf', + 'secto3d', 'segs_properties', 'semi', 'semicolon', 'semidef', 'sensi', 'set', 'set_posfig_dim', + 'setbpt', 'setdiff', 'setenv', 'seteventhandler', 'setfield', 'sethomedirectory', 'setlanguage', 'setmenu', + 'sfact', 'Sfgrayplot', 'Sgrayplot', 'sgrid', 'shortest_path', 'show_arcs', 'show_graph', 'show_nodes', + 'show_pixmap', 'showprofile', 'sident', 'sign', 'Signal', 'signm', 'simp', 'simp_mode', 'sin', 'sinc', + 'sincd', 'sinh', 'sinhm', 'sinm', 'size', 'slash', 'sleep', 'sm2des', 'sm2ss', 'smooth', 'solve', + 'sorder', 'sort', 'sound', 'soundsec', 'sp2adj', 'spaninter', 'spanplus', 'spantwo', 'spchol', + 'spcompack', 'spec', 'specfact', 'speye', 'spget', 'splin', 'splin2d', 'splin3d', 'split_edge', 'spones', + 'sprand', 'sprintf', 'spzeros', 'sqroot', 'sqrt', 'sqrtm', 'square', 'squarewave', 'srfaur', 'srkf', 'ss2des', + 'ss2ss', 'ss2tf', 'sscanf', 'sskf', 'ssprint', 'ssrand', 'st_deviation', 'st_ility', 'stabil', 'stacksize', + 'star', 'startup', 'stdev', 'stdevf', 'str2code', 'strange', 'strcat', 'strindex', 'string', 'stringbox', + 'strings', 'stripblanks', 'strong_con_nodes', 'strong_connex', 'strsplit', 'strsubst', 'struct', 'sub2ind', + 'subf', 'subgraph', 'subplot', 'successors', 'sum', 'supernode', 'surf', 'surface_properties', 'sva', + 'svd', 'svplot', 'sylm', 'sylv', 'symbols', 'sysconv', 'sysdiag', 'sysfact', 'syslin', 'syssize', 'system', + 'systems', 'systmat', 'tabul', 'tan', 'tangent', 'tanh', 'tanhm', 'tanm', 'TCL_CreateSlave', 'TCL_DeleteInterp', + 'TCL_EvalFile', 'TCL_EvalStr', 'TCL_ExistInterp', 'TCL_ExistVar', 'TCL_GetVar', 'TCL_GetVersion', 'TCL_SetVar', + 'TCL_UnsetVar', 'TCL_UpVar', 'tdinit', 'testmatrix', 'texprint', 'text_properties', 'tf2des', 'tf2ss', 'then', + 'thrownan', 'tic', 'tilda', 'time_id', 'timer', 'title', 'titlepage', 'TK_EvalFile', 'TK_EvalStr', 'tk_getdir', + 'tk_getfile', 'TK_GetVar', 'tk_savefile', 'TK_SetVar', 'toc', 'toeplitz', 'tohome', 'tokenpos', + 'tokens', 'toolbar', 'toprint', 'trace', 'trans', 'trans_closure', 'translatepaths', 'tree2code', 'trfmod', + 'trianfml', 'tril', 'trimmean', 'trisolve', 'triu', 'try', 'trzeros', 'twinkle', 'type', 'Type', 'typename', + 'typeof', 'ui_observer', 'uicontrol', 'uimenu', 'uint16', 'uint32', 'uint8', 'ulink', 'unglue', 'union', + 'unique', 'unix', 'unix_g', 'unix_s', 'unix_w', 'unix_x', 'unobs', 'unsetmenu', 'unzoom', 'user', 'varargin', + 'varargout', 'Variable', 'variance', 'variancef', 'varn', 'vectorfind', 'waitbar', 'warning', 'wavread', + 'wavwrite', 'wcenter', 'wfir', 'what', 'where', 'whereami', 'whereis', 'who', 'who_user', 'whos', + 'wiener', 'wigner', 'winclose', 'window', 'winlist', 'winopen', 'winqueryreg', 'winsid', 'with_atlas', + 'with_gtk', 'with_javasci', 'with_pvm', 'with_texmacs', 'with_tk', 'writb', 'write', 'write4b', 'x_choices', + 'x_choose', 'x_dialog', 'x_matrix', 'x_mdialog', 'x_message', 'x_message_modeless', 'xarc', 'xarcs', 'xarrows', + 'xaxis', 'xbasc', 'xbasimp', 'xbasr', 'xchange', 'xclea', 'xclear', 'xclick', 'xclip', 'xdel', 'xend', + 'xfarc', 'xfarcs', 'xfpoly', 'xfpolys', 'xfrect', 'xget', 'xgetech', 'xgetfile', 'xgetmouse', 'xgraduate', + 'xgrid', 'xinfo', 'xinit', 'xlfont', 'xload', 'xls_open', 'xls_read', 'xmltohtml', 'xname', 'xnumb', 'xpause', + 'xpoly', 'xpolys', 'xrect', 'xrects', 'xrpoly', 'xs2bmp', 'xs2emf', 'xs2eps', 'xs2fig', 'xs2gif', 'xs2ppm', + 'xs2ps', 'xsave', 'xsegs', 'xselect', 'xset', 'xsetech', 'xsetm', 'xstring', 'xstringb', 'xstringl', 'xtape', + 'xtitle', 'yulewalk', 'zeropen', 'zeros', 'zgrid', 'zoom_rect', 'zpbutt', 'zpch1', 'zpch2', 'zpell' + ) + ), + 'SYMBOLS' => array( + '<', '>', '=', + '!', '@', '~', '&', '|', + '+','-', '*', '/', '%', + ',', ';', '?', ':', "'" + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => true, + 1 => true, + 2 => true, + 3 => true, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #000000; font-weight: bold;', + 3 => 'color: #000066;' + ), + 'COMMENTS' => array( + 1 => 'color: #666666; font-style: italic;', + 2 => '', + 'MULTI' => 'color: #666666; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;', + 'HARD' => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;', + 'HARD' => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;', + 2 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;', + 4 => 'color: #009999;', + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://www.scilab.org/product/dic-mat-sci/M2SCI_doc.htm', + 2 => 'http://www.scilab.org/product/dic-mat-sci/M2SCI_doc.htm', + 3 => 'http://www.scilab.org/product/dic-mat-sci/M2SCI_doc.htm' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '->', + 2 => '::' + ), + 'REGEXPS' => array( + //Variable + 0 => '[\\$%@]+[a-zA-Z_][a-zA-Z0-9_]*', + //File Descriptor + 4 => '<[a-zA-Z_][a-zA-Z0-9_]*>', + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/sdlbasic.php b/examples/includes/geshi/geshi/sdlbasic.php new file mode 100644 index 0000000..2e85964 --- /dev/null +++ b/examples/includes/geshi/geshi/sdlbasic.php @@ -0,0 +1,165 @@ + 'sdlBasic', + 'COMMENT_SINGLE' => array(1 => "'", 2 => "rem", 3 => "!", 4 => "#"), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'const', 'option', 'explicit', 'qbasic', 'include', 'argc', + 'argv', 'command', 'command$', 'run', 'shell', 'os', 'declare', + 'sub', 'function', 'return', 'while', 'wend', 'exit', 'end', + 'continue', 'if', 'then', 'else', 'elseif', + 'select', 'case', 'for', 'each', 'step', + 'next', 'to', 'dim', 'shared', 'common', 'lbound', 'bound', + 'erase', 'asc', 'chr', 'chr$', 'insert', 'insert$', 'instr', 'lcase', + 'lcase$', 'left', 'left$', 'len', 'length', 'ltrim', 'ltrim$', 'mid', + 'mid$', 'replace', 'replace$', 'replacesubstr', 'replacesubstr$', + 'reverse', 'reverse$', 'right', 'right$', 'rinstr', 'rtrim', 'rtrim$', + 'space', 'space$', 'str', 'str$', 'strf', 'strf$', 'string', 'string$', + 'tally', 'trim', 'trim$', 'typeof', 'typeof$', 'ucase', 'ucase$', 'val', + 'abs', 'acos', 'andbit', 'asin', 'atan', 'bitwiseand', 'bitwiseor', + 'bitwisexor', 'cos', 'exp', 'fix', 'floor', 'frac', 'hex', 'hex$', 'int', + 'log', 'min', 'max', 'orbit', 'randomize', 'rnd', 'round', 'sgn', 'sin', + 'sqr', 'tan', 'xorbit', 'open', 'as', 'file', 'input', 'close', 'output', + 'append', 'eof', 'fileexists', 'filecopy', 'filemove', 'filerename', + 'freefile', 'kill', 'loc', 'lof', 'readbyte', 'rename', 'seek', + 'writebyte', 'chdir', 'dir', 'dir$', 'direxists', 'dirfirst', 'dirnext', + 'mkdir', 'rmdir', 'print', 'date', 'date$', 'time', 'time$', 'ticks', + 'data', 'read', 'reservebank', 'freebank', 'copybank', 'loadbank', + 'savebank', 'setbank', 'sizebank', 'poke', 'doke', 'loke', 'peek', 'deek', + 'leek', 'memcopy', 'setdisplay', 'setcaption', 'caption', 'displaywidth', + 'displayheight', 'displaybpp', 'screen', 'directscreen', 'screenopen', + 'screenclose', 'screenclone', 'screencopy', 'screenfade', 'screenfadein', + 'screencrossfade', 'screenalpha', 'screenlock', 'screenunlock', + 'screenrect', 'xscreenrect', 'yscreenrect', 'wscreenrect', 'hscreenrect', + 'flagscreenrect', 'screenwidth', 'screenheight', 'offset', 'xoffset', + 'yoffset', 'cls', 'screenswap', 'autoback', 'setautoback', + 'dualplayfield', 'waitvbl', 'fps', 'rgb', 'enablepalette', 'color', + 'palette', 'colorcycling', 'ink', 'point', 'dot', 'plot', 'line', 'box', + 'bar', 'circle', 'fillcircle', 'ellipse', 'fillellipse', 'paint', + 'loadimage', 'saveimage', 'loadsound', 'savesound', 'loadmusic', + 'hotspot', 'setcolorkey', 'imageexists', 'imagewidth', 'imageheight', + 'deleteimage', 'copyimage', 'setalpha', 'zoomimage', 'rotateimage', + 'rotozoomimage', 'blt', 'pastebob', 'pasteicon', 'grab', 'spriteclip', + 'sprite', 'deletesprite', 'xsprite', 'ysprite', 'spritewidth', + 'spriteheight', 'frsprite', 'livesprite', 'spritehit', 'autoupdatesprite', + 'updatesprite', 'setbob', 'bob', 'deletebob', 'xbob', 'ybob', 'bobwidth', + 'bobheight', 'frbob', 'livebob', 'bobhit', 'autoupdatebob', 'updatebob', + 'text', 'setfont', 'textrender', 'pen', 'paper', 'prints', 'locate', + 'atx', 'aty', 'curson', 'cursoff', 'inputs', 'zoneinputs', + 'isenabledsound', 'soundexists', 'deletesound', 'copysound', + 'musicexists', 'playsound', 'volumesound', 'stopsound', 'pausesound', + 'resumesound', 'vumetersound', 'positionsound', 'soundchannels', + 'playmusic', 'positionmusic', 'stopmusic', 'fademusic', 'pausemusic', + 'resumemusic', 'rewindmusic', 'volumemusic', 'speedmusic', 'numdrivescd', + 'namecd', 'getfreecd', 'opencd', 'indrivecd', 'trackscd', 'curtrackcd', + 'curframecd', 'playcd', 'playtrackscd', + 'pausecd', 'resumecd', 'stopcd', 'ejectcd', 'closecd', 'tracktypecd', + 'tracklengthcd', 'trackoffsetcd', 'key', 'inkey', 'waitkey', 'xmouse', + 'ymouse', 'xmousescreen', 'ymousescreen', 'bmouse', 'changemouse', + 'locatemouse', 'mouseshow', 'mousehide', 'mousezone', 'numjoysticks', + 'namejoystick', 'numaxesjoystick', 'numballsjoystick', 'numhatsjoystick', + 'numbuttonsjoystick', 'getaxisjoystick', 'gethatjoystick', + 'getbuttonjoystick', 'xgetballjoystick', 'ygetballjoystick', 'joy', + 'bjoy', 'wait', 'timer', 'isenabledsock', 'getfreesock', 'opensock', + 'acceptsock', 'isserverready', 'connectsock', 'connectionreadysock', + 'isclientready', 'losesock', 'peeksock', 'readsock', 'readbytesock', + 'readlinesock', 'writesock', 'writebytesock', 'writelinesock', + 'getremoteip', 'getremoteport', 'getlocalip' + ) + ), + 'SYMBOLS' => array( + '(', ')' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080;', + 2 => 'color: #808080;', + 3 => 'color: #808080;', + 4 => 'color: #808080;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #66cc66;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/smalltalk.php b/examples/includes/geshi/geshi/smalltalk.php new file mode 100644 index 0000000..9316773 --- /dev/null +++ b/examples/includes/geshi/geshi/smalltalk.php @@ -0,0 +1,160 @@ + 'Smalltalk', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('"' => '"'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'"), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array('self','super','true','false','nil') + ), + 'SYMBOLS' => array( + '[', ']', '=' , ':=', '(', ')', '#' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #7f007f;' + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #007f00; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'BRACKETS' => array( + 0 => '' + ), + 'STRINGS' => array( + 0 => 'color: #7f0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #7f0000;' + ), + 'METHODS' => array( + 0 => '' + ), + 'SYMBOLS' => array( + 0 => 'color: #000066; font-weight:bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;', + 1 => 'color: #7f0000;', + 2 => 'color: #7f0000;', + 3 => 'color: #00007f;', + 4 => 'color: #7f007f;', + 5 => 'color: #00007f;', + 6 => 'color: #00007f;' + ), + 'SCRIPT' => array( + 0 => '' + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 0 => array( + GESHI_SEARCH => '([^a-zA-Z0-9_#<])([A-Z]+[a-zA-Z0-9_]*)(?!>)', //class names + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 1 => array( + GESHI_SEARCH => '(#+)([a-zA-Z0-9_]+)', //symbols + GESHI_REPLACE => '\\1\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 2 => array( + GESHI_SEARCH => '(#\s*\([^)]*\))', //array symbols + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 3 => array( + GESHI_SEARCH => '([a-zA-Z0-9_\s]+)', //temporary variables + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '|', + GESHI_AFTER => '|' + ), + 4 => array( + GESHI_SEARCH => '(self|super|true|false|nil)', //keywords again (to avoid matching in next regexp) + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 5 => array( + GESHI_SEARCH => '([:(,=[.*\/+-]\s*)([a-zA-Z0-9_]+)', //message parameters, message receivers + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 's', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + 6 => array( + GESHI_SEARCH => '([a-zA-Z0-9_]+)(\s*:=)', //assignment targets + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '\\2' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/smarty.php b/examples/includes/geshi/geshi/smarty.php new file mode 100644 index 0000000..112ab5a --- /dev/null +++ b/examples/includes/geshi/geshi/smarty.php @@ -0,0 +1,192 @@ + 'Smarty', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array('{*' => '*}'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + '$smarty', 'now', 'const', 'capture', 'config', 'section', 'foreach', 'template', 'version', 'ldelim', 'rdelim', + 'foreachelse', 'include', 'include_php', 'insert', 'if', 'elseif', 'else', 'php', + 'sectionelse', 'is_cached', + ), + 2 => array( + 'capitalize', 'count_characters', 'cat', 'count_paragraphs', 'count_sentences', 'count_words', 'date_format', + 'default', 'escape', 'indent', 'lower', 'nl2br', 'regex_replace', 'replace', 'spacify', 'string_format', + 'strip', 'strip_tags', 'truncate', 'upper', 'wordwrap', + ), + 3 => array( + 'counter', 'cycle', 'debug', 'eval', 'html_checkboxes', 'html_image', 'html_options', + 'html_radios', 'html_select_date', 'html_select_time', 'html_table', 'math', 'mailto', 'popup_init', + 'popup', 'textformat' + ), + 4 => array( + '$template_dir', '$compile_dir', '$config_dir', '$plugins_dir', '$debugging', '$debug_tpl', + '$debugging_ctrl', '$autoload_filters', '$compile_check', '$force_compile', '$caching', '$cache_dir', + '$cache_lifetime', '$cache_handler_func', '$cache_modified_check', '$config_overwrite', + '$config_booleanize', '$config_read_hidden', '$config_fix_newlines', '$default_template_handler_func', + '$php_handling', '$security', '$secure_dir', '$security_settings', '$trusted_dir', '$left_delimiter', + '$right_delimiter', '$compiler_class', '$request_vars_order', '$request_use_auto_globals', + '$error_reporting', '$compile_id', '$use_sub_dirs', '$default_modifiers', '$default_resource_type' + ), + 5 => array( + 'append', 'append_by_ref', 'assign', 'assign_by_ref', 'clear_all_assign', 'clear_all_cache', + 'clear_assign', 'clear_cache', 'clear_compiled_tpl', 'clear_config', 'config_load', 'display', + 'fetch', 'get_config_vars', 'get_registered_object', 'get_template_vars', + 'load_filter', 'register_block', 'register_compiler_function', 'register_function', + 'register_modifier', 'register_object', 'register_outputfilter', 'register_postfilter', + 'register_prefilter', 'register_resource', 'trigger_error', 'template_exists', 'unregister_block', + 'unregister_compiler_function', 'unregister_function', 'unregister_modifier', 'unregister_object', + 'unregister_outputfilter', 'unregister_postfilter', 'unregister_prefilter', 'unregister_resource' + ), + 6 => array( + 'name', 'file', 'scope', 'global', 'key', 'once', 'script', + 'loop', 'start', 'step', 'max', 'show', 'values', 'value', 'from', 'item' + ), + 7 => array( + 'eq', 'neq', 'ne', 'lte', 'gte', 'ge', 'le', 'not', 'mod' + ), + 8 => array( + // some common php functions + 'isset', 'is_array', 'empty', 'count', 'sizeof' + ) + ), + 'SYMBOLS' => array( + '/', '=', '==', '!=', '>', '<', '>=', '<=', '!', '%' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false, + 8 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0600FF;', //Functions + 2 => 'color: #008000;', //Modifiers + 3 => 'color: #0600FF;', //Custom Functions + 4 => 'color: #804040;', //Variables + 5 => 'color: #008000;', //Methods + 6 => 'color: #6A0A0A;', //Attributes + 7 => 'color: #D36900;', //Text-based symbols + 8 => 'color: #0600FF;' //php functions + ), + 'COMMENTS' => array( + 'MULTI' => 'color: #008080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #D36900;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #D36900;' + ), + 'SCRIPT' => array( + 0 => '', + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #009000;' + ), + 'REGEXPS' => array( + 0 => 'color: #00aaff;' + ) + ), + 'URLS' => array( + 1 => 'http://smarty.php.net/{FNAMEL}', + 2 => 'http://smarty.php.net/{FNAMEL}', + 3 => 'http://smarty.php.net/{FNAMEL}', + 4 => 'http://smarty.php.net/{FNAMEL}', + 5 => 'http://smarty.php.net/{FNAMEL}', + 6 => '', + 7 => 'http://smarty.php.net/{FNAMEL}', + 8 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + // variables + 0 => '\$[a-zA-Z][a-zA-Z0-9_]*' + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + 0 => array( + '{' => '}' + ), + 1 => array( + '', + ), + 2 => array( + '<' => '>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => false, + 2 => false + ), + 'PARSER_CONTROL' => array( + 'KEYWORDS' => array( + 'DISALLOWED_BEFORE' => "(?|^])", + 'DISALLOWED_AFTER' => "(?![a-zA-Z0-9_<\|%\\-&])" + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/sql.php b/examples/includes/geshi/geshi/sql.php new file mode 100644 index 0000000..00e4fd2 --- /dev/null +++ b/examples/includes/geshi/geshi/sql.php @@ -0,0 +1,140 @@ + 'SQL', + 'COMMENT_SINGLE' => array(1 =>'--', 2 => '#'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => 1, + 'QUOTEMARKS' => array("'", '"', '`'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'ADD', 'ALL', 'ALTER', 'AND', 'AS', 'ASC', + 'AUTO_INCREMENT', 'BETWEEN', 'BINARY', 'BOOLEAN', + 'BOTH', 'BY', 'CHANGE', 'CHECK', 'COLUMN', 'COLUMNS', + 'CREATE', 'CROSS', 'DATA', 'DATABASE', 'DATABASES', + 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', + 'DISTINCT', 'DROP', 'ENCLOSED', 'ESCAPED', 'EXISTS', + 'EXPLAIN', 'FIELD', 'FIELDS', 'FLUSH', 'FOR', + 'FOREIGN', 'FROM', 'FULL', 'FUNCTION', 'GRANT', + 'GROUP', 'HAVING', 'IDENTIFIED', 'IF', 'IGNORE', + 'IN', 'INDEX', 'INFILE', 'INNER', 'INSERT', 'INTO', + 'IS', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LANGUAGE', + 'LEADING', 'LEFT', 'LIKE', 'LIMIT', 'LINES', 'LOAD', + 'LOCAL', 'LOCK', 'LOW_PRIORITY', 'MODIFY', 'NATURAL', + 'NEXTVAL', 'NOT', 'NULL', 'ON', 'OPTIMIZE', 'OPTION', + 'OPTIONALLY', 'OR', 'ORDER', 'OUTER', 'OUTFILE', + 'PRIMARY', 'PROCEDURAL', 'PROCEEDURE', 'READ', + 'REFERENCES', 'REGEXP', 'RENAME', 'REPLACE', + 'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SELECT', + 'SET', 'SETVAL', 'SHOW', 'SONAME', 'STATUS', + 'STRAIGHT_JOIN', 'TABLE', 'TABLES', 'TEMINATED', + 'TEMPORARY', 'TO', 'TRAILING', 'TRIGGER', 'TRUNCATE', + 'TRUSTED', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', + 'UPDATE', 'USE', 'USING', 'VALUES', 'VARIABLES', + 'VIEW', 'WHERE', 'WITH', 'WRITE', 'XOR', 'ZEROFILL' + ) + ), + 'SYMBOLS' => array( + '(', ')', '=', '<', '>', '|', ',', '.', '+', '-', '*', '/' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #993333; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #808080; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/tcl.php b/examples/includes/geshi/geshi/tcl.php new file mode 100644 index 0000000..9badb21 --- /dev/null +++ b/examples/includes/geshi/geshi/tcl.php @@ -0,0 +1,194 @@ + 'TCL', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + 1 => '/(? '/{[^}\n]+}/' + ), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"', "'"), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + /* + * Set 1: reserved words + * http://python.org/doc/current/ref/keywords.html + */ + 1 => array( + 'proc', 'global', 'upvar', 'if', 'then', 'else', 'elseif', 'for', 'foreach', + 'break', 'continue', 'while', 'set', 'eval', 'case', 'in', 'switch', + 'default', 'exit', 'error', 'return', 'uplevel', 'loop', + 'for_array_keys', 'for_recursive_glob', 'for_file', 'unwind_protect', + 'expr', 'catch', 'namespace', 'rename', 'variable', + // itcl + 'method', 'itcl_class', 'public', 'protected'), + + /* + * Set 2: builtins + * http://asps.activatestate.com/ASPN/docs/ActiveTcl/8.4/tcl/tcl_2_contents.htm + */ + 2 => array( + // string handling + 'append', 'binary', 'format', 're_syntax', 'regexp', 'regsub', + 'scan', 'string', 'subst', + // list handling + 'concat', 'join', 'lappend', 'lindex', 'list', 'llength', 'lrange', + 'lreplace', 'lsearch', 'lset', 'lsort', 'split', + // procedures and output + 'incr', 'close', 'eof', 'fblocked', 'fconfigure', 'fcopy', 'file', + 'fileevent', 'flush', 'gets', 'open', 'puts', 'read', 'seek', + 'socket', 'tell', + // packages and source files + 'load', 'loadTk', 'package', 'pgk::create', 'pgk_mkIndex', 'source', + // interpreter routines + 'bgerror', 'history', 'info', 'interp', 'memory', 'unknown', + // library routines + 'enconding', 'http', 'msgcat', + // system related + 'cd', 'clock', 'exec', 'glob', 'pid', 'pwd', 'time', + // platform specified + 'dde', 'registry', 'resource', + // special variables + '$argc', '$argv', '$errorCode', '$errorInfo', '$argv0', + '$auto_index', '$auto_oldpath', '$auto_path', '$env', + '$tcl_interactive', '$tcl_libpath', '$tcl_library', + '$tcl_pkgPath', '$tcl_platform', '$tcl_precision', '$tcl_traceExec', + ), + + /* + * Set 3: standard library + */ + 3 => array( + 'comment', 'filename', 'library', 'packagens', 'tcltest', 'tclvars', + ), + + /* + * Set 4: special methods + */ +// 4 => array( +// ) + + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '$', '*', '&', '%', '!', ';', '<', '>', '?' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, +// 4 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #ff7700;font-weight:bold;', // Reserved + 2 => 'color: #008000;', // Built-ins + self + 3 => 'color: #dc143c;', // Standard lib +// 4 => 'color: #0000cd;' // Special methods + ), + 'COMMENTS' => array( + 1 => 'color: #808080; font-style: italic;', + 2 => 'color: #483d8b;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: black;' + ), + 'STRINGS' => array( + 0 => 'color: #483d8b;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff4500;' + ), + 'METHODS' => array( + 1 => 'color: black;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + 0 => 'color: #ff3333;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', +// 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '::' + ), + 'REGEXPS' => array( + //Special variables + 0 => '[\\$]+[a-zA-Z_][a-zA-Z0-9_]*', + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'COMMENTS' => array( + 'DISALLOWED_BEFORE' => '\\' + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/teraterm.php b/examples/includes/geshi/geshi/teraterm.php new file mode 100644 index 0000000..f2938ca --- /dev/null +++ b/examples/includes/geshi/geshi/teraterm.php @@ -0,0 +1,317 @@ + 'Tera Term Macro', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /* Commands */ + 1 => array( + 'Beep', + 'BplusRecv', + 'BplusSend', + 'Break', // (version 4.53 or later) + 'Call', + 'CallMenu', // (version 4.56 or later) + 'ChangeDir', + 'ClearScreen', + 'Clipb2Var', //(version 4.46 or later) + 'ClosesBox', + 'CloseTT', + 'Code2Str', + 'Connect', + 'CRC32', // (version 4.60 or later) + 'CRC32File', // (version 4.60 or later) + 'CygConnect', // (version 4.57 or later) + 'DelPassword', + 'Disconnect', + 'Do', // (version 4.56 or later) + 'Else', + 'EnableKeyb', + 'End', + 'EndIf', + 'EndUntil', // (version 4.56 or later) + 'EndWhile', + 'Exec', + 'ExecCmnd', + 'Exit', + 'FileClose', + 'FileConcat', + 'FileCopy', + 'FileCreate', + 'FileDelete', + 'FileMarkPtr', + 'FilenameBox', //(version 4.54 or later) + 'FileOpen', + 'FileRead', + 'FileReadln', // (version 4.48 or later) + 'FileRename', + 'FileSearch', + 'FileSeek', + 'FileSeekBack', + 'FileStrSeek', + 'FileStrSeek2', + 'FileWrite', + 'FileWriteln', + 'FindOperations', + 'FlushRecv', + 'ForNext', + 'GetDate', + 'GetDir', //(version 4.46 or later) + 'GetEnv', + 'GetPassword', + 'GetTime', + 'GetTitle', + 'GetVer', //(version 4.58 or later) + 'GoTo', + 'If', + 'IfDefined', // (version 4.46 or later) + 'IfThenElseIf', + 'Include', + 'InputBox', + 'Int2Str', + 'KmtFinish', + 'KmtGet', + 'KmtRecv', + 'KmtSend', + 'LoadKeyMap', + 'LogClose', + 'LogOpen', + 'LogPause', + 'LogStart', + 'LogWrite', + 'Loop', // (version 4.56 or later) + 'MakePath', + 'MessageBox', + 'MPause', // (version 4.27 or later) + 'PasswordBox', + 'Pause', + 'QuickvanRecv', + 'QuickvanSend', + 'Random', //(version 4.27 or later) + 'Recvln', + 'RestoreSetup', + 'Return', + 'RotateLeft', //(version 4.54 or later) + 'RotateRight', //(version 4.54 or later) + 'ScpRecv', // (version 4.57 or later) + 'ScpSend', // (version 4.57 or later) + 'Send', + 'SendBreak', + 'SendFile', + 'SendKcode', + 'Sendln', + 'SetBaud', // (version 4.58 or later) + 'SetDate', + 'SetDir', + 'SetDlgPos', + 'SetDTR', // (version 4.59 or later) + 'SetRTS', // (version 4.59 or later) + 'SetEnv', // (version 4.54 or later) + 'SetEcho', + 'SetExitCode', + 'SetSync', + 'SetTime', + 'SetTitle', + 'Show', + 'ShowTT', + 'Sprintf', // (version 4.52 or later) + 'StatusBox', + 'Str2Code', + 'Str2Int', + 'StrCompare', + 'StrConcat', + 'StrCopy', + 'StrLen', + 'StrMatch', // (version 4.59 or later) + 'StrScan', + 'Testlink', + 'Then', + 'ToLower', //(version 4.53 or later) + 'ToUpper', //(version 4.53 or later) + 'Unlink', + 'Until', // (version 4.56 or later) + 'Var2Clipb', //(version 4.46 or later) + 'Wait', + 'WaitEvent', + 'Waitln', + 'WaitRecv', + 'WaitRegex', // (version 4.21 or later) + 'While', + 'XmodemRecv', + 'XmodemSend', + 'YesNoBox', + 'ZmodemRecv', + 'ZmodemSend' + ), + /* System Variables */ + 2 => array( + 'groupmatchstr1', + 'groupmatchstr2', + 'groupmatchstr3', + 'groupmatchstr4', + 'groupmatchstr5', + 'groupmatchstr6', + 'groupmatchstr7', + 'groupmatchstr8', + 'groupmatchstr9', + 'inputstr', + 'matchstr', + 'param2', + 'param3', + 'param4', + 'param5', + 'param6', + 'param7', + 'param8', + 'param9', + 'result', + 'timeout' + ), + /* LogMeTT Key Words */ + 3 => array( + '$[1]', + '$[2]', + '$[3]', + '$[4]', + '$[5]', + '$[6]', + '$[7]', + '$[8]', + '$connection$', + '$email$', + '$logdir$', + '$logfilename$', + '$logit$', + '$mobile$', + '$name$', + '$pager$', + '$parent$', + '$phone$', + '$snippet$', + '$ttdir$', + '$user$', + '$windir$', + ), + /* Keyword Symbols */ + 4 => array( + 'and', + 'not', + 'or', + 'xor' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', + '~', '!', '+', '-', '*', '/', '%', '>>', '<<', '<<<', '>>>', '&', '^', '|', + '<>', '<=', '>=', '=', '==', '<>', '!=', '&&', '||' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000080; font-weight: bold!important;', + 2 => 'color: #808000; font-weight: bold;', // System Variables + 3 => 'color: #ff0000; font-weight: bold;', // LogMeTT Key Words + 4 => 'color: #ff00ff; font-weight: bold;' // Keyword Symbols + ), + 'COMMENTS' => array( + 1 => 'color: #008000; font-style: italic;', + ), + 'ESCAPE_CHAR' => array(), + 'BRACKETS' => array( + 0 => 'color: #ff00ff; font-weight: bold;' + ), + 'STRINGS' => array( + 0 => 'color: #800080;' + ), + 'NUMBERS' => array( + 0 => 'color: #008080;' + ), + 'SCRIPT' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #ff00ff; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff; font-weight: bold;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + 0 => array ( + GESHI_SEARCH => '(\:[_a-zA-Z][_a-zA-Z0-9]+)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array(), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/text.php b/examples/includes/geshi/geshi/text.php new file mode 100644 index 0000000..6c6e260 --- /dev/null +++ b/examples/includes/geshi/geshi/text.php @@ -0,0 +1,84 @@ + 'Text', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array(), + 'SYMBOLS' => array(), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false + ), + 'STYLES' => array( + 'KEYWORDS' => array(), + 'COMMENTS' => array(), + 'ESCAPE_CHAR' => array(), + 'BRACKETS' => array(), + 'STRINGS' => array(), + 'NUMBERS' => array(), + 'METHODS' => array(), + 'SYMBOLS' => array(), + 'SCRIPT' => array(), + 'REGEXPS' => array() + ), + 'URLS' => array(), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array(), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array(), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'ALL' => GESHI_NEVER + ), + ) +); + +?> diff --git a/examples/includes/geshi/geshi/thinbasic.php b/examples/includes/geshi/geshi/thinbasic.php new file mode 100644 index 0000000..caa6edf --- /dev/null +++ b/examples/includes/geshi/geshi/thinbasic.php @@ -0,0 +1,868 @@ + 'thinBasic', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'XOR','XML_TREETOSTRING','XML_PARSEFILE','XML_PARSE','XML_PARENT','XML_NODETYPE','XML_NODETOSTRING','XML_NEXTSIBLING', + 'XML_LASTERROR','XML_GETTAG','XML_FREE','XML_FINDNODE','XML_DECODEPARAM','XML_CHILDDATA','XML_CHILD','XML_ATTRIBVALUE', + 'XML_ATTRIBNAME','XML_ATTRIBCOUNT','WORD','WITH','WIN_SHOW','WIN_SETTITLE','WIN_SETFOREGROUND','WIN_ISZOOMED', + 'WIN_ISVISIBLE','WIN_ISICONIC','WIN_GETTITLE','WIN_GETFOREGROUND','WIN_GETCLASS','WIN_GETACTIVE','WIN_FLASH','WIN_FINDBYTITLE', + 'WIN_FINDBYCLASS','WHILE','WEND','VERIFY','VARPTR','VARIANTVT$','VARIANTVT','VARIANT', + 'VARIABLE_GETINFO','VARIABLE_EXISTS','VARIABLE_EXIST','VALUE','VAL','USING$','USING','USES', + 'USER','UNTIL','UNITS','UNION','UNICODE2ASCII','UDP_SEND','UDP_RECV','UDP_OPENSERVER', + 'UDP_OPEN','UDP_FREEFILE','UDP_CLOSE','UCODE$','UCASE$','UBOUND','TYPE','TRIMFULL$', + 'TRIM$','TOOLTIP','TOKENIZER_MOVETOEOL','TOKENIZER_KEYSETUSERSTRING','TOKENIZER_KEYSETUSERNUMBER','TOKENIZER_KEYGETUSERSTRING','TOKENIZER_KEYGETUSERNUMBER','TOKENIZER_KEYGETSUBTYPE', + 'TOKENIZER_KEYGETNAME','TOKENIZER_KEYGETMAINTYPE','TOKENIZER_KEYFIND','TOKENIZER_KEYADD','TOKENIZER_GETNEXTTOKEN','TOKENIZER_DEFAULT_SET','TOKENIZER_DEFAULT_GET','TOKENIZER_DEFAULT_CODE', + 'TOKENIZER_DEFAULT_CHAR','TO','TIMER','TIME$','THEN','TEXTBOX','TEXT','TCP_SEND', + 'TCP_RECV','TCP_PRINT','TCP_OPEN','TCP_LINEINPUT','TCP_FREEFILE','TCP_CLOSE','TB_IMGCTX_SETIMAGEADJUSTMENT','TB_IMGCTX_LOADIMAGE', + 'TB_IMGCTX_GETIMAGEADJUSTMENT','TBGL_VIEWPORT','TBGL_VERTEX','TBGL_USETEXTUREFLAG','TBGL_USETEXTURE','TBGL_USELINESTIPPLEFLAG','TBGL_USELINESTIPPLE','TBGL_USELIGHTSOURCEFLAG', + 'TBGL_USELIGHTSOURCE','TBGL_USELIGHTINGFLAG','TBGL_USELIGHTING','TBGL_USEFOGFLAG','TBGL_USEFOG','TBGL_USEDEPTHMASK','TBGL_USEDEPTHFLAG','TBGL_USEDEPTH', + 'TBGL_USECLIPPLANEFLAG','TBGL_USECLIPPLANE','TBGL_USEBLENDFLAG','TBGL_USEBLEND','TBGL_USEALPHATEST','TBGL_TRANSLATE','TBGL_TORUS','TBGL_TEXCOORD2D', + 'TBGL_SPHERE','TBGL_SHOWWINDOW','TBGL_SHOWCURSOR','TBGL_SETWINDOWTITLE','TBGL_SETUPLIGHTSOURCE','TBGL_SETUPFOG','TBGL_SETUPCLIPPLANE','TBGL_SETPRIMITIVEQUALITY', + 'TBGL_SETLIGHTPARAMETER','TBGL_SETDRAWDISTANCE','TBGL_SCALE','TBGL_SAVESCREENSHOT','TBGL_ROTATEXYZ','TBGL_ROTATE','TBGL_RESETMATRIX','TBGL_RENDERTOTEXTURE', + 'TBGL_RENDERMATRIX3D','TBGL_RENDERMATRIX2D','TBGL_PUSHMATRIX','TBGL_PRINTFONT','TBGL_PRINTBMP','TBGL_PRINT','TBGL_POS3DTOPOS2D','TBGL_POPMATRIX', + 'TBGL_POLYGONLOOK','TBGL_POINTSIZE','TBGL_POINTINSIDE3D','TBGL_NORMAL','TBGL_NEWLIST','TBGL_MOUSEGETWHEELDELTA','TBGL_MOUSEGETRBUTTON','TBGL_MOUSEGETPOSY', + 'TBGL_MOUSEGETPOSX','TBGL_MOUSEGETMBUTTON','TBGL_MOUSEGETLBUTTON','TBGL_M15SETVERTEXZ','TBGL_M15SETVERTEXY','TBGL_M15SETVERTEXXYZ','TBGL_M15SETVERTEXX','TBGL_M15SETVERTEXTEXY', + 'TBGL_M15SETVERTEXTEXXY','TBGL_M15SETVERTEXTEXX','TBGL_M15SETVERTEXTEXN','TBGL_M15SETVERTEXRGB','TBGL_M15SETVERTEXR','TBGL_M15SETVERTEXPSTOP','TBGL_M15SETVERTEXPARAM','TBGL_M15SETVERTEXLAYER', + 'TBGL_M15SETVERTEXG','TBGL_M15SETVERTEXB','TBGL_M15SETMODELVERTEXCOUNT','TBGL_M15SETBONECHILD','TBGL_M15ROTBONEZ','TBGL_M15ROTBONEY','TBGL_M15ROTBONEX','TBGL_M15ROTBONE', + 'TBGL_M15RESETBONES','TBGL_M15RECALCNORMALS','TBGL_M15LOADMODEL','TBGL_M15INITMODELBUFFERS','TBGL_M15GETVERTEXZ','TBGL_M15GETVERTEXY','TBGL_M15GETVERTEXXYZ','TBGL_M15GETVERTEXX', + 'TBGL_M15GETVERTEXTEXY','TBGL_M15GETVERTEXTEXXY','TBGL_M15GETVERTEXTEXX','TBGL_M15GETVERTEXTEXN','TBGL_M15GETVERTEXRGB','TBGL_M15GETVERTEXR','TBGL_M15GETVERTEXPSTOP','TBGL_M15GETVERTEXPARAM', + 'TBGL_M15GETVERTEXLAYER','TBGL_M15GETVERTEXG','TBGL_M15GETVERTEXB','TBGL_M15GETMODELVERTEXCOUNT','TBGL_M15GETMODELPOLYCOUNT','TBGL_M15ERASECHILDBONES','TBGL_M15DRAWMODEL','TBGL_M15DEFBONERESET', + 'TBGL_M15DEFBONELAYER','TBGL_M15DEFBONEBOX','TBGL_M15DEFBONEANCHOR','TBGL_M15DEFBONEADDVERTEX','TBGL_M15CLEARMODEL','TBGL_M15APPLYBONES','TBGL_M15ADDBONETREEITEM','TBGL_LOADTEXTURE', + 'TBGL_LOADFONT','TBGL_LOADBMPFONT','TBGL_LINEWIDTH','TBGL_LINESTIPPLE','TBGL_KILLFONT','TBGL_ISWINDOW','TBGL_ISPOINTVISIBLE','TBGL_ISPOINTBEHINDVIEW', + 'TBGL_GETWINDOWMULTIKEYSTATE','TBGL_GETWINDOWKEYSTATE','TBGL_GETWINDOWKEYONCE','TBGL_GETWINDOWCLIENT','TBGL_GETTEXTURENAME','TBGL_GETTEXTURELIST','TBGL_GETPIXELINFO','TBGL_GETMULTIASYNCKEYSTATE', + 'TBGL_GETLASTGLERROR','TBGL_GETFRAMERATE','TBGL_GETDESKTOPINFO','TBGL_GETASYNCKEYSTATE','TBGL_ERRORMESSAGES','TBGL_ENDPOLY','TBGL_ENDLIST','TBGL_DRAWFRAME', + 'TBGL_DESTROYWINDOW','TBGL_DELETELIST','TBGL_CYLINDER','TBGL_CREATEWINDOWEX','TBGL_CREATEWINDOW','TBGL_COLORALPHA','TBGL_COLOR','TBGL_CLEARFRAME', + 'TBGL_CAMERA','TBGL_CALLLIST','TBGL_BUILDFONT','TBGL_BOX','TBGL_BLENDFUNC','TBGL_BINDTEXTURE','TBGL_BEGINPOLY','TBGL_BACKCOLOR', + 'TBGL_ALPHAFUNC','TBDI_JOYZ','TBDI_JOYY','TBDI_JOYX','TBDI_JOYSTOPEFFECT','TBDI_JOYSLIDER','TBDI_JOYSETRANGEZ','TBDI_JOYSETRANGEY', + 'TBDI_JOYSETRANGEXYZ','TBDI_JOYSETRANGEX','TBDI_JOYSETDEADZONEZ','TBDI_JOYSETDEADZONEY','TBDI_JOYSETDEADZONEXYZ','TBDI_JOYSETDEADZONEX','TBDI_JOYSETAUTOCENTER','TBDI_JOYRZ', + 'TBDI_JOYRY','TBDI_JOYRX','TBDI_JOYPOV','TBDI_JOYPLAYEFFECT','TBDI_JOYLOADEFFECT','TBDI_JOYHASFF','TBDI_JOYHASEFFECT','TBDI_JOYGETEFFECTNAME', + 'TBDI_JOYGETEFFECTGUID','TBDI_JOYCREATEEFFECT','TBDI_JOYCOUNTPOV','TBDI_JOYCOUNTEFFECTS','TBDI_JOYCOUNTBTN','TBDI_JOYCOUNTAXES','TBDI_JOYBUTTON','TBDI_JOYAVAIL', + 'TBDI_INIT','TBASS_STREAMFREE','TBASS_STREAMCREATEFILE','TBASS_SETVOLUME','TBASS_SETEAXPRESET','TBASS_SETEAXPARAMETERS','TBASS_SETCONFIG','TBASS_SET3DPOSITION', + 'TBASS_SET3DFACTORS','TBASS_SAMPLELOAD','TBASS_SAMPLEGETCHANNEL','TBASS_MUSICLOAD','TBASS_MUSICFREE','TBASS_INIT','TBASS_GETVOLUME','TBASS_GETVERSION', + 'TBASS_GETCONFIG','TBASS_FREE','TBASS_ERRORGETCODE','TBASS_CHANNELSTOP','TBASS_CHANNELSETPOSITION','TBASS_CHANNELSETATTRIBUTES','TBASS_CHANNELSET3DPOSITION','TBASS_CHANNELPLAY', + 'TBASS_CHANNELPAUSE','TBASS_CHANNELISACTIVE','TBASS_CHANNELGETPOSITION','TBASS_CHANNELGETLENGTH','TBASS_CHANNELGETATTRIBUTES','TBASS_APPLY3D','TANH','TANGENT', + 'TAN','TALLY','TABCTRL_ONNOTIFY','TABCTRL_INSERTITEM','TABCTRL_GETCURSEL','SWAP','SUB','STRZIP$', + 'STRUNZIP$','STRREVERSE$','STRPTRLEN','STRPTR','STRINSERT$','STRING$','STRING','STRDELETE$', + 'STR$','STOP','STEP','STDOUT','STDIN','STAT_SUM','STAT_STDERROR','STAT_STDDEVIATION', + 'STAT_RANDOM','STAT_PRODUCT','STAT_MIN','STAT_MEDIAN','STAT_MEANHARMONIC','STAT_MEANGEOMETRIC','STAT_MEANARITHMETIC','STAT_MAX', + 'STAT_INVERSESUM','STAT_HISTOGRAM','STAT_FILLARRAY','STAT_COUNT','STAT_COPYARRAY','STAT_CLONEARRAY','STAT_CHISQUARE','STATIC', + 'STATE','SQR','SPLIT','SORT','SMTP_STATISTICS','SMTP_SETOPTION','SMTP_SETLOGFILE','SMTP_SENDHTML', + 'SMTP_SENDEMAIL','SMTP_GETERROR','SMTP_FINISHED','SMTP_DEBUG','SMTP_CONNECT','SMTP_CLOSE','SLEEP','SIZEOF', + 'SIZE','SINH','SINGLE','SIN','SIGNED','SHOW','SHIFT','SHAPETOBMP', + 'SGN','SETAT','SET','SENDMESSAGE','SENDKEYSBULK','SENDKEYS','SEND','SELECTEXPRESSION', + 'SELECT','SECH','SEC','SCAN','SAPI_SPEAK','SAPI_SETVOLUME','SAPI_SETRATE','SAPI_MODULELOADED', + 'SAPI_GETVOLUME','SAPI_GETRATE','RTRIM$','RTF_SETTEXT','RTF_SETFONTSIZE','RTF_SETFONTNAME','RTF_SETFGCOLOR','RTF_SETEFFECT', + 'RTF_SETBGCOLOR','RTF_SETALIGN','RTF_SAVETOFILE','RTF_LOADFROMFILE','RTF_GETTEXT','RTF_GETFONTSIZE','RTF_GETFONTNAME','RTF_GETEFFECT', + 'RTF_GETCLASS','RTF_APPENDTEXT','RSET$','ROUND','RNDF','RND','RIGHT$','RIGHT', + 'RGB','RESOURCE','RESIZE','RESET','REPLACE$','REPEAT$','REMOVE$','REM', + 'REGISTRY_SETVALUE','REGISTRY_SETTXTNUM','REGISTRY_SETTXTBOOL','REGISTRY_SETDWORD','REGISTRY_GETVALUE','REGISTRY_GETTXTNUM','REGISTRY_GETTXTBOOL','REGISTRY_GETDWORD', + 'REGISTRY_GETALLKEYS','REGISTRY_DELVALUE','REGISTRY_DELKEY','REFERENCE','REF','REDRAW','REDIM','RAS_SETPARAMS', + 'RAS_OPENDIALUPDIALOG','RAS_LOADENTRIES','RAS_HANGUPALL','RAS_HANGUP','RAS_GETENTRY','RAS_BEGINDIAL','RANDOMIZE','RADTODEG', + 'QUERYPERFORMANCEFREQUENCY','QUERYPERFORMANCECOUNTER','QUAD','PTR','PRESERVE','POST','POPUP','POKE$', + 'POKE','PIXELS','PI','PERMUTATIONS','PEEKMESSAGE','PEEK$','PEEK','PC_SYSTEMUPFROM', + 'PC_SUSPENDSTATE','PC_SHUTDOWN','PC_SHOWCARET','PC_SETCARETBLINKTIME','PC_RESTARTDIALOG','PC_PREVENTSHUTDOWN','PC_LOCK','PC_INSERTCD', + 'PC_HIDECARET','PC_GETSTATEONOFF','PC_GETSCROLLLOCKKEYSTATE','PC_GETNUMLOCKKEYSTATE','PC_GETCARETBLINKTIME','PC_GETCAPSLOCKKEYSTATE','PC_EMPTYBIN','PC_EJECTCD', + 'PC_DECODECDERROR','PCT','PARSESET$','PARSECOUNT','PARSE$','PARSE','PARAMETERS','OUTSIDE', + 'OS_WINVERSIONTEXT','OS_WINGETVERSIONTIMELINE','OS_SHELLEXECUTE','OS_SHELLABOUT','OS_SHELL','OS_SETLASTCALLDLLERROR','OS_SERVICESTOP','OS_SERVICESTATUSDESCRIPTION', + 'OS_SERVICESTARTTYPEDESCRIPTION','OS_SERVICESTART','OS_SERVICESETSTARTTYPE','OS_SERVICEQUERY','OS_SERVICEGETSTARTTYPE','OS_SERVICEGETLIST','OS_PROCESSKILLBYNAME','OS_PROCESSKILLBYID', + 'OS_PROCESSISRUNNING','OS_PROCESSGETLIST','OS_PROCESSGETID','OS_PROCESSARERUNNING','OS_MESSAGEBEEP','OS_ISWOW64','OS_ISFEATUREPRESENT','OS_IEVERSION', + 'OS_GETWINDOWSDIR','OS_GETUSERNAME','OS_GETTEMPDIR','OS_GETSYSTEMDIR','OS_GETSPECIALFOLDER','OS_GETLASTCALLDLLSTATUS','OS_GETLASTCALLDLLERROR','OS_GETCURRENTTHREADID', + 'OS_GETCURRENTPROCESSID','OS_GETCOMPUTERNAME','OS_GETCOMMANDS','OS_GETCOMMAND','OS_FLASHWINDOW','OS_FATALAPPEXIT','OS_ENVIRON','OS_CALLDLL', + 'OR','OPTIONAL','OPTION','OPT','ONCE','ON','OFF','NUMBER', + 'NOT','NEXT','NEW','MSGBOX','MOUSEPTR','MODULE','MODELESS','MODAL', + 'MOD','MKWRD$','MKS$','MKQ$','MKL$','MKI$','MKE$','MKDWD$', + 'MKD$','MKCUX$','MKCUR$','MKBYT$','MIN$','MIN','MID$','MENU', + 'MDI_CREATE','MCASE$','MAX$','MAX','MAKWRD','MAKLNG','MAKINT','MAKDWR', + 'LTRIM$','LSET$','LOWRD','LOOP','LONG','LOINT','LOG_WRITE','LOGB', + 'LOG2','LOG10','LOG','LOCAL','LOC','LL_UPDATEBYNAME','LL_UPDATE','LL_TOSTRING', + 'LL_TOFILE','LL_NAME','LL_GETITEM','LL_GETBYNUMBER','LL_FROMFILE','LL_FREE','LL_FINDLAST','LL_FINDBYNAME', + 'LL_FINDBYDATA','LL_DELETELIKE','LL_DELETEBYNAME','LL_DELETE','LL_DATABYNAME','LL_DATA','LL_COUNT','LL_ADD', + 'LISTBOX','LINE','LIBRARY_EXISTS','LIB','LEN','LEFT$','LEFT','LCASE$', + 'LBOUND','LABEL','KILL','JOIN$','ITERATE','ISWINDOW','ISUNICODE','ISTRUE', + 'ISODD','ISLIKE','ISFALSE','ISEVEN','IP_TOSTRING','IP_ADDR','INTERNALINFO','INTEGER', + 'INT','INSTR','INSIDE','INPUTBOX$','INI_SETKEY','INI_GETSECTIONSLIST','INI_GETSECTIONKEYLIST','INI_GETKEY', + 'INET_URLDOWNLOAD','INET_PING','INET_OPENDIALUPDIALOG','INET_GETSTATE','INET_GETREMOTEMACADDRESS','INET_GETIP','INET_GETCONNECTIONMODE','INCR', + 'IN','IMAGE','IIF$','IIF','IF','ICRYPTO_TESTSHA1','ICRYPTO_TESTMD5','ICRYPTO_TESTCRC32', + 'ICRYPTO_TESTCRC16','ICRYPTO_STRING2ASCII','ICRYPTO_SHA1','ICRYPTO_MD5','ICRYPTO_ENCRYPTRIJNDAEL','ICRYPTO_ENCRYPTRC4','ICRYPTO_DECRYPTRIJNDAEL','ICRYPTO_DECRYPTRC4', + 'ICRYPTO_CRC32','ICRYPTO_CRC16','ICRYPTO_BYTEXOR','ICRYPTO_BIN2ASCII','ICRYPTO_ASCII2STRING','ICRYPTO_ASCII2BIN','HOST_ADDR','HOSTNAME_TOIP', + 'HOSTIP_TONAME','HIWRD','HIINT','HEX$','HASH','HANDLE','GUIDTXT$','GUID$', + 'GRAPHIC','GLVOID','GLUSHORT','GLUINT','GLUBYTE','GLSIZEI','GLSHORT','GLOBAL', + 'GLINT','GLFLOAT','GLENUM','GLDOUBLE','GLCLAMPF','GLCLAMPD','GLBYTE','GLBOOLEAN', + 'GLBITFIELD','GETWINDOWMULTIKEYSTATE','GETWINDOWKEYSTATE','GETTICKCOUNT','GETS','GETMULTIASYNCKEYSTATE','GETMESSAGE','GETCURRENTINSTANCE', + 'GETAT','GETASYNCKEYSTATE','GET','FUNCTION_NPARAMS','FUNCTION_EXISTS','FUNCTION_CPARAMS','FUNCTION','FTP_SETSTRING', + 'FTP_SETSERVERDIR','FTP_SETNUMBER','FTP_SETMODE','FTP_SETLOGFILE','FTP_SETLOCALDIR','FTP_QUIT','FTP_PUTFILE','FTP_GETSTRING', + 'FTP_GETSERVERDIR','FTP_GETNUMBER','FTP_GETLOCALDIR','FTP_GETLIST','FTP_GETFILE','FTP_GETERRORSTRING','FTP_GETERRORNUMBER','FTP_FINISHED', + 'FTP_EXTRACT','FTP_DELFILE','FTP_CONNECT','FTP_COMMAND','FRAME','FRAC','FORMAT$','FOR', + 'FONT_LIST','FONT_CREATE','FONT','FOCUS','FLUSH','FIX','FILE_SIZE','FILE_SHELLDELETE', + 'FILE_SHELLCOPY','FILE_SETDATETIME','FILE_SEEK','FILE_SAVE','FILE_RENAME','FILE_PUT','FILE_PATHSPLIT','FILE_OPEN', + 'FILE_LOF','FILE_LOAD','FILE_LINEPRINT','FILE_LINEINPUT','FILE_KILL','FILE_GETVERSIONSTRING','FILE_GETVERSION','FILE_GETTIME', + 'FILE_GETDATETIMESTAMP','FILE_GETDATETIME','FILE_GETDATE','FILE_GET','FILE_EXISTS','FILE_EOF','FILE_COPY','FILE_CLOSE', + 'FILE_CHANGED','FILE_APPEND','FACTORIAL','EXTRACT$','EXT','EXPORT','EXP2','EXP10', + 'EXP','EXIT','EVAL_STRING','EVAL_SETSTRING','EVAL_SETNUMBER','EVAL_MATH','EVAL_LINKEXT','EVAL_GETSTRING', + 'EVAL_GETNUMBER','EVAL_ERRORGETTOKEN','EVAL_ERRORDESCRIPTION','EVAL_ERRORCLEAR','EVAL','ERRCLEAR','ERR','ENGINE_GETCURRENTTOKEN', + 'ENDIF','END','ENABLE','ELSEIF','ELSE','ECHO','DWORD','DT_YEAR', + 'DT_TIMETOSEC','DT_TIMESUBSECONDS','DT_TIMEFORMAT','DT_TIMEADDSECONDS','DT_SETTIMESEPARATOR','DT_SETDATESEPARATOR','DT_SETDATECENTURY','DT_SECTOTIME', + 'DT_SECTODATE','DT_SECOND','DT_MONTH','DT_MINUTE','DT_LASTDAYOFMONTH','DT_ISVALIDDATE','DT_ISLEAPYEAR','DT_HOUR', + 'DT_GETWEEKDAYNAME','DT_GETWEEKDAY','DT_GETTIMESTAMP','DT_GETTIMESEPARATOR','DT_GETMONTHNAME','DT_GETDATESEPARATOR','DT_GETDATECENTURY','DT_DAY', + 'DT_DATETOSEC','DT_DATETIMESUBSECONDS','DT_DATETIMEADDSECONDS','DT_DATESUBDAYS','DT_DATEFORMAT','DT_DATEDIFF','DT_DATEADDDAYS','DT_COOKIEDATE', + 'DRAW','DOUBLE','DOEVENTS','DO','DISABLE','DIR_REMOVE','DIR_MAKEALL','DIR_MAKE', + 'DIR_LISTARRAY','DIR_LIST','DIR_ISEMPTY','DIR_ISDIR','DIR_GETCURRENT','DIR_EXISTS','DIR_CHANGEDRIVE','DIR_CHANGE', + 'DIM','DICTIONARY_MEMINFO','DICTIONARY_LISTKEYS','DICTIONARY_FREE','DICTIONARY_FIND','DICTIONARY_EXISTS','DICTIONARY_CREATE','DICTIONARY_COUNT', + 'DICTIONARY_ADD','DIALOG_STOPEVENTS','DIALOG_SAVEFILE','DIALOG_OPENFILE','DIALOG_GETCONTROL','DIALOG_CHOOSECOLOR','DIALOG_BROWSEFORFOLDER','DIALOG', + 'DESKTOP','DESCENDING','DESCEND','DELETEOBJECT','DELETE','DEGTORAD','DECR','DECLARE', + 'DATE$','CVWRD','CVS','CVQ','CVL','CVI','CVE','CVDWD', + 'CVD','CVCUX','CVCUR','CVBYT','CURRENCY','CUR','CSET$','CSCH', + 'CSC','CRYPTO_GETPROVIDERTYPESCOUNT','CRYPTO_GETPROVIDERSCOUNT','CRYPTO_GETDEFAULTPROVIDER','CRYPTO_GENRANDOMSTRING','CRYPTO_ENUMPROVIDERTYPES','CRYPTO_ENUMPROVIDERS','CRYPTO_ENCRYPT', + 'CRYPTO_DECRYPT','CREATEFONT','COTH','COTAN','COSH','COS','CONTROL_SETTEXT','CONTROL_GETTEXT', + 'CONTROL_GETNUMBER','CONTROL','CONST','CONSOLE_WRITELINE','CONSOLE_WRITE','CONSOLE_WAITKEY','CONSOLE_SHOWWINDOW','CONSOLE_SHOWCURSOR', + 'CONSOLE_SETTITLE','CONSOLE_SETTEXTATTRIBUTE','CONSOLE_SETSTDHANDLE','CONSOLE_SETSCREENBUFFERSIZE','CONSOLE_SETPROGRESSBARCHAR','CONSOLE_SETOUTPUTMODE','CONSOLE_SETOUTPUTCP','CONSOLE_SETINPUTMODE', + 'CONSOLE_SETFILEAPISTOOEM','CONSOLE_SETFILEAPISTOANSI','CONSOLE_SETCURSORSIZE','CONSOLE_SETCURSORPOSITION','CONSOLE_SETCP','CONSOLE_SETACTIVESCREENBUFFER','CONSOLE_SCROLLWINDOW','CONSOLE_SCROLLBUFFERONEROW', + 'CONSOLE_SCROLLBUFFER','CONSOLE_SAVESCREEN','CONSOLE_RESTORESCREEN','CONSOLE_READLINE','CONSOLE_READ','CONSOLE_PROGRESSBAR','CONSOLE_PRINTLINE','CONSOLE_PRINTAT', + 'CONSOLE_PRINT','CONSOLE_NORMALSCREEN','CONSOLE_LINE','CONSOLE_INKEYB','CONSOLE_INKEY','CONSOLE_HIDECURSOR','CONSOLE_GETTITLE','CONSOLE_GETTEXTATTRIBUTE', + 'CONSOLE_GETSTDHANDLE','CONSOLE_GETSIZEY','CONSOLE_GETSIZEX','CONSOLE_GETPROGRESSBARCHAR','CONSOLE_GETOUTPUTMODE','CONSOLE_GETOUTPUTCP','CONSOLE_GETNUMBEROFMOUSEBUTTONS','CONSOLE_GETINPUTMODE', + 'CONSOLE_GETCURSORY','CONSOLE_GETCURSORX','CONSOLE_GETCURSORSIZE','CONSOLE_GETCURRENTFONTINDEX','CONSOLE_GETCP','CONSOLE_GENERATECTRLEVENT','CONSOLE_FULLSCREEN','CONSOLE_FREE', + 'CONSOLE_FOREGROUNDRGB','CONSOLE_ENABLECTRLC','CONSOLE_DISABLECTRLC','CONSOLE_CREATESCREENBUFFER','CONSOLE_COLORAT','CONSOLE_CLS','CONSOLE_BOX','CONSOLE_BACKGROUNDRGB', + 'CONSOLE_ATTACH','CONSOLE_AREFILEAPISANSI','CONSOLE_ALLOC','COM_VARIANTINIT','COM_VARIANTCOPY','COM_VARIANTCLEAR','COM_SUCCEEDED','COM_STRINGFROMCLSID', + 'COM_RELEASE','COM_QUERYINTERFACE','COM_PROGIDFROMCLSID','COM_ISEQUALIID','COM_ISEQUALGUID','COM_ISEQUALCLSID','COM_GETOBJECT','COM_GETENGINEGUID', + 'COM_EXECUTE','COM_DISPLAYERROR','COM_CREATEOBJECT','COM_CLSIDFROMSTRING','COM_CLSIDFROMPROGID','COM_BUILDVARIANT','COMBOBOX','COMBINATIONS', + 'COLOR','CLIPBOARD_SETTEXT','CLIPBOARD_GETTEXT','CLIENT','CLEARMESSAGES','CHR$','CHOOSE$','CHOOSE', + 'CHECKBOX','CHECK3STATE','CHECK','CGI_WRITELOGFILE','CGI_WRITE','CGI_URLDECODESTRING','CGI_UPLOADFILESTIME','CGI_UPLOADFILESNUMBER', + 'CGI_UPLOADFILESIZE','CGI_STARTSESSION','CGI_SETSESSIONVARIABLE','CGI_RESETDEFAULTSETTINGS','CGI_REMOVESPECIALCHARSPREFIX','CGI_REMOVEQUOTE','CGI_READ','CGI_LOADCONFIGFILE', + 'CGI_HEADER','CGI_GETSESSIONVARIABLE','CGI_GETREQUESTMETHOD','CGI_GETQUERYVALUE','CGI_GETCURRENTSESSION','CGI_GETCURRENTGUID','CGI_ENVIRON','CGI_CFGSETOPTION', + 'CGI_CFGGETOPTION','CGI_ADDSPECIALCHARSPREFIX','CGI_ADDQUOTE','CEIL','CASE','CALL','BYVAL','BYTE', + 'BYREF','BYCMD','BUTTON','BUNDLE_SETSCRIPTPARAMETERS','BUNDLE_SETSCRIPTNAME','BUNDLE_SETFLAGOBFUSCATEMAINSCRIPT','BUNDLE_SETFLAGDELETEAFTERRUN','BUNDLE_SETFLAGCOMPRESSALLFILES', + 'BUNDLE_SETFLAGASKBEFOREEXTRACT','BUNDLE_SETEXTRACTIONFOLDER','BUNDLE_SETCREATIONFOLDER','BUNDLE_SETBUNDLENAME','BUNDLE_RESET','BUNDLE_MAKE','BUNDLE_BUILDER','BUNDLE_ADDFOLDER', + 'BUNDLE_ADDFILE','BOUNDCHECK','BIN$','BIFF_WRITETEXT','BIFF_WRITENUMBER','BIFF_WRITEDATE','BIFF_SETROWHEIGHT','BIFF_SETCOLWIDTH', + 'BIFF_SETBUFFER','BIFF_CREATEFILE','BIFF_CLOSEFILE','BETWEEN','BEEP','BAR','ATTACH','ATN', + 'AT','ASSIGN','ASCIZ','ASCIIZ','ASCII2UNICODE','ASCENDING','ASCEND','ASC', + 'AS','ARRAY','ARCTANH','ARCSINH','ARCSIN','ARCSECH','ARCSEC','ARCCSCH', + 'ARCCSC','ARCCOTH','ARCCOT','ARCCOSH','ARCCOS','APP_TIMER','APP_SOURCEPATH','APP_SOURCENAME', + 'APP_SOURCEFULLNAME','APP_PATH','APP_NAME','APP_LISTVARIABLES','APP_LISTKEYWORDS','APP_LISTFUNCTIONS','APP_LISTEQUATES','APP_INCLUDEPATH', + 'APP_GETMODULEFULLPATH','APP_COUNTER','APPEND','ANY','ANIMATE_STOP','ANIMATE_PLAY','ANIMATE_OPEN','AND', + 'ALIAS','ALERT','ADD','ACODE$','ABS','%DEF','#MINVERSION','#IF', + '#ENDIF','#ELSEIF','#ELSE','#DEFAULT','#DEF','SQLWRITEPRIVATEPROFILESTRING','SQLWRITEFILEDSN','SQLWRITEDSNTOINI', + 'SQLVALIDDSN','SQLTRANSACT','SQLTABLES','SQLTABLEPRIVILEGES','SQLSTATISTICS','SQLSPECIALCOLUMNS','SQLSETSTMTOPTION','SQLSETSTMTATTR', + 'SQLSETSCROLLOPTIONS','SQLSETPOS','SQLSETPARAM','SQLSETENVATTR','SQLSETDESCREC','SQLSETDESCFIELD','SQLSETCURSORNAME','SQLSETCONNECTOPTION', + 'SQLSETCONNECTATTR','SQLSETCONFIGMODE','SQLROWCOUNT','SQLREMOVETRANSLATOR','SQLREMOVEDSNFROMINI','SQLREMOVEDRIVERMANAGER','SQLREMOVEDRIVER','SQLREADFILEDSN', + 'SQLPUTDATA','SQLPROCEDURES','SQLPROCEDURECOLUMNS','SQLPRIMARYKEYS','SQLPREPARE','SQLPOSTINSTALLERERROR','SQLPARAMOPTIONS','SQLPARAMDATA', + 'SQLNUMRESULTCOLS','SQLNUMPARAMS','SQLNATIVESQL','SQLMORERESULTS','SQLMANAGEDATASOURCES','SQLINSTALLTRANSLATOREX','SQLINSTALLERERROR','SQLINSTALLDRIVERMANAGER', + 'SQLINSTALLDRIVEREX','SQLGETTYPEINFO','SQLGETTRANSLATOR','SQLGETSTMTOPTION','SQLGETSTMTATTR','SQLGETPRIVATEPROFILESTRING','SQLGETINSTALLEDDRIVERS','SQLGETINFO', + 'SQLGETFUNCTIONS','SQLGETENVATTR','SQLGETDIAGREC','SQLGETDIAGFIELD','SQLGETDESCREC','SQLGETDESCFIELD','SQLGETDATA','SQLGETCURSORNAME', + 'SQLGETCONNECTOPTION','SQLGETCONNECTATTR','SQLGETCONFIGMODE','SQLFREESTMT','SQLFREEHANDLE','SQLFREEENV','SQLFREECONNECT','SQLFOREIGNKEYS', + 'SQLFETCHSCROLL','SQLFETCH','SQLEXTENDEDFETCH','SQLEXECUTE','SQLEXECDIRECT','SQLERROR','SQLENDTRAN','SQLDRIVERS', + 'SQLDRIVERCONNECT','SQLDISCONNECT','SQLDESCRIBEPARAM','SQLDESCRIBECOL','SQLDATASOURCES','SQLCREATEDATASOURCE','SQLCOPYDESC','SQLCONNECT', + 'SQLCONFIGDRIVER','SQLCONFIGDATASOURCE','SQLCOLUMNS','SQLCOLUMNPRIVILEGES','SQLCOLATTRIBUTES','SQLCOLATTRIBUTE','SQLCLOSECURSOR','SQLCANCEL', + 'SQLBULKOPERATIONS','SQLBROWSECONNECT','SQLBINDPARAMETER','SQLBINDPARAM','SQLBINDCOL','SQLALLOCSTMT','SQLALLOCHANDLE','SQLALLOCENV', + 'SQLALLOCCONNECT','ODBCWRONGDRIVER','ODBCWRITEPRIVATEPROFILESTRING','ODBCWRITEFILEDSN','ODBCWRITEDSNTOINI','ODBCVALIDDSN','ODBCUPDATERECORD','ODBCUPDATEBYBOOKMARK', + 'ODBCUNLOCKRECORD','ODBCUNBINDCOLUMNS','ODBCUNBINDCOL','ODBCTABLESCOUNT','ODBCTABLES','ODBCTABLEPRIVILEGESCOUNT','ODBCTABLEPRIVILEGES','ODBCSUPPORTS', + 'ODBCSTATTABLESCHEMANAME','ODBCSTATTABLEPAGES','ODBCSTATTABLECATALOGNAME','ODBCSTATTABLECARDINALITY','ODBCSTATISTICSCOUNT','ODBCSTATISTICS','ODBCSTATINDEXSORTSEQUENCE','ODBCSTATINDEXSCHEMANAME', + 'ODBCSTATINDEXQUALIFIER','ODBCSTATINDEXPAGES','ODBCSTATINDEXFILTERCONDITION','ODBCSTATINDEXCOLUMNORDINALPOSITION','ODBCSTATINDEXCOLUMNNAME','ODBCSTATINDEXCATALOGNAME','ODBCSTATINDEXCARDINALITY','ODBCSTATINDEXALLOWDUPLICATES', + 'ODBCSPECIALCOLUMNSCOUNT','ODBCSPECIALCOLUMNS','ODBCSETTXNISOLATION','ODBCSETTRANSLATELIB','ODBCSETTRACEFILE','ODBCSETTRACE','ODBCSETSTMTUSEBOOKMARKS','ODBCSETSTMTSIMULATECURSOR', + 'ODBCSETSTMTROWSTATUSPTR','ODBCSETSTMTROWSFETCHEDPTR','ODBCSETSTMTROWOPERATIONPTR','ODBCSETSTMTROWBINDTYPE','ODBCSETSTMTROWBINDOFFSETPTR','ODBCSETSTMTROWARRAYSIZE','ODBCSETSTMTRETRIEVEDATA','ODBCSETSTMTQUERYTIMEOUT', + 'ODBCSETSTMTPARAMSTATUSPTR','ODBCSETSTMTPARAMSPROCESSEDPTR','ODBCSETSTMTPARAMSETSIZE','ODBCSETSTMTPARAMOPERATIONPTR','ODBCSETSTMTPARAMBINDTYPE','ODBCSETSTMTPARAMBINDOFFSETPTR','ODBCSETSTMTNOSCAN','ODBCSETSTMTMETADATAID', + 'ODBCSETSTMTMAXROWS','ODBCSETSTMTMAXLENGTH','ODBCSETSTMTKEYSETSIZE','ODBCSETSTMTFETCHBOOKMARKPTR','ODBCSETSTMTENABLEAUTOIPD','ODBCSETSTMTCURSORTYPE','ODBCSETSTMTCURSORSENSITIVITY','ODBCSETSTMTCURSORSCROLLABLE', + 'ODBCSETSTMTCONCURRENCY','ODBCSETSTMTATTR','ODBCSETSTMTASYNCENABLE','ODBCSETSTMTAPPROWDESC','ODBCSETSTMTAPPPARAMDESC','ODBCSETSTATICCURSOR','ODBCSETROWVERCONCURRENCY','ODBCSETRESULT', + 'ODBCSETRELATIVEPOSITION','ODBCSETREADONLYCONCURRENCY','ODBCSETQUIETMODE','ODBCSETPOSITION','ODBCSETPOS','ODBCSETPACKETMODE','ODBCSETOPTIMISTICCONCURRENCY','ODBCSETODBCCURSORS', + 'ODBCSETMULTIUSERKEYSETCURSOR','ODBCSETMETADATAID','ODBCSETLOGINTIMEOUT','ODBCSETLOCKCONCURRENCY','ODBCSETKEYSETDRIVENCURSOR','ODBCSETFORWARDONLYCURSOR','ODBCSETENVOUTPUTNTS','ODBCSETENVODBCVERSION', + 'ODBCSETENVCPMATCH','ODBCSETENVCONNECTIONPOOLING','ODBCSETENVATTR','ODBCSETDYNAMICCURSOR','ODBCSETDESCREC','ODBCSETDESCFIELD','ODBCSETCURSORTYPE','ODBCSETCURSORSENSITIVITY', + 'ODBCSETCURSORSCROLLABILITY','ODBCSETCURSORNAME','ODBCSETCURSORLOCKTYPE','ODBCSETCURSORKEYSETSIZE','ODBCSETCURSORCONCURRENCY','ODBCSETCURRENTCATALOG','ODBCSETCONNECTIONTIMEOUT','ODBCSETCONNECTATTR', + 'ODBCSETCONFIGMODE','ODBCSETCONCURVALUESCONCURRENCY','ODBCSETAUTOCOMMITON','ODBCSETAUTOCOMMITOFF','ODBCSETAUTOCOMMIT','ODBCSETASYNCENABLE','ODBCSETACCESSMODE','ODBCSETABSOLUTEPOSITION', + 'ODBCROWCOUNT','ODBCROLLBACKTRAN','ODBCROLLBACKENVTRAN','ODBCROLLBACKDBCTRAN','ODBCRESULT','ODBCRESETPARAMS','ODBCREMOVETRANSLATOR','ODBCREMOVEDSNFROMINI', + 'ODBCREMOVEDRIVERMANAGER','ODBCREMOVEDRIVER','ODBCREFRESHRECORD','ODBCRECORDCOUNT','ODBCREADFILEDSN','ODBCQUOTEDIDENTIFIERCASE','ODBCPUTDATA','ODBCPROCEDURESCOUNT', + 'ODBCPROCEDURES','ODBCPROCEDURECOLUMNSCOUNT','ODBCPROCEDURECOLUMNS','ODBCPRIMARYKEYSCOUNT','ODBCPRIMARYKEYS','ODBCPREPARE','ODBCPOSTINSTALLERERROR','ODBCPARAMDATA', + 'ODBCOPENSTMT','ODBCOPENCONNECTION','ODBCNUMRESULTCOLS','ODBCNUMPARAMS','ODBCNATIVESQL','ODBCMOVEPREVIOUS','ODBCMOVENEXT','ODBCMOVELAST', + 'ODBCMOVEFIRST','ODBCMOVE','ODBCMORERESULTS','ODBCMANAGEDATASOURCES','ODBCLOCKRECORD','ODBCINSTALLTRANSLATOREX','ODBCINSTALLERERROR','ODBCINSTALLDRIVERMANAGER', + 'ODBCINSTALLDRIVEREX','ODBCGETXOPENCLIYEAR','ODBCGETUSERNAME','ODBCGETUNION','ODBCGETTYPEINFOCOUNT','ODBCGETTYPEINFO','ODBCGETTXNISOLATIONOPTION','ODBCGETTXNISOLATION', + 'ODBCGETTXNCAPABLE','ODBCGETTRANSLATOR','ODBCGETTRANSLATELIB','ODBCGETTRACEFILE','ODBCGETTRACE','ODBCGETTIMEDATEFUNCTIONS','ODBCGETTIMEDATEDIFFINTERVALS','ODBCGETTIMEDATEADDINTERVALS', + 'ODBCGETTABLETERM','ODBCGETSYSTEMFUNCTIONS','ODBCGETSUBQUERIES','ODBCGETSTRINGFUNCTIONS','ODBCGETSTMTUSEBOOKMARKS','ODBCGETSTMTSQLSTATE','ODBCGETSTMTSIMULATECURSOR','ODBCGETSTMTROWSTATUSPTR', + 'ODBCGETSTMTROWSFETCHEDPTR','ODBCGETSTMTROWOPERATIONPTR','ODBCGETSTMTROWNUMBER','ODBCGETSTMTROWBINDTYPE','ODBCGETSTMTROWBINDOFFSETPTR','ODBCGETSTMTROWARRAYSIZE','ODBCGETSTMTRETRIEVEDATA','ODBCGETSTMTQUERYTIMEOUT', + 'ODBCGETSTMTPARAMSTATUSPTR','ODBCGETSTMTPARAMSPROCESSEDPTR','ODBCGETSTMTPARAMSETSIZE','ODBCGETSTMTPARAMOPERATIONPTR','ODBCGETSTMTPARAMBINDTYPE','ODBCGETSTMTPARAMBINDOFFSETPTR','ODBCGETSTMTNOSCAN','ODBCGETSTMTMETADATAID', + 'ODBCGETSTMTMAXROWS','ODBCGETSTMTMAXLENGTH','ODBCGETSTMTKEYSETSIZE','ODBCGETSTMTIMPROWDESC','ODBCGETSTMTIMPPARAMDESC','ODBCGETSTMTFETCHBOOKMARKPTR','ODBCGETSTMTERRORINFO','ODBCGETSTMTENABLEAUTOIPD', + 'ODBCGETSTMTCURSORTYPE','ODBCGETSTMTCURSORSENSITIVITY','ODBCGETSTMTCURSORSCROLLABLE','ODBCGETSTMTCONCURRENCY','ODBCGETSTMTATTR','ODBCGETSTMTASYNCENABLE','ODBCGETSTMTAPPROWDESC','ODBCGETSTMTAPPPARAMDESC', + 'ODBCGETSTATICCURSORATTRIBUTES2','ODBCGETSTATICCURSORATTRIBUTES1','ODBCGETSTATEMENTSQLSTATE','ODBCGETSTATEMENTERRORINFO','ODBCGETSTANDARDCLICONFORMANCE','ODBCGETSQLSTATE','ODBCGETSQLCONFORMANCE','ODBCGETSQL92VALUEEXPRESSIONS', + 'ODBCGETSQL92STRINGFUNCTIONS','ODBCGETSQL92ROWVALUECONSTRUCTOR','ODBCGETSQL92REVOKE','ODBCGETSQL92RELATIONALJOINOPERATORS','ODBCGETSQL92PREDICATES','ODBCGETSQL92NUMERICVALUEFUNCTIONS','ODBCGETSQL92GRANT','ODBCGETSQL92FOREIGNKEYUPDATERULE', + 'ODBCGETSQL92FOREIGNKEYDELETERULE','ODBCGETSQL92DATETIMEFUNCTIONS','ODBCGETSPECIALCHARACTERS','ODBCGETSERVERNAME','ODBCGETSEARCHPATTERNESCAPE','ODBCGETSCROLLOPTIONS','ODBCGETSCHEMAUSAGE','ODBCGETSCHEMATERM', + 'ODBCGETROWUPDATES','ODBCGETQUIETMODE','ODBCGETPROCEDURETERM','ODBCGETPROCEDURESSUPPORT','ODBCGETPRIVATEPROFILESTRING','ODBCGETPOSOPERATIONS','ODBCGETPARAMARRAYSELECTS','ODBCGETPARAMARRAYROWCOUNTS', + 'ODBCGETPACKETMODE','ODBCGETOUTERJOINS','ODBCGETORDERBYCOLUMNSINSELECT','ODBCGETOJCAPABILITIES','ODBCGETODBCVER','ODBCGETODBCINTERFACECONFORMANCE','ODBCGETODBCCURSORS','ODBCGETNUMERICFUNCTIONS', + 'ODBCGETNULLCOLLATION','ODBCGETNONNULLABLECOLUMNS','ODBCGETNEEDLONGDATALEN','ODBCGETMULTRESULTSETS','ODBCGETMULTIPLEACTIVETXN','ODBCGETMETADATAID','ODBCGETMAXUSERNAMELEN','ODBCGETMAXTABLESINSELECT', + 'ODBCGETMAXTABLENAMELEN','ODBCGETMAXSTATEMENTLEN','ODBCGETMAXSCHEMANAMELEN','ODBCGETMAXROWSIZEINCLUDESLONG','ODBCGETMAXROWSIZE','ODBCGETMAXPROCEDURENAMELEN','ODBCGETMAXINDEXSIZE','ODBCGETMAXIDENTIFIERLEN', + 'ODBCGETMAXDRIVERCONNECTIONS','ODBCGETMAXCURSORNAMELEN','ODBCGETMAXCONCURRENTACTIVITIES','ODBCGETMAXCOLUMNSINTABLE','ODBCGETMAXCOLUMNSINSELECT','ODBCGETMAXCOLUMNSINORDERBY','ODBCGETMAXCOLUMNSININDEX','ODBCGETMAXCOLUMNSINGROUPBY', + 'ODBCGETMAXCOLUMNNAMELEN','ODBCGETMAXCHARLITERALLEN','ODBCGETMAXCATALOGNAMELEN','ODBCGETMAXBINARYLITERALLEN','ODBCGETMAXASYNCCONCURRENTSTATEMENTS','ODBCGETLONGVARCHARDATABYCOLNAME','ODBCGETLONGVARCHARDATA','ODBCGETLOGINTIMEOUT', + 'ODBCGETLIKEESCAPECLAUSE','ODBCGETKEYWORDS','ODBCGETKEYSETCURSORATTRIBUTES2','ODBCGETKEYSETCURSORATTRIBUTES1','ODBCGETINTEGRITY','ODBCGETINSTALLERERRORMESSAGE','ODBCGETINSTALLERERRORCODE','ODBCGETINSTALLEDDRIVERS', + 'ODBCGETINSERTSTATEMENT','ODBCGETINFOSTR','ODBCGETINFOSCHEMAVIEWS','ODBCGETINFOLONG','ODBCGETINFOINT','ODBCGETINFO','ODBCGETINDEXKEYWORDS','ODBCGETIMPROWDESCREC', + 'ODBCGETIMPROWDESCFIELDTYPE','ODBCGETIMPROWDESCFIELDSCALE','ODBCGETIMPROWDESCFIELDPRECISION','ODBCGETIMPROWDESCFIELDOCTETLENGTH','ODBCGETIMPROWDESCFIELDNULLABLE','ODBCGETIMPROWDESCFIELDNAME','ODBCGETIMPROWDESCFIELD','ODBCGETIMPPARAMDESCREC', + 'ODBCGETIMPPARAMDESCFIELDTYPE','ODBCGETIMPPARAMDESCFIELDSCALE','ODBCGETIMPPARAMDESCFIELDPRECISION','ODBCGETIMPPARAMDESCFIELDOCTETLENGTH','ODBCGETIMPPARAMDESCFIELDNULLABLE','ODBCGETIMPPARAMDESCFIELDNAME','ODBCGETIMPPARAMDESCFIELD','ODBCGETIDENTIFIERQUOTECHAR', + 'ODBCGETIDENTIFIERCASE','ODBCGETGROUPBY','ODBCGETFUNCTIONS','ODBCGETFORWARDONLYCURSORATTRIBUTES2','ODBCGETFORWARDONLYCURSORATTRIBUTES1','ODBCGETFILEUSAGE','ODBCGETEXPRESSIONSINORDERBY','ODBCGETERRORINFO', + 'ODBCGETENVSQLSTATE','ODBCGETENVOUTPUTNTS','ODBCGETENVODBCVERSION','ODBCGETENVIRONMENTSQLSTATE','ODBCGETENVIRONMENTERRORINFO','ODBCGETENVERRORINFO','ODBCGETENVCPMATCH','ODBCGETENVCONNECTIONPOOLING', + 'ODBCGETENVATTR','ODBCGETDYNAMICCURSORATTRIBUTES2','ODBCGETDYNAMICCURSORATTRIBUTES1','ODBCGETDROPVIEW','ODBCGETDROPTRANSLATION','ODBCGETDROPTABLE','ODBCGETDROPSCHEMA','ODBCGETDROPDOMAIN', + 'ODBCGETDROPCOLLATION','ODBCGETDROPCHARACTERSET','ODBCGETDROPASSERTION','ODBCGETDRIVERVER','ODBCGETDRIVERODBCVER','ODBCGETDRIVERNAME','ODBCGETDRIVERMANAGERINSTALLPATH','ODBCGETDRIVERHLIB', + 'ODBCGETDRIVERHENV','ODBCGETDRIVERHDBC','ODBCGETDMVERMINOR','ODBCGETDMVERMAJOR','ODBCGETDMVER','ODBCGETDIAGREC','ODBCGETDIAGFIELD','ODBCGETDESCSQLSTATE', + 'ODBCGETDESCRIPTORSQLSTATE','ODBCGETDESCRIPTORERRORINFO','ODBCGETDESCRIBEPARAMETER','ODBCGETDESCREC','ODBCGETDESCFIELD','ODBCGETDESCERRORINFO','ODBCGETDEFAULTTXNISOLATION','ODBCGETDDLINDEX', + 'ODBCGETDBMSVER','ODBCGETDBMSNAME','ODBCGETDBCSQLSTATE','ODBCGETDBCERRORINFO','ODBCGETDATETIMELITERALS','ODBCGETDATASTRINGBYCOLNAME','ODBCGETDATASTRING','ODBCGETDATASOURCEREADONLY', + 'ODBCGETDATASOURCENAME','ODBCGETDATAEXTENSIONS','ODBCGETDATABASENAME','ODBCGETDATA','ODBCGETCURSORTYPE','ODBCGETCURSORSENSITIVITYSUPPORT','ODBCGETCURSORSENSITIVITY','ODBCGETCURSORSCROLLABILITY', + 'ODBCGETCURSORROLLBACKBEHAVIOR','ODBCGETCURSORNAME','ODBCGETCURSORLOCKTYPE','ODBCGETCURSORKEYSETSIZE','ODBCGETCURSORCONCURRENCY','ODBCGETCURSORCOMMITBEHAVIOR','ODBCGETCURRENTCATALOG','ODBCGETCREATEVIEW', + 'ODBCGETCREATETRANSLATION','ODBCGETCREATETABLE','ODBCGETCREATESCHEMA','ODBCGETCREATEDOMAIN','ODBCGETCREATECOLLATION','ODBCGETCREATECHARACTERSET','ODBCGETCREATEASSERTION','ODBCGETCORRELATIONNAME', + 'ODBCGETCONVERTVARCHAR','ODBCGETCONVERTVARBINARY','ODBCGETCONVERTTINYINT','ODBCGETCONVERTTIMESTAMP','ODBCGETCONVERTTIME','ODBCGETCONVERTSMALLINT','ODBCGETCONVERTREAL','ODBCGETCONVERTNUMERIC', + 'ODBCGETCONVERTLONGVARCHAR','ODBCGETCONVERTLONGVARBINARY','ODBCGETCONVERTINTERVALYEARMONTH','ODBCGETCONVERTINTERVALDAYTIME','ODBCGETCONVERTINTEGER','ODBCGETCONVERTFUNCTIONS','ODBCGETCONVERTFLOAT','ODBCGETCONVERTDOUBLE', + 'ODBCGETCONVERTDECIMAL','ODBCGETCONVERTDATE','ODBCGETCONVERTCHAR','ODBCGETCONVERTBIT','ODBCGETCONVERTBINARY','ODBCGETCONVERTBIGINT','ODBCGETCONNECTIONTIMEOUT','ODBCGETCONNECTIONSQLSTATE', + 'ODBCGETCONNECTIONERRORINFO','ODBCGETCONNECTIONDEAD','ODBCGETCONNECTATTR','ODBCGETCONFIGMODE','ODBCGETCONCATNULLBEHAVIOR','ODBCGETCOLUMNALIAS','ODBCGETCOLLATIONSEQ','ODBCGETCATALOGUSAGE', + 'ODBCGETCATALOGTERM','ODBCGETCATALOGNAMESEPARATOR','ODBCGETCATALOGNAME','ODBCGETCATALOGLOCATION','ODBCGETBOOKMARKPERSISTENCE','ODBCGETBATCHSUPPORT','ODBCGETBATCHROWCOUNT','ODBCGETAUTOIPD', + 'ODBCGETAUTOCOMMIT','ODBCGETASYNCMODE','ODBCGETASYNCENABLE','ODBCGETALTERTABLE','ODBCGETALTERDOMAIN','ODBCGETAGGREGATEFUNCTIONS','ODBCGETACTIVEENVIRONMENTS','ODBCGETACCESSMODE', + 'ODBCGETACCESSIBLETABLES','ODBCGETACCESSIBLEPROCEDURES','ODBCFREESTMT','ODBCFREEHANDLE','ODBCFREEENV','ODBCFREEDESC','ODBCFREEDBC','ODBCFREECONNECT', + 'ODBCFOREIGNKEYSCOUNT','ODBCFOREIGNKEYS','ODBCFETCHSCROLL','ODBCFETCHBYBOOKMARK','ODBCFETCH','ODBCEXTENDEDFETCH','ODBCEXECUTE','ODBCEXECDIRECT', + 'ODBCERROR','ODBCEOF','ODBCENDTRAN','ODBCDRIVERSCOUNT','ODBCDRIVERS','ODBCDRIVERCONNECT','ODBCDISCONNECT','ODBCDESCRIBEPARAM', + 'ODBCDESCRIBECOL','ODBCDELETERECORD','ODBCDELETEBYBOOKMARK','ODBCDATASOURCES','ODBCCREATEDATASOURCE','ODBCCOPYDESC','ODBCCONNECTIONISDEAD','ODBCCONNECTIONISALIVE', + 'ODBCCONNECT','ODBCCONFIGDRIVER','ODBCCONFIGDATASOURCE','ODBCCOMMITTRAN','ODBCCOMMITENVTRAN','ODBCCOMMITDBCTRAN','ODBCCOLUPDATABLE','ODBCCOLUNSIGNED', + 'ODBCCOLUNNAMED','ODBCCOLUMNSCOUNT','ODBCCOLUMNS','ODBCCOLUMNPRIVILEGESCOUNT','ODBCCOLUMNPRIVILEGES','ODBCCOLUMN','ODBCCOLTYPENAME','ODBCCOLTYPE', + 'ODBCCOLTABLENAME','ODBCCOLSEARCHABLE','ODBCCOLSCHEMANAME','ODBCCOLSCALE','ODBCCOLPRECISION','ODBCCOLOCTETLENGTH','ODBCCOLNUMPRECRADIX','ODBCCOLNULLABLE', + 'ODBCCOLNAME','ODBCCOLLOCALTYPENAME','ODBCCOLLITERALSUFFIX','ODBCCOLLITERALPREFIX','ODBCCOLLENGTH','ODBCCOLLABEL','ODBCCOLISNULL','ODBCCOLFIXEDPRECSCALE', + 'ODBCCOLDISPLAYSIZE','ODBCCOLCOUNT','ODBCCOLCONCISETYPE','ODBCCOLCATALOGNAME','ODBCCOLCASESENSITIVE','ODBCCOLBASETABLENAME','ODBCCOLBASECOLUMNNAME','ODBCCOLAUTOUNIQUEVALUE', + 'ODBCCOLATTRIBUTE','ODBCCLOSESTMTCURSOR','ODBCCLOSESTMT','ODBCCLOSECURSOR','ODBCCLOSECONNECTION','ODBCCLEARRESULT','ODBCCANCEL','ODBCBULKOPERATIONS', + 'ODBCBROWSECONNECT','ODBCBINDPARAMETER','ODBCBINDCOLTOWORD','ODBCBINDCOLTOTIMESTAMP','ODBCBINDCOLTOTIME','ODBCBINDCOLTOSTRING','ODBCBINDCOLTOSINGLE','ODBCBINDCOLTOQUAD', + 'ODBCBINDCOLTONUMERIC','ODBCBINDCOLTOLONG','ODBCBINDCOLTOINTEGER','ODBCBINDCOLTODWORD','ODBCBINDCOLTODOUBLE','ODBCBINDCOLTODECIMAL','ODBCBINDCOLTODATE','ODBCBINDCOLTOCURRENCY', + 'ODBCBINDCOLTOBYTE','ODBCBINDCOLTOBIT','ODBCBINDCOLTOBINARY','ODBCBINDCOL','ODBCALLOCSTMT','ODBCALLOCHANDLE','ODBCALLOCENV','ODBCALLOCDESC', + 'ODBCALLOCDBC','ODBCALLOCCONNECT','ODBCADDRECORD','GLVIEWPORT','GLVERTEXPOINTER','GLVERTEX4SV','GLVERTEX4S','GLVERTEX4IV', + 'GLVERTEX4I','GLVERTEX4FV','GLVERTEX4F','GLVERTEX4DV','GLVERTEX4D','GLVERTEX3SV','GLVERTEX3S','GLVERTEX3IV', + 'GLVERTEX3I','GLVERTEX3FV','GLVERTEX3F','GLVERTEX3DV','GLVERTEX3D','GLVERTEX2SV','GLVERTEX2S','GLVERTEX2IV', + 'GLVERTEX2I','GLVERTEX2FV','GLVERTEX2F','GLVERTEX2DV','GLVERTEX2D','GLUUNPROJECT','GLUTESSVERTEX','GLUTESSPROPERTY', + 'GLUTESSNORMAL','GLUTESSENDPOLYGON','GLUTESSENDCONTOUR','GLUTESSCALLBACK','GLUTESSBEGINPOLYGON','GLUTESSBEGINCONTOUR','GLUSPHERE','GLUSCALEIMAGE', + 'GLUQUADRICTEXTURE','GLUQUADRICORIENTATION','GLUQUADRICNORMALS','GLUQUADRICDRAWSTYLE','GLUQUADRICCALLBACK','GLUPWLCURVE','GLUPROJECT','GLUPICKMATRIX', + 'GLUPERSPECTIVE','GLUPARTIALDISK','GLUORTHO2D','GLUNURBSSURFACE','GLUNURBSPROPERTY','GLUNURBSCURVE','GLUNURBSCALLBACK','GLUNEXTCONTOUR', + 'GLUNEWTESS','GLUNEWQUADRIC','GLUNEWNURBSRENDERER','GLULOOKAT','GLULOADSAMPLINGMATRICES','GLUGETTESSPROPERTY','GLUGETSTRING','GLUGETNURBSPROPERTY', + 'GLUERRORSTRING','GLUENDTRIM','GLUENDSURFACE','GLUENDPOLYGON','GLUENDCURVE','GLUDISK','GLUDELETETESS','GLUDELETEQUADRIC', + 'GLUDELETENURBSRENDERER','GLUCYLINDER','GLUBUILD2DMIPMAPS','GLUBUILD1DMIPMAPS','GLUBEGINTRIM','GLUBEGINSURFACE','GLUBEGINPOLYGON','GLUBEGINCURVE', + 'GLTRANSLATEF','GLTRANSLATED','GLTEXSUBIMAGE2D','GLTEXSUBIMAGE1D','GLTEXPARAMETERIV','GLTEXPARAMETERI','GLTEXPARAMETERFV','GLTEXPARAMETERF', + 'GLTEXIMAGE2D','GLTEXIMAGE1D','GLTEXGENIV','GLTEXGENI','GLTEXGENFV','GLTEXGENF','GLTEXGENDV','GLTEXGEND', + 'GLTEXENVIV','GLTEXENVI','GLTEXENVFV','GLTEXENVF','GLTEXCOORDPOINTER','GLTEXCOORD4SV','GLTEXCOORD4S','GLTEXCOORD4IV', + 'GLTEXCOORD4I','GLTEXCOORD4FV','GLTEXCOORD4F','GLTEXCOORD4DV','GLTEXCOORD4D','GLTEXCOORD3SV','GLTEXCOORD3S','GLTEXCOORD3IV', + 'GLTEXCOORD3I','GLTEXCOORD3FV','GLTEXCOORD3F','GLTEXCOORD3DV','GLTEXCOORD3D','GLTEXCOORD2SV','GLTEXCOORD2S','GLTEXCOORD2IV', + 'GLTEXCOORD2I','GLTEXCOORD2FV','GLTEXCOORD2F','GLTEXCOORD2DV','GLTEXCOORD2D','GLTEXCOORD1SV','GLTEXCOORD1S','GLTEXCOORD1IV', + 'GLTEXCOORD1I','GLTEXCOORD1FV','GLTEXCOORD1F','GLTEXCOORD1DV','GLTEXCOORD1D','GLSTENCILOP','GLSTENCILMASK','GLSTENCILFUNC', + 'GLSHADEMODEL','GLSELECTBUFFER','GLSCISSOR','GLSCALEF','GLSCALED','GLROTATEF','GLROTATED','GLRENDERMODE', + 'GLRECTSV','GLRECTS','GLRECTIV','GLRECTI','GLRECTFV','GLRECTF','GLRECTDV','GLRECTD', + 'GLREADPIXELS','GLREADBUFFER','GLRASTERPOS4SV','GLRASTERPOS4S','GLRASTERPOS4IV','GLRASTERPOS4I','GLRASTERPOS4FV','GLRASTERPOS4F', + 'GLRASTERPOS4DV','GLRASTERPOS4D','GLRASTERPOS3SV','GLRASTERPOS3S','GLRASTERPOS3IV','GLRASTERPOS3I','GLRASTERPOS3FV','GLRASTERPOS3F', + 'GLRASTERPOS3DV','GLRASTERPOS3D','GLRASTERPOS2SV','GLRASTERPOS2S','GLRASTERPOS2IV','GLRASTERPOS2I','GLRASTERPOS2FV','GLRASTERPOS2F', + 'GLRASTERPOS2DV','GLRASTERPOS2D','GLPUSHNAME','GLPUSHMATRIX','GLPUSHCLIENTATTRIB','GLPUSHATTRIB','GLPRIORITIZETEXTURES','GLPOPNAME', + 'GLPOPMATRIX','GLPOPCLIENTATTRIB','GLPOPATTRIB','GLPOLYGONSTIPPLE','GLPOLYGONOFFSET','GLPOLYGONMODE','GLPOINTSIZE','GLPIXELZOOM', + 'GLPIXELTRANSFERI','GLPIXELTRANSFERF','GLPIXELSTOREI','GLPIXELSTOREF','GLPIXELMAPUSV','GLPIXELMAPUIV','GLPIXELMAPFV','GLPASSTHROUGH', + 'GLORTHO','GLNORMALPOINTER','GLNORMAL3SV','GLNORMAL3S','GLNORMAL3IV','GLNORMAL3I','GLNORMAL3FV','GLNORMAL3F', + 'GLNORMAL3DV','GLNORMAL3D','GLNORMAL3BV','GLNORMAL3B','GLNEWLIST','GLMULTMATRIXF','GLMULTMATRIXD','GLMATRIXMODE', + 'GLMATERIALIV','GLMATERIALI','GLMATERIALFV','GLMATERIALF','GLMAPGRID2F','GLMAPGRID2D','GLMAPGRID1F','GLMAPGRID1D', + 'GLMAP2F','GLMAP2D','GLMAP1F','GLMAP1D','GLLOGICOP','GLLOADNAME','GLLOADMATRIXF','GLLOADMATRIXD', + 'GLLOADIDENTITY','GLLISTBASE','GLLINEWIDTH','GLLINESTIPPLE','GLLIGHTMODELIV','GLLIGHTMODELI','GLLIGHTMODELFV','GLLIGHTMODELF', + 'GLLIGHTIV','GLLIGHTI','GLLIGHTFV','GLLIGHTF','GLISTEXTURE','GLISLIST','GLISENABLED','GLINTERLEAVEDARRAYS', + 'GLINITNAMES','GLINDEXUBV','GLINDEXUB','GLINDEXSV','GLINDEXS','GLINDEXPOINTER','GLINDEXMASK','GLINDEXIV', + 'GLINDEXI','GLINDEXFV','GLINDEXF','GLINDEXDV','GLINDEXD','GLHINT','GLGETTEXPARAMETERIV','GLGETTEXPARAMETERFV', + 'GLGETTEXLEVELPARAMETERIV','GLGETTEXLEVELPARAMETERFV','GLGETTEXIMAGE','GLGETTEXGENIV','GLGETTEXGENFV','GLGETTEXGENDV','GLGETTEXENVIV','GLGETTEXENVFV', + 'GLGETSTRING','GLGETPOLYGONSTIPPLE','GLGETPOINTERV','GLGETPIXELMAPUSV','GLGETPIXELMAPUIV','GLGETPIXELMAPFV','GLGETMATERIALIV','GLGETMATERIALFV', + 'GLGETMAPIV','GLGETMAPFV','GLGETMAPDV','GLGETLIGHTIV','GLGETLIGHTFV','GLGETINTEGERV','GLGETFLOATV','GLGETERROR', + 'GLGETDOUBLEV','GLGETCLIPPLANE','GLGETBOOLEANV','GLGENTEXTURES','GLGENLISTS','GLFRUSTUM','GLFRONTFACE','GLFOGIV', + 'GLFOGI','GLFOGFV','GLFOGF','GLFLUSH','GLFINISH','GLFEEDBACKBUFFER','GLEVALPOINT2','GLEVALPOINT1', + 'GLEVALMESH2','GLEVALMESH1','GLEVALCOORD2FV','GLEVALCOORD2F','GLEVALCOORD2DV','GLEVALCOORD2D','GLEVALCOORD1FV','GLEVALCOORD1F', + 'GLEVALCOORD1DV','GLEVALCOORD1D','GLENDLIST','GLEND','GLENABLECLIENTSTATE','GLENABLE','GLEDGEFLAGV','GLEDGEFLAGPOINTER', + 'GLEDGEFLAG','GLDRAWPIXELS','GLDRAWELEMENTS','GLDRAWBUFFER','GLDRAWARRAYS','GLDISABLECLIENTSTATE','GLDISABLE','GLDEPTHRANGE', + 'GLDEPTHMASK','GLDEPTHFUNC','GLDELETETEXTURES','GLDELETELISTS','GLCULLFACE','GLCOPYTEXSUBIMAGE2D','GLCOPYTEXSUBIMAGE1D','GLCOPYTEXIMAGE2D', + 'GLCOPYTEXIMAGE1D','GLCOPYPIXELS','GLCOLORPOINTER','GLCOLORMATERIAL','GLCOLORMASK','GLCOLOR4USV','GLCOLOR4US','GLCOLOR4UIV', + 'GLCOLOR4UI','GLCOLOR4UBV','GLCOLOR4UB','GLCOLOR4SV','GLCOLOR4S','GLCOLOR4IV','GLCOLOR4I','GLCOLOR4FV', + 'GLCOLOR4F','GLCOLOR4DV','GLCOLOR4D','GLCOLOR4BV','GLCOLOR4B','GLCOLOR3USV','GLCOLOR3US','GLCOLOR3UIV', + 'GLCOLOR3UI','GLCOLOR3UBV','GLCOLOR3UB','GLCOLOR3SV','GLCOLOR3S','GLCOLOR3IV','GLCOLOR3I','GLCOLOR3FV', + 'GLCOLOR3F','GLCOLOR3DV','GLCOLOR3D','GLCOLOR3BV','GLCOLOR3B','GLCLIPPLANE','GLCLEARSTENCIL','GLCLEARINDEX', + 'GLCLEARDEPTH','GLCLEARCOLOR','GLCLEARACCUM','GLCLEAR','GLCALLLISTS','GLCALLLIST','GLBLENDFUNC','GLBITMAP', + 'GLBINDTEXTURE','GLBEGIN','GLARRAYELEMENT','GLARETEXTURESRESIDENT','GLALPHAFUNC','GLACCUM'), + 2 => array( + '$BEL','$BS','$CR','$CRLF','$DQ','$DT_DATE_SEPARATOR','$DT_LANGUAGE','$DT_TIME_SEPARATOR', + '$ESC','$FF','$LF','$NUL','$PC_SD_MY_PC','$SPC','$SQL_OPT_TRACE_FILE_DEFAULT','$SQL_SPEC_STRING', + '$TAB','$TRACKBAR_CLASS','$VT','%ACM_OPEN','%ACM_OPENW','%ACM_PLAY','%ACM_STOP','%ACN_START', + '%ACN_STOP','%ACS_AUTOPLAY','%ACS_CENTER','%ACS_TIMER','%ACS_TRANSPARENT','%APP_COUNTER_FUNLOOKUP','%APP_COUNTER_KEYLOOKUP','%APP_COUNTER_LOOKUP', + '%APP_COUNTER_TESTALPHA','%APP_COUNTER_UDTLOOKUP','%APP_COUNTER_VARLOOKUP','%APP_TIMER_EXECTOTAL','%APP_TIMER_INIT','%APP_TIMER_LOAD','%APP_TIMER_PREPROCESSOR','%AW_ACTIVATE', + '%AW_BLEND','%AW_CENTER','%AW_HIDE','%AW_HOR_NEGATIVE','%AW_HOR_POSITIVE','%AW_SLIDE','%AW_VER_NEGATIVE','%AW_VER_POSITIVE', + '%BCM_FIRST','%BLACK','%BLUE','%BM_GETCHECK','%BM_SETCHECK','%BST_CHECKED','%BST_UNCHECKED','%BS_AUTOCHECKBOX', + '%BS_BOTTOM','%BS_CENTER','%BS_DEFAULT','%BS_DEFPUSHBUTTON','%BS_FLAT','%BS_LEFT','%BS_LEFTTEXT','%BS_MULTILINE', + '%BS_NOTIFY','%BS_OWNERDRAW','%BS_PUSHLIKE','%BS_RIGHT','%BS_TOP','%BS_VCENTER','%BUNDLE_BUILDER_CANCELLED','%CBM_FIRST', + '%CBN_CLOSEUP','%CBN_DBLCLK','%CBN_DROPDOWN','%CBN_EDITCHANGE','%CBN_EDITUPDATE','%CBN_ERRSPACE','%CBN_KILLFOCUS','%CBN_SELCANCEL', + '%CBN_SELCHANGE','%CBN_SELENDCANCEL','%CBN_SELENDOK','%CBN_SETFOCUS','%CBS_AUTOHSCROLL','%CBS_DISABLENOSCROLL','%CBS_DROPDOWN','%CBS_DROPDOWNLIST', + '%CBS_HASSTRINGS','%CBS_LOWERCASE','%CBS_NOINTEGRALHEIGHT','%CBS_SIMPLE','%CBS_SORT','%CBS_UPPERCASE','%CB_SELECTSTRING','%CCM_FIRST', + '%CC_ANYCOLOR','%CC_ENABLEHOOK','%CC_ENABLETEMPLATE','%CC_ENABLETEMPLATEHANDLE','%CC_FULLOPEN','%CC_PREVENTFULLOPEN','%CC_RGBINIT','%CC_SHOWHELP', + '%CC_SOLIDCOLOR','%CFE_BOLD','%CFE_ITALIC','%CFE_LINK','%CFE_PROTECTED','%CFE_STRIKEOUT','%CFE_UNDERLINE','%CFM_ANIMATION', + '%CFM_BACKCOLOR','%CFM_BOLD','%CFM_CHARSET','%CFM_COLOR','%CFM_FACE','%CFM_ITALIC','%CFM_KERNING','%CFM_LCID', + '%CFM_LINK','%CFM_OFFSET','%CFM_PROTECTED','%CFM_REVAUTHOR','%CFM_SIZE','%CFM_SPACING','%CFM_STRIKEOUT','%CFM_STYLE', + '%CFM_UNDERLINE','%CFM_UNDERLINETYPE','%CFM_WEIGHT','%CGI_ACCEPT_FILE_UPLOAD','%CGI_AUTO_ADD_SPECIAL_CHARS_PREFIX','%CGI_AUTO_CREATE_VARS','%CGI_BUFFERIZE_OUTPUT','%CGI_DOUBLE_QUOTE', + '%CGI_FILE_UPLOAD_BASEPATH','%CGI_FORCE_SESSION_VALIDATION','%CGI_MAX_BYTE_FROM_STD_IN','%CGI_REQUEST_METHOD_GET','%CGI_REQUEST_METHOD_POST','%CGI_SESSION_FILE_BASEPATH','%CGI_SINGLE_QUOTE','%CGI_SPECIAL_CHARS_PREFIX', + '%CGI_TEMPORARY_UPLOAD_PATH','%CGI_UPLOAD_CAN_OVERWRITE','%CGI_WRITE_LOG_FILE','%CGI_WRITE_VARS_INTO_LOG_FILE','%CONOLE_ATTACH_PARENT_PROCESS','%CONSOLE_BACKGROUND_BLUE','%CONSOLE_BACKGROUND_GREEN','%CONSOLE_BACKGROUND_INTENSITY', + '%CONSOLE_BACKGROUND_RED','%CONSOLE_BOX_FLAG_3DOFF','%CONSOLE_BOX_FLAG_3DON','%CONSOLE_BOX_FLAG_SHADOW','%CONSOLE_COMMON_LVB_GRID_HORIZONTAL','%CONSOLE_COMMON_LVB_GRID_LVERTICAL','%CONSOLE_COMMON_LVB_GRID_RVERTICAL','%CONSOLE_COMMON_LVB_LEADING_BYTE', + '%CONSOLE_COMMON_LVB_REVERSE_VIDEO','%CONSOLE_COMMON_LVB_TRAILING_BYTE','%CONSOLE_COMMON_LVB_UNDERSCORE','%CONSOLE_CTRL_BREAK_EVENT','%CONSOLE_CTRL_C_EVENT','%CONSOLE_DOUBLE_CLICK','%CONSOLE_ENABLE_AUTO_POSITION','%CONSOLE_ENABLE_ECHO_INPUT', + '%CONSOLE_ENABLE_EXTENDED_FLAGS','%CONSOLE_ENABLE_INSERT_MODE','%CONSOLE_ENABLE_LINE_INPUT','%CONSOLE_ENABLE_MOUSE_INPUT','%CONSOLE_ENABLE_PROCESSED_INPUT','%CONSOLE_ENABLE_PROCESSED_OUTPUT','%CONSOLE_ENABLE_QUICK_EDIT_MODE','%CONSOLE_ENABLE_WINDOW_INPUT', + '%CONSOLE_ENABLE_WRAP_AT_EOL_OUTPUT','%CONSOLE_FOREGROUND_BLUE','%CONSOLE_FOREGROUND_GREEN','%CONSOLE_FOREGROUND_INTENSITY','%CONSOLE_FOREGROUND_RED','%CONSOLE_LBUTTON','%CONSOLE_LINE_HORIZONTAL','%CONSOLE_LINE_VERTICAL', + '%CONSOLE_MBUTTON','%CONSOLE_MOUSE_MOVED','%CONSOLE_MOUSE_WHEELED','%CONSOLE_RBUTTON','%CONSOLE_SCROLLBUF_DOWN','%CONSOLE_SCROLLBUF_UP','%CONSOLE_SCROLLWND_ABSOLUTE','%CONSOLE_SCROLLWND_RELATIVE', + '%CONSOLE_STD_ERROR_HANDLE','%CONSOLE_STD_INPUT_HANDLE','%CONSOLE_STD_OUTPUT_HANDLE','%CONSOLE_SW_FORCEMINIMIZE','%CONSOLE_SW_HIDE','%CONSOLE_SW_MAXIMIZE','%CONSOLE_SW_MINIMIZE','%CONSOLE_SW_RESTORE', + '%CONSOLE_SW_SHOW','%CONSOLE_SW_SHOWDEFAULT','%CONSOLE_SW_SHOWMAXIMIZED','%CONSOLE_SW_SHOWMINIMIZED','%CONSOLE_SW_SHOWMINNOACTIVE','%CONSOLE_SW_SHOWNA','%CONSOLE_SW_SHOWNOACTIVATE','%CONSOLE_SW_SHOWNORMAL', + '%CONSOLE_UNAVAILABLE','%CRYPTO_CALG_DES','%CRYPTO_CALG_RC2','%CRYPTO_CALG_RC4','%CRYPTO_PROV_DH_SCHANNEL','%CRYPTO_PROV_DSS','%CRYPTO_PROV_DSS_DH','%CRYPTO_PROV_FORTEZZA', + '%CRYPTO_PROV_MS_EXCHANGE','%CRYPTO_PROV_RSA_FULL','%CRYPTO_PROV_RSA_SCHANNEL','%CRYPTO_PROV_RSA_SIG','%CRYPTO_PROV_SSL','%CSIDL_ADMINTOOLS','%CSIDL_ALTSTARTUP','%CSIDL_APPDATA', + '%CSIDL_BITBUCKET','%CSIDL_CDBURN_AREA','%CSIDL_COMMON_ADMINTOOLS','%CSIDL_COMMON_ALTSTARTUP','%CSIDL_COMMON_APPDATA','%CSIDL_COMMON_DESKTOPDIRECTORY','%CSIDL_COMMON_DOCUMENTS','%CSIDL_COMMON_FAVORITES', + '%CSIDL_COMMON_MUSIC','%CSIDL_COMMON_PICTURES','%CSIDL_COMMON_PROGRAMS','%CSIDL_COMMON_STARTMENU','%CSIDL_COMMON_STARTUP','%CSIDL_COMMON_TEMPLATES','%CSIDL_COMMON_VIDEO','%CSIDL_CONTROLS', + '%CSIDL_COOKIES','%CSIDL_DESKTOP','%CSIDL_DESKTOPDIRECTORY','%CSIDL_DRIVES','%CSIDL_FAVORITES','%CSIDL_FLAG_CREATE','%CSIDL_FONTS','%CSIDL_HISTORY', + '%CSIDL_INTERNET','%CSIDL_INTERNET_CACHE','%CSIDL_LOCAL_APPDATA','%CSIDL_MYDOCUMENTS','%CSIDL_MYMUSIC','%CSIDL_MYPICTURES','%CSIDL_MYVIDEO','%CSIDL_NETHOOD', + '%CSIDL_NETWORK','%CSIDL_PERSONAL','%CSIDL_PRINTERS','%CSIDL_PRINTHOOD','%CSIDL_PROFILE','%CSIDL_PROGRAMS','%CSIDL_PROGRAM_FILES','%CSIDL_PROGRAM_FILES_COMMON', + '%CSIDL_RECENT','%CSIDL_SENDTO','%CSIDL_STARTMENU','%CSIDL_STARTUP','%CSIDL_SYSTEM','%CSIDL_TEMPLATES','%CSIDL_WINDOWS','%CW_USEDEFAULT', + '%CYAN','%DATE_TIME_FILE_CREATION','%DATE_TIME_LAST_FILE_ACCESS','%DATE_TIME_LAST_FILE_WRITE','%DICTIONARY_MEMINFO_DATA','%DICTIONARY_MEMINFO_KEYS','%DICTIONARY_MEMINFO_TOTAL','%DICTIONARY_SORTDESCENDING', + '%DICTIONARY_SORTKEYS','%DSCAPS_CERTIFIED','%DSCAPS_CONTINUOUSRATE','%DSCAPS_EMULDRIVER','%DSCAPS_SECONDARY16BIT','%DSCAPS_SECONDARY8BIT','%DSCAPS_SECONDARYMONO','%DSCAPS_SECONDARYSTEREO', + '%DSCCAPS_CERTIFIED','%DSCCAPS_EMULDRIVER','%DS_3DLOOK','%DS_ABSALIGN','%DS_CENTER','%DS_CENTERMOUSE','%DS_CONTEXTHELP','%DS_CONTROL', + '%DS_MODALFRAME','%DS_NOFAILCREATE','%DS_SETFONT','%DS_SETFOREGROUND','%DS_SYSMODAL','%DTM_FIRST','%DTM_GETMCCOLOR','%DTM_GETMCFONT', + '%DTM_GETMONTHCAL','%DTM_GETRANGE','%DTM_GETSYSTEMTIME','%DTM_SETFORMAT','%DTM_SETFORMATW','%DTM_SETMCCOLOR','%DTM_SETMCFONT','%DTM_SETRANGE', + '%DTM_SETSYSTEMTIME','%DTN_CLOSEUP','%DTN_DATETIMECHANGE','%DTN_DROPDOWN','%DTN_FORMAT','%DTN_FORMATQUERY','%DTN_FORMATQUERYW','%DTN_FORMATW', + '%DTN_USERSTRING','%DTN_USERSTRINGW','%DTN_WMKEYDOWN','%DTN_WMKEYDOWNW','%DTS_APPCANPARSE','%DTS_LONGDATEFORMAT','%DTS_RIGHTALIGN','%DTS_SHORTDATECENTURYFORMAT', + '%DTS_SHORTDATEFORMAT','%DTS_SHOWNONE','%DTS_TIMEFORMAT','%DTS_UPDOWN','%DT_DATE_CENTURY','%DT_DATE_OK','%DT_DAY_IN_YEAR','%DT_DIFF_IN_DAYS', + '%DT_DIFF_IN_HOURS','%DT_DIFF_IN_MINUTES','%DT_DIFF_IN_SECONDS','%DT_HOURS_IN_DAY','%DT_MINUTES_IN_HOUR','%DT_SECONDS_IN_DAY','%DT_SECONDS_IN_HOUR','%DT_SECONDS_IN_MINUTE', + '%DT_SECONDS_IN_YEAR','%DT_USE_LONG_FORM','%DT_USE_SHORT_FORM','%DT_WRONG_DATE','%DT_WRONG_DAY','%DT_WRONG_MONTH','%ECM_FIRST','%ECOOP_AND', + '%ECOOP_OR','%ECOOP_SET','%ECOOP_XOR','%ECO_AUTOHSCROLL','%ECO_AUTOVSCROLL','%ECO_AUTOWORDSELECTION','%ECO_NOHIDESEL','%ECO_READONLY', + '%ECO_SELECTIONBAR','%ECO_WANTRETURN','%EM_AUTOURLDETECT','%EM_CANPASTE','%EM_CANREDO','%EM_CANUNDO','%EM_CHARFROMPOS','%EM_DISPLAYBAND', + '%EM_EMPTYUNDOBUFFER','%EM_EXGETSEL','%EM_EXLIMITTEXT','%EM_EXLINEFROMCHAR','%EM_EXSETSEL','%EM_FINDTEXT','%EM_FINDTEXTEX','%EM_FINDWORDBREAK', + '%EM_FMTLINES','%EM_FORMATRANGE','%EM_GETAUTOURLDETECT','%EM_GETCHARFORMAT','%EM_GETEDITSTYLE','%EM_GETEVENTMASK','%EM_GETFIRSTVISIBLELINE','%EM_GETHANDLE', + '%EM_GETIMESTATUS','%EM_GETLIMITTEXT','%EM_GETLINE','%EM_GETLINECOUNT','%EM_GETMARGINS','%EM_GETMODIFY','%EM_GETOLEINTERFACE','%EM_GETOPTIONS', + '%EM_GETPARAFORMAT','%EM_GETPASSWORDCHAR','%EM_GETRECT','%EM_GETREDONAME','%EM_GETSCROLLPOS','%EM_GETSEL','%EM_GETSELTEXT','%EM_GETTEXTMODE', + '%EM_GETTEXTRANGE','%EM_GETTHUMB','%EM_GETUNDONAME','%EM_GETWORDBREAKPROC','%EM_GETWORDBREAKPROCEX','%EM_HIDESELECTION','%EM_LIMITTEXT','%EM_LINEFROMCHAR', + '%EM_LINEINDEX','%EM_LINELENGTH','%EM_LINESCROLL','%EM_PASTESPECIAL','%EM_POSFROMCHAR','%EM_REDO','%EM_REPLACESEL','%EM_REQUESTRESIZE', + '%EM_SCROLL','%EM_SCROLLCARET','%EM_SELECTIONTYPE','%EM_SETBKGNDCOLOR','%EM_SETCHARFORMAT','%EM_SETEDITSTYLE','%EM_SETEVENTMASK','%EM_SETHANDLE', + '%EM_SETIMESTATUS','%EM_SETLIMITTEXT','%EM_SETMARGINS','%EM_SETMODIFY','%EM_SETOLECALLBACK','%EM_SETOPTIONS','%EM_SETPARAFORMAT','%EM_SETPASSWORDCHAR', + '%EM_SETREADONLY','%EM_SETRECT','%EM_SETRECTNP','%EM_SETSCROLLPOS','%EM_SETSEL','%EM_SETTABSTOPS','%EM_SETTARGETDEVICE','%EM_SETTEXTMODE', + '%EM_SETUNDOLIMIT','%EM_SETWORDBREAKPROC','%EM_SETWORDBREAKPROCEX','%EM_SETWORDWRAPMODE','%EM_SETZOOM','%EM_STOPGROUPTYPING','%EM_STREAMIN','%EM_STREAMOUT', + '%EM_UNDO','%ENM_CHANGE','%ENM_CORRECTTEXT','%ENM_DRAGDROPDONE','%ENM_DROPFILES','%ENM_KEYEVENTS','%ENM_MOUSEEVENTS','%ENM_NONE', + '%ENM_PARAGRAPHEXPANDED','%ENM_PROTECTED','%ENM_REQUESTRESIZE','%ENM_SCROLL','%ENM_SCROLLEVENTS','%ENM_SELCHANGE','%ENM_UPDATE','%EN_CHANGE', + '%EN_MSGFILTER','%EN_SELCHANGE','%EN_UPDATE','%ES_AUTOHSCROLL','%ES_AUTOVSCROLL','%ES_CENTER','%ES_DISABLENOSCROLL','%ES_EX_NOCALLOLEINIT', + '%ES_LEFT','%ES_LOWERCASE','%ES_MULTILINE','%ES_NOHIDESEL','%ES_NOOLEDRAGDROP','%ES_NUMBER','%ES_OEMCONVERT','%ES_PASSWORD', + '%ES_READONLY','%ES_RIGHT','%ES_SAVESEL','%ES_SELECTIONBAR','%ES_SUNKEN','%ES_UPPERCASE','%ES_WANTRETURN','%EVAL_EXEC_STRING', + '%FALSE','%FILE_ADDPATH','%FILE_ARCHIVE','%FILE_BUILDVERSION','%FILE_HIDDEN','%FILE_MAJORVERSION','%FILE_MINORVERSION','%FILE_NORMAL', + '%FILE_READONLY','%FILE_REVISIONVERSION','%FILE_SUBDIR','%FILE_SYSTEM','%FILE_VLABEL','%FTP_GET_CONNECT_STATUS','%FTP_GET_FILE_BYTES_RCVD','%FTP_GET_FILE_BYTES_SENT', + '%FTP_GET_LAST_RESPONSE','%FTP_GET_LOCAL_IP','%FTP_GET_SERVER_IP','%FTP_GET_TOTAL_BYTES_RCVD','%FTP_GET_TOTAL_BYTES_SENT','%FTP_LIST_FULLLIST','%FTP_LIST_FULLLISTDIR','%FTP_LIST_FULLLISTFILE', + '%FTP_SET_ASYNC','%FTP_SET_CONNECT_WAIT','%FTP_SET_MAX_LISTEN_WAIT','%FTP_SET_MAX_RESPONSE_WAIT','%FTP_SET_PASSIVE','%FTP_SET_SYNC','%FW_BLACK','%FW_BOLD', + '%FW_DEMIBOLD','%FW_DONTCARE','%FW_EXTRABOLD','%FW_EXTRALIGHT','%FW_HEAVY','%FW_LIGHT','%FW_MEDIUM','%FW_NORMAL', + '%FW_REGULAR','%FW_SEMIBOLD','%FW_THIN','%FW_ULTRABOLD','%FW_ULTRALIGHT','%GDTR_MAX','%GDTR_MIN','%GLU_AUTO_LOAD_MATRIX', + '%GLU_BEGIN','%GLU_CCW','%GLU_CULLING','%GLU_CW','%GLU_DISPLAY_MODE','%GLU_DOMAIN_DISTANCE','%GLU_EDGE_FLAG','%GLU_END', + '%GLU_ERROR','%GLU_EXTENSIONS','%GLU_EXTERIOR','%GLU_FALSE','%GLU_FILL','%GLU_FLAT','%GLU_INCOMPATIBLE_GL_VERSION','%GLU_INSIDE', + '%GLU_INTERIOR','%GLU_INVALID_ENUM','%GLU_INVALID_VALUE','%GLU_LINE','%GLU_MAP1_TRIM_2','%GLU_MAP1_TRIM_3','%GLU_NONE','%GLU_NURBS_ERROR1', + '%GLU_NURBS_ERROR10','%GLU_NURBS_ERROR11','%GLU_NURBS_ERROR12','%GLU_NURBS_ERROR13','%GLU_NURBS_ERROR14','%GLU_NURBS_ERROR15','%GLU_NURBS_ERROR16','%GLU_NURBS_ERROR17', + '%GLU_NURBS_ERROR18','%GLU_NURBS_ERROR19','%GLU_NURBS_ERROR2','%GLU_NURBS_ERROR20','%GLU_NURBS_ERROR21','%GLU_NURBS_ERROR22','%GLU_NURBS_ERROR23','%GLU_NURBS_ERROR24', + '%GLU_NURBS_ERROR25','%GLU_NURBS_ERROR26','%GLU_NURBS_ERROR27','%GLU_NURBS_ERROR28','%GLU_NURBS_ERROR29','%GLU_NURBS_ERROR3','%GLU_NURBS_ERROR30','%GLU_NURBS_ERROR31', + '%GLU_NURBS_ERROR32','%GLU_NURBS_ERROR33','%GLU_NURBS_ERROR34','%GLU_NURBS_ERROR35','%GLU_NURBS_ERROR36','%GLU_NURBS_ERROR37','%GLU_NURBS_ERROR4','%GLU_NURBS_ERROR5', + '%GLU_NURBS_ERROR6','%GLU_NURBS_ERROR7','%GLU_NURBS_ERROR8','%GLU_NURBS_ERROR9','%GLU_OUTLINE_PATCH','%GLU_OUTLINE_POLYGON','%GLU_OUTSIDE','%GLU_OUT_OF_MEMORY', + '%GLU_PARAMETRIC_ERROR','%GLU_PARAMETRIC_TOLERANCE','%GLU_PATH_LENGTH','%GLU_POINT','%GLU_SAMPLING_METHOD','%GLU_SAMPLING_TOLERANCE','%GLU_SILHOUETTE','%GLU_SMOOTH', + '%GLU_TESS_BEGIN','%GLU_TESS_BEGIN_DATA','%GLU_TESS_BOUNDARY_ONLY','%GLU_TESS_COMBINE','%GLU_TESS_COMBINE_DATA','%GLU_TESS_COORD_TOO_LARGE','%GLU_TESS_EDGE_FLAG','%GLU_TESS_EDGE_FLAG_DATA', + '%GLU_TESS_END','%GLU_TESS_END_DATA','%GLU_TESS_ERROR','%GLU_TESS_ERROR1','%GLU_TESS_ERROR2','%GLU_TESS_ERROR3','%GLU_TESS_ERROR4','%GLU_TESS_ERROR5', + '%GLU_TESS_ERROR6','%GLU_TESS_ERROR7','%GLU_TESS_ERROR8','%GLU_TESS_ERROR_DATA','%GLU_TESS_MISSING_BEGIN_CONTOUR','%GLU_TESS_MISSING_BEGIN_POLYGON','%GLU_TESS_MISSING_END_CONTOUR','%GLU_TESS_MISSING_END_POLYGON', + '%GLU_TESS_NEED_COMBINE_CALLBACK','%GLU_TESS_TOLERANCE','%GLU_TESS_VERTEX','%GLU_TESS_VERTEX_DATA','%GLU_TESS_WINDING_ABS_GEQ_TWO','%GLU_TESS_WINDING_NEGATIVE','%GLU_TESS_WINDING_NONZERO','%GLU_TESS_WINDING_ODD', + '%GLU_TESS_WINDING_POSITIVE','%GLU_TESS_WINDING_RULE','%GLU_TRUE','%GLU_UNKNOWN','%GLU_U_STEP','%GLU_VERSION','%GLU_VERSION_1_1','%GLU_VERSION_1_2', + '%GLU_VERTEX','%GLU_V_STEP','%GL_2D','%GL_2_BYTES','%GL_3D','%GL_3D_COLOR','%GL_3D_COLOR_TEXTURE','%GL_3_BYTES', + '%GL_4D_COLOR_TEXTURE','%GL_4_BYTES','%GL_ABGR_EXT','%GL_ACCUM','%GL_ACCUM_ALPHA_BITS','%GL_ACCUM_BLUE_BITS','%GL_ACCUM_BUFFER_BIT','%GL_ACCUM_CLEAR_VALUE', + '%GL_ACCUM_GREEN_BITS','%GL_ACCUM_RED_BITS','%GL_ADD','%GL_ALL_ATTRIB_BITS','%GL_ALPHA','%GL_ALPHA12','%GL_ALPHA16','%GL_ALPHA4', + '%GL_ALPHA8','%GL_ALPHA_BIAS','%GL_ALPHA_BITS','%GL_ALPHA_SCALE','%GL_ALPHA_TEST','%GL_ALPHA_TEST_FUNC','%GL_ALPHA_TEST_REF','%GL_ALWAYS', + '%GL_AMBIENT','%GL_AMBIENT_AND_DIFFUSE','%GL_AND','%GL_AND_INVERTED','%GL_AND_REVERSE','%GL_ARRAY_ELEMENT_LOCK_COUNT_EXT','%GL_ARRAY_ELEMENT_LOCK_FIRST_EXT','%GL_ATTRIB_STACK_DEPTH', + '%GL_AUTO_NORMAL','%GL_AUX0','%GL_AUX1','%GL_AUX2','%GL_AUX3','%GL_AUX_BUFFERS','%GL_BACK','%GL_BACK_LEFT', + '%GL_BACK_RIGHT','%GL_BGRA_EXT','%GL_BGR_EXT','%GL_BITMAP','%GL_BITMAP_TOKEN','%GL_BLEND','%GL_BLEND_COLOR_EXT','%GL_BLEND_DST', + '%GL_BLEND_EQUATION_EXT','%GL_BLEND_SRC','%GL_BLUE','%GL_BLUE_BIAS','%GL_BLUE_BITS','%GL_BLUE_SCALE','%GL_BYTE','%GL_C3F_V3F', + '%GL_C4F_N3F_V3F','%GL_C4UB_V2F','%GL_C4UB_V3F','%GL_CCW','%GL_CLAMP','%GL_CLEAR','%GL_CLIENT_ALL_ATTRIB_BITS','%GL_CLIENT_ATTRIB_STACK_DEPTH', + '%GL_CLIENT_PIXEL_STORE_BIT','%GL_CLIENT_VERTEX_ARRAY_BIT','%GL_CLIP_PLANE0','%GL_CLIP_PLANE1','%GL_CLIP_PLANE2','%GL_CLIP_PLANE3','%GL_CLIP_PLANE4','%GL_CLIP_PLANE5', + '%GL_CLIP_VOLUME_CLIPPING_HINT_EXT','%GL_COEFF','%GL_COLOR','%GL_COLOR_ARRAY','%GL_COLOR_ARRAY_COUNT_EXT','%GL_COLOR_ARRAY_EXT','%GL_COLOR_ARRAY_POINTER','%GL_COLOR_ARRAY_POINTER_EXT', + '%GL_COLOR_ARRAY_SIZE','%GL_COLOR_ARRAY_SIZE_EXT','%GL_COLOR_ARRAY_STRIDE','%GL_COLOR_ARRAY_STRIDE_EXT','%GL_COLOR_ARRAY_TYPE','%GL_COLOR_ARRAY_TYPE_EXT','%GL_COLOR_BUFFER_BIT','%GL_COLOR_CLEAR_VALUE', + '%GL_COLOR_INDEX','%GL_COLOR_INDEX12_EXT','%GL_COLOR_INDEX16_EXT','%GL_COLOR_INDEX1_EXT','%GL_COLOR_INDEX2_EXT','%GL_COLOR_INDEX4_EXT','%GL_COLOR_INDEX8_EXT','%GL_COLOR_INDEXES', + '%GL_COLOR_LOGIC_OP','%GL_COLOR_MATERIAL','%GL_COLOR_MATERIAL_FACE','%GL_COLOR_MATERIAL_PARAMETER','%GL_COLOR_SUM_EXT','%GL_COLOR_TABLE_ALPHA_SIZE_EXT','%GL_COLOR_TABLE_BIAS_EXT','%GL_COLOR_TABLE_BLUE_SIZE_EXT', + '%GL_COLOR_TABLE_EXT','%GL_COLOR_TABLE_FORMAT_EXT','%GL_COLOR_TABLE_GREEN_SIZE_EXT','%GL_COLOR_TABLE_INTENSITY_SIZE_EXT','%GL_COLOR_TABLE_LUMINANCE_SIZE_EXT','%GL_COLOR_TABLE_RED_SIZE_EXT','%GL_COLOR_TABLE_SCALE_EXT','%GL_COLOR_TABLE_WIDTH_EXT', + '%GL_COLOR_WRITEMASK','%GL_COMPILE','%GL_COMPILE_AND_EXECUTE','%GL_CONSTANT_ALPHA_EXT','%GL_CONSTANT_ATTENUATION','%GL_CONSTANT_COLOR_EXT','%GL_CONVOLUTION_1D_EXT','%GL_CONVOLUTION_2D_EXT', + '%GL_CONVOLUTION_BORDER_MODE_EXT','%GL_CONVOLUTION_FILTER_BIAS_EXT','%GL_CONVOLUTION_FILTER_SCALE_EXT','%GL_CONVOLUTION_FORMAT_EXT','%GL_CONVOLUTION_HEIGHT_EXT','%GL_CONVOLUTION_WIDTH_EXT','%GL_COPY','%GL_COPY_INVERTED', + '%GL_COPY_PIXEL_TOKEN','%GL_CULL_FACE','%GL_CULL_FACE_MODE','%GL_CULL_VERTEX_EXT','%GL_CULL_VERTEX_EYE_POSITION_EXT','%GL_CULL_VERTEX_OBJECT_POSITION_EXT','%GL_CURRENT_BIT','%GL_CURRENT_COLOR', + '%GL_CURRENT_INDEX','%GL_CURRENT_NORMAL','%GL_CURRENT_RASTER_COLOR','%GL_CURRENT_RASTER_DISTANCE','%GL_CURRENT_RASTER_INDEX','%GL_CURRENT_RASTER_POSITION','%GL_CURRENT_RASTER_POSITION_VALID','%GL_CURRENT_RASTER_TEXTURE_COORDS', + '%GL_CURRENT_SECONDARY_COLOR_EXT','%GL_CURRENT_TEXTURE_COORDS','%GL_CW','%GL_DECAL','%GL_DECR','%GL_DEPTH','%GL_DEPTH_BIAS','%GL_DEPTH_BITS', + '%GL_DEPTH_BUFFER_BIT','%GL_DEPTH_CLEAR_VALUE','%GL_DEPTH_COMPONENT','%GL_DEPTH_FUNC','%GL_DEPTH_RANGE','%GL_DEPTH_SCALE','%GL_DEPTH_TEST','%GL_DEPTH_WRITEMASK', + '%GL_DIFFUSE','%GL_DITHER','%GL_DOMAIN','%GL_DONT_CARE','%GL_DOUBLE','%GL_DOUBLEBUFFER','%GL_DOUBLE_EXT','%GL_DRAW_BUFFER', + '%GL_DRAW_PIXEL_TOKEN','%GL_DST_ALPHA','%GL_DST_COLOR','%GL_EDGE_FLAG','%GL_EDGE_FLAG_ARRAY','%GL_EDGE_FLAG_ARRAY_COUNT_EXT','%GL_EDGE_FLAG_ARRAY_EXT','%GL_EDGE_FLAG_ARRAY_POINTER', + '%GL_EDGE_FLAG_ARRAY_POINTER_EXT','%GL_EDGE_FLAG_ARRAY_STRIDE','%GL_EDGE_FLAG_ARRAY_STRIDE_EXT','%GL_EMISSION','%GL_ENABLE_BIT','%GL_EQUAL','%GL_EQUIV','%GL_EVAL_BIT', + '%GL_EXP','%GL_EXP2','%GL_EXTENSIONS','%GL_EXT_ABGR','%GL_EXT_BGRA','%GL_EXT_BLEND_COLOR','%GL_EXT_BLEND_MINMAX','%GL_EXT_BLEND_SUBTRACT', + '%GL_EXT_CLIP_VOLUME_HINT','%GL_EXT_COLOR_TABLE','%GL_EXT_COMPILED_VERTEX_ARRAY','%GL_EXT_CONVOLUTION','%GL_EXT_CULL_VERTEX','%GL_EXT_HISTOGRAM','%GL_EXT_PACKED_PIXELS','%GL_EXT_PALETTED_TEXTURE', + '%GL_EXT_POLYGON_OFFSET','%GL_EXT_SECONDARY_COLOR','%GL_EXT_SEPARATE_SPECULAR_COLOR','%GL_EXT_VERTEX_ARRAY','%GL_EYE_LINEAR','%GL_EYE_PLANE','%GL_FALSE','%GL_FASTEST', + '%GL_FEEDBACK','%GL_FEEDBACK_BUFFER_POINTER','%GL_FEEDBACK_BUFFER_SIZE','%GL_FEEDBACK_BUFFER_TYPE','%GL_FILL','%GL_FLAT','%GL_FLOAT','%GL_FOG', + '%GL_FOG_BIT','%GL_FOG_COLOR','%GL_FOG_DENSITY','%GL_FOG_END','%GL_FOG_HINT','%GL_FOG_INDEX','%GL_FOG_MODE','%GL_FOG_START', + '%GL_FRONT','%GL_FRONT_AND_BACK','%GL_FRONT_FACE','%GL_FRONT_LEFT','%GL_FRONT_RIGHT','%GL_FUNC_ADD_EXT','%GL_FUNC_REVERSE_SUBTRACT_EXT','%GL_FUNC_SUBTRACT_EXT', + '%GL_GEQUAL','%GL_GREATER','%GL_GREEN','%GL_GREEN_BIAS','%GL_GREEN_BITS','%GL_GREEN_SCALE','%GL_HINT_BIT','%GL_HISTOGRAM_ALPHA_SIZE_EXT', + '%GL_HISTOGRAM_BLUE_SIZE_EXT','%GL_HISTOGRAM_EXT','%GL_HISTOGRAM_FORMAT_EXT','%GL_HISTOGRAM_GREEN_SIZE_EXT','%GL_HISTOGRAM_LUMINANCE_SIZE_EXT','%GL_HISTOGRAM_RED_SIZE_EXT','%GL_HISTOGRAM_SINK_EXT','%GL_HISTOGRAM_WIDTH_EXT', + '%GL_INCR','%GL_INDEX_ARRAY','%GL_INDEX_ARRAY_COUNT_EXT','%GL_INDEX_ARRAY_EXT','%GL_INDEX_ARRAY_POINTER','%GL_INDEX_ARRAY_POINTER_EXT','%GL_INDEX_ARRAY_STRIDE','%GL_INDEX_ARRAY_STRIDE_EXT', + '%GL_INDEX_ARRAY_TYPE','%GL_INDEX_ARRAY_TYPE_EXT','%GL_INDEX_BITS','%GL_INDEX_CLEAR_VALUE','%GL_INDEX_LOGIC_OP','%GL_INDEX_MODE','%GL_INDEX_OFFSET','%GL_INDEX_SHIFT', + '%GL_INDEX_WRITEMASK','%GL_INT','%GL_INTENSITY','%GL_INTENSITY12','%GL_INTENSITY16','%GL_INTENSITY4','%GL_INTENSITY8','%GL_INVALID_ENUM', + '%GL_INVALID_OPERATION','%GL_INVALID_VALUE','%GL_INVERT','%GL_KEEP','%GL_LEFT','%GL_LEQUAL','%GL_LESS','%GL_LIGHT0', + '%GL_LIGHT1','%GL_LIGHT2','%GL_LIGHT3','%GL_LIGHT4','%GL_LIGHT5','%GL_LIGHT6','%GL_LIGHT7','%GL_LIGHTING', + '%GL_LIGHTING_BIT','%GL_LIGHT_MODEL_AMBIENT','%GL_LIGHT_MODEL_COLOR_CONTROL_EXT','%GL_LIGHT_MODEL_LOCAL_VIEWER','%GL_LIGHT_MODEL_TWO_SIDE','%GL_LINE','%GL_LINEAR','%GL_LINEAR_ATTENUATION', + '%GL_LINEAR_MIPMAP_LINEAR','%GL_LINEAR_MIPMAP_NEAREST','%GL_LINES','%GL_LINE_BIT','%GL_LINE_LOOP','%GL_LINE_RESET_TOKEN','%GL_LINE_SMOOTH','%GL_LINE_SMOOTH_HINT', + '%GL_LINE_STIPPLE','%GL_LINE_STIPPLE_PATTERN','%GL_LINE_STIPPLE_REPEAT','%GL_LINE_STRIP','%GL_LINE_TOKEN','%GL_LINE_WIDTH','%GL_LINE_WIDTH_GRANULARITY','%GL_LINE_WIDTH_RANGE', + '%GL_LIST_BASE','%GL_LIST_BIT','%GL_LIST_INDEX','%GL_LIST_MODE','%GL_LOAD','%GL_LOGIC_OP','%GL_LOGIC_OP_MODE','%GL_LUMINANCE', + '%GL_LUMINANCE12','%GL_LUMINANCE12_ALPHA12','%GL_LUMINANCE12_ALPHA4','%GL_LUMINANCE16','%GL_LUMINANCE16_ALPHA16','%GL_LUMINANCE4','%GL_LUMINANCE4_ALPHA4','%GL_LUMINANCE6_ALPHA2', + '%GL_LUMINANCE8','%GL_LUMINANCE8_ALPHA8','%GL_LUMINANCE_ALPHA','%GL_MAP1_COLOR_4','%GL_MAP1_GRID_DOMAIN','%GL_MAP1_GRID_SEGMENTS','%GL_MAP1_INDEX','%GL_MAP1_NORMAL', + '%GL_MAP1_TEXTURE_COORD_1','%GL_MAP1_TEXTURE_COORD_2','%GL_MAP1_TEXTURE_COORD_3','%GL_MAP1_TEXTURE_COORD_4','%GL_MAP1_VERTEX_3','%GL_MAP1_VERTEX_4','%GL_MAP2_COLOR_4','%GL_MAP2_GRID_DOMAIN', + '%GL_MAP2_GRID_SEGMENTS','%GL_MAP2_INDEX','%GL_MAP2_NORMAL','%GL_MAP2_TEXTURE_COORD_1','%GL_MAP2_TEXTURE_COORD_2','%GL_MAP2_TEXTURE_COORD_3','%GL_MAP2_TEXTURE_COORD_4','%GL_MAP2_VERTEX_3', + '%GL_MAP2_VERTEX_4','%GL_MAP_COLOR','%GL_MAP_STENCIL','%GL_MATRIX_MODE','%GL_MAX_ATTRIB_STACK_DEPTH','%GL_MAX_CLIENT_ATTRIB_STACK_DEPTH','%GL_MAX_CLIP_PLANES','%GL_MAX_CONVOLUTION_HEIGHT_EXT', + '%GL_MAX_CONVOLUTION_WIDTH_EXT','%GL_MAX_EVAL_ORDER','%GL_MAX_EXT','%GL_MAX_LIGHTS','%GL_MAX_LIST_NESTING','%GL_MAX_MODELVIEW_STACK_DEPTH','%GL_MAX_NAME_STACK_DEPTH','%GL_MAX_PIXEL_MAP_TABLE', + '%GL_MAX_PROJECTION_STACK_DEPTH','%GL_MAX_TEXTURE_SIZE','%GL_MAX_TEXTURE_STACK_DEPTH','%GL_MAX_VIEWPORT_DIMS','%GL_MINMAX_EXT','%GL_MINMAX_FORMAT_EXT','%GL_MINMAX_SINK_EXT','%GL_MIN_EXT', + '%GL_MODELVIEW','%GL_MODELVIEW_MATRIX','%GL_MODELVIEW_STACK_DEPTH','%GL_MODULATE','%GL_MULT','%GL_N3F_V3F','%GL_NAME_STACK_DEPTH','%GL_NAND', + '%GL_NEAREST','%GL_NEAREST_MIPMAP_LINEAR','%GL_NEAREST_MIPMAP_NEAREST','%GL_NEVER','%GL_NICEST','%GL_NONE','%GL_NOOP','%GL_NOR', + '%GL_NORMALIZE','%GL_NORMAL_ARRAY','%GL_NORMAL_ARRAY_COUNT_EXT','%GL_NORMAL_ARRAY_EXT','%GL_NORMAL_ARRAY_POINTER','%GL_NORMAL_ARRAY_POINTER_EXT','%GL_NORMAL_ARRAY_STRIDE','%GL_NORMAL_ARRAY_STRIDE_EXT', + '%GL_NORMAL_ARRAY_TYPE','%GL_NORMAL_ARRAY_TYPE_EXT','%GL_NOTEQUAL','%GL_NO_ERROR','%GL_OBJECT_LINEAR','%GL_OBJECT_PLANE','%GL_ONE','%GL_ONE_MINUS_CONSTANT_ALPHA_EXT', + '%GL_ONE_MINUS_CONSTANT_COLOR_EXT','%GL_ONE_MINUS_DST_ALPHA','%GL_ONE_MINUS_DST_COLOR','%GL_ONE_MINUS_SRC_ALPHA','%GL_ONE_MINUS_SRC_COLOR','%GL_OR','%GL_ORDER','%GL_OR_INVERTED', + '%GL_OR_REVERSE','%GL_OUT_OF_MEMORY','%GL_PACK_ALIGNMENT','%GL_PACK_LSB_FIRST','%GL_PACK_ROW_LENGTH','%GL_PACK_SKIP_PIXELS','%GL_PACK_SKIP_ROWS','%GL_PACK_SWAP_BYTES', + '%GL_PASS_THROUGH_TOKEN','%GL_PERSPECTIVE_CORRECTION_HINT','%GL_PIXEL_MAP_A_TO_A','%GL_PIXEL_MAP_A_TO_A_SIZE','%GL_PIXEL_MAP_B_TO_B','%GL_PIXEL_MAP_B_TO_B_SIZE','%GL_PIXEL_MAP_G_TO_G','%GL_PIXEL_MAP_G_TO_G_SIZE', + '%GL_PIXEL_MAP_I_TO_A','%GL_PIXEL_MAP_I_TO_A_SIZE','%GL_PIXEL_MAP_I_TO_B','%GL_PIXEL_MAP_I_TO_B_SIZE','%GL_PIXEL_MAP_I_TO_G','%GL_PIXEL_MAP_I_TO_G_SIZE','%GL_PIXEL_MAP_I_TO_I','%GL_PIXEL_MAP_I_TO_I_SIZE', + '%GL_PIXEL_MAP_I_TO_R','%GL_PIXEL_MAP_I_TO_R_SIZE','%GL_PIXEL_MAP_R_TO_R','%GL_PIXEL_MAP_R_TO_R_SIZE','%GL_PIXEL_MAP_S_TO_S','%GL_PIXEL_MAP_S_TO_S_SIZE','%GL_PIXEL_MODE_BIT','%GL_POINT', + '%GL_POINTS','%GL_POINT_BIT','%GL_POINT_SIZE','%GL_POINT_SIZE_GRANULARITY','%GL_POINT_SIZE_RANGE','%GL_POINT_SMOOTH','%GL_POINT_SMOOTH_HINT','%GL_POINT_TOKEN', + '%GL_POLYGON','%GL_POLYGON_BIT','%GL_POLYGON_MODE','%GL_POLYGON_OFFSET_BIAS_EXT','%GL_POLYGON_OFFSET_EXT','%GL_POLYGON_OFFSET_FACTOR','%GL_POLYGON_OFFSET_FACTOR_EXT','%GL_POLYGON_OFFSET_FILL', + '%GL_POLYGON_OFFSET_LINE','%GL_POLYGON_OFFSET_POINT','%GL_POLYGON_OFFSET_UNITS','%GL_POLYGON_SMOOTH','%GL_POLYGON_SMOOTH_HINT','%GL_POLYGON_STIPPLE','%GL_POLYGON_STIPPLE_BIT','%GL_POLYGON_TOKEN', + '%GL_POSITION','%GL_POST_COLOR_MATRIX_COLOR_TABLE_EXT','%GL_POST_CONVOLUTION_ALPHA_BIAS_EXT','%GL_POST_CONVOLUTION_ALPHA_SCALE_EXT','%GL_POST_CONVOLUTION_BLUE_BIAS_EXT','%GL_POST_CONVOLUTION_BLUE_SCALE_EXT','%GL_POST_CONVOLUTION_COLOR_TABLE_EXT','%GL_POST_CONVOLUTION_GREEN_BIAS_EXT', + '%GL_POST_CONVOLUTION_GREEN_SCALE_EXT','%GL_POST_CONVOLUTION_RED_BIAS_EXT','%GL_POST_CONVOLUTION_RED_SCALE_EXT','%GL_PROJECTION','%GL_PROJECTION_MATRIX','%GL_PROJECTION_STACK_DEPTH','%GL_PROXY_COLOR_TABLE_EXT','%GL_PROXY_HISTOGRAM_EXT', + '%GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_EXT','%GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_EXT','%GL_PROXY_TEXTURE_1D','%GL_PROXY_TEXTURE_2D','%GL_Q','%GL_QUADRATIC_ATTENUATION','%GL_QUADS','%GL_QUAD_STRIP', + '%GL_R','%GL_R3_G3_B2','%GL_READ_BUFFER','%GL_RED','%GL_REDUCE_EXT','%GL_RED_BIAS','%GL_RED_BITS','%GL_RED_SCALE', + '%GL_RENDER','%GL_RENDERER','%GL_RENDER_MODE','%GL_REPEAT','%GL_REPLACE','%GL_RETURN','%GL_RGB','%GL_RGB10', + '%GL_RGB10_A2','%GL_RGB12','%GL_RGB16','%GL_RGB4','%GL_RGB5','%GL_RGB5_A1','%GL_RGB8','%GL_RGBA', + '%GL_RGBA12','%GL_RGBA16','%GL_RGBA2','%GL_RGBA4','%GL_RGBA8','%GL_RGBA_MODE','%GL_RIGHT','%GL_S', + '%GL_SCISSOR_BIT','%GL_SCISSOR_BOX','%GL_SCISSOR_TEST','%GL_SECONDARY_COLOR_ARRAY_EXT','%GL_SECONDARY_COLOR_ARRAY_POINTER_EXT','%GL_SECONDARY_COLOR_ARRAY_SIZE_EXT','%GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT','%GL_SECONDARY_COLOR_ARRAY_TYPE_EXT', + '%GL_SELECT','%GL_SELECTION_BUFFER_POINTER','%GL_SELECTION_BUFFER_SIZE','%GL_SEPARABLE_2D_EXT','%GL_SEPARATE_SPECULAR_COLOR_EXT','%GL_SET','%GL_SHADE_MODEL','%GL_SHININESS', + '%GL_SHORT','%GL_SINGLE_COLOR_EXT','%GL_SMOOTH','%GL_SPECULAR','%GL_SPHERE_MAP','%GL_SPOT_CUTOFF','%GL_SPOT_DIRECTION','%GL_SPOT_EXPONENT', + '%GL_SRC_ALPHA','%GL_SRC_ALPHA_SATURATE','%GL_SRC_COLOR','%GL_STACK_OVERFLOW','%GL_STACK_UNDERFLOW','%GL_STENCIL','%GL_STENCIL_BITS','%GL_STENCIL_BUFFER_BIT', + '%GL_STENCIL_CLEAR_VALUE','%GL_STENCIL_FAIL','%GL_STENCIL_FUNC','%GL_STENCIL_INDEX','%GL_STENCIL_PASS_DEPTH_FAIL','%GL_STENCIL_PASS_DEPTH_PASS','%GL_STENCIL_REF','%GL_STENCIL_TEST', + '%GL_STENCIL_VALUE_MASK','%GL_STENCIL_WRITEMASK','%GL_STEREO','%GL_SUBPIXEL_BITS','%GL_T','%GL_T2F_C3F_V3F','%GL_T2F_C4F_N3F_V3F','%GL_T2F_C4UB_V3F', + '%GL_T2F_N3F_V3F','%GL_T2F_V3F','%GL_T4F_C4F_N3F_V4F','%GL_T4F_V4F','%GL_TABLE_TOO_LARGE_EXT','%GL_TEXTURE','%GL_TEXTURE_1D','%GL_TEXTURE_2D', + '%GL_TEXTURE_ALPHA_SIZE','%GL_TEXTURE_BINDING_1D','%GL_TEXTURE_BINDING_2D','%GL_TEXTURE_BIT','%GL_TEXTURE_BLUE_SIZE','%GL_TEXTURE_BORDER','%GL_TEXTURE_BORDER_COLOR','%GL_TEXTURE_COMPONENTS', + '%GL_TEXTURE_COORD_ARRAY','%GL_TEXTURE_COORD_ARRAY_COUNT_EXT','%GL_TEXTURE_COORD_ARRAY_EXT','%GL_TEXTURE_COORD_ARRAY_POINTER','%GL_TEXTURE_COORD_ARRAY_POINTER_EXT','%GL_TEXTURE_COORD_ARRAY_SIZE','%GL_TEXTURE_COORD_ARRAY_SIZE_EXT','%GL_TEXTURE_COORD_ARRAY_STRIDE', + '%GL_TEXTURE_COORD_ARRAY_STRIDE_EXT','%GL_TEXTURE_COORD_ARRAY_TYPE','%GL_TEXTURE_COORD_ARRAY_TYPE_EXT','%GL_TEXTURE_ENV','%GL_TEXTURE_ENV_COLOR','%GL_TEXTURE_ENV_MODE','%GL_TEXTURE_GEN_MODE','%GL_TEXTURE_GEN_Q', + '%GL_TEXTURE_GEN_R','%GL_TEXTURE_GEN_S','%GL_TEXTURE_GEN_T','%GL_TEXTURE_GREEN_SIZE','%GL_TEXTURE_HEIGHT','%GL_TEXTURE_INTENSITY_SIZE','%GL_TEXTURE_INTERNAL_FORMAT','%GL_TEXTURE_LUMINANCE_SIZE', + '%GL_TEXTURE_MAG_FILTER','%GL_TEXTURE_MATRIX','%GL_TEXTURE_MIN_FILTER','%GL_TEXTURE_PRIORITY','%GL_TEXTURE_RED_SIZE','%GL_TEXTURE_RESIDENT','%GL_TEXTURE_STACK_DEPTH','%GL_TEXTURE_WIDTH', + '%GL_TEXTURE_WRAP_S','%GL_TEXTURE_WRAP_T','%GL_TRANSFORM_BIT','%GL_TRIANGLES','%GL_TRIANGLE_FAN','%GL_TRIANGLE_STRIP','%GL_TRUE','%GL_UNPACK_ALIGNMENT', + '%GL_UNPACK_LSB_FIRST','%GL_UNPACK_ROW_LENGTH','%GL_UNPACK_SKIP_PIXELS','%GL_UNPACK_SKIP_ROWS','%GL_UNPACK_SWAP_BYTES','%GL_UNSIGNED_BYTE','%GL_UNSIGNED_BYTE_3_3_2_EXT','%GL_UNSIGNED_INT', + '%GL_UNSIGNED_INT_10_10_10_2_EXT','%GL_UNSIGNED_INT_8_8_8_8_EXT','%GL_UNSIGNED_SHORT','%GL_UNSIGNED_SHORT_4_4_4_4_EXT','%GL_UNSIGNED_SHORT_5_5_5_1_EXT','%GL_V2F','%GL_V3F','%GL_VENDOR', + '%GL_VERSION','%GL_VERSION_1_1','%GL_VERTEX_ARRAY','%GL_VERTEX_ARRAY_COUNT_EXT','%GL_VERTEX_ARRAY_EXT','%GL_VERTEX_ARRAY_POINTER','%GL_VERTEX_ARRAY_POINTER_EXT','%GL_VERTEX_ARRAY_SIZE', + '%GL_VERTEX_ARRAY_SIZE_EXT','%GL_VERTEX_ARRAY_STRIDE','%GL_VERTEX_ARRAY_STRIDE_EXT','%GL_VERTEX_ARRAY_TYPE','%GL_VERTEX_ARRAY_TYPE_EXT','%GL_VIEWPORT','%GL_VIEWPORT_BIT','%GL_WIN_SWAP_HINT', + '%GL_XOR','%GL_ZERO','%GL_ZOOM_X','%GL_ZOOM_Y','%GRAY','%GREEN','%GWLP_HINSTANCE','%GWLP_HWNDPARENT', + '%GWLP_ID','%GWLP_USERDATA','%GWLP_WNDPROC','%GWL_EXSTYLE','%GWL_HINSTANCE','%GWL_HWNDPARENT','%GWL_ID','%GWL_STYLE', + '%GWL_USERDATA','%GWL_WNDPROC','%HDM_FIRST','%HTCAPTION','%HWND_BOTTOM','%HWND_DESKTOP','%HWND_MESSAGE','%HWND_NOTOPMOST', + '%HWND_TOP','%HWND_TOPMOST','%ICRYPTO_XOR_DECREASE','%ICRYPTO_XOR_INCREASE','%ICRYPTO_XOR_NORMAL','%IDABORT','%IDCANCEL','%IDCONTINUE', + '%IDIGNORE','%IDNO','%IDOK','%IDRETRY','%IDTIMEOUT','%IDTRYAGAIN','%IDYES','%INTERNET_CONNECTION_CONFIGURED', + '%INTERNET_CONNECTION_LAN','%INTERNET_CONNECTION_MODEM','%INTERNET_CONNECTION_MODEM_BUSY','%INTERNET_CONNECTION_OFFLINE','%INTERNET_CONNECTION_PROXY','%INTERNET_RAS_INSTALLED','%LBN_DBLCLK','%LBN_KILLFOCUS', + '%LBN_SELCANCEL','%LBN_SELCHANGE','%LBN_SETFOCUS','%LBS_DISABLENOSCROLL','%LBS_EXTENDEDSEL','%LBS_MULTICOLUMN','%LBS_MULTIPLESEL','%LBS_NOINTEGRALHEIGHT', + '%LBS_NOSEL','%LBS_NOTIFY','%LBS_SORT','%LBS_STANDARD','%LBS_USETABSTOPS','%LB_ADDFILE','%LB_ADDSTRING','%LB_DELETESTRING', + '%LB_DIR','%LB_FINDSTRING','%LB_FINDSTRINGEXACT','%LB_GETANCHORINDEX','%LB_GETCARETINDEX','%LB_GETCOUNT','%LB_GETCURSEL','%LB_GETHORIZONTALEXTENT', + '%LB_GETITEMDATA','%LB_GETITEMHEIGHT','%LB_GETITEMRECT','%LB_GETLISTBOXINFO','%LB_GETLOCALE','%LB_GETSEL','%LB_GETSELCOUNT','%LB_GETSELITEMS', + '%LB_GETTEXT','%LB_GETTEXTLEN','%LB_GETTOPINDEX','%LB_INITSTORAGE','%LB_INSERTSTRING','%LB_ITEMFROMPOINT','%LB_MULTIPLEADDSTRING','%LB_RESETCONTENT', + '%LB_SELECTSTRING','%LB_SELITEMRANGE','%LB_SELITEMRANGEEX','%LB_SETANCHORINDEX','%LB_SETCARETINDEX','%LB_SETCOLUMNWIDTH','%LB_SETCOUNT','%LB_SETCURSEL', + '%LB_SETHORIZONTALEXTENT','%LB_SETITEMDATA','%LB_SETITEMHEIGHT','%LB_SETLOCALE','%LB_SETSEL','%LB_SETTABSTOPS','%LB_SETTOPINDEX','%LF_FACESIZE', + '%LTGRAY','%LVM_FIRST','%LWA_ALPHA','%LWA_COLORKEY','%MAGENTA','%MAXBYTE','%MAXCHAR','%MAXDWORD', + '%MAXSHORT','%MAXWORD','%MAX_PATH','%MB_ABORTRETRYIGNORE','%MB_APPLMODAL','%MB_CANCELTRYCONTINUE','%MB_DEFBUTTON1','%MB_DEFBUTTON2', + '%MB_DEFBUTTON3','%MB_HELP','%MB_ICONASTERISK','%MB_ICONERROR','%MB_ICONEXCLAMATION','%MB_ICONHAND','%MB_ICONINFORMATION','%MB_ICONQUESTION', + '%MB_ICONSTOP','%MB_ICONWARNING','%MB_OK','%MB_OKCANCEL','%MB_RETRYCANCEL','%MB_SIMPLE','%MB_SYSTEMMODAL','%MB_TOPMOST', + '%MB_YESNO','%MB_YESNOCANCEL','%MF_CHECKED','%MF_DISABLED','%MF_ENABLED','%MF_GRAYED','%MF_SEPARATOR','%MF_UNCHECKED', + '%MINCHAR','%MINLONG','%MINSHORT','%NULL','%ODBC352_INC','%ODBCVER','%ODBC_ADD_DSN','%ODBC_ADD_SYS_DSN', + '%ODBC_BOTH_DSN','%ODBC_CONFIG_DRIVER','%ODBC_CONFIG_DRIVER_MAX','%ODBC_CONFIG_DSN','%ODBC_CONFIG_SYS_DSN','%ODBC_DRIVER_VERSION','%ODBC_ERROR_COMPONENT_NOT_FOUND','%ODBC_ERROR_CREATE_DSN_FAILED', + '%ODBC_ERROR_GENERAL_ERR','%ODBC_ERROR_INVALID_BUFF_LEN','%ODBC_ERROR_INVALID_DSN','%ODBC_ERROR_INVALID_HWND','%ODBC_ERROR_INVALID_INF','%ODBC_ERROR_INVALID_KEYWORD_VALUE','%ODBC_ERROR_INVALID_LOG_FILE','%ODBC_ERROR_INVALID_NAME', + '%ODBC_ERROR_INVALID_PARAM_SEQUENCE','%ODBC_ERROR_INVALID_PATH','%ODBC_ERROR_INVALID_REQUEST_TYPE','%ODBC_ERROR_INVALID_STR','%ODBC_ERROR_LOAD_LIB_FAILED','%ODBC_ERROR_OUTPUT_STRING_TRUNCATED','%ODBC_ERROR_OUT_OF_MEM','%ODBC_ERROR_REMOVE_DSN_FAILED', + '%ODBC_ERROR_REQUEST_FAILED','%ODBC_ERROR_USAGE_UPDATE_FAILED','%ODBC_ERROR_USER_CANCELED','%ODBC_ERROR_WRITING_SYSINFO_FAILED','%ODBC_INSTALL_COMPLETE','%ODBC_INSTALL_DRIVER','%ODBC_INSTALL_INQUIRY','%ODBC_REMOVE_DEFAULT_DSN', + '%ODBC_REMOVE_DRIVER','%ODBC_REMOVE_DSN','%ODBC_REMOVE_SYS_DSN','%ODBC_SYSTEM_DSN','%ODBC_USER_DSN','%OFN_ALLOWMULTISELECT','%OFN_CREATEPROMPT','%OFN_ENABLEHOOK', + '%OFN_ENABLEINCLUDENOTIFY','%OFN_ENABLESIZING','%OFN_ENABLETEMPLATE','%OFN_ENABLETEMPLATEHANDLE','%OFN_EXPLORER','%OFN_EXTENSIONDIFFERENT','%OFN_FILEMUSTEXIST','%OFN_HIDEREADONLY', + '%OFN_LONGNAMES','%OFN_NOCHANGEDIR','%OFN_NODEREFERENCELINKS','%OFN_NOLONGNAMES','%OFN_NONETWORKBUTTON','%OFN_NOREADONLYRETURN','%OFN_NOTESTFILECREATE','%OFN_NOVALIDATE', + '%OFN_OVERWRITEPROMPT','%OFN_PATHMUSTEXIST','%OFN_READONLY','%OFN_SHAREAWARE','%OFN_SHOWHELP','%OS_ERROR_CALLFUNCTION','%OS_ERROR_EMPTYSTRING','%OS_ERROR_LOADLIBRARY', + '%OS_ERROR_SUCCESS','%OS_ERROR_WRONGPARAMETER','%OS_SHELL_ASYNC','%OS_SHELL_SYNC','%OS_WINDOWS_2K','%OS_WINDOWS_95','%OS_WINDOWS_95_OSR2','%OS_WINDOWS_98', + '%OS_WINDOWS_98_SE','%OS_WINDOWS_ME','%OS_WINDOWS_NT','%OS_WINDOWS_SERVER_2003','%OS_WINDOWS_SERVER_LONGHORN','%OS_WINDOWS_SERVER_LONGHORN_DC','%OS_WINDOWS_VISTA','%OS_WINDOWS_XP', + '%OS_WNDSTYLE_HIDE','%OS_WNDSTYLE_MAXIMIZED','%OS_WNDSTYLE_MINIMIZED','%OS_WNDSTYLE_MINIMIZEDNOFOCUS','%OS_WNDSTYLE_NORMAL','%OS_WNDSTYLE_NORMALNOFOCUS','%PATH_EXT','%PATH_FILE', + '%PATH_FILEEXT','%PATH_ROOT','%PATH_ROOTPATH','%PATH_ROOTPATHPROG','%PATH_ROOTPATHPROGEXT','%PBM_DELTAPOS','%PBM_GETPOS','%PBM_GETRANGE', + '%PBM_SETBARCOLOR','%PBM_SETBKCOLOR','%PBM_SETPOS','%PBM_SETRANGE','%PBM_SETRANGE32','%PBM_SETSTEP','%PBM_STEPIT','%PBS_SMOOTH', + '%PBS_VERTICAL','%PC_DISABLEWAKEEVENT_OFF','%PC_DISABLEWAKEEVENT_ON','%PC_EB_NOCONFIRMATION','%PC_EB_NOPROGRESSUI','%PC_EB_NORMAL','%PC_EB_NOSOUND','%PC_FORCECRITICAL_OFF', + '%PC_FORCECRITICAL_ON','%PC_HIBERNATE_OFF','%PC_HIBERNATE_ON','%PC_RD_FORCE','%PC_RD_FORCEIFHUNG','%PC_RD_LOGOFF','%PC_RD_POWEROFF','%PC_RD_REBOOT', + '%PC_RD_SHUTDOWN','%PC_SD_DONOT_FORCE','%PC_SD_DONOT_REBOOT','%PC_SD_FORCE','%PC_SD_REBOOT','%PFA_CENTER','%PFA_LEFT','%PFA_RIGHT', + '%PF_3DNOW_INSTRUCTIONS_AVAILABLE','%PF_CHANNELS_ENABLED','%PF_COMPARE64_EXCHANGE128','%PF_COMPARE_EXCHANGE128','%PF_COMPARE_EXCHANGE_DOUBLE','%PF_FLOATING_POINT_EMULATED','%PF_FLOATING_POINT_PRECISION_ERRATA','%PF_MMX_INSTRUCTIONS_AVAILABLE', + '%PF_NX_ENABLED','%PF_PAE_ENABLED','%PF_RDTSC_INSTRUCTION_AVAILABLE','%PF_SSE3_INSTRUCTIONS_AVAILABLE','%PF_XMMI64_INSTRUCTIONS_AVAILABLE','%PF_XMMI_INSTRUCTIONS_AVAILABLE','%PGM_FIRST','%RED', + '%RTF_UBB','%SAPI_SVSFDEFAULT','%SAPI_SVSFISFILENAME','%SAPI_SVSFISNOTXML','%SAPI_SVSFISXML','%SAPI_SVSFLAGSASYNC','%SAPI_SVSFNLPMASK','%SAPI_SVSFNLPSPEAKPUNC', + '%SAPI_SVSFPERSISTXML','%SAPI_SVSFPURGEBEFORESPEAK','%SAPI_SVSFUNUSEDFLAGS','%SAPI_SVSFVOICEMASK','%SBS_SIZEGRIP','%SB_BOTTOM','%SB_ENDSCROLL','%SB_LEFT', + '%SB_LINEDOWN','%SB_LINELEFT','%SB_LINERIGHT','%SB_LINEUP','%SB_PAGEDOWN','%SB_PAGELEFT','%SB_PAGERIGHT','%SB_PAGEUP', + '%SB_RIGHT','%SB_SETPARTS','%SB_SETTEXT','%SB_THUMBPOSITION','%SB_THUMBTRACK','%SB_TOP','%SCF_ALL','%SCF_ASSOCIATEFONT', + '%SCF_DEFAULT','%SCF_NOKBUPDATE','%SCF_SELECTION','%SCF_USEUIRULES','%SCF_WORD','%SC_CLOSE','%SC_CONTEXTHELP','%SC_HOTKEY', + '%SC_HSCROLL','%SC_KEYMENU','%SC_MAXIMIZE','%SC_MINIMIZE','%SC_MONITORPOWER','%SC_MOUSEMENU','%SC_MOVE','%SC_NEXTWINDOW', + '%SC_PREVWINDOW','%SC_RESTORE','%SC_SCREENSAVE','%SC_SIZE','%SC_TASKLIST','%SC_VSCROLL','%SERVICE_ACTIVE','%SERVICE_AUTO_START', + '%SERVICE_BOOT_START','%SERVICE_CONTINUE_PENDING','%SERVICE_DEMAND_START','%SERVICE_DISABLED','%SERVICE_DRIVER','%SERVICE_INACTIVE','%SERVICE_INFO_DISPLAY_NAME','%SERVICE_INFO_NAME', + '%SERVICE_PAUSED','%SERVICE_PAUSE_PENDING','%SERVICE_RUNNING','%SERVICE_START_PENDING','%SERVICE_STATE_ALL','%SERVICE_STOPPED','%SERVICE_STOP_PENDING','%SERVICE_SYSTEM_START', + '%SERVICE_TYPE_ALL','%SERVICE_WIN32','%SES_ALLOWBEEPS','%SES_BEEPONMAXTEXT','%SES_BIDI','%SES_EMULATE10','%SES_EMULATESYSEDIT','%SES_EXTENDBACKCOLOR', + '%SES_LOWERCASE','%SES_MAPCPS','%SES_NOIME','%SES_NOINPUTSEQUENCECHK','%SES_SCROLLONKILLFOCUS','%SES_UPPERCASE','%SES_USEAIMM','%SES_USECRLF', + '%SES_XLTCRCRLFTOCR','%SF_RTF','%SF_TEXT','%SMTP_SET_ATTACH_CONTENT_TYPE','%SMTP_SET_CONTENT_TYPE_PREFIX','%SQL_AA_FALSE','%SQL_AA_TRUE','%SQL_ACCESSIBLE_PROCEDURES', + '%SQL_ACCESSIBLE_TABLES','%SQL_ACCESS_MODE','%SQL_ACTIVE_CONNECTIONS','%SQL_ACTIVE_ENVIRONMENTS','%SQL_ACTIVE_STATEMENTS','%SQL_ADD','%SQL_AD_ADD_CONSTRAINT_DEFERRABLE','%SQL_AD_ADD_CONSTRAINT_INITIALLY_DEFERRED', + '%SQL_AD_ADD_CONSTRAINT_INITIALLY_IMMEDIATE','%SQL_AD_ADD_CONSTRAINT_NON_DEFERRABLE','%SQL_AD_ADD_DOMAIN_CONSTRAINT','%SQL_AD_ADD_DOMAIN_DEFAULT','%SQL_AD_CONSTRAINT_NAME_DEFINITION','%SQL_AD_DROP_DOMAIN_CONSTRAINT','%SQL_AD_DROP_DOMAIN_DEFAULT','%SQL_AF_ALL', + '%SQL_AF_AVG','%SQL_AF_COUNT','%SQL_AF_DISTINCT','%SQL_AF_MAX','%SQL_AF_MIN','%SQL_AF_SUM','%SQL_AGGREGATE_FUNCTIONS','%SQL_ALL_EXCEPT_LIKE', + '%SQL_ALL_TYPES','%SQL_ALTER_DOMAIN','%SQL_ALTER_TABLE','%SQL_AM_CONNECTION','%SQL_AM_NONE','%SQL_AM_STATEMENT','%SQL_API_ALL_FUNCTIONS','%SQL_API_LOADBYORDINAL', + '%SQL_API_ODBC3_ALL_FUNCTIONS','%SQL_API_ODBC3_ALL_FUNCTIONS_SIZE','%SQL_API_SQLALLOCCONNECT','%SQL_API_SQLALLOCENV','%SQL_API_SQLALLOCHANDLE','%SQL_API_SQLALLOCHANDLESTD','%SQL_API_SQLALLOCSTMT','%SQL_API_SQLBINDCOL', + '%SQL_API_SQLBINDPARAM','%SQL_API_SQLBINDPARAMETER','%SQL_API_SQLBROWSECONNECT','%SQL_API_SQLBULKOPERATIONS','%SQL_API_SQLCANCEL','%SQL_API_SQLCLOSECURSOR','%SQL_API_SQLCOLATTRIBUTE','%SQL_API_SQLCOLATTRIBUTES', + '%SQL_API_SQLCOLUMNPRIVILEGES','%SQL_API_SQLCOLUMNS','%SQL_API_SQLCONNECT','%SQL_API_SQLCOPYDESC','%SQL_API_SQLDATASOURCES','%SQL_API_SQLDESCRIBECOL','%SQL_API_SQLDESCRIBEPARAM','%SQL_API_SQLDISCONNECT', + '%SQL_API_SQLDRIVERCONNECT','%SQL_API_SQLDRIVERS','%SQL_API_SQLENDTRAN','%SQL_API_SQLERROR','%SQL_API_SQLEXECDIRECT','%SQL_API_SQLEXECUTE','%SQL_API_SQLEXTENDEDFETCH','%SQL_API_SQLFETCH', + '%SQL_API_SQLFETCHSCROLL','%SQL_API_SQLFOREIGNKEYS','%SQL_API_SQLFREECONNECT','%SQL_API_SQLFREEENV','%SQL_API_SQLFREEHANDLE','%SQL_API_SQLFREESTMT','%SQL_API_SQLGETCONNECTATTR','%SQL_API_SQLGETCONNECTOPTION', + '%SQL_API_SQLGETCURSORNAME','%SQL_API_SQLGETDATA','%SQL_API_SQLGETDESCFIELD','%SQL_API_SQLGETDESCREC','%SQL_API_SQLGETDIAGFIELD','%SQL_API_SQLGETDIAGREC','%SQL_API_SQLGETENVATTR','%SQL_API_SQLGETFUNCTIONS', + '%SQL_API_SQLGETINFO','%SQL_API_SQLGETSTMTATTR','%SQL_API_SQLGETSTMTOPTION','%SQL_API_SQLGETTYPEINFO','%SQL_API_SQLMORERESULTS','%SQL_API_SQLNATIVESQL','%SQL_API_SQLNUMPARAMS','%SQL_API_SQLNUMRESULTCOLS', + '%SQL_API_SQLPARAMDATA','%SQL_API_SQLPARAMOPTIONS','%SQL_API_SQLPREPARE','%SQL_API_SQLPRIMARYKEYS','%SQL_API_SQLPROCEDURECOLUMNS','%SQL_API_SQLPROCEDURES','%SQL_API_SQLPUTDATA','%SQL_API_SQLROWCOUNT', + '%SQL_API_SQLSETCONNECTATTR','%SQL_API_SQLSETCONNECTOPTION','%SQL_API_SQLSETCURSORNAME','%SQL_API_SQLSETDESCFIELD','%SQL_API_SQLSETDESCREC','%SQL_API_SQLSETENVATTR','%SQL_API_SQLSETPARAM','%SQL_API_SQLSETPOS', + '%SQL_API_SQLSETSCROLLOPTIONS','%SQL_API_SQLSETSTMTATTR','%SQL_API_SQLSETSTMTOPTION','%SQL_API_SQLSPECIALCOLUMNS','%SQL_API_SQLSTATISTICS','%SQL_API_SQLTABLEPRIVILEGES','%SQL_API_SQLTABLES','%SQL_API_SQLTRANSACT', + '%SQL_ARD_TYPE','%SQL_ASYNC_ENABLE','%SQL_ASYNC_ENABLE_DEFAULT','%SQL_ASYNC_ENABLE_OFF','%SQL_ASYNC_ENABLE_ON','%SQL_ASYNC_MODE','%SQL_ATTR_ACCESS_MODE','%SQL_ATTR_ANSI_APP', + '%SQL_ATTR_APP_PARAM_DESC','%SQL_ATTR_APP_ROW_DESC','%SQL_ATTR_ASYNC_ENABLE','%SQL_ATTR_AUTOCOMMIT','%SQL_ATTR_AUTO_IPD','%SQL_ATTR_CONCURRENCY','%SQL_ATTR_CONNECTION_DEAD','%SQL_ATTR_CONNECTION_POOLING', + '%SQL_ATTR_CONNECTION_TIMEOUT','%SQL_ATTR_CP_MATCH','%SQL_ATTR_CURRENT_CATALOG','%SQL_ATTR_CURSOR_SCROLLABLE','%SQL_ATTR_CURSOR_SENSITIVITY','%SQL_ATTR_CURSOR_TYPE','%SQL_ATTR_DISCONNECT_BEHAVIOR','%SQL_ATTR_ENABLE_AUTO_IPD', + '%SQL_ATTR_ENLIST_IN_DTC','%SQL_ATTR_ENLIST_IN_XA','%SQL_ATTR_FETCH_BOOKMARK_PTR','%SQL_ATTR_IMP_PARAM_DESC','%SQL_ATTR_IMP_ROW_DESC','%SQL_ATTR_KEYSET_SIZE','%SQL_ATTR_LOGIN_TIMEOUT','%SQL_ATTR_MAX_LENGTH', + '%SQL_ATTR_MAX_ROWS','%SQL_ATTR_METADATA_ID','%SQL_ATTR_NOSCAN','%SQL_ATTR_ODBC_CURSORS','%SQL_ATTR_ODBC_VERSION','%SQL_ATTR_OUTPUT_NTS','%SQL_ATTR_PACKET_SIZE','%SQL_ATTR_PARAMSET_SIZE', + '%SQL_ATTR_PARAMS_PROCESSED_PTR','%SQL_ATTR_PARAM_BIND_OFFSET_PTR','%SQL_ATTR_PARAM_BIND_TYPE','%SQL_ATTR_PARAM_OPERATION_PTR','%SQL_ATTR_PARAM_STATUS_PTR','%SQL_ATTR_QUERY_TIMEOUT','%SQL_ATTR_QUIET_MODE','%SQL_ATTR_READONLY', + '%SQL_ATTR_READWRITE_UNKNOWN','%SQL_ATTR_RETRIEVE_DATA','%SQL_ATTR_ROWS_FETCHED_PTR','%SQL_ATTR_ROW_ARRAY_SIZE','%SQL_ATTR_ROW_BIND_OFFSET_PTR','%SQL_ATTR_ROW_BIND_TYPE','%SQL_ATTR_ROW_NUMBER','%SQL_ATTR_ROW_OPERATION_PTR', + '%SQL_ATTR_ROW_STATUS_PTR','%SQL_ATTR_SIMULATE_CURSOR','%SQL_ATTR_TRACE','%SQL_ATTR_TRACEFILE','%SQL_ATTR_TRANSLATE_LIB','%SQL_ATTR_TRANSLATE_OPTION','%SQL_ATTR_TXN_ISOLATION','%SQL_ATTR_USE_BOOKMARKS', + '%SQL_ATTR_WRITE','%SQL_AT_ADD_COLUMN','%SQL_AT_ADD_COLUMN_COLLATION','%SQL_AT_ADD_COLUMN_DEFAULT','%SQL_AT_ADD_COLUMN_SINGLE','%SQL_AT_ADD_CONSTRAINT','%SQL_AT_ADD_TABLE_CONSTRAINT','%SQL_AT_CONSTRAINT_DEFERRABLE', + '%SQL_AT_CONSTRAINT_INITIALLY_DEFERRED','%SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE','%SQL_AT_CONSTRAINT_NAME_DEFINITION','%SQL_AT_CONSTRAINT_NON_DEFERRABLE','%SQL_AT_DROP_COLUMN','%SQL_AT_DROP_COLUMN_CASCADE','%SQL_AT_DROP_COLUMN_DEFAULT','%SQL_AT_DROP_COLUMN_RESTRICT', + '%SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE','%SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT','%SQL_AT_SET_COLUMN_DEFAULT','%SQL_AUTOCOMMIT','%SQL_AUTOCOMMIT_DEFAULT','%SQL_AUTOCOMMIT_OFF','%SQL_AUTOCOMMIT_ON','%SQL_BATCH_ROW_COUNT', + '%SQL_BATCH_SUPPORT','%SQL_BEST_ROWID','%SQL_BIGINT','%SQL_BINARY','%SQL_BIND_BY_COLUMN','%SQL_BIND_TYPE','%SQL_BIND_TYPE_DEFAULT','%SQL_BIT', + '%SQL_BOOKMARK_PERSISTENCE','%SQL_BP_CLOSE','%SQL_BP_DELETE','%SQL_BP_DROP','%SQL_BP_OTHER_HSTMT','%SQL_BP_SCROLL','%SQL_BP_TRANSACTION','%SQL_BP_UPDATE', + '%SQL_BRC_EXPLICIT','%SQL_BRC_PROCEDURES','%SQL_BRC_ROLLED_UP','%SQL_BS_ROW_COUNT_EXPLICIT','%SQL_BS_ROW_COUNT_PROC','%SQL_BS_SELECT_EXPLICIT','%SQL_BS_SELECT_PROC','%SQL_CA1_ABSOLUTE', + '%SQL_CA1_BOOKMARK','%SQL_CA1_BULK_ADD','%SQL_CA1_BULK_DELETE_BY_BOOKMARK','%SQL_CA1_BULK_FETCH_BY_BOOKMARK','%SQL_CA1_BULK_UPDATE_BY_BOOKMARK','%SQL_CA1_LOCK_EXCLUSIVE','%SQL_CA1_LOCK_NO_CHANGE','%SQL_CA1_LOCK_UNLOCK', + '%SQL_CA1_NEXT','%SQL_CA1_POSITIONED_DELETE','%SQL_CA1_POSITIONED_UPDATE','%SQL_CA1_POS_DELETE','%SQL_CA1_POS_POSITION','%SQL_CA1_POS_REFRESH','%SQL_CA1_POS_UPDATE','%SQL_CA1_RELATIVE', + '%SQL_CA1_SELECT_FOR_UPDATE','%SQL_CA2_CRC_APPROXIMATE','%SQL_CA2_CRC_EXACT','%SQL_CA2_LOCK_CONCURRENCY','%SQL_CA2_MAX_ROWS_AFFECTS_ALL','%SQL_CA2_MAX_ROWS_CATALOG','%SQL_CA2_MAX_ROWS_DELETE','%SQL_CA2_MAX_ROWS_INSERT', + '%SQL_CA2_MAX_ROWS_SELECT','%SQL_CA2_MAX_ROWS_UPDATE','%SQL_CA2_OPT_ROWVER_CONCURRENCY','%SQL_CA2_OPT_VALUES_CONCURRENCY','%SQL_CA2_READ_ONLY_CONCURRENCY','%SQL_CA2_SENSITIVITY_ADDITIONS','%SQL_CA2_SENSITIVITY_DELETIONS','%SQL_CA2_SENSITIVITY_UPDATES', + '%SQL_CA2_SIMULATE_NON_UNIQUE','%SQL_CA2_SIMULATE_TRY_UNIQUE','%SQL_CA2_SIMULATE_UNIQUE','%SQL_CASCADE','%SQL_CATALOG_LOCATION','%SQL_CATALOG_NAME','%SQL_CATALOG_NAME_SEPARATOR','%SQL_CATALOG_TERM', + '%SQL_CATALOG_USAGE','%SQL_CA_CONSTRAINT_DEFERRABLE','%SQL_CA_CONSTRAINT_INITIALLY_DEFERRED','%SQL_CA_CONSTRAINT_INITIALLY_IMMEDIATE','%SQL_CA_CONSTRAINT_NON_DEFERRABLE','%SQL_CA_CREATE_ASSERTION','%SQL_CB_CLOSE','%SQL_CB_DELETE', + '%SQL_CB_NON_NULL','%SQL_CB_NULL','%SQL_CB_PRESERVE','%SQL_CCOL_CREATE_COLLATION','%SQL_CCS_COLLATE_CLAUSE','%SQL_CCS_CREATE_CHARACTER_SET','%SQL_CCS_LIMITED_COLLATION','%SQL_CC_CLOSE', + '%SQL_CC_DELETE','%SQL_CC_PRESERVE','%SQL_CDO_COLLATION','%SQL_CDO_CONSTRAINT','%SQL_CDO_CONSTRAINT_DEFERRABLE','%SQL_CDO_CONSTRAINT_INITIALLY_DEFERRED','%SQL_CDO_CONSTRAINT_INITIALLY_IMMEDIATE','%SQL_CDO_CONSTRAINT_NAME_DEFINITION', + '%SQL_CDO_CONSTRAINT_NON_DEFERRABLE','%SQL_CDO_CREATE_DOMAIN','%SQL_CDO_DEFAULT','%SQL_CD_FALSE','%SQL_CD_TRUE','%SQL_CHAR','%SQL_CLOSE','%SQL_CL_END', + '%SQL_CL_START','%SQL_CN_ANY','%SQL_CN_DIFFERENT','%SQL_CN_NONE','%SQL_CODE_DATE','%SQL_CODE_DAY','%SQL_CODE_DAY_TO_HOUR','%SQL_CODE_DAY_TO_MINUTE', + '%SQL_CODE_DAY_TO_SECOND','%SQL_CODE_HOUR','%SQL_CODE_HOUR_TO_MINUTE','%SQL_CODE_HOUR_TO_SECOND','%SQL_CODE_MINUTE','%SQL_CODE_MINUTE_TO_SECOND','%SQL_CODE_MONTH','%SQL_CODE_SECOND', + '%SQL_CODE_TIME','%SQL_CODE_TIMESTAMP','%SQL_CODE_YEAR','%SQL_CODE_YEAR_TO_MONTH','%SQL_COLATT_OPT_MAX','%SQL_COLATT_OPT_MIN','%SQL_COLLATION_SEQ','%SQL_COLUMN_ALIAS', + '%SQL_COLUMN_AUTO_INCREMENT','%SQL_COLUMN_CASE_SENSITIVE','%SQL_COLUMN_COUNT','%SQL_COLUMN_DISPLAY_SIZE','%SQL_COLUMN_IGNORE','%SQL_COLUMN_LABEL','%SQL_COLUMN_LENGTH','%SQL_COLUMN_MONEY', + '%SQL_COLUMN_NAME','%SQL_COLUMN_NULLABLE','%SQL_COLUMN_NUMBER_UNKNOWN','%SQL_COLUMN_OWNER_NAME','%SQL_COLUMN_PRECISION','%SQL_COLUMN_QUALIFIER_NAME','%SQL_COLUMN_SCALE','%SQL_COLUMN_SEARCHABLE', + '%SQL_COLUMN_TABLE_NAME','%SQL_COLUMN_TYPE','%SQL_COLUMN_TYPE_NAME','%SQL_COLUMN_UNSIGNED','%SQL_COLUMN_UPDATABLE','%SQL_COL_PRED_BASIC','%SQL_COL_PRED_CHAR','%SQL_COMMIT', + '%SQL_CONCAT_NULL_BEHAVIOR','%SQL_CONCURRENCY','%SQL_CONCUR_DEFAULT','%SQL_CONCUR_LOCK','%SQL_CONCUR_READ_ONLY','%SQL_CONCUR_ROWVER','%SQL_CONCUR_TIMESTAMP','%SQL_CONCUR_VALUES', + '%SQL_CONVERT_BIGINT','%SQL_CONVERT_BINARY','%SQL_CONVERT_BIT','%SQL_CONVERT_CHAR','%SQL_CONVERT_DATE','%SQL_CONVERT_DECIMAL','%SQL_CONVERT_DOUBLE','%SQL_CONVERT_FLOAT', + '%SQL_CONVERT_FUNCTIONS','%SQL_CONVERT_GUID','%SQL_CONVERT_INTEGER','%SQL_CONVERT_INTERVAL_DAY_TIME','%SQL_CONVERT_INTERVAL_YEAR_MONTH','%SQL_CONVERT_LONGVARBINARY','%SQL_CONVERT_LONGVARCHAR','%SQL_CONVERT_NUMERIC', + '%SQL_CONVERT_REAL','%SQL_CONVERT_SMALLINT','%SQL_CONVERT_TIME','%SQL_CONVERT_TIMESTAMP','%SQL_CONVERT_TINYINT','%SQL_CONVERT_VARBINARY','%SQL_CONVERT_VARCHAR','%SQL_CONVERT_WCHAR', + '%SQL_CONVERT_WLONGVARCHAR','%SQL_CONVERT_WVARCHAR','%SQL_CORRELATION_NAME','%SQL_CP_DEFAULT','%SQL_CP_MATCH_DEFAULT','%SQL_CP_OFF','%SQL_CP_ONE_PER_DRIVER','%SQL_CP_ONE_PER_HENV', + '%SQL_CP_RELAXED_MATCH','%SQL_CP_STRICT_MATCH','%SQL_CREATE_ASSERTION','%SQL_CREATE_CHARACTER_SET','%SQL_CREATE_COLLATION','%SQL_CREATE_DOMAIN','%SQL_CREATE_SCHEMA','%SQL_CREATE_TABLE', + '%SQL_CREATE_TRANSLATION','%SQL_CREATE_VIEW','%SQL_CR_CLOSE','%SQL_CR_DELETE','%SQL_CR_PRESERVE','%SQL_CS_AUTHORIZATION','%SQL_CS_CREATE_SCHEMA','%SQL_CS_DEFAULT_CHARACTER_SET', + '%SQL_CTR_CREATE_TRANSLATION','%SQL_CT_COLUMN_COLLATION','%SQL_CT_COLUMN_CONSTRAINT','%SQL_CT_COLUMN_DEFAULT','%SQL_CT_COMMIT_DELETE','%SQL_CT_COMMIT_PRESERVE','%SQL_CT_CONSTRAINT_DEFERRABLE','%SQL_CT_CONSTRAINT_INITIALLY_DEFERRED', + '%SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE','%SQL_CT_CONSTRAINT_NAME_DEFINITION','%SQL_CT_CONSTRAINT_NON_DEFERRABLE','%SQL_CT_CREATE_TABLE','%SQL_CT_GLOBAL_TEMPORARY','%SQL_CT_LOCAL_TEMPORARY','%SQL_CT_TABLE_CONSTRAINT','%SQL_CURRENT_QUALIFIER', + '%SQL_CURSOR_COMMIT_BEHAVIOR','%SQL_CURSOR_DYNAMIC','%SQL_CURSOR_FORWARD_ONLY','%SQL_CURSOR_KEYSET_DRIVEN','%SQL_CURSOR_ROLLBACK_BEHAVIOR','%SQL_CURSOR_SENSITIVITY','%SQL_CURSOR_STATIC','%SQL_CURSOR_TYPE', + '%SQL_CURSOR_TYPE_DEFAULT','%SQL_CUR_DEFAULT','%SQL_CUR_USE_DRIVER','%SQL_CUR_USE_IF_NEEDED','%SQL_CUR_USE_ODBC','%SQL_CU_DML_STATEMENTS','%SQL_CU_INDEX_DEFINITION','%SQL_CU_PRIVILEGE_DEFINITION', + '%SQL_CU_PROCEDURE_INVOCATION','%SQL_CU_TABLE_DEFINITION','%SQL_CVT_BIGINT','%SQL_CVT_BINARY','%SQL_CVT_BIT','%SQL_CVT_CHAR','%SQL_CVT_DATE','%SQL_CVT_DECIMAL', + '%SQL_CVT_DOUBLE','%SQL_CVT_FLOAT','%SQL_CVT_GUID','%SQL_CVT_INTEGER','%SQL_CVT_INTERVAL_DAY_TIME','%SQL_CVT_INTERVAL_YEAR_MONTH','%SQL_CVT_LONGVARBINARY','%SQL_CVT_LONGVARCHAR', + '%SQL_CVT_NUMERIC','%SQL_CVT_REAL','%SQL_CVT_SMALLINT','%SQL_CVT_TIME','%SQL_CVT_TIMESTAMP','%SQL_CVT_TINYINT','%SQL_CVT_VARBINARY','%SQL_CVT_VARCHAR', + '%SQL_CVT_WCHAR','%SQL_CVT_WLONGVARCHAR','%SQL_CVT_WVARCHAR','%SQL_CV_CASCADED','%SQL_CV_CHECK_OPTION','%SQL_CV_CREATE_VIEW','%SQL_CV_LOCAL','%SQL_C_BINARY', + '%SQL_C_BIT','%SQL_C_BOOKMARK','%SQL_C_CHAR','%SQL_C_DATE','%SQL_C_DEFAULT','%SQL_C_DOUBLE','%SQL_C_FLOAT','%SQL_C_GUID', + '%SQL_C_INTERVAL_DAY','%SQL_C_INTERVAL_DAY_TO_HOUR','%SQL_C_INTERVAL_DAY_TO_MINUTE','%SQL_C_INTERVAL_DAY_TO_SECOND','%SQL_C_INTERVAL_HOUR','%SQL_C_INTERVAL_HOUR_TO_MINUTE','%SQL_C_INTERVAL_HOUR_TO_SECOND','%SQL_C_INTERVAL_MINUTE', + '%SQL_C_INTERVAL_MINUTE_TO_SECOND','%SQL_C_INTERVAL_MONTH','%SQL_C_INTERVAL_SECOND','%SQL_C_INTERVAL_YEAR','%SQL_C_INTERVAL_YEAR_TO_MONTH','%SQL_C_LONG','%SQL_C_NUMERIC','%SQL_C_SBIGINT', + '%SQL_C_SHORT','%SQL_C_SLONG','%SQL_C_SSHORT','%SQL_C_STINYINT','%SQL_C_TIME','%SQL_C_TIMESTAMP','%SQL_C_TINYINT','%SQL_C_TYPE_DATE', + '%SQL_C_TYPE_TIME','%SQL_C_TYPE_TIMESTAMP','%SQL_C_UBIGINT','%SQL_C_ULONG','%SQL_C_USHORT','%SQL_C_UTINYINT','%SQL_C_VARBOOKMARK','%SQL_DATABASE_NAME', + '%SQL_DATA_AT_EXEC','%SQL_DATA_SOURCE_NAME','%SQL_DATA_SOURCE_READ_ONLY','%SQL_DATE','%SQL_DATETIME','%SQL_DATETIME_LITERALS','%SQL_DATE_LEN','%SQL_DAY', + '%SQL_DAY_TO_HOUR','%SQL_DAY_TO_MINUTE','%SQL_DAY_TO_SECOND','%SQL_DA_DROP_ASSERTION','%SQL_DBMS_NAME','%SQL_DBMS_VER','%SQL_DB_DEFAULT','%SQL_DB_DISCONNECT', + '%SQL_DB_RETURN_TO_POOL','%SQL_DCS_DROP_CHARACTER_SET','%SQL_DC_DROP_COLLATION','%SQL_DDL_INDEX','%SQL_DD_CASCADE','%SQL_DD_DROP_DOMAIN','%SQL_DD_RESTRICT','%SQL_DECIMAL', + '%SQL_DEFAULT','%SQL_DEFAULT_PARAM','%SQL_DEFAULT_TXN_ISOLATION','%SQL_DELETE','%SQL_DELETE_BY_BOOKMARK','%SQL_DESCRIBE_PARAMETER','%SQL_DESC_ALLOC_AUTO','%SQL_DESC_ALLOC_TYPE', + '%SQL_DESC_ALLOC_USER','%SQL_DESC_ARRAY_SIZE','%SQL_DESC_ARRAY_STATUS_PTR','%SQL_DESC_AUTO_UNIQUE_VALUE','%SQL_DESC_BASE_COLUMN_NAME','%SQL_DESC_BASE_TABLE_NAME','%SQL_DESC_BIND_OFFSET_PTR','%SQL_DESC_BIND_TYPE', + '%SQL_DESC_CASE_SENSITIVE','%SQL_DESC_CATALOG_NAME','%SQL_DESC_CONCISE_TYPE','%SQL_DESC_COUNT','%SQL_DESC_DATA_PTR','%SQL_DESC_DATETIME_INTERVAL_CODE','%SQL_DESC_DATETIME_INTERVAL_PRECISION','%SQL_DESC_DISPLAY_SIZE', + '%SQL_DESC_FIXED_PREC_SCALE','%SQL_DESC_INDICATOR_PTR','%SQL_DESC_LABEL','%SQL_DESC_LENGTH','%SQL_DESC_LITERAL_PREFIX','%SQL_DESC_LITERAL_SUFFIX','%SQL_DESC_LOCAL_TYPE_NAME','%SQL_DESC_MAXIMUM_SCALE', + '%SQL_DESC_MINIMUM_SCALE','%SQL_DESC_NAME','%SQL_DESC_NULLABLE','%SQL_DESC_NUM_PREC_RADIX','%SQL_DESC_OCTET_LENGTH','%SQL_DESC_OCTET_LENGTH_PTR','%SQL_DESC_PARAMETER_TYPE','%SQL_DESC_PRECISION', + '%SQL_DESC_ROWS_PROCESSED_PTR','%SQL_DESC_SCALE','%SQL_DESC_SCHEMA_NAME','%SQL_DESC_SEARCHABLE','%SQL_DESC_TABLE_NAME','%SQL_DESC_TYPE','%SQL_DESC_TYPE_NAME','%SQL_DESC_UNNAMED', + '%SQL_DESC_UNSIGNED','%SQL_DESC_UPDATABLE','%SQL_DIAG_ALTER_TABLE','%SQL_DIAG_CALL','%SQL_DIAG_CLASS_ORIGIN','%SQL_DIAG_COLUMN_NUMBER','%SQL_DIAG_CONNECTION_NAME','%SQL_DIAG_CREATE_INDEX', + '%SQL_DIAG_CREATE_TABLE','%SQL_DIAG_CREATE_VIEW','%SQL_DIAG_CURSOR_ROW_COUNT','%SQL_DIAG_DELETE_WHERE','%SQL_DIAG_DROP_INDEX','%SQL_DIAG_DROP_TABLE','%SQL_DIAG_DROP_VIEW','%SQL_DIAG_DYNAMIC_DELETE_CURSOR', + '%SQL_DIAG_DYNAMIC_FUNCTION','%SQL_DIAG_DYNAMIC_FUNCTION_CODE','%SQL_DIAG_DYNAMIC_UPDATE_CURSOR','%SQL_DIAG_GRANT','%SQL_DIAG_INSERT','%SQL_DIAG_MESSAGE_TEXT','%SQL_DIAG_NATIVE','%SQL_DIAG_NUMBER', + '%SQL_DIAG_RETURNCODE','%SQL_DIAG_REVOKE','%SQL_DIAG_ROW_COUNT','%SQL_DIAG_ROW_NUMBER','%SQL_DIAG_SELECT_CURSOR','%SQL_DIAG_SERVER_NAME','%SQL_DIAG_SQLSTATE','%SQL_DIAG_SUBCLASS_ORIGIN', + '%SQL_DIAG_UNKNOWN_STATEMENT','%SQL_DIAG_UPDATE_WHERE','%SQL_DI_CREATE_INDEX','%SQL_DI_DROP_INDEX','%SQL_DL_SQL92_DATE','%SQL_DL_SQL92_INTERVAL_DAY','%SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR','%SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE', + '%SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND','%SQL_DL_SQL92_INTERVAL_HOUR','%SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE','%SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND','%SQL_DL_SQL92_INTERVAL_MINUTE','%SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND','%SQL_DL_SQL92_INTERVAL_MONTH','%SQL_DL_SQL92_INTERVAL_SECOND', + '%SQL_DL_SQL92_INTERVAL_YEAR','%SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH','%SQL_DL_SQL92_TIME','%SQL_DL_SQL92_TIMESTAMP','%SQL_DM_VER','%SQL_DOUBLE','%SQL_DRIVER_COMPLETE','%SQL_DRIVER_COMPLETE_REQUIRED', + '%SQL_DRIVER_HDBC','%SQL_DRIVER_HDESC','%SQL_DRIVER_HENV','%SQL_DRIVER_HLIB','%SQL_DRIVER_HSTMT','%SQL_DRIVER_NAME','%SQL_DRIVER_NOPROMPT','%SQL_DRIVER_ODBC_VER', + '%SQL_DRIVER_PROMPT','%SQL_DRIVER_VER','%SQL_DROP','%SQL_DROP_ASSERTION','%SQL_DROP_CHARACTER_SET','%SQL_DROP_COLLATION','%SQL_DROP_DOMAIN','%SQL_DROP_SCHEMA', + '%SQL_DROP_TABLE','%SQL_DROP_TRANSLATION','%SQL_DROP_VIEW','%SQL_DS_CASCADE','%SQL_DS_DROP_SCHEMA','%SQL_DS_RESTRICT','%SQL_DTC_DONE','%SQL_DTC_ENLIST_EXPENSIVE', + '%SQL_DTC_TRANSITION_COST','%SQL_DTC_UNENLIST_EXPENSIVE','%SQL_DTR_DROP_TRANSLATION','%SQL_DT_CASCADE','%SQL_DT_DROP_TABLE','%SQL_DT_RESTRICT','%SQL_DV_CASCADE','%SQL_DV_DROP_VIEW', + '%SQL_DV_RESTRICT','%SQL_DYNAMIC_CURSOR_ATTRIBUTES1','%SQL_DYNAMIC_CURSOR_ATTRIBUTES2','%SQL_ENSURE','%SQL_ENTIRE_ROWSET','%SQL_ERROR','%SQL_EXPRESSIONS_IN_ORDERBY','%SQL_FALSE', + '%SQL_FD_FETCH_ABSOLUTE','%SQL_FD_FETCH_BOOKMARK','%SQL_FD_FETCH_FIRST','%SQL_FD_FETCH_LAST','%SQL_FD_FETCH_NEXT','%SQL_FD_FETCH_PREV','%SQL_FD_FETCH_PRIOR','%SQL_FD_FETCH_RELATIVE', + '%SQL_FETCH_ABSOLUTE','%SQL_FETCH_BOOKMARK','%SQL_FETCH_BY_BOOKMARK','%SQL_FETCH_DIRECTION','%SQL_FETCH_FIRST','%SQL_FETCH_FIRST_SYSTEM','%SQL_FETCH_FIRST_USER','%SQL_FETCH_LAST', + '%SQL_FETCH_NEXT','%SQL_FETCH_PREV','%SQL_FETCH_PRIOR','%SQL_FETCH_RELATIVE','%SQL_FILE_CATALOG','%SQL_FILE_NOT_SUPPORTED','%SQL_FILE_QUALIFIER','%SQL_FILE_TABLE', + '%SQL_FILE_USAGE','%SQL_FLOAT','%SQL_FN_CVT_CAST','%SQL_FN_CVT_CONVERT','%SQL_FN_NUM_ABS','%SQL_FN_NUM_ACOS','%SQL_FN_NUM_ASIN','%SQL_FN_NUM_ATAN', + '%SQL_FN_NUM_ATAN2','%SQL_FN_NUM_CEILING','%SQL_FN_NUM_COS','%SQL_FN_NUM_COT','%SQL_FN_NUM_DEGREES','%SQL_FN_NUM_EXP','%SQL_FN_NUM_FLOOR','%SQL_FN_NUM_LOG', + '%SQL_FN_NUM_LOG10','%SQL_FN_NUM_MOD','%SQL_FN_NUM_PI','%SQL_FN_NUM_POWER','%SQL_FN_NUM_RADIANS','%SQL_FN_NUM_RAND','%SQL_FN_NUM_ROUND','%SQL_FN_NUM_SIGN', + '%SQL_FN_NUM_SIN','%SQL_FN_NUM_SQRT','%SQL_FN_NUM_TAN','%SQL_FN_NUM_TRUNCATE','%SQL_FN_STR_ASCII','%SQL_FN_STR_BIT_LENGTH','%SQL_FN_STR_CHAR','%SQL_FN_STR_CHARACTER_LENGTH', + '%SQL_FN_STR_CHAR_LENGTH','%SQL_FN_STR_CONCAT','%SQL_FN_STR_DIFFERENCE','%SQL_FN_STR_INSERT','%SQL_FN_STR_LCASE','%SQL_FN_STR_LEFT','%SQL_FN_STR_LENGTH','%SQL_FN_STR_LOCATE', + '%SQL_FN_STR_LOCATE_2','%SQL_FN_STR_LTRIM','%SQL_FN_STR_OCTET_LENGTH','%SQL_FN_STR_POSITION','%SQL_FN_STR_REPEAT','%SQL_FN_STR_REPLACE','%SQL_FN_STR_RIGHT','%SQL_FN_STR_RTRIM', + '%SQL_FN_STR_SOUNDEX','%SQL_FN_STR_SPACE','%SQL_FN_STR_SUBSTRING','%SQL_FN_STR_UCASE','%SQL_FN_SYS_DBNAME','%SQL_FN_SYS_IFNULL','%SQL_FN_SYS_USERNAME','%SQL_FN_TD_CURDATE', + '%SQL_FN_TD_CURRENT_DATE','%SQL_FN_TD_CURRENT_TIME','%SQL_FN_TD_CURRENT_TIMESTAMP','%SQL_FN_TD_CURTIME','%SQL_FN_TD_DAYNAME','%SQL_FN_TD_DAYOFMONTH','%SQL_FN_TD_DAYOFWEEK','%SQL_FN_TD_DAYOFYEAR', + '%SQL_FN_TD_EXTRACT','%SQL_FN_TD_HOUR','%SQL_FN_TD_MINUTE','%SQL_FN_TD_MONTH','%SQL_FN_TD_MONTHNAME','%SQL_FN_TD_NOW','%SQL_FN_TD_QUARTER','%SQL_FN_TD_SECOND', + '%SQL_FN_TD_TIMESTAMPADD','%SQL_FN_TD_TIMESTAMPDIFF','%SQL_FN_TD_WEEK','%SQL_FN_TD_YEAR','%SQL_FN_TSI_DAY','%SQL_FN_TSI_FRAC_SECOND','%SQL_FN_TSI_HOUR','%SQL_FN_TSI_MINUTE', + '%SQL_FN_TSI_MONTH','%SQL_FN_TSI_QUARTER','%SQL_FN_TSI_SECOND','%SQL_FN_TSI_WEEK','%SQL_FN_TSI_YEAR','%SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1','%SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2','%SQL_GB_COLLATE', + '%SQL_GB_GROUP_BY_CONTAINS_SELECT','%SQL_GB_GROUP_BY_EQUALS_SELECT','%SQL_GB_NOT_SUPPORTED','%SQL_GB_NO_RELATION','%SQL_GD_ANY_COLUMN','%SQL_GD_ANY_ORDER','%SQL_GD_BLOCK','%SQL_GD_BOUND', + '%SQL_GETDATA_EXTENSIONS','%SQL_GET_BOOKMARK','%SQL_GROUP_BY','%SQL_GUID','%SQL_HANDLE_DBC','%SQL_HANDLE_DESC','%SQL_HANDLE_ENV','%SQL_HANDLE_SENV', + '%SQL_HANDLE_STMT','%SQL_HOUR','%SQL_HOUR_TO_MINUTE','%SQL_HOUR_TO_SECOND','%SQL_IC_LOWER','%SQL_IC_MIXED','%SQL_IC_SENSITIVE','%SQL_IC_UPPER', + '%SQL_IDENTIFIER_CASE','%SQL_IDENTIFIER_QUOTE_CHAR','%SQL_IGNORE','%SQL_IK_ALL','%SQL_IK_ASC','%SQL_IK_DESC','%SQL_IK_NONE','%SQL_INDEX_ALL', + '%SQL_INDEX_CLUSTERED','%SQL_INDEX_HASHED','%SQL_INDEX_KEYWORDS','%SQL_INDEX_OTHER','%SQL_INDEX_UNIQUE','%SQL_INFO_FIRST','%SQL_INFO_SCHEMA_VIEWS','%SQL_INITIALLY_DEFERRED', + '%SQL_INITIALLY_IMMEDIATE','%SQL_INSENSITIVE','%SQL_INSERT_STATEMENT','%SQL_INTEGER','%SQL_INTEGRITY','%SQL_INTERVAL','%SQL_INTERVAL_DAY','%SQL_INTERVAL_DAY_TO_HOUR', + '%SQL_INTERVAL_DAY_TO_MINUTE','%SQL_INTERVAL_DAY_TO_SECOND','%SQL_INTERVAL_HOUR','%SQL_INTERVAL_HOUR_TO_MINUTE','%SQL_INTERVAL_HOUR_TO_SECOND','%SQL_INTERVAL_MINUTE','%SQL_INTERVAL_MINUTE_TO_SECOND','%SQL_INTERVAL_MONTH', + '%SQL_INTERVAL_SECOND','%SQL_INTERVAL_YEAR','%SQL_INTERVAL_YEAR_TO_MONTH','%SQL_INVALID_HANDLE','%SQL_ISV_ASSERTIONS','%SQL_ISV_CHARACTER_SETS','%SQL_ISV_CHECK_CONSTRAINTS','%SQL_ISV_COLLATIONS', + '%SQL_ISV_COLUMNS','%SQL_ISV_COLUMN_DOMAIN_USAGE','%SQL_ISV_COLUMN_PRIVILEGES','%SQL_ISV_CONSTRAINT_COLUMN_USAGE','%SQL_ISV_CONSTRAINT_TABLE_USAGE','%SQL_ISV_DOMAINS','%SQL_ISV_DOMAIN_CONSTRAINTS','%SQL_ISV_KEY_COLUMN_USAGE', + '%SQL_ISV_REFERENTIAL_CONSTRAINTS','%SQL_ISV_SCHEMATA','%SQL_ISV_SQL_LANGUAGES','%SQL_ISV_TABLES','%SQL_ISV_TABLE_CONSTRAINTS','%SQL_ISV_TABLE_PRIVILEGES','%SQL_ISV_TRANSLATIONS','%SQL_ISV_USAGE_PRIVILEGES', + '%SQL_ISV_VIEWS','%SQL_ISV_VIEW_COLUMN_USAGE','%SQL_ISV_VIEW_TABLE_USAGE','%SQL_IS_DAY','%SQL_IS_DAY_TO_HOUR','%SQL_IS_DAY_TO_MINUTE','%SQL_IS_DAY_TO_SECOND','%SQL_IS_HOUR', + '%SQL_IS_HOUR_TO_MINUTE','%SQL_IS_HOUR_TO_SECOND','%SQL_IS_INSERT_LITERALS','%SQL_IS_INSERT_SEARCHED','%SQL_IS_INTEGER','%SQL_IS_MINUTE','%SQL_IS_MINUTE_TO_SECOND','%SQL_IS_MONTH', + '%SQL_IS_POINTER','%SQL_IS_SECOND','%SQL_IS_SELECT_INTO','%SQL_IS_SMALLINT','%SQL_IS_UINTEGER','%SQL_IS_USMALLINT','%SQL_IS_YEAR','%SQL_IS_YEAR_TO_MONTH', + '%SQL_KEYSET_CURSOR_ATTRIBUTES1','%SQL_KEYSET_CURSOR_ATTRIBUTES2','%SQL_KEYSET_SIZE','%SQL_KEYSET_SIZE_DEFAULT','%SQL_KEYWORDS','%SQL_LCK_EXCLUSIVE','%SQL_LCK_NO_CHANGE','%SQL_LCK_UNLOCK', + '%SQL_LEN_BINARY_ATTR_OFFSET','%SQL_LEN_DATA_AT_EXEC_OFFSET','%SQL_LIKE_ESCAPE_CLAUSE','%SQL_LIKE_ONLY','%SQL_LOCK_EXCLUSIVE','%SQL_LOCK_NO_CHANGE','%SQL_LOCK_TYPES','%SQL_LOCK_UNLOCK', + '%SQL_LOGIN_TIMEOUT','%SQL_LOGIN_TIMEOUT_DEFAULT','%SQL_LONGVARBINARY','%SQL_LONGVARCHAR','%SQL_MAXIMUM_CATALOG_NAME_LENGTH','%SQL_MAXIMUM_COLUMNS_IN_GROUP_BY','%SQL_MAXIMUM_COLUMNS_IN_INDEX','%SQL_MAXIMUM_COLUMNS_IN_ORDER_BY', + '%SQL_MAXIMUM_COLUMNS_IN_SELECT','%SQL_MAXIMUM_COLUMN_NAME_LENGTH','%SQL_MAXIMUM_CONCURRENT_ACTIVITIES','%SQL_MAXIMUM_CURSOR_NAME_LENGTH','%SQL_MAXIMUM_DRIVER_CONNECTIONS','%SQL_MAXIMUM_IDENTIFIER_LENGTH','%SQL_MAXIMUM_INDEX_SIZE','%SQL_MAXIMUM_ROW_SIZE', + '%SQL_MAXIMUM_SCHEMA_NAME_LENGTH','%SQL_MAXIMUM_STATEMENT_LENGTH','%SQL_MAXIMUM_TABLES_IN_SELECT','%SQL_MAXIMUM_USER_NAME_LENGTH','%SQL_MAX_ASYNC_CONCURRENT_STATEMENTS','%SQL_MAX_BINARY_LITERAL_LEN','%SQL_MAX_CATALOG_NAME_LEN','%SQL_MAX_CHAR_LITERAL_LEN', + '%SQL_MAX_COLUMNS_IN_GROUP_BY','%SQL_MAX_COLUMNS_IN_INDEX','%SQL_MAX_COLUMNS_IN_ORDER_BY','%SQL_MAX_COLUMNS_IN_SELECT','%SQL_MAX_COLUMNS_IN_TABLE','%SQL_MAX_COLUMN_NAME_LEN','%SQL_MAX_CONCURRENT_ACTIVITIES','%SQL_MAX_CURSOR_NAME_LEN', + '%SQL_MAX_DRIVER_CONNECTIONS','%SQL_MAX_DSN_LENGTH','%SQL_MAX_IDENTIFIER_LEN','%SQL_MAX_INDEX_SIZE','%SQL_MAX_LENGTH','%SQL_MAX_LENGTH_DEFAULT','%SQL_MAX_MESSAGE_LENGTH','%SQL_MAX_NUMERIC_LEN', + '%SQL_MAX_OPTION_STRING_LENGTH','%SQL_MAX_OWNER_NAME_LEN','%SQL_MAX_PROCEDURE_NAME_LEN','%SQL_MAX_QUALIFIER_NAME_LEN','%SQL_MAX_ROWS','%SQL_MAX_ROWS_DEFAULT','%SQL_MAX_ROW_SIZE','%SQL_MAX_ROW_SIZE_INCLUDES_LONG', + '%SQL_MAX_SCHEMA_NAME_LEN','%SQL_MAX_STATEMENT_LEN','%SQL_MAX_TABLES_IN_SELECT','%SQL_MAX_TABLE_NAME_LEN','%SQL_MAX_USER_NAME_LEN','%SQL_MINUTE','%SQL_MINUTE_TO_SECOND','%SQL_MODE_DEFAULT', + '%SQL_MODE_READ_ONLY','%SQL_MODE_READ_WRITE','%SQL_MONTH','%SQL_MULTIPLE_ACTIVE_TXN','%SQL_MULT_RESULT_SETS','%SQL_NAMED','%SQL_NC_END','%SQL_NC_HIGH', + '%SQL_NC_LOW','%SQL_NC_START','%SQL_NEED_DATA','%SQL_NEED_LONG_DATA_LEN','%SQL_NNC_NON_NULL','%SQL_NNC_NULL','%SQL_NONSCROLLABLE','%SQL_NON_NULLABLE_COLUMNS', + '%SQL_NOSCAN','%SQL_NOSCAN_DEFAULT','%SQL_NOSCAN_OFF','%SQL_NOSCAN_ON','%SQL_NOT_DEFERRABLE','%SQL_NO_ACTION','%SQL_NO_COLUMN_NUMBER','%SQL_NO_DATA', + '%SQL_NO_DATA_FOUND','%SQL_NO_NULLS','%SQL_NO_ROW_NUMBER','%SQL_NO_TOTAL','%SQL_NTS','%SQL_NTSL','%SQL_NULLABLE','%SQL_NULLABLE_UNKNOWN', + '%SQL_NULL_COLLATION','%SQL_NULL_DATA','%SQL_NULL_HANDLE','%SQL_NULL_HDBC','%SQL_NULL_HDESC','%SQL_NULL_HENV','%SQL_NULL_HSTMT','%SQL_NUMERIC', + '%SQL_NUMERIC_FUNCTIONS','%SQL_OAC_LEVEL1','%SQL_OAC_LEVEL2','%SQL_OAC_NONE','%SQL_ODBC_API_CONFORMANCE','%SQL_ODBC_CURSORS','%SQL_ODBC_INTERFACE_CONFORMANCE','%SQL_ODBC_SAG_CLI_CONFORMANCE', + '%SQL_ODBC_SQL_CONFORMANCE','%SQL_ODBC_SQL_OPT_IEF','%SQL_ODBC_VER','%SQL_OIC_CORE','%SQL_OIC_LEVEL1','%SQL_OIC_LEVEL2','%SQL_OJ_ALL_COMPARISON_OPS','%SQL_OJ_CAPABILITIES', + '%SQL_OJ_FULL','%SQL_OJ_INNER','%SQL_OJ_LEFT','%SQL_OJ_NESTED','%SQL_OJ_NOT_ORDERED','%SQL_OJ_RIGHT','%SQL_OPT_TRACE','%SQL_OPT_TRACEFILE', + '%SQL_OPT_TRACE_DEFAULT','%SQL_OPT_TRACE_OFF','%SQL_OPT_TRACE_ON','%SQL_ORDER_BY_COLUMNS_IN_SELECT','%SQL_OSCC_COMPLIANT','%SQL_OSCC_NOT_COMPLIANT','%SQL_OSC_CORE','%SQL_OSC_EXTENDED', + '%SQL_OSC_MINIMUM','%SQL_OUTER_JOINS','%SQL_OUTER_JOIN_CAPABILITIES','%SQL_OU_DML_STATEMENTS','%SQL_OU_INDEX_DEFINITION','%SQL_OU_PRIVILEGE_DEFINITION','%SQL_OU_PROCEDURE_INVOCATION','%SQL_OU_TABLE_DEFINITION', + '%SQL_OV_ODBC2','%SQL_OV_ODBC3','%SQL_OWNER_TERM','%SQL_OWNER_USAGE','%SQL_PACKET_SIZE','%SQL_PARAM_ARRAY_ROW_COUNTS','%SQL_PARAM_ARRAY_SELECTS','%SQL_PARAM_BIND_BY_COLUMN', + '%SQL_PARAM_BIND_TYPE_DEFAULT','%SQL_PARAM_DIAG_UNAVAILABLE','%SQL_PARAM_ERROR','%SQL_PARAM_IGNORE','%SQL_PARAM_INPUT','%SQL_PARAM_INPUT_OUTPUT','%SQL_PARAM_OUTPUT','%SQL_PARAM_PROCEED', + '%SQL_PARAM_SUCCESS','%SQL_PARAM_SUCCESS_WITH_INFO','%SQL_PARAM_TYPE_DEFAULT','%SQL_PARAM_TYPE_UNKNOWN','%SQL_PARAM_UNUSED','%SQL_PARC_BATCH','%SQL_PARC_NO_BATCH','%SQL_PAS_BATCH', + '%SQL_PAS_NO_BATCH','%SQL_PAS_NO_SELECT','%SQL_PC_NON_PSEUDO','%SQL_PC_NOT_PSEUDO','%SQL_PC_PSEUDO','%SQL_PC_UNKNOWN','%SQL_POSITION','%SQL_POSITIONED_STATEMENTS', + '%SQL_POS_ADD','%SQL_POS_DELETE','%SQL_POS_OPERATIONS','%SQL_POS_POSITION','%SQL_POS_REFRESH','%SQL_POS_UPDATE','%SQL_PRED_BASIC','%SQL_PRED_CHAR', + '%SQL_PRED_NONE','%SQL_PRED_SEARCHABLE','%SQL_PROCEDURES','%SQL_PROCEDURE_TERM','%SQL_PS_POSITIONED_DELETE','%SQL_PS_POSITIONED_UPDATE','%SQL_PS_SELECT_FOR_UPDATE','%SQL_PT_FUNCTION', + '%SQL_PT_PROCEDURE','%SQL_PT_UNKNOWN','%SQL_QL_END','%SQL_QL_START','%SQL_QUALIFIER_LOCATION','%SQL_QUALIFIER_NAME_SEPARATOR','%SQL_QUALIFIER_TERM','%SQL_QUALIFIER_USAGE', + '%SQL_QUERY_TIMEOUT','%SQL_QUERY_TIMEOUT_DEFAULT','%SQL_QUICK','%SQL_QUIET_MODE','%SQL_QUOTED_IDENTIFIER_CASE','%SQL_QU_DML_STATEMENTS','%SQL_QU_INDEX_DEFINITION','%SQL_QU_PRIVILEGE_DEFINITION', + '%SQL_QU_PROCEDURE_INVOCATION','%SQL_QU_TABLE_DEFINITION','%SQL_RD_DEFAULT','%SQL_RD_OFF','%SQL_RD_ON','%SQL_REAL','%SQL_REFRESH','%SQL_RESET_PARAMS', + '%SQL_RESTRICT','%SQL_RESULT_COL','%SQL_RETRIEVE_DATA','%SQL_RETURN_VALUE','%SQL_ROLLBACK','%SQL_ROWSET_SIZE','%SQL_ROWSET_SIZE_DEFAULT','%SQL_ROWVER', + '%SQL_ROW_ADDED','%SQL_ROW_DELETED','%SQL_ROW_ERROR','%SQL_ROW_IDENTIFIER','%SQL_ROW_IGNORE','%SQL_ROW_NOROW','%SQL_ROW_NUMBER','%SQL_ROW_NUMBER_UNKNOWN', + '%SQL_ROW_PROCEED','%SQL_ROW_SUCCESS','%SQL_ROW_SUCCESS_WITH_INFO','%SQL_ROW_UPDATED','%SQL_ROW_UPDATES','%SQL_SCCO_LOCK','%SQL_SCCO_OPT_ROWVER','%SQL_SCCO_OPT_TIMESTAMP', + '%SQL_SCCO_OPT_VALUES','%SQL_SCCO_READ_ONLY','%SQL_SCC_ISO92_CLI','%SQL_SCC_XOPEN_CLI_VERSION1','%SQL_SCHEMA_TERM','%SQL_SCHEMA_USAGE','%SQL_SCOPE_CURROW','%SQL_SCOPE_SESSION', + '%SQL_SCOPE_TRANSACTION','%SQL_SCROLLABLE','%SQL_SCROLL_CONCURRENCY','%SQL_SCROLL_DYNAMIC','%SQL_SCROLL_FORWARD_ONLY','%SQL_SCROLL_KEYSET_DRIVEN','%SQL_SCROLL_OPTIONS','%SQL_SCROLL_STATIC', + '%SQL_SC_FIPS127_2_TRANSITIONAL','%SQL_SC_NON_UNIQUE','%SQL_SC_SQL92_ENTRY','%SQL_SC_SQL92_FULL','%SQL_SC_SQL92_INTERMEDIATE','%SQL_SC_TRY_UNIQUE','%SQL_SC_UNIQUE','%SQL_SDF_CURRENT_DATE', + '%SQL_SDF_CURRENT_TIME','%SQL_SDF_CURRENT_TIMESTAMP','%SQL_SEARCHABLE','%SQL_SEARCH_PATTERN_ESCAPE','%SQL_SECOND','%SQL_SENSITIVE','%SQL_SERVER_NAME','%SQL_SETPARAM_VALUE_MAX', + '%SQL_SETPOS_MAX_LOCK_VALUE','%SQL_SETPOS_MAX_OPTION_VALUE','%SQL_SET_DEFAULT','%SQL_SET_NULL','%SQL_SFKD_CASCADE','%SQL_SFKD_NO_ACTION','%SQL_SFKD_SET_DEFAULT','%SQL_SFKD_SET_NULL', + '%SQL_SFKU_CASCADE','%SQL_SFKU_NO_ACTION','%SQL_SFKU_SET_DEFAULT','%SQL_SFKU_SET_NULL','%SQL_SG_DELETE_TABLE','%SQL_SG_INSERT_COLUMN','%SQL_SG_INSERT_TABLE','%SQL_SG_REFERENCES_COLUMN', + '%SQL_SG_REFERENCES_TABLE','%SQL_SG_SELECT_TABLE','%SQL_SG_UPDATE_COLUMN','%SQL_SG_UPDATE_TABLE','%SQL_SG_USAGE_ON_CHARACTER_SET','%SQL_SG_USAGE_ON_COLLATION','%SQL_SG_USAGE_ON_DOMAIN','%SQL_SG_USAGE_ON_TRANSLATION', + '%SQL_SG_WITH_GRANT_OPTION','%SQL_SIGNED_OFFSET','%SQL_SIMULATE_CURSOR','%SQL_SMALLINT','%SQL_SNVF_BIT_LENGTH','%SQL_SNVF_CHARACTER_LENGTH','%SQL_SNVF_CHAR_LENGTH','%SQL_SNVF_EXTRACT', + '%SQL_SNVF_OCTET_LENGTH','%SQL_SNVF_POSITION','%SQL_SO_DYNAMIC','%SQL_SO_FORWARD_ONLY','%SQL_SO_KEYSET_DRIVEN','%SQL_SO_MIXED','%SQL_SO_STATIC','%SQL_SPECIAL_CHARACTERS', + '%SQL_SPEC_MAJOR','%SQL_SPEC_MINOR','%SQL_SP_BETWEEN','%SQL_SP_COMPARISON','%SQL_SP_EXISTS','%SQL_SP_IN','%SQL_SP_ISNOTNULL','%SQL_SP_ISNULL', + '%SQL_SP_LIKE','%SQL_SP_MATCH_FULL','%SQL_SP_MATCH_PARTIAL','%SQL_SP_MATCH_UNIQUE_FULL','%SQL_SP_MATCH_UNIQUE_PARTIAL','%SQL_SP_OVERLAPS','%SQL_SP_QUANTIFIED_COMPARISON','%SQL_SP_UNIQUE', + '%SQL_SQL92_DATETIME_FUNCTIONS','%SQL_SQL92_FOREIGN_KEY_DELETE_RULE','%SQL_SQL92_FOREIGN_KEY_UPDATE_RULE','%SQL_SQL92_GRANT','%SQL_SQL92_NUMERIC_VALUE_FUNCTIONS','%SQL_SQL92_PREDICATES','%SQL_SQL92_RELATIONAL_JOIN_OPERATORS','%SQL_SQL92_REVOKE', + '%SQL_SQL92_ROW_VALUE_CONSTRUCTOR','%SQL_SQL92_STRING_FUNCTIONS','%SQL_SQL92_VALUE_EXPRESSIONS','%SQL_SQLSTATE_SIZE','%SQL_SQL_CONFORMANCE','%SQL_SQ_COMPARISON','%SQL_SQ_CORRELATED_SUBQUERIES','%SQL_SQ_EXISTS', + '%SQL_SQ_IN','%SQL_SQ_QUANTIFIED','%SQL_SRJO_CORRESPONDING_CLAUSE','%SQL_SRJO_CROSS_JOIN','%SQL_SRJO_EXCEPT_JOIN','%SQL_SRJO_FULL_OUTER_JOIN','%SQL_SRJO_INNER_JOIN','%SQL_SRJO_INTERSECT_JOIN', + '%SQL_SRJO_LEFT_OUTER_JOIN','%SQL_SRJO_NATURAL_JOIN','%SQL_SRJO_RIGHT_OUTER_JOIN','%SQL_SRJO_UNION_JOIN','%SQL_SRVC_DEFAULT','%SQL_SRVC_NULL','%SQL_SRVC_ROW_SUBQUERY','%SQL_SRVC_VALUE_EXPRESSION', + '%SQL_SR_CASCADE','%SQL_SR_DELETE_TABLE','%SQL_SR_GRANT_OPTION_FOR','%SQL_SR_INSERT_COLUMN','%SQL_SR_INSERT_TABLE','%SQL_SR_REFERENCES_COLUMN','%SQL_SR_REFERENCES_TABLE','%SQL_SR_RESTRICT', + '%SQL_SR_SELECT_TABLE','%SQL_SR_UPDATE_COLUMN','%SQL_SR_UPDATE_TABLE','%SQL_SR_USAGE_ON_CHARACTER_SET','%SQL_SR_USAGE_ON_COLLATION','%SQL_SR_USAGE_ON_DOMAIN','%SQL_SR_USAGE_ON_TRANSLATION','%SQL_SSF_CONVERT', + '%SQL_SSF_LOWER','%SQL_SSF_SUBSTRING','%SQL_SSF_TRANSLATE','%SQL_SSF_TRIM_BOTH','%SQL_SSF_TRIM_LEADING','%SQL_SSF_TRIM_TRAILING','%SQL_SSF_UPPER','%SQL_SS_ADDITIONS', + '%SQL_SS_DELETIONS','%SQL_SS_UPDATES','%SQL_STANDARD_CLI_CONFORMANCE','%SQL_STATIC_CURSOR_ATTRIBUTES1','%SQL_STATIC_CURSOR_ATTRIBUTES2','%SQL_STATIC_SENSITIVITY','%SQL_STILL_EXECUTING','%SQL_STRING_FUNCTIONS', + '%SQL_SUBQUERIES','%SQL_SUCCESS','%SQL_SUCCESS_WITH_INFO','%SQL_SU_DML_STATEMENTS','%SQL_SU_INDEX_DEFINITION','%SQL_SU_PRIVILEGE_DEFINITION','%SQL_SU_PROCEDURE_INVOCATION','%SQL_SU_TABLE_DEFINITION', + '%SQL_SVE_CASE','%SQL_SVE_CAST','%SQL_SVE_COALESCE','%SQL_SVE_NULLIF','%SQL_SYSTEM_FUNCTIONS','%SQL_TABLE_STAT','%SQL_TABLE_TERM','%SQL_TC_ALL', + '%SQL_TC_DDL_COMMIT','%SQL_TC_DDL_IGNORE','%SQL_TC_DML','%SQL_TC_NONE','%SQL_TIME','%SQL_TIMEDATE_ADD_INTERVALS','%SQL_TIMEDATE_DIFF_INTERVALS','%SQL_TIMEDATE_FUNCTIONS', + '%SQL_TIMESTAMP','%SQL_TIMESTAMP_LEN','%SQL_TIME_LEN','%SQL_TINYINT','%SQL_TRANSACTION_CAPABLE','%SQL_TRANSACTION_ISOLATION_OPTION','%SQL_TRANSACTION_READ_COMMITTED','%SQL_TRANSACTION_READ_UNCOMMITTED', + '%SQL_TRANSACTION_REPEATABLE_READ','%SQL_TRANSACTION_SERIALIZABLE','%SQL_TRANSLATE_DLL','%SQL_TRANSLATE_OPTION','%SQL_TRUE','%SQL_TXN_CAPABLE','%SQL_TXN_ISOLATION','%SQL_TXN_ISOLATION_OPTION', + '%SQL_TXN_READ_COMMITTED','%SQL_TXN_READ_UNCOMMITTED','%SQL_TXN_REPEATABLE_READ','%SQL_TXN_SERIALIZABLE','%SQL_TYPE_DATE','%SQL_TYPE_NULL','%SQL_TYPE_TIME','%SQL_TYPE_TIMESTAMP', + '%SQL_UB_DEFAULT','%SQL_UB_FIXED','%SQL_UB_OFF','%SQL_UB_ON','%SQL_UB_VARIABLE','%SQL_UNBIND','%SQL_UNICODE','%SQL_UNICODE_CHAR', + '%SQL_UNICODE_LONGVARCHAR','%SQL_UNICODE_VARCHAR','%SQL_UNION','%SQL_UNION_STATEMENT','%SQL_UNKNOWN_TYPE','%SQL_UNNAMED','%SQL_UNSEARCHABLE','%SQL_UNSIGNED_OFFSET', + '%SQL_UNSPECIFIED','%SQL_UPDATE','%SQL_UPDATE_BY_BOOKMARK','%SQL_USER_NAME','%SQL_USE_BOOKMARKS','%SQL_US_UNION','%SQL_US_UNION_ALL','%SQL_U_UNION', + '%SQL_U_UNION_ALL','%SQL_VARBINARY','%SQL_VARCHAR','%SQL_XOPEN_CLI_YEAR','%SQL_YEAR','%SQL_YEAR_TO_MONTH','%SRCCOPY','%SS_BITMAP', + '%SS_BLACKFRAME','%SS_BLACKRECT','%SS_CENTER','%SS_CENTERIMAGE','%SS_ENDELLIPSIS','%SS_ETCHEDFRAME','%SS_ETCHEDHORZ','%SS_ETCHEDVERT', + '%SS_GRAYFRAME','%SS_GRAYRECT','%SS_LEFT','%SS_NOPREFIX','%SS_NOTIFY','%SS_NOWORDWRAP','%SS_PATHELLIPSIS','%SS_RIGHT', + '%SS_RIGHTJUST','%SS_SIMPLE','%SS_SUNKEN','%SS_WHITEFRAME','%SS_WHITERECT','%SS_WORDELLIPSIS','%STAT_FILL_FROM_MEMORY','%STAT_FILL_NATURAL', + '%STAT_FILL_NATURAL_ERASTONE','%STAT_FILL_NATURAL_EVEN','%STAT_FILL_NATURAL_FIBONACCI','%STAT_FILL_NATURAL_ODD','%STAT_FILL_WITH_NUMBER','%STAT_MINMAX_INDEX','%STAT_MINMAX_VALUE','%STAT_TYPE_BYTE', + '%STAT_TYPE_CURRENCY','%STAT_TYPE_DOUBLE','%STAT_TYPE_DWORD','%STAT_TYPE_EXT','%STAT_TYPE_INTEGER','%STAT_TYPE_LONG','%STAT_TYPE_QUAD','%STAT_TYPE_SINGLE', + '%STAT_TYPE_WORD','%SWP_ASYNCWINDOWPOS','%SWP_DEFERERASE','%SWP_DRAWFRAME','%SWP_FRAMECHANGED','%SWP_HIDEWINDOW','%SWP_NOACTIVATE','%SWP_NOCOPYBITS', + '%SWP_NOMOVE','%SWP_NOOWNERZORDER','%SWP_NOREDRAW','%SWP_NOREPOSITION','%SWP_NOSENDCHANGING','%SWP_NOSIZE','%SWP_NOZORDER','%SWP_SHOWWINDOW', + '%SW_FORCEMINIMIZE','%SW_HIDE','%SW_MAXIMIZE','%SW_MINIMIZE','%SW_NORMAL','%SW_RESTORE','%SW_SHOW','%SW_SHOWDEFAULT', + '%SW_SHOWMAXIMIZED','%SW_SHOWMINIMIZED','%SW_SHOWMINNOACTIVE','%SW_SHOWNA','%SW_SHOWNOACTIVATE','%SW_SHOWNORMAL','%TBASS_3DALG_DEFAULT','%TBASS_3DALG_FULL', + '%TBASS_3DALG_LIGHT','%TBASS_3DALG_OFF','%TBASS_3DMODE_NORMAL','%TBASS_3DMODE_OFF','%TBASS_3DMODE_RELATIVE','%TBASS_ACTIVE_PAUSED','%TBASS_ACTIVE_PLAYING','%TBASS_ACTIVE_STALLED', + '%TBASS_ACTIVE_STOPPED','%TBASS_CONFIG_3DALGORITHM','%TBASS_CONFIG_BUFFER','%TBASS_CONFIG_CURVE_PAN','%TBASS_CONFIG_CURVE_VOL','%TBASS_CONFIG_FLOATDSP','%TBASS_CONFIG_GVOL_MUSIC','%TBASS_CONFIG_GVOL_SAMPLE', + '%TBASS_CONFIG_GVOL_STREAM','%TBASS_CONFIG_MAXVOL','%TBASS_CONFIG_MP3_CODEC','%TBASS_CONFIG_NET_AGENT','%TBASS_CONFIG_NET_BUFFER','%TBASS_CONFIG_NET_PASSIVE','%TBASS_CONFIG_NET_PREBUF','%TBASS_CONFIG_NET_PROXY', + '%TBASS_CONFIG_NET_TIMEOUT','%TBASS_CONFIG_PAUSE_NOPLAY','%TBASS_CONFIG_UPDATEPERIOD','%TBASS_CTYPE_MUSIC_IT','%TBASS_CTYPE_MUSIC_MO3','%TBASS_CTYPE_MUSIC_MOD','%TBASS_CTYPE_MUSIC_MTM','%TBASS_CTYPE_MUSIC_S3M', + '%TBASS_CTYPE_MUSIC_XM','%TBASS_CTYPE_RECORD','%TBASS_CTYPE_SAMPLE','%TBASS_CTYPE_STREAM','%TBASS_CTYPE_STREAM_AIFF','%TBASS_CTYPE_STREAM_MP1','%TBASS_CTYPE_STREAM_MP2','%TBASS_CTYPE_STREAM_MP3', + '%TBASS_CTYPE_STREAM_OGG','%TBASS_CTYPE_STREAM_WAV','%TBASS_CTYPE_STREAM_WAV_FLOAT','%TBASS_CTYPE_STREAM_WAV_PCM','%TBASS_DATA_AVAILABLE','%TBASS_DATA_FFT1024','%TBASS_DATA_FFT2048','%TBASS_DATA_FFT4096', + '%TBASS_DATA_FFT512','%TBASS_DATA_FFT_INDIVIDUAL','%TBASS_DATA_FFT_NOWINDOW','%TBASS_DATA_FLOAT','%TBASS_DEVICE_3D','%TBASS_DEVICE_8BITS','%TBASS_DEVICE_LATENCY','%TBASS_DEVICE_MONO', + '%TBASS_DEVICE_NOSPEAKER','%TBASS_DEVICE_SPEAKERS','%TBASS_EAX_ENVIRONMENT_ALLEY','%TBASS_EAX_ENVIRONMENT_ARENA','%TBASS_EAX_ENVIRONMENT_AUDITORIUM','%TBASS_EAX_ENVIRONMENT_BATHROOM','%TBASS_EAX_ENVIRONMENT_CARPETEDHALLWAY','%TBASS_EAX_ENVIRONMENT_CAVE', + '%TBASS_EAX_ENVIRONMENT_CITY','%TBASS_EAX_ENVIRONMENT_CONCERTHALL','%TBASS_EAX_ENVIRONMENT_COUNT','%TBASS_EAX_ENVIRONMENT_DIZZY','%TBASS_EAX_ENVIRONMENT_DRUGGED','%TBASS_EAX_ENVIRONMENT_FOREST','%TBASS_EAX_ENVIRONMENT_GENERIC','%TBASS_EAX_ENVIRONMENT_HALLWAY', + '%TBASS_EAX_ENVIRONMENT_HANGAR','%TBASS_EAX_ENVIRONMENT_LIVINGROOM','%TBASS_EAX_ENVIRONMENT_MOUNTAINS','%TBASS_EAX_ENVIRONMENT_PADDEDCELL','%TBASS_EAX_ENVIRONMENT_PARKINGLOT','%TBASS_EAX_ENVIRONMENT_PLAIN','%TBASS_EAX_ENVIRONMENT_PSYCHOTIC','%TBASS_EAX_ENVIRONMENT_QUARRY', + '%TBASS_EAX_ENVIRONMENT_ROOM','%TBASS_EAX_ENVIRONMENT_SEWERPIPE','%TBASS_EAX_ENVIRONMENT_STONECORRIDOR','%TBASS_EAX_ENVIRONMENT_STONEROOM','%TBASS_EAX_ENVIRONMENT_UNDERWATER','%TBASS_ERROR_ALREADY','%TBASS_ERROR_BUFLOST','%TBASS_ERROR_CODEC', + '%TBASS_ERROR_CREATE','%TBASS_ERROR_DECODE','%TBASS_ERROR_DEVICE','%TBASS_ERROR_DRIVER','%TBASS_ERROR_DX','%TBASS_ERROR_EMPTY','%TBASS_ERROR_FILEFORM','%TBASS_ERROR_FILEOPEN', + '%TBASS_ERROR_FORMAT','%TBASS_ERROR_FREQ','%TBASS_ERROR_HANDLE','%TBASS_ERROR_ILLPARAM','%TBASS_ERROR_ILLTYPE','%TBASS_ERROR_INIT','%TBASS_ERROR_MEM','%TBASS_ERROR_NO3D', + '%TBASS_ERROR_NOCHAN','%TBASS_ERROR_NOEAX','%TBASS_ERROR_NOFX','%TBASS_ERROR_NOHW','%TBASS_ERROR_NONET','%TBASS_ERROR_NOPAUSE','%TBASS_ERROR_NOPLAY','%TBASS_ERROR_NOTAVAIL', + '%TBASS_ERROR_NOTFILE','%TBASS_ERROR_PLAYING','%TBASS_ERROR_POSITION','%TBASS_ERROR_SPEAKER','%TBASS_ERROR_START','%TBASS_ERROR_TIMEOUT','%TBASS_ERROR_UNKNOWN','%TBASS_ERROR_VERSION', + '%TBASS_FALSE','%TBASS_FILEPOS_CURRENT','%TBASS_FILEPOS_DECODE','%TBASS_FILEPOS_DOWNLOAD','%TBASS_FILEPOS_END','%TBASS_FILEPOS_START','%TBASS_FILE_CLOSE','%TBASS_FILE_LEN', + '%TBASS_FILE_READ','%TBASS_FILE_SEEK','%TBASS_FX_CHORUS','%TBASS_FX_COMPRESSOR','%TBASS_FX_DISTORTION','%TBASS_FX_ECHO','%TBASS_FX_FLANGER','%TBASS_FX_GARGLE', + '%TBASS_FX_I3DL2REVERB','%TBASS_FX_PARAMEQ','%TBASS_FX_PHASE_180','%TBASS_FX_PHASE_90','%TBASS_FX_PHASE_NEG_180','%TBASS_FX_PHASE_NEG_90','%TBASS_FX_PHASE_ZERO','%TBASS_FX_REVERB', + '%TBASS_INPUT_LEVEL','%TBASS_INPUT_OFF','%TBASS_INPUT_ON','%TBASS_INPUT_TYPE_ANALOG','%TBASS_INPUT_TYPE_AUX','%TBASS_INPUT_TYPE_CD','%TBASS_INPUT_TYPE_DIGITAL','%TBASS_INPUT_TYPE_LINE', + '%TBASS_INPUT_TYPE_MASK','%TBASS_INPUT_TYPE_MIC','%TBASS_INPUT_TYPE_PHONE','%TBASS_INPUT_TYPE_SPEAKER','%TBASS_INPUT_TYPE_SYNTH','%TBASS_INPUT_TYPE_UNDEF','%TBASS_INPUT_TYPE_WAVE','%TBASS_MP3_SETPOS', + '%TBASS_MUSIC_3D','%TBASS_MUSIC_ATTRIB_AMPLIFY','%TBASS_MUSIC_ATTRIB_BPM','%TBASS_MUSIC_ATTRIB_PANSEP','%TBASS_MUSIC_ATTRIB_PSCALER','%TBASS_MUSIC_ATTRIB_SPEED','%TBASS_MUSIC_ATTRIB_VOL_CHAN','%TBASS_MUSIC_ATTRIB_VOL_GLOBAL', + '%TBASS_MUSIC_ATTRIB_VOL_INST','%TBASS_MUSIC_AUTOFREE','%TBASS_MUSIC_CALCLEN','%TBASS_MUSIC_DECODE','%TBASS_MUSIC_FLOAT','%TBASS_MUSIC_FT2MOD','%TBASS_MUSIC_FX','%TBASS_MUSIC_LOOP', + '%TBASS_MUSIC_MONO','%TBASS_MUSIC_NONINTER','%TBASS_MUSIC_NOSAMPLE','%TBASS_MUSIC_POSRESET','%TBASS_MUSIC_POSRESETEX','%TBASS_MUSIC_PRESCAN','%TBASS_MUSIC_PT1MOD','%TBASS_MUSIC_RAMP', + '%TBASS_MUSIC_RAMPS','%TBASS_MUSIC_STOPBACK','%TBASS_MUSIC_SURROUND','%TBASS_MUSIC_SURROUND2','%TBASS_OBJECT_DS','%TBASS_OBJECT_DS3DL','%TBASS_OK','%TBASS_RECORD_PAUSE', + '%TBASS_SAMPLE_3D','%TBASS_SAMPLE_8BITS','%TBASS_SAMPLE_FLOAT','%TBASS_SAMPLE_FX','%TBASS_SAMPLE_LOOP','%TBASS_SAMPLE_MONO','%TBASS_SAMPLE_MUTEMAX','%TBASS_SAMPLE_OVER_DIST', + '%TBASS_SAMPLE_OVER_POS','%TBASS_SAMPLE_OVER_VOL','%TBASS_SAMPLE_SOFTWARE','%TBASS_SAMPLE_VAM','%TBASS_SLIDE_FREQ','%TBASS_SLIDE_PAN','%TBASS_SLIDE_VOL','%TBASS_SPEAKER_CENLFE', + '%TBASS_SPEAKER_CENTER','%TBASS_SPEAKER_FRONT','%TBASS_SPEAKER_FRONTLEFT','%TBASS_SPEAKER_FRONTRIGHT','%TBASS_SPEAKER_LEFT','%TBASS_SPEAKER_LFE','%TBASS_SPEAKER_REAR','%TBASS_SPEAKER_REAR2', + '%TBASS_SPEAKER_REAR2LEFT','%TBASS_SPEAKER_REAR2RIGHT','%TBASS_SPEAKER_REARLEFT','%TBASS_SPEAKER_REARRIGHT','%TBASS_SPEAKER_RIGHT','%TBASS_STREAMPROC_END','%TBASS_STREAM_AUTOFREE','%TBASS_STREAM_BLOCK', + '%TBASS_STREAM_DECODE','%TBASS_STREAM_PRESCAN','%TBASS_STREAM_RESTRATE','%TBASS_STREAM_STATUS','%TBASS_SYNC_DOWNLOAD','%TBASS_SYNC_END','%TBASS_SYNC_FREE','%TBASS_SYNC_MESSAGE', + '%TBASS_SYNC_META','%TBASS_SYNC_MIXTIME','%TBASS_SYNC_MUSICFX','%TBASS_SYNC_MUSICINST','%TBASS_SYNC_MUSICPOS','%TBASS_SYNC_ONETIME','%TBASS_SYNC_POS','%TBASS_SYNC_SLIDE', + '%TBASS_SYNC_STALL','%TBASS_TAG_HTTP','%TBASS_TAG_ICY','%TBASS_TAG_ID3','%TBASS_TAG_ID3V2','%TBASS_TAG_META','%TBASS_TAG_MUSIC_INST','%TBASS_TAG_MUSIC_MESSAGE', + '%TBASS_TAG_MUSIC_NAME','%TBASS_TAG_MUSIC_SAMPLE','%TBASS_TAG_OGG','%TBASS_TAG_RIFF_INFO','%TBASS_TAG_VENDOR','%TBASS_TRUE','%TBASS_UNICODE','%TBASS_VAM_HARDWARE', + '%TBASS_VAM_SOFTWARE','%TBASS_VAM_TERM_DIST','%TBASS_VAM_TERM_PRIO','%TBASS_VAM_TERM_TIME','%TBASS_VERSION','%TBCD_CHANNEL','%TBCD_THUMB','%TBCD_TICS', + '%TBGL_ALIGN_CENTER','%TBGL_ALIGN_CENTER_CENTER','%TBGL_ALIGN_CENTER_DOWN','%TBGL_ALIGN_CENTER_UP','%TBGL_ALIGN_LEFT','%TBGL_ALIGN_LEFT_CENTER','%TBGL_ALIGN_LEFT_DOWN','%TBGL_ALIGN_LEFT_UP', + '%TBGL_ALIGN_RIGHT','%TBGL_ALIGN_RIGHT_CENTER','%TBGL_ALIGN_RIGHT_DOWN','%TBGL_ALIGN_RIGHT_UP','%TBGL_ALWAYS','%TBGL_EQUAL','%TBGL_ERROR_FILE','%TBGL_ERROR_MSGBOX', + '%TBGL_ERROR_NONE','%TBGL_GEQUAL','%TBGL_GREATER','%TBGL_LEQUAL','%TBGL_LESS','%TBGL_LIGHT_AMBIENT','%TBGL_LIGHT_CONSTANT_ATTENUATION','%TBGL_LIGHT_DIFFUSE', + '%TBGL_LIGHT_LINEAR_ATTENUATION','%TBGL_LIGHT_POSITION','%TBGL_LIGHT_QUADRATIC_ATTENUATION','%TBGL_LIGHT_SPECULAR','%TBGL_LIGHT_SPOT_CUTOFF','%TBGL_LIGHT_SPOT_DIRECTION','%TBGL_LIGHT_SPOT_EXPONENT','%TBGL_M15B', + '%TBGL_M15G','%TBGL_M15LAYER','%TBGL_M15PSTOP','%TBGL_M15R','%TBGL_M15TEXN','%TBGL_M15TEXX','%TBGL_M15TEXY','%TBGL_M15X', + '%TBGL_M15Y','%TBGL_M15Z','%TBGL_NEVER','%TBGL_NORMAL_NONE','%TBGL_NORMAL_PRECISE','%TBGL_NORMAL_SMOOTH','%TBGL_NOTEQUAL','%TBGL_OBJ_CUBE', + '%TBGL_OBJ_CUBE3','%TBGL_OBJ_CYLINDER','%TBGL_OBJ_SPHERE','%TBGL_PINFO_RGB','%TBGL_PINFO_XYZ','%TBGL_TEX_LINEAR','%TBGL_TEX_MIPMAP','%TBGL_TEX_NEAREST', + '%TBM_CLEARSEL','%TBM_CLEARTICS','%TBM_GETBUDDY','%TBM_GETCHANNELRECT','%TBM_GETLINESIZE','%TBM_GETNUMTICS','%TBM_GETPAGESIZE','%TBM_GETPOS', + '%TBM_GETPTICS','%TBM_GETRANGEMAX','%TBM_GETRANGEMIN','%TBM_GETSELEND','%TBM_GETSELSTART','%TBM_GETTHUMBLENGTH','%TBM_GETTHUMBRECT','%TBM_GETTIC', + '%TBM_GETTICPOS','%TBM_GETTOOLTIPS','%TBM_GETUNICODEFORMAT','%TBM_SETBUDDY','%TBM_SETLINESIZE','%TBM_SETPAGESIZE','%TBM_SETPOS','%TBM_SETRANGE', + '%TBM_SETRANGEMAX','%TBM_SETRANGEMIN','%TBM_SETSEL','%TBM_SETSELEND','%TBM_SETSELSTART','%TBM_SETTHUMBLENGTH','%TBM_SETTIC','%TBM_SETTICFREQ', + '%TBM_SETTIPSIDE','%TBM_SETTOOLTIPS','%TBM_SETUNICODEFORMAT','%TBS_AUTOTICKS','%TBS_BOTH','%TBS_BOTTOM','%TBS_DOWNISLEFT','%TBS_ENABLESELRANGE', + '%TBS_FIXEDLENGTH','%TBS_HORZ','%TBS_LEFT','%TBS_NOTHUMB','%TBS_NOTICKS','%TBS_REVERSED','%TBS_RIGHT','%TBS_TOOLTIPS', + '%TBS_TOP','%TBS_VERT','%TBTS_BOTTOM','%TBTS_LEFT','%TBTS_RIGHT','%TBTS_TOP','%TB_%VT_BSTR','%TB_%VT_CY', + '%TB_%VT_DATE','%TB_%VT_EMPTY','%TB_%VT_I2','%TB_%VT_I4','%TB_%VT_NULL','%TB_%VT_R4','%TB_%VT_R8','%TB_BOTTOM', + '%TB_CLASS_E_NOAGGREGATION','%TB_CO_E_CLASSSTRING','%TB_DISPATCH_METHOD','%TB_DISPATCH_PROPERTYGET','%TB_DISPATCH_PROPERTYPUT','%TB_DISPATCH_PROPERTYPUTREF','%TB_ENDTRACK','%TB_E_INVALIDARG', + '%TB_E_NOINTERFACE','%TB_E_OUTOFMEMORY','%TB_IMGCTX_ACTUALSIZE','%TB_IMGCTX_AUTOSIZE','%TB_IMGCTX_FITTOHEIGHT','%TB_IMGCTX_FITTOWIDTH','%TB_IMGCTX_STRETCH','%TB_LINEDOWN', + '%TB_LINEUP','%TB_MK_E_CONNECTMANUALLY','%TB_MK_E_EXCEEDEDDEADLINE','%TB_MK_E_INTERMEDIATEINTERFACENOTSUPPORTED','%TB_MK_E_NOOBJECT','%TB_MK_E_SYNTAX','%TB_PAGEDOWN','%TB_PAGEUP', + '%TB_REGDB_E_CLASSNOTREG','%TB_REGDB_E_WRITEREGDB','%TB_SIZEOF_TBVARIANT','%TB_S_FALSE','%TB_S_OK','%TB_THUMBPOSITION','%TB_THUMBTRACK','%TB_TOP', + '%TCM_FIRST','%TCM_GETCURSEL','%TCN_FOCUSCHANGE','%TCN_GETOBJECT','%TCN_SELCHANGE','%TCN_SELCHANGING','%TCS_BOTTOM','%TCS_BUTTONS', + '%TCS_EX_FLATSEPARATORS','%TCS_EX_REGISTERDROP','%TCS_FIXEDWIDTH','%TCS_FLATBUTTONS','%TCS_FOCUSNEVER','%TCS_FOCUSONBUTTONDOWN','%TCS_FORCEICONLEFT','%TCS_FORCELABELLEFT', + '%TCS_HOTTRACK','%TCS_MULTILINE','%TCS_MULTISELECT','%TCS_OWNERDRAWFIXED','%TCS_RAGGEDRIGHT','%TCS_RIGHT','%TCS_RIGHTJUSTIFY','%TCS_SCROLLOPPOSITE', + '%TCS_SINGLELINE','%TCS_TABS','%TCS_TOOLTIPS','%TCS_VERTICAL','%TM_PLAINTEXT','%TM_RICHTEXT','%TOKENIZER_DEFAULT_ALPHA','%TOKENIZER_DEFAULT_DELIM', + '%TOKENIZER_DEFAULT_DQUOTE','%TOKENIZER_DEFAULT_NEWLINE','%TOKENIZER_DEFAULT_NUMERIC','%TOKENIZER_DEFAULT_SPACE','%TOKENIZER_DELIMITER','%TOKENIZER_EOL','%TOKENIZER_ERROR','%TOKENIZER_FINISHED', + '%TOKENIZER_NUMBER','%TOKENIZER_QUOTE','%TOKENIZER_STRING','%TOKENIZER_UNDEFTOK','%TRUE','%TV_FIRST','%UDM_GETACCEL','%UDM_GETBASE', + '%UDM_GETBUDDY','%UDM_GETPOS','%UDM_GETPOS32','%UDM_GETRANGE','%UDM_GETRANGE32','%UDM_GETUNICODEFORMAT','%UDM_SETACCEL','%UDM_SETBASE', + '%UDM_SETBUDDY','%UDM_SETPOS','%UDM_SETPOS32','%UDM_SETRANGE','%UDM_SETRANGE32','%UDM_SETUNICODEFORMAT','%UDS_ALIGNLEFT','%UDS_ALIGNRIGHT', + '%UDS_ARROWKEYS','%UDS_AUTOBUDDY','%UDS_HORZ','%UDS_HOTTRACK','%UDS_NOTHOUSANDS','%UDS_SETBUDDYINT','%UDS_WRAP','%UD_MAXVAL', + '%UD_MINVAL','%VK_0','%VK_1','%VK_2','%VK_3','%VK_4','%VK_5','%VK_6', + '%VK_7','%VK_8','%VK_9','%VK_A','%VK_ACCEPT','%VK_ADD','%VK_APPS','%VK_B', + '%VK_BACK','%VK_C','%VK_CANCEL','%VK_CAPITAL','%VK_CLEAR','%VK_CONTROL','%VK_CONVERT','%VK_D', + '%VK_DECIMAL','%VK_DELETE','%VK_DIVIDE','%VK_DOWN','%VK_E','%VK_END','%VK_ESCAPE','%VK_EXECUTE', + '%VK_F','%VK_F1','%VK_F10','%VK_F11','%VK_F12','%VK_F13','%VK_F14','%VK_F15', + '%VK_F16','%VK_F17','%VK_F18','%VK_F19','%VK_F2','%VK_F20','%VK_F21','%VK_F22', + '%VK_F23','%VK_F24','%VK_F3','%VK_F4','%VK_F5','%VK_F6','%VK_F7','%VK_F8', + '%VK_F9','%VK_FINAL','%VK_G','%VK_H','%VK_HANGEUL','%VK_HANGUL','%VK_HANJA','%VK_HELP', + '%VK_HOME','%VK_I','%VK_INSERT','%VK_J','%VK_JUNJA','%VK_K','%VK_KANA','%VK_KANJI', + '%VK_L','%VK_LBUTTON','%VK_LEFT','%VK_LINEFEED','%VK_LWIN','%VK_M','%VK_MBUTTON','%VK_MENU', + '%VK_MODECHANGE','%VK_MULTIPLY','%VK_N','%VK_NEXT','%VK_NONCONVERT','%VK_NUMLOCK','%VK_NUMPAD0','%VK_NUMPAD1', + '%VK_NUMPAD2','%VK_NUMPAD3','%VK_NUMPAD4','%VK_NUMPAD5','%VK_NUMPAD6','%VK_NUMPAD7','%VK_NUMPAD8','%VK_NUMPAD9', + '%VK_O','%VK_P','%VK_PAUSE','%VK_PGDN','%VK_PGUP','%VK_PRINT','%VK_PRIOR','%VK_Q', + '%VK_R','%VK_RBUTTON','%VK_RETURN','%VK_RIGHT','%VK_RWIN','%VK_S','%VK_SCROLL','%VK_SELECT', + '%VK_SEPARATOR','%VK_SHIFT','%VK_SLEEP','%VK_SNAPSHOT','%VK_SPACE','%VK_SUBTRACT','%VK_T','%VK_TAB', + '%VK_U','%VK_UP','%VK_V','%VK_W','%VK_X','%VK_XBUTTON1','%VK_XBUTTON2','%VK_Y', + '%VK_Z','%VT_ARRAY','%VT_BLOB','%VT_BLOB_OBJECT','%VT_BOOL','%VT_BSTR','%VT_BYREF','%VT_CARRAY', + '%VT_CF','%VT_CLSID','%VT_CY','%VT_DATE','%VT_DISPATCH','%VT_EMPTY','%VT_ERROR','%VT_FILETIME', + '%VT_HRESULT','%VT_I1','%VT_I2','%VT_I4','%VT_I8','%VT_INT','%VT_LPSTR','%VT_LPWSTR', + '%VT_NULL','%VT_PTR','%VT_R4','%VT_R8','%VT_RECORD','%VT_RESERVED','%VT_SAFEARRAY','%VT_STORAGE', + '%VT_STORED_OBJECT','%VT_STREAM','%VT_STREAMED_OBJECT','%VT_UI1','%VT_UI2','%VT_UI4','%VT_UI8','%VT_UINT', + '%VT_UNKNOWN','%VT_USERDEFINED','%VT_VARIANT','%VT_VECTOR','%VT_VOID','%WAVE_FORMAT_1M08','%WAVE_FORMAT_1M16','%WAVE_FORMAT_1S08', + '%WAVE_FORMAT_1S16','%WAVE_FORMAT_2M08','%WAVE_FORMAT_2M16','%WAVE_FORMAT_2S08','%WAVE_FORMAT_2S16','%WAVE_FORMAT_4M08','%WAVE_FORMAT_4M16','%WAVE_FORMAT_4S08', + '%WAVE_FORMAT_4S16','%WBF_CUSTOM','%WBF_LEVEL1','%WBF_LEVEL2','%WBF_OVERFLOW','%WBF_WORDBREAK','%WBF_WORDWRAP','%WHITE', + '%WIN_FINDTITLECONTAIN','%WIN_FINDTITLEEND','%WIN_FINDTITLEEQUAL','%WIN_FINDTITLESTART','%WM_ACTIVATE','%WM_ACTIVATEAPP','%WM_CAPTURECHANGED','%WM_CHAR', + '%WM_CLOSE','%WM_COMMAND','%WM_DESTROY','%WM_DROPFILES','%WM_ERASEBKGND','%WM_GETTEXTLENGTH','%WM_HOTKEY','%WM_HSCROLL', + '%WM_IDLE','%WM_INITDIALOG','%WM_KEYDOWN','%WM_KEYUP','%WM_KILLFOCUS','%WM_LBUTTONDBLCLK','%WM_LBUTTONDOWN','%WM_LBUTTONUP', + '%WM_MBUTTONDBLCLK','%WM_MBUTTONDOWN','%WM_MBUTTONUP','%WM_MOUSEFIRST','%WM_MOUSEMOVE','%WM_MOUSEWHEEL','%WM_MOVE','%WM_MOVING', + '%WM_NCLBUTTONDOWN','%WM_NCRBUTTONDOWN','%WM_NEXTDLGCTL','%WM_NOTIFY','%WM_PAINT','%WM_QUIT','%WM_RBUTTONDBLCLK','%WM_RBUTTONDOWN', + '%WM_RBUTTONUP','%WM_SETFOCUS','%WM_SETFONT','%WM_SETTEXT','%WM_SIZE','%WM_SIZING','%WM_SYSCOMMAND','%WM_TIMER', + '%WM_USER','%WM_VSCROLL','%WS_BORDER','%WS_CAPTION','%WS_CHILD','%WS_CLIPCHILDREN','%WS_CLIPSIBLINGS','%WS_DISABLED', + '%WS_DLGFRAME','%WS_EX_ACCEPTFILES','%WS_EX_APPWINDOW','%WS_EX_CLIENTEDGE','%WS_EX_CONTEXTHELP','%WS_EX_CONTROLPARENT','%WS_EX_LAYERED','%WS_EX_LEFT', + '%WS_EX_LEFTSCROLLBAR','%WS_EX_LTRREADING','%WS_EX_MDICHILD','%WS_EX_NOPARENTNOTIFY','%WS_EX_OVERLAPPEDWINDOW','%WS_EX_PALETTEWINDOW','%WS_EX_RIGHT','%WS_EX_RIGHTSCROLLBAR', + '%WS_EX_RTLREADING','%WS_EX_STATICEDGE','%WS_EX_TOOLWINDOW','%WS_EX_TOPMOST','%WS_EX_TRANSPARENT','%WS_EX_WINDOWEDGE','%WS_GROUP','%WS_HSCROLL', + '%WS_ICONIC','%WS_MAXIMIZE','%WS_MAXIMIZEBOX','%WS_MINIMIZE','%WS_MINIMIZEBOX','%WS_OVERLAPPEDWINDOW','%WS_POPUP','%WS_POPUPWINDOW', + '%WS_SYSMENU','%WS_TABSTOP','%WS_THICKFRAME','%WS_VISIBLE','%WS_VSCROLL','%YELLOW','%ZERO','CRLF', + 'FALSE','M_E','M_PI','NULL','TAB','TRUE' + ) + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', '^', '&', ':' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000FF; font-weight: bold;', + 2 => 'color: #993333; font-style: italic; font-weight: bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000;' + ), + 'BRACKETS' => array( + 0 => 'color: #333333;' + ), + 'STRINGS' => array( + 0 => 'color: #800080;' + ), + 'NUMBERS' => array( + 0 => 'color: #CC0000;' + ), + 'METHODS' => array( + 1 => 'color: #66cc66;' + ), + 'SYMBOLS' => array( + 0 => 'color: #333333;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + 1 => '_' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/tsql.php b/examples/includes/geshi/geshi/tsql.php new file mode 100644 index 0000000..dd6b0cc --- /dev/null +++ b/examples/includes/geshi/geshi/tsql.php @@ -0,0 +1,378 @@ + 'T-SQL', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + // Datatypes + 'bigint', 'int', 'smallint', 'tinyint', 'bit', 'decimal', 'numeric', 'money', + 'smallmoney', 'float', 'real', 'datetime', 'smalldatetime', 'char', 'varchar', + 'text', 'nchar', 'nvarchar', 'ntext', 'binary', 'varbinary', 'image', 'cursor', + 'sql_variant', 'table', 'timestamp', 'uniqueidentifier', + + // Keywords + 'ABSOLUTE', 'ACTION', 'ADD', 'ADMIN', 'AFTER', 'AGGREGATE', 'ALIAS', 'ALLOCATE', 'ALTER', 'ARE', 'ARRAY', 'AS', + 'ASC', 'ASSERTION', 'AT', 'AUTHORIZATION', 'BACKUP', 'BEFORE', 'BEGIN', 'BINARY', 'BIT', 'BLOB', 'BOOLEAN', 'BOTH', 'BREADTH', + 'BREAK', 'BROWSE', 'BULK', 'BY', 'CALL', 'CASCADE', 'CASCADED', 'CASE', 'CAST', 'CATALOG', 'CHAR', 'CHARACTER', 'CHECK', 'CHECKPOINT', + 'CLASS', 'CLOB', 'CLOSE', 'CLUSTERED', 'COALESCE', 'COLLATE', 'COLLATION', 'COLUMN', 'COMMIT', 'COMPLETION', 'COMPUTE', 'CONNECT', + 'CONNECTION', 'CONSTRAINT', 'CONSTRAINTS', 'CONSTRUCTOR', 'CONTAINS', 'CONTAINSTABLE', 'CONTINUE', 'CONVERT', 'CORRESPONDING', 'CREATE', + 'CUBE', 'CURRENT', 'CURRENT_DATE', 'CURRENT_PATH', 'CURRENT_ROLE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', + 'CURSOR', 'CYCLE', 'DATA', 'DATABASE', 'DATE', 'DAY', 'DBCC', 'DEALLOCATE', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DEFERRABLE', + 'DEFERRED', 'DELETE', 'DENY', 'DEPTH', 'DEREF', 'DESC', 'DESCRIBE', 'DESCRIPTOR', 'DESTROY', 'DESTRUCTOR', 'DETERMINISTIC', + 'DIAGNOSTICS', 'DICTIONARY', 'DISCONNECT', 'DISK', 'DISTINCT', 'DISTRIBUTED', 'DOMAIN', 'DOUBLE', 'DROP', 'DUMMY', 'DUMP', 'DYNAMIC', + 'EACH', 'ELSE', 'END', 'END-EXEC', 'EQUALS', 'ERRLVL', 'ESCAPE', 'EVERY', 'EXCEPT', 'EXCEPTION', 'EXEC', 'EXECUTE', 'EXIT', + 'EXTERNAL', 'FALSE', 'FETCH', 'FILE', 'FILLFACTOR', 'FIRST', 'FLOAT', 'FOR', 'FOREIGN', 'FOUND', 'FREE', 'FREETEXT', 'FREETEXTTABLE', + 'FROM', 'FULL', 'FUNCTION', 'GENERAL', 'GET', 'GLOBAL', 'GOTO', 'GRANT', 'GROUP', 'GROUPING', 'HAVING', 'HOLDLOCK', 'HOST', 'HOUR', + 'IDENTITY', 'IDENTITY_INSERT', 'IDENTITYCOL', 'IF', 'IGNORE', 'IMMEDIATE', 'INDEX', 'INDICATOR', 'INITIALIZE', 'INITIALLY', + 'INNER', 'INOUT', 'INPUT', 'INSERT', 'INT', 'INTEGER', 'INTERSECT', 'INTERVAL', 'INTO', 'IS', 'ISOLATION', 'ITERATE', 'KEY', + 'KILL', 'LANGUAGE', 'LARGE', 'LAST', 'LATERAL', 'LEADING', 'LEFT', 'LESS', 'LEVEL', 'LIMIT', 'LINENO', 'LOAD', 'LOCAL', + 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCATOR', 'MAP', 'MATCH', 'MINUTE', 'MODIFIES', 'MODIFY', 'MODULE', 'MONTH', 'NAMES', 'NATIONAL', + 'NATURAL', 'NCHAR', 'NCLOB', 'NEW', 'NEXT', 'NO', 'NOCHECK', 'NONCLUSTERED', 'NONE', 'NULLIF', 'NUMERIC', 'OBJECT', 'OF', + 'OFF', 'OFFSETS', 'OLD', 'ON', 'ONLY', 'OPEN', 'OPENDATASOURCE', 'OPENQUERY', 'OPENROWSET', 'OPENXML', 'OPERATION', 'OPTION', + 'ORDER', 'ORDINALITY', 'OUT', 'OUTPUT', 'OVER', 'PAD', 'PARAMETER', 'PARAMETERS', 'PARTIAL', 'PATH', 'PERCENT', 'PLAN', + 'POSTFIX', 'PRECISION', 'PREFIX', 'PREORDER', 'PREPARE', 'PRESERVE', 'PRIMARY', 'PRINT', 'PRIOR', 'PRIVILEGES', 'PROC', 'PROCEDURE', + 'PUBLIC', 'RAISERROR', 'READ', 'READS', 'READTEXT', 'REAL', 'RECONFIGURE', 'RECURSIVE', 'REF', 'REFERENCES', 'REFERENCING', 'RELATIVE', + 'REPLICATION', 'RESTORE', 'RESTRICT', 'RESULT', 'RETURN', 'RETURNS', 'REVOKE', 'RIGHT', 'ROLE', 'ROLLBACK', 'ROLLUP', 'ROUTINE', 'ROW', + 'ROWGUIDCOL', 'ROWS', 'RULE', 'SAVE', 'SAVEPOINT', 'SCHEMA', 'SCOPE', 'SCROLL', 'SEARCH', 'SECOND', 'SECTION', 'SELECT', + 'SEQUENCE', 'SESSION', 'SESSION_USER', 'SET', 'SETS', 'SETUSER', 'SHUTDOWN', 'SIZE', 'SMALLINT', 'SPACE', 'SPECIFIC', + 'SPECIFICTYPE', 'SQL', 'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'START', 'STATE', 'STATEMENT', 'STATIC', 'STATISTICS', 'STRUCTURE', + 'SYSTEM_USER', 'TABLE', 'TEMPORARY', 'TERMINATE', 'TEXTSIZE', 'THAN', 'THEN', 'TIME', 'TIMESTAMP', 'TIMEZONE_HOUR', 'TIMEZONE_MINUTE', + 'TO', 'TOP', 'TRAILING', 'TRAN', 'TRANSACTION', 'TRANSLATION', 'TREAT', 'TRIGGER', 'TRUE', 'TRUNCATE', 'TSEQUAL', 'UNDER', 'UNION', + 'UNIQUE', 'UNKNOWN', 'UNNEST', 'UPDATE', 'UPDATETEXT', 'USAGE', 'USE', 'USER', 'USING', 'VALUE', 'VALUES', 'VARCHAR', 'VARIABLE', + 'VARYING', 'VIEW', 'WAITFOR', 'WHEN', 'WHENEVER', 'WHERE', 'WHILE', 'WITH', 'WITHOUT', 'WORK', 'WRITE', 'WRITETEXT', 'YEAR', 'ZONE', + 'UNCOMMITTED', 'NOCOUNT', + ), + 2 => array( + /* + Built-in functions + Highlighted in pink. + */ + + //Configuration Functions + '@@DATEFIRST','@@OPTIONS','@@DBTS','@@REMSERVER','@@LANGID','@@SERVERNAME', + '@@LANGUAGE','@@SERVICENAME','@@LOCK_TIMEOUT','@@SPID','@@MAX_CONNECTIONS','@@TEXTSIZE', + '@@MAX_PRECISION','@@VERSION','@@NESTLEVEL', + + //Cursor Functions + '@@CURSOR_ROWS','@@FETCH_STATUS', + + //Date and Time Functions + 'DATEADD','DATEDIFF','DATENAME','DATEPART','DAY','GETDATE','GETUTCDATE','MONTH','YEAR', + + //Mathematical Functions + 'ABS','DEGREES','RAND','ACOS','EXP','ROUND','ASIN','FLOOR','SIGN', + 'ATAN','LOG','SIN','ATN2','LOG10','SQUARE','CEILING','PI','SQRT','COS', + 'POWER','TAN','COT','RADIANS', + + //Meta Data Functions + 'COL_LENGTH','fn_listextendedproperty','COL_NAME','FULLTEXTCATALOGPROPERTY', + 'COLUMNPROPERTY','FULLTEXTSERVICEPROPERTY','DATABASEPROPERTY','INDEX_COL', + 'DATABASEPROPERTYEX','INDEXKEY_PROPERTY','DB_ID','INDEXPROPERTY','DB_NAME', + 'OBJECT_ID','FILE_ID','OBJECT_NAME','FILE_NAME','OBJECTPROPERTY','FILEGROUP_ID', + '@@PROCID','FILEGROUP_NAME','SQL_VARIANT_PROPERTY','FILEGROUPPROPERTY', + 'TYPEPROPERTY','FILEPROPERTY', + + //Security Functions + 'fn_trace_geteventinfo','IS_SRVROLEMEMBER','fn_trace_getfilterinfo','SUSER_SID', + 'fn_trace_getinfo','SUSER_SNAME','fn_trace_gettable','USER_ID','HAS_DBACCESS', + 'IS_MEMBER', + + //String Functions + 'ASCII','NCHAR','SOUNDEX','CHAR','PATINDEX','SPACE','CHARINDEX', + 'REPLACE','STR','DIFFERENCE','QUOTENAME','STUFF','LEFT','REPLICATE', + 'SUBSTRING','LEN','REVERSE','UNICODE','LOWER','RIGHT','UPPER','LTRIM', + 'RTRIM', + + //System Functions + 'APP_NAME','COLLATIONPROPERTY','@@ERROR','fn_helpcollations', + 'fn_servershareddrives','fn_virtualfilestats','FORMATMESSAGE', + 'GETANSINULL','HOST_ID','HOST_NAME','IDENT_CURRENT','IDENT_INCR', + 'IDENT_SEED','@@IDENTITY','ISDATE','ISNUMERIC','PARSENAME','PERMISSIONS', + '@@ROWCOUNT','ROWCOUNT_BIG','SCOPE_IDENTITY','SERVERPROPERTY','SESSIONPROPERTY', + 'STATS_DATE','@@TRANCOUNT','USER_NAME', + + //System Statistical Functions + '@@CONNECTIONS','@@PACK_RECEIVED','@@CPU_BUSY','@@PACK_SENT', + '@@TIMETICKS','@@IDLE','@@TOTAL_ERRORS','@@IO_BUSY', + '@@TOTAL_READ','@@PACKET_ERRORS','@@TOTAL_WRITE', + + //Text and Image Functions + 'TEXTPTR','TEXTVALID', + + //Aggregate functions + 'AVG', 'MAX', 'BINARY_CHECKSUM', 'MIN', 'CHECKSUM', 'SUM', 'CHECKSUM_AGG', + 'STDEV', 'COUNT', 'STDEVP', 'COUNT_BIG', 'VAR', 'GROUPING', 'VARP' + ), + 3 => array( + /* + System stored procedures + Higlighted dark brown + */ + + //Active Directory Procedures + 'sp_ActiveDirectory_Obj', 'sp_ActiveDirectory_SCP', + + //Catalog Procedures + 'sp_column_privileges', 'sp_special_columns', 'sp_columns', 'sp_sproc_columns', + 'sp_databases', 'sp_statistics', 'sp_fkeys', 'sp_stored_procedures', 'sp_pkeys', + 'sp_table_privileges', 'sp_server_info', 'sp_tables', + + //Cursor Procedures + 'sp_cursor_list', 'sp_describe_cursor_columns', 'sp_describe_cursor', 'sp_describe_cursor_tables', + + //Database Maintenance Plan Procedures + 'sp_add_maintenance_plan', 'sp_delete_maintenance_plan_db', 'sp_add_maintenance_plan_db', + 'sp_delete_maintenance_plan_job', 'sp_add_maintenance_plan_job', 'sp_help_maintenance_plan', + 'sp_delete_maintenance_plan', + + //Distributed Queries Procedures + 'sp_addlinkedserver', 'sp_indexes', 'sp_addlinkedsrvlogin', 'sp_linkedservers', 'sp_catalogs', + 'sp_primarykeys', 'sp_column_privileges_ex', 'sp_columns_ex', + 'sp_table_privileges_ex', 'sp_tables_ex', 'sp_foreignkeys', + + //Full-Text Search Procedures + 'sp_fulltext_catalog', 'sp_help_fulltext_catalogs_cursor', 'sp_fulltext_column', + 'sp_help_fulltext_columns', 'sp_fulltext_database', 'sp_help_fulltext_columns_cursor', + 'sp_fulltext_service', 'sp_help_fulltext_tables', 'sp_fulltext_table', + 'sp_help_fulltext_tables_cursor', 'sp_help_fulltext_catalogs', + + //Log Shipping Procedures + 'sp_add_log_shipping_database', 'sp_delete_log_shipping_database', 'sp_add_log_shipping_plan', + 'sp_delete_log_shipping_plan', 'sp_add_log_shipping_plan_database', + 'sp_delete_log_shipping_plan_database', 'sp_add_log_shipping_primary', + 'sp_delete_log_shipping_primary', 'sp_add_log_shipping_secondary', + 'sp_delete_log_shipping_secondary', 'sp_can_tlog_be_applied', 'sp_get_log_shipping_monitor_info', + 'sp_change_monitor_role', 'sp_remove_log_shipping_monitor', 'sp_change_primary_role', + 'sp_resolve_logins', 'sp_change_secondary_role', 'sp_update_log_shipping_monitor_info', + 'sp_create_log_shipping_monitor_account', 'sp_update_log_shipping_plan', + 'sp_define_log_shipping_monitor', 'sp_update_log_shipping_plan_database', + + //OLE Automation Extended Stored Procedures + 'sp_OACreate', 'sp_OAMethod', 'sp_OADestroy', 'sp_OASetProperty', 'sp_OAGetErrorInfo', + 'sp_OAStop', 'sp_OAGetProperty', + + //Replication Procedures + 'sp_add_agent_parameter', 'sp_enableagentoffload', 'sp_add_agent_profile', + 'sp_enumcustomresolvers', 'sp_addarticle', 'sp_enumdsn', 'sp_adddistpublisher', + 'sp_enumfullsubscribers', 'sp_adddistributiondb', 'sp_expired_subscription_cleanup', + 'sp_adddistributor', 'sp_generatefilters', 'sp_addmergealternatepublisher', + 'sp_getagentoffloadinfo', 'sp_addmergearticle', 'sp_getmergedeletetype', 'sp_addmergefilter', + 'sp_get_distributor', 'sp_addmergepublication', 'sp_getqueuedrows', 'sp_addmergepullsubscription', + 'sp_getsubscriptiondtspackagename', 'sp_addmergepullsubscription_agent', 'sp_grant_publication_access', + 'sp_addmergesubscription', 'sp_help_agent_default', 'sp_addpublication', 'sp_help_agent_parameter', + 'sp_addpublication_snapshot', 'sp_help_agent_profile', 'sp_addpublisher70', 'sp_helparticle', + 'sp_addpullsubscription', 'sp_helparticlecolumns', 'sp_addpullsubscription_agent', 'sp_helparticledts', + 'sp_addscriptexec', 'sp_helpdistpublisher', 'sp_addsubscriber', 'sp_helpdistributiondb', + 'sp_addsubscriber_schedule', 'sp_helpdistributor', 'sp_addsubscription', 'sp_helpmergealternatepublisher', + 'sp_addsynctriggers', 'sp_helpmergearticle', 'sp_addtabletocontents', 'sp_helpmergearticlecolumn', + 'sp_adjustpublisheridentityrange', 'sp_helpmergearticleconflicts', 'sp_article_validation', + 'sp_helpmergeconflictrows', 'sp_articlecolumn', 'sp_helpmergedeleteconflictrows', 'sp_articlefilter', + 'sp_helpmergefilter', 'sp_articlesynctranprocs', 'sp_helpmergepublication', 'sp_articleview', + 'sp_helpmergepullsubscription', 'sp_attachsubscription', 'sp_helpmergesubscription', 'sp_browsesnapshotfolder', + 'sp_helppublication', 'sp_browsemergesnapshotfolder', 'sp_help_publication_access', 'sp_browsereplcmds', + 'sp_helppullsubscription', 'sp_change_agent_parameter', 'sp_helpreplfailovermode', 'sp_change_agent_profile', + 'sp_helpreplicationdboption', 'sp_changearticle', 'sp_helpreplicationoption', 'sp_changedistpublisher', + 'sp_helpsubscriberinfo', 'sp_changedistributiondb', 'sp_helpsubscription', 'sp_changedistributor_password', + 'sp_ivindexhasnullcols', 'sp_changedistributor_property', 'sp_helpsubscription_properties', 'sp_changemergearticle', + 'sp_link_publication', 'sp_changemergefilter', 'sp_marksubscriptionvalidation', 'sp_changemergepublication', + 'sp_mergearticlecolumn', 'sp_changemergepullsubscription', 'sp_mergecleanupmetadata', 'sp_changemergesubscription', + 'sp_mergedummyupdate', 'sp_changepublication', 'sp_mergesubscription_cleanup', 'sp_changesubscriber', + 'sp_publication_validation', 'sp_changesubscriber_schedule', 'sp_refreshsubscriptions', 'sp_changesubscriptiondtsinfo', + 'sp_reinitmergepullsubscription', 'sp_changesubstatus', 'sp_reinitmergesubscription', 'sp_change_subscription_properties', + 'sp_reinitpullsubscription', 'sp_check_for_sync_trigger', 'sp_reinitsubscription', 'sp_copymergesnapshot', + 'sp_removedbreplication', 'sp_copysnapshot', 'sp_repladdcolumn', 'sp_copysubscription', 'sp_replcmds', + 'sp_deletemergeconflictrow', 'sp_replcounters', 'sp_disableagentoffload', 'sp_repldone', 'sp_drop_agent_parameter', + 'sp_repldropcolumn', 'sp_drop_agent_profile', 'sp_replflush', 'sp_droparticle', 'sp_replicationdboption', + 'sp_dropanonymouseagent', 'sp_replication_agent_checkup', 'sp_dropdistpublisher', 'sp_replqueuemonitor', + 'sp_dropdistributiondb', 'sp_replsetoriginator', 'sp_dropmergealternatepublisher', 'sp_replshowcmds', + 'sp_dropdistributor', 'sp_repltrans', 'sp_dropmergearticle', 'sp_restoredbreplication', 'sp_dropmergefilter', + 'sp_revoke_publication_access', 'sp_scriptsubconflicttable', 'sp_dropmergepublication', 'sp_script_synctran_commands', + 'sp_dropmergepullsubscription', 'sp_setreplfailovermode', 'sp_showrowreplicainfo', 'sp_dropmergesubscription', + 'sp_subscription_cleanup', 'sp_droppublication', 'sp_table_validation', 'sp_droppullsubscription', + 'sp_update_agent_profile', 'sp_dropsubscriber', 'sp_validatemergepublication', 'sp_dropsubscription', + 'sp_validatemergesubscription', 'sp_dsninfo', 'sp_vupgrade_replication', 'sp_dumpparamcmd', + + //Security Procedures + 'sp_addalias', 'sp_droprolemember', 'sp_addapprole', 'sp_dropserver', 'sp_addgroup', 'sp_dropsrvrolemember', + 'sp_dropuser', 'sp_addlogin', 'sp_grantdbaccess', 'sp_addremotelogin', + 'sp_grantlogin', 'sp_addrole', 'sp_helpdbfixedrole', 'sp_addrolemember', 'sp_helpgroup', + 'sp_addserver', 'sp_helplinkedsrvlogin', 'sp_addsrvrolemember', 'sp_helplogins', 'sp_adduser', + 'sp_helpntgroup', 'sp_approlepassword', 'sp_helpremotelogin', 'sp_changedbowner', 'sp_helprole', + 'sp_changegroup', 'sp_helprolemember', 'sp_changeobjectowner', 'sp_helprotect', 'sp_change_users_login', + 'sp_helpsrvrole', 'sp_dbfixedrolepermission', 'sp_helpsrvrolemember', 'sp_defaultdb', 'sp_helpuser', + 'sp_defaultlanguage', 'sp_MShasdbaccess', 'sp_denylogin', 'sp_password', 'sp_dropalias', 'sp_remoteoption', + 'sp_dropapprole', 'sp_revokedbaccess', 'sp_dropgroup', 'sp_revokelogin', 'sp_droplinkedsrvlogin', + 'sp_setapprole', 'sp_droplogin', 'sp_srvrolepermission', 'sp_dropremotelogin', 'sp_validatelogins', 'sp_droprole', + + //SQL Mail Procedures + 'sp_processmail', 'xp_sendmail', 'xp_deletemail', 'xp_startmail', 'xp_findnextmsg', 'xp_stopmail', 'xp_readmail', + + //SQL Profiler Procedures + 'sp_trace_create', 'sp_trace_setfilter', 'sp_trace_generateevent', 'sp_trace_setstatus', 'sp_trace_setevent', + + //SQL Server Agent Procedures + 'sp_add_alert', 'sp_help_jobhistory', 'sp_add_category', 'sp_help_jobschedule', 'sp_add_job', + 'sp_help_jobserver', 'sp_add_jobschedule', 'sp_help_jobstep', 'sp_add_jobserver', 'sp_help_notification', + 'sp_add_jobstep', 'sp_help_operator', 'sp_add_notification', 'sp_help_targetserver', + 'sp_add_operator', 'sp_help_targetservergroup', 'sp_add_targetservergroup', 'sp_helptask', + 'sp_add_targetsvrgrp_member', 'sp_manage_jobs_by_login', 'sp_addtask', 'sp_msx_defect', + 'sp_apply_job_to_targets', 'sp_msx_enlist', 'sp_delete_alert', 'sp_post_msx_operation', + 'sp_delete_category', 'sp_purgehistory', 'sp_delete_job', 'sp_purge_jobhistory', 'sp_delete_jobschedule', + 'sp_reassigntask', 'sp_delete_jobserver', 'sp_remove_job_from_targets', 'sp_delete_jobstep', + 'sp_resync_targetserver', 'sp_delete_notification', 'sp_start_job', 'sp_delete_operator', + 'sp_stop_job', 'sp_delete_targetserver', 'sp_update_alert', 'sp_delete_targetservergroup', + 'sp_update_category', 'sp_delete_targetsvrgrp_member', 'sp_update_job', 'sp_droptask', + 'sp_update_jobschedule', 'sp_help_alert', 'sp_update_jobstep', 'sp_help_category', + 'sp_update_notification', 'sp_help_downloadlist', 'sp_update_operator', 'sp_helphistory', + 'sp_update_targetservergroup', 'sp_help_job', 'sp_updatetask', 'xp_sqlagent_proxy_account', + + //System Procedures + 'sp_add_data_file_recover_suspect_db', 'sp_helpconstraint', 'sp_addextendedproc', + 'sp_helpdb', 'sp_addextendedproperty', 'sp_helpdevice', 'sp_add_log_file_recover_suspect_db', + 'sp_helpextendedproc', 'sp_addmessage', 'sp_helpfile', 'sp_addtype', 'sp_helpfilegroup', + 'sp_addumpdevice', 'sp_helpindex', 'sp_altermessage', 'sp_helplanguage', 'sp_autostats', + 'sp_helpserver', 'sp_attach_db', 'sp_helpsort', 'sp_attach_single_file_db', 'sp_helpstats', + 'sp_bindefault', 'sp_helptext', 'sp_bindrule', 'sp_helptrigger', 'sp_bindsession', + 'sp_indexoption', 'sp_certify_removable', 'sp_invalidate_textptr', 'sp_configure', + 'sp_lock', 'sp_create_removable', 'sp_monitor', 'sp_createstats', 'sp_procoption', + 'sp_cycle_errorlog', 'sp_recompile', 'sp_datatype_info', 'sp_refreshview', 'sp_dbcmptlevel', + 'sp_releaseapplock', 'sp_dboption', 'sp_rename', 'sp_dbremove', 'sp_renamedb', + 'sp_delete_backuphistory', 'sp_resetstatus', 'sp_depends', 'sp_serveroption', 'sp_detach_db', + 'sp_setnetname', 'sp_dropdevice', 'sp_settriggerorder', 'sp_dropextendedproc', 'sp_spaceused', + 'sp_dropextendedproperty', 'sp_tableoption', 'sp_dropmessage', 'sp_unbindefault', 'sp_droptype', + 'sp_unbindrule', 'sp_executesql', 'sp_updateextendedproperty', 'sp_getapplock', 'sp_updatestats', + 'sp_getbindtoken', 'sp_validname', 'sp_help', 'sp_who', + + //Web Assistant Procedures + 'sp_dropwebtask', 'sp_makewebtask', 'sp_enumcodepages', 'sp_runwebtask', + + //XML Procedures + 'sp_xml_preparedocument', 'sp_xml_removedocument', + + //General Extended Procedures + 'xp_cmdshellxp_logininfo', 'xp_enumgroups', 'xp_msver', 'xp_findnextmsgxp_revokelogin', + 'xp_grantlogin', 'xp_sprintf', 'xp_logevent', 'xp_sqlmaint', 'xp_loginconfig', 'xp_sscanf', + + //API System Stored Procedures + 'sp_cursor', 'sp_cursorclose', 'sp_cursorexecute', 'sp_cursorfetch', 'sp_cursoropen', + 'sp_cursoroption', 'sp_cursorprepare', 'sp_cursorunprepare', 'sp_execute', 'sp_prepare', 'sp_unprepare', + + //Misc + 'sp_createorphan', 'sp_droporphans', 'sp_reset_connection', 'sp_sdidebug' + ), + 4 => array( + //Function/sp's higlighted brown. + 'fn_helpcollations', 'fn_listextendedproperty ', 'fn_servershareddrives', + 'fn_trace_geteventinfo', 'fn_trace_getfilterinfo', 'fn_trace_getinfo', + 'fn_trace_gettable', 'fn_virtualfilestats', + ), + ), + 'SYMBOLS' => array( + '!', '!=', '%', '&', '&&', '(', ')', '*', '+', '-', '/', '<', '<<', '<=', + '<=>', '<>', '=', '>', '>=', '>>', '^', 'ALL', 'AND', 'ANY', 'BETWEEN', 'CROSS', + 'EXISTS', 'IN', 'JOIN', 'LIKE', 'NOT', 'NULL', 'OR', 'OUTER', 'SOME', '|', '||', '~' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000FF;', + 2 => 'color: #FF00FF;', + 3 => 'color: #AF0000;', + 4 => 'color: #AF0000;' + ), + 'COMMENTS' => array( + 1 => 'color: #008080;', + 'MULTI' => 'color: #008080;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #808080;' + ), + 'STRINGS' => array( + 0 => 'color: #FF0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000;' + ), + 'METHODS' => array( + 1 => 'color: #202020;', + 2 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #808080;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/typoscript.php b/examples/includes/geshi/geshi/typoscript.php new file mode 100644 index 0000000..b0ae753 --- /dev/null +++ b/examples/includes/geshi/geshi/typoscript.php @@ -0,0 +1,300 @@ + Complete rewrite + * 2005/07/29 (1.0.0) + * - First Release + * + * TODO (updated 2004/07/14) + * ------------------------- + * + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'TypoScript', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array(2 => '/(? GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + // Conditions: http://documentation.typo3.org/documentation/tsref/conditions/ + 1 => array( + 'browser', 'compatVersion', 'dayofmonth', 'dayofweek', 'device', + 'globalString', 'globalVars', 'hostname', 'hour', + 'ip', 'language', 'loginUser', 'loginuser', 'minute', + 'month', 'PIDinRootline', 'PIDupinRootline', + 'system', 'treelevel', 'useragent', 'userFunc', + 'usergroup', 'version' + ), + + // Functions: http://documentation.typo3.org/documentation/tsref/functions/ + 2 => array( + 'addParams', 'encapsLines', 'filelink', 'HTMLparser', + 'HTMLparser_tags', 'if', 'imageLinkWrap', + 'imgResource', 'makelinks', 'numRows', 'parseFunc', + 'select', 'split', 'stdWrap', 'tableStyle', 'tags', + 'textStyle', 'typolink' + ), + + // Toplevel objects: http://documentation.typo3.org/documentation/tsref/tlo-objects/ + 3 => array( + 'CARRAY', 'CONFIG', 'CONSTANTS', 'FE_DATA', 'FE_TABLE', 'FRAME', + 'FRAMESET', 'META', 'PAGE', 'plugin' + ), + + // Content Objects (cObject) : http://documentation.typo3.org/documentation/tsref/cobjects/ + 4 => array( + 'CASE', 'CLEARGIF', 'COA', 'COA_INT', 'COBJ_ARRAY', 'COLUMNS', + 'CONTENT', 'CTABLE', 'EDITPANEL', 'FILE', 'FORM', + 'HMENU', 'HRULER', 'HTML', 'IMAGE', 'IMGTEXT', + 'IMG_RESOURCE', 'LOAD_REGISTER', 'MULTIMEDIA', + 'OTABLE', 'PHP_SCRIPT', 'PHP_SCRIPT_EXT', + 'PHP_SCRIPT_INT', 'RECORDS', 'RESTORE_REGISTER', + 'SEARCHRESULT', 'TEMPLATE', 'TEXT', 'USER', + 'USER_INT' + ), + + // GIFBUILDER toplevel link: http://documentation.typo3.org/documentation/tsref/gifbuilder/ + 5 => array( + 'GIFBUILDER', + ), + + // GIFBUILDER: http://documentation.typo3.org/documentation/tsref/gifbuilder/ + // skipped fields: IMAGE, TEXT + // NOTE! the IMAGE and TEXT field already are linked in group 4, they + // cannot be linked twice . . . . unfortunately + 6 => array( + 'ADJUST', 'BOX', 'CROP', 'EFFECT', 'EMBOSS', + 'IMGMAP', 'OUTLINE', 'SCALE', 'SHADOW', + 'WORKAREA' + ), + + // MENU Objects: http://documentation.typo3.org/documentation/tsref/menu/ + 7 => array( + 'GMENU', 'GMENU_FOLDOUT', 'GMENU_LAYERS', 'IMGMENU', + 'IMGMENUITEM', 'JSMENU', 'JSMENUITEM', 'TMENU', + 'TMENUITEM', 'TMENU_LAYERS' + ), + + // MENU common properties: http://documentation.typo3.org/documentation/tsref/menu/common-properties/ + 8 => array( + 'alternativeSortingField', 'begin', 'debugItemConf', + 'imgNameNotRandom', 'imgNamePrefix', + 'itemArrayProcFunc', 'JSWindow', 'maxItems', + 'minItems', 'overrideId', 'sectionIndex', + 'showAccessRestrictedPages', 'submenuObjSuffixes' + ), + + // MENU item states: http://documentation.typo3.org/documentation/tsref/menu/item-states/ + 9 => array( + 'ACT', 'ACTIFSUB', 'ACTIFSUBRO', 'ACTRO', 'CUR', 'CURIFSUB', + 'CURIFSUBRO', 'CURRO', 'IFSUB', 'IFSUBRO', 'NO', + 'SPC', 'USERDEF1', 'USERDEF1RO', 'USERDEF2', + 'USERDEF2RO', 'USR', 'USRRO' + ), + ), + + // Does not include '-' because of stuff like htmlTag_langKey = en-GB and + // lib.nav-sub + 'SYMBOLS' => array( + 0 => array( + '|', + '+', '*', '/', '%', + '!', '&&', '^', + '<', '>', '=', + '?', ':', + '.' + ), + 1 => array( + '(', ')', '{', '}', '[', ']' + ) + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #ed7d14;', + 2 => 'font-weight: bold;', + 3 => 'color: #990000; font-weight: bold;', + 4 => 'color: #990000; font-weight: bold;', + 5 => 'color: #990000; font-weight: bold;', + 6 => 'color: #990000; font-weight: bold;', + 7 => 'color: #990000; font-weight: bold;', + 8 => 'font-weight: bold;', + 9 => 'color: #990000; font-weight: bold;', + ), + 'COMMENTS' => array( + 1 => 'color: #aaa; font-style: italic;', + 2 => 'color: #aaa; font-style: italic;', + 'MULTI' => 'color: #aaa; font-style: italic;' + ), + 'STRINGS' => array( + 0 => 'color: #ac14aa;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc0000;' + ), + 'METHODS' => array( + 1 => 'color: #0000e0; font-weight: bold;', + 2 => 'color: #0000e0; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #009900;' + ), + 'SYMBOLS' => array( + 0 => 'color: #339933; font-weight: bold;', + // Set this to the same value as brackets above + 1 => 'color: #009900; font-weight: bold;' + ), + 'REGEXPS' => array( + 0 => 'color: #009900;', + 1 => 'color: #009900; font-weight: bold;', + 2 => 'color: #3366CC;', + 3 => 'color: #000066; font-weight: bold;', + 4 => 'color: #ed7d14;', + 5 => 'color: #000066; font-weight: bold;', + 6 => 'color: #009900;', + 7 => 'color: #3366CC;' + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => 'http://documentation.typo3.org/documentation/tsref/conditions/{FNAME}/', + 2 => 'http://documentation.typo3.org/documentation/tsref/functions/{FNAME}/', + 3 => 'http://documentation.typo3.org/documentation/tsref/tlo-objects/{FNAME}/', + 4 => 'http://documentation.typo3.org/documentation/tsref/cobjects/{FNAME}/', + 5 => 'http://documentation.typo3.org/documentation/tsref/gifbuilder/', + 6 => 'http://documentation.typo3.org/documentation/tsref/gifbuilder/{FNAME}/', + 7 => 'http://documentation.typo3.org/documentation/tsref/menu/{FNAME}/', + 8 => 'http://documentation.typo3.org/documentation/tsref/menu/common-properties/', + 9 => 'http://documentation.typo3.org/documentation/tsref/menu/item-states/' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + // Constant + 0 => array( + GESHI_SEARCH => '(\{)(\$[a-zA-Z_\.]+[a-zA-Z0-9_\.]*)(\})', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '\\3' + ), + + // Constant dollar sign + 1 => array( + GESHI_SEARCH => '(\$)([a-zA-Z_\.]+[a-zA-Z0-9_\.]*)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '\\2' + ), + + // xhtml tag + 2 => array( + GESHI_SEARCH => '(<[a-zA-Z\!\/].*?>)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 's', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + + // extension keys / tables: (static|user|ttx|tx|tt|fe)_something[_something] + 3 => array( + GESHI_SEARCH => '(plugin\.|[^\.]\b)((?:static|user|ttx|tx|tt|fe)(?:_[0-9A-Za-z_]+?)\b)', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + + // conditions and controls + 4 => array( + GESHI_SEARCH => '(\[)(globalVar|global|end)\b', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + + // lowlevel setup and constant objects + 5 => array( + GESHI_SEARCH => '([^\.\$-\{]\b)(cObj|field|config|content|file|frameset|includeLibs|lib|page|plugin|register|resources|sitemap|sitetitle|styles|temp|tt_content|tt_news|types|xmlnews)\b', + GESHI_REPLACE => '\\2', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '\\1', + GESHI_AFTER => '' + ), + + // markers + 6 => array( + GESHI_SEARCH => '(###[^#]+###)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + + // hex color codes + 7 => array( + GESHI_SEARCH => '(#[a-fA-F0-9]{6}\b|#[a-fA-F0-9]{3}\b)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => '', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ) + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), +); + +?> diff --git a/examples/includes/geshi/geshi/vb.php b/examples/includes/geshi/geshi/vb.php new file mode 100644 index 0000000..0409058 --- /dev/null +++ b/examples/includes/geshi/geshi/vb.php @@ -0,0 +1,133 @@ + 'Visual Basic', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + // Comments (either single or multiline with _ + 1 => '/\'.*(? GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'AddressOf', 'Alias', 'And', 'Append', 'As', 'BF', 'Binary', + 'Boolean', 'ByRef', 'Byte', 'ByVal', 'Call', 'Case', 'CBool', + 'CByte', 'CCur', 'CDate', 'CDbl', 'CDec', 'CInt', 'CLng', + 'Close', 'Collection', 'Const', 'Control', 'CSng', 'CStr', + 'Currency', 'CVar', 'Date', 'Declare', 'Dim', 'Do', 'Double', + 'Each', 'Else', 'ElseIf', 'End', 'Enum', 'Erase', 'Error', + 'Event', 'Exit', 'Explicit', 'False', 'For', 'Friend', + 'Function', 'Get', 'GoSub', 'Goto', 'If', 'Implements', 'In', + 'Input', 'Integer', 'Is', 'LBound', 'Let', 'Lib', 'Like', + 'Line', 'Long', 'Loop', 'Mod', 'New', 'Next', 'Not', + 'Nothing', 'Object', 'On', 'Open', 'Option', 'Optional', + 'Or', 'Output', 'ParamArray', 'Preserve', 'Print', 'Private', + 'Property', 'Public', 'RaiseEvent', 'Random', 'ReDim', + 'Resume', 'Select', 'Set', 'Single', 'Static', 'Step', + 'Stop', 'String', 'Sub', 'Then', 'To', 'True', 'Type', + 'TypeOf', 'UBound', 'Until', 'Variant', 'While', 'With', + 'WithEvents', 'Xor' + ) + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000080;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000;' + ), + 'BRACKETS' => array( + ), + 'STRINGS' => array( + 0 => 'color: #800000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #800000; font-weight: bold;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + ) + ), + 'URLS' => array( + 1 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'BRACKETS' => GESHI_NEVER, + 'SYMBOLS' => GESHI_NEVER, + 'NUMBERS' => GESHI_NEVER + ) + ) +); + +?> \ No newline at end of file diff --git a/examples/includes/geshi/geshi/vbnet.php b/examples/includes/geshi/geshi/vbnet.php new file mode 100644 index 0000000..4a0f000 --- /dev/null +++ b/examples/includes/geshi/geshi/vbnet.php @@ -0,0 +1,201 @@ + 'vb.net', + 'COMMENT_SINGLE' => array(1 => "'"), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + '3DDKSHADOW', '3DHIGHLIGHT', '3DLIGHT', 'ABORT', 'ABORTRETRYIGNORE', 'ACTIVEBORDER', + 'ACTIVETITLEBAR', 'ALIAS', 'APPLICATIONMODAL', 'APPLICATIONWORKSPACE', 'ARCHIVE', + 'BACK', 'BINARYCOMPARE', 'BLACK', 'BLUE', 'BUTTONFACE', 'BUTTONSHADOW', 'BUTTONTEXT', + 'CANCEL', 'CDROM', 'CR', 'CRITICAL', 'CRLF', 'CYAN', 'DEFAULT', 'DEFAULTBUTTON1', + 'DEFAULTBUTTON2', 'DEFAULTBUTTON3', 'DESKTOP', 'DIRECTORY', 'EXCLAMATION', 'FALSE', + 'FIXED', 'FORAPPENDING', 'FORMFEED', 'FORREADING', 'FORWRITING', 'FROMUNICODE', + 'GRAYTEXT', 'GREEN', 'HIDDEN', 'HIDE', 'HIGHLIGHT', 'HIGHLIGHTTEXT', 'HIRAGANA', + 'IGNORE', 'INACTIVEBORDER', 'INACTIVECAPTIONTEXT', 'INACTIVETITLEBAR', 'INFOBACKGROUND', + 'INFORMATION', 'INFOTEXT', 'KATAKANALF', 'LOWERCASE', 'MAGENTA', 'MAXIMIZEDFOCUS', + 'MENUBAR', 'MENUTEXT', 'METHOD', 'MINIMIZEDFOCUS', 'MINIMIZEDNOFOCUS', 'MSGBOXRIGHT', + 'MSGBOXRTLREADING', 'MSGBOXSETFOREGROUND', 'NARROW', 'NEWLINE', 'NO', 'NORMAL', + 'NORMALFOCUS', 'NORMALNOFOCUS', 'NULLSTRING', 'OBJECTERROR', 'OK', 'OKCANCEL', 'OKONLY', + 'PROPERCASE', 'QUESTION', 'RAMDISK', 'READONLY', 'RED', 'REMOTE', 'REMOVABLE', 'RETRY', + 'RETRYCANCEL', 'SCROLLBARS', 'SYSTEMFOLDER', 'SYSTEMMODAL', 'TEMPORARYFOLDER', + 'TEXTCOMPARE', 'TITLEBARTEXT', 'TRUE', 'UNICODE', 'UNKNOWN', 'UPPERCASE', 'VERTICALTAB', + 'VOLUME', 'WHITE', 'WIDE', 'WIN16', 'WIN32', 'WINDOWBACKGROUND', 'WINDOWFRAME', + 'WINDOWSFOLDER', 'WINDOWTEXT', 'YELLOW', 'YES', 'YESNO', 'YESNOCANCEL' + ), + 2 => array( + 'AndAlso', 'As', 'ADDHANDLER', 'ASSEMBLY', 'AUTO', 'Binary', 'ByRef', 'ByVal', 'BEGINEPILOGUE', + 'Else', 'ElseIf', 'Empty', 'Error', 'ENDPROLOGUE', 'EXTERNALSOURCE', 'ENVIRON', 'For', + 'Friend', 'GET', 'HANDLES', 'Input', 'Is', 'IsNot', 'Len', 'Lock', 'Me', 'Mid', 'MUSTINHERIT', 'MustOverride', + 'MYBASE', 'MYCLASS', 'New', 'Next', 'Nothing', 'Null', 'NOTINHERITABLE', + 'NOTOVERRIDABLE', 'OFF', 'On', 'Option', 'Optional', 'Overloads', 'OVERRIDABLE', 'Overrides', 'ParamArray', + 'Print', 'Private', 'Property', 'Public', 'Resume', 'Return', 'Seek', 'Static', 'Step', + 'String', 'SHELL', 'SENDKEYS', 'SET', 'Shared', 'Then', 'Time', 'To', 'THROW', 'WithEvents' + ), + 3 => array( + 'COLLECTION', 'DEBUG', 'DICTIONARY', 'DRIVE', 'DRIVES', 'ERR', 'FILE', 'FILES', + 'FILESYSTEMOBJECT', 'FOLDER', 'FOLDERS', 'TEXTSTREAM' + ), + 4 => array( + 'BOOLEAN', 'BYTE', 'DATE', 'DECIMIAL', 'DOUBLE', 'INTEGER', 'LONG', 'OBJECT', + 'SINGLE STRING' + ), + 5 => array( + 'ADDRESSOF', 'AND', 'BITAND', 'BITNOT', 'BITOR', 'BITXOR', + 'GETTYPE', 'LIKE', 'MOD', 'NOT', 'ORXOR' + ), + 6 => array( + 'APPACTIVATE', 'BEEP', 'CALL', 'CHDIR', 'CHDRIVE', 'CLASS', 'CASE', 'CATCH', 'CONST', + 'DECLARE', 'DELEGATE', 'DELETESETTING', 'DIM', 'DO', 'DOEVENTS', 'END', 'ENUM', + 'EVENT', 'EXIT', 'EACH', 'FUNCTION', 'FINALLY', 'IF', 'IMPORTS', 'INHERITS', + 'INTERFACE', 'IMPLEMENTS', 'KILL', 'LOOP', 'NAMESPACE', 'OPEN', 'PUT', + 'RAISEEVENT', 'RANDOMIZE', 'REDIM', 'REM', 'RESET', 'SAVESETTING', 'SELECT', + 'SETATTR', 'STOP', 'SUB', 'SYNCLOCK', 'STRUCTURE', 'SHADOWS', 'SWITCH', + 'TRY', 'WIDTH', 'WITH', 'WRITE', 'WHILE' + ), + 7 => array( + 'ABS', 'ARRAY', 'ASC', 'ASCB', 'ASCW', 'CALLBYNAME', 'CBOOL', 'CBYTE', 'CCHAR', + 'CCHR', 'CDATE', 'CDBL', 'CDEC', 'CHOOSE', 'CHR', 'CHR$', 'CHRB', 'CHRB$', 'CHRW', + 'CINT', 'CLNG', 'CLNG8', 'CLOSE', 'COBJ', 'COMMAND', 'COMMAND$', 'CONVERSION', + 'COS', 'CREATEOBJECT', 'CSHORT', 'CSTR', 'CURDIR', 'CTYPE', 'CVDATE', 'DATEADD', + 'DATEDIFF', 'DATEPART', 'DATESERIAL', 'DATEVALUE', 'DAY', 'DDB', 'DIR', 'DIR$', + 'EOF', 'ERROR$', 'EXP', 'FILEATTR', 'FILECOPY', 'FILEDATATIME', 'FILELEN', 'FILTER', + 'FIX', 'FORMAT', 'FORMAT$', 'FORMATCURRENCY', 'FORMATDATETIME', 'FORMATNUMBER', + 'FORMATPERCENT', 'FREEFILE', 'FV', 'GETALLSETTINGS', 'GETATTRGETOBJECT', 'GETSETTING', + 'HEX', 'HEX$', 'HOUR', 'IIF', 'IMESTATUS', 'INPUT$', 'INPUTB', 'INPUTB$', 'INPUTBOX', + 'INSTR', 'INSTRB', 'INSTRREV', 'INT', 'IPMT', 'IRR', 'ISARRAY', 'ISDATE', 'ISEMPTY', + 'ISERROR', 'ISNULL', 'ISNUMERIC', 'ISOBJECT', 'JOIN', 'LBOUND', 'LCASE', 'LCASE$', + 'LEFT', 'LEFT$', 'LEFTB', 'LEFTB$', 'LENB', 'LINEINPUT', 'LOC', 'LOF', 'LOG', 'LTRIM', + 'LTRIM$', 'MID$', 'MIDB', 'MIDB$', 'MINUTE', 'MIRR', 'MKDIR', 'MONTH', 'MONTHNAME', + 'MSGBOX', 'NOW', 'NPER', 'NPV', 'OCT', 'OCT$', 'PARTITION', 'PMT', 'PPMT', 'PV', + 'RATE', 'REPLACE', 'RIGHT', 'RIGHT$', 'RIGHTB', 'RIGHTB$', 'RMDIR', 'RND', 'RTRIM', + 'RTRIM$', 'SECOND', 'SIN', 'SLN', 'SPACE', 'SPACE$', 'SPC', 'SPLIT', 'SQRT', 'STR', 'STR$', + 'STRCOMP', 'STRCONV', 'STRING$', 'STRREVERSE', 'SYD', 'TAB', 'TAN', 'TIMEOFDAY', + 'TIMER', 'TIMESERIAL', 'TIMEVALUE', 'TODAY', 'TRIM', 'TRIM$', 'TYPENAME', 'UBOUND', + 'UCASE', 'UCASE$', 'VAL', 'WEEKDAY', 'WEEKDAYNAME', 'YEAR' + ), + 8 => array( + 'ANY', 'ATN', 'CALENDAR', 'CIRCLE', 'CURRENCY', 'DEFBOOL', 'DEFBYTE', 'DEFCUR', + 'DEFDATE', 'DEFDBL', 'DEFDEC', 'DEFINT', 'DEFLNG', 'DEFOBJ', 'DEFSNG', 'DEFSTR', + 'DEFVAR', 'EQV', 'GOSUB', 'IMP', 'INITIALIZE', 'ISMISSING', 'LET', 'LINE', 'LSET', + 'RSET', 'SGN', 'SQR', 'TERMINATE', 'VARIANT', 'VARTYPE', 'WEND' + ), + ), + 'SYMBOLS' => array( + '&', '&=', '*', '*=', '+', '+=', '-', '-=', '//', '/', '/=', '=', '\\', '\\=', + '^', '^=' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false, + 6 => false, + 7 => false, + 8 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0600FF;', //Constants + 2 => 'color: #FF8000;', //Keywords + 3 => 'color: #008000;', //Data Types + 4 => 'color: #FF0000;', //Objects + 5 => 'color: #804040;', //Operators + 6 => 'color: #0600FF;', //Statements + 7 => 'color: #0600FF;', //Functions + 8 => 'color: #0600FF;' //Deprecated + ), + 'COMMENTS' => array( + 1 => 'color: #008080; font-style: italic;', + 'MULTI' => 'color: #008080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008080; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #808080;' + ), + 'NUMBERS' => array( + 0 => 'color: #FF0000;' + ), + 'METHODS' => array( + 1 => 'color: #0000FF;' + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => 'http://www.google.com/search?q={FNAMEU}+site:msdn.microsoft.com', + 4 => '', + 5 => '', + 6 => '', + 7 => '', + 8 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 =>'.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/verilog.php b/examples/includes/geshi/geshi/verilog.php new file mode 100644 index 0000000..57d268e --- /dev/null +++ b/examples/includes/geshi/geshi/verilog.php @@ -0,0 +1,173 @@ + + * Copyright: (C) 2008 Guenter Dannoritzer + * Release Version: 1.0.8.3 + * Date Started: 2008/05/28 + * + * Verilog language file for GeSHi. + * + * CHANGES + * ------- + * 2008/05/29 + * - added regular expression to find numbers of the form 4'b001xz + * - added regular expression to find values for `timescale command + * - extended macro keywords + * + * TODO (updated 2008/05/29) + * ------------------------- + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'Verilog', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'COMMENT_REGEXP' => array(1 => '/\/\/(?:\\\\\\\\|\\\\\\n|.)*$/m'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + // keywords + 1 => array('always', 'and', 'assign', 'begin', 'buf', 'bufif0', 'bufif1', 'case', + 'casex', 'casez', 'cmos', 'deassign', 'default', 'defparam', + 'disable', 'edge', 'else', 'end', 'endcase', 'endfunction', + 'endmodule', 'endprimitive', 'endspecify', 'endtable', 'endtask', + 'event', 'for', 'force', 'forever', 'function', 'highz0', + 'highz1', 'if', 'ifnone', 'initial', 'inout', 'input', 'integer', + 'join', 'large', 'macromodule', 'medium', 'module', 'nand', + 'negedge', 'nmos', 'nor', 'not', 'notif0', 'notif1', 'or', + 'output', 'parameter', 'pmos', 'posedge', 'primitive', 'pull0', + 'pull1', 'pulldown', 'pullup', 'rcmos', 'real', 'realtime', 'reg', + 'release', 'repeat', 'rnmos', 'rpmos', 'rtran', 'rtranif0', + 'rtranif1', 'scalared', 'small', 'specify', 'specparam', + 'strong0', 'strong1', 'supply0', 'supply1', 'table', 'task', + 'time', 'tran', 'tranif0', 'tranif1', 'tri', 'tri0', 'tri1', + 'triand', 'trior', 'trireg', 'vectored', 'wait', 'wand', 'weak0', + 'weak1', 'while', 'wire', 'wor', 'xnor', 'xor' + ), + // system tasks + 2 => array( + '$display', '$monitor', + '$dumpall', '$dumpfile', '$dumpflush', '$dumplimit', '$dumpoff', + '$dumpon', '$dumpvars', + '$fclose', '$fdisplay', '$fopen', + '$finish', '$fmonitor', '$fstrobe', '$fwrite', + '$fgetc', '$ungetc', '$fgets', '$fscanf', '$fread', '$ftell', + '$fseek', '$frewind', '$ferror', '$fflush', '$feof', + '$random', + '$readmemb', '$readmemh', '$readmemx', + '$signed', '$stime', '$stop', + '$strobe', '$time', '$unsigned', '$write' + ), + // macros + 3 => array( + '`default-net', '`define', + '`celldefine', '`default_nettype', '`else', '`elsif', '`endcelldefine', + '`endif', '`ifdef', '`ifndef', '`include', '`line', '`nounconnected_drive', + '`resetall', '`timescale', '`unconnected_drive', '`undef' + ), + ), + 'SYMBOLS' => array( + '(', ')', '{', '}', '[', ']', '=', '+', '-', '*', '/', '!', '%', + '^', '&', '|', '~', + '?', ':', + '#', '<<', '<<<', + '>', '<', '>=', '<=', + '@', ';', ',' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #A52A2A; font-weight: bold;', + 2 => 'color: #9932CC;', + 3 => 'color: #008800;' + ), + 'COMMENTS' => array( + 1 => 'color: #00008B; font-style: italic;', + 'MULTI' => 'color: #00008B; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #9F79EE' + ), + 'BRACKETS' => array( + 0 => 'color: #9F79EE;' + ), + 'STRINGS' => array( + 0 => 'color: #FF00FF;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff0055;' + ), + 'METHODS' => array( + 1 => 'color: #202020;', + 2 => 'color: #202020;' + ), + 'SYMBOLS' => array( + 0 => 'color: #5D478B;' + ), + 'REGEXPS' => array( + 0 => 'color: #ff0055;', + 1 => 'color: #ff0055;', + ), + 'SCRIPT' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + 1 => '' + ), + 'REGEXPS' => array( + // numbers + 0 => "\d'[bdh][0-9_a-fA-FxXzZ]+", + // time -> 1, 10, or 100; s, ms, us, ns, ps, of fs + 1 => "1[0]{0,2}[munpf]?s" + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + 1 => '' + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + 0 => true, + 1 => true, + 2 => true, + 3 => true + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/vhdl.php b/examples/includes/geshi/geshi/vhdl.php new file mode 100644 index 0000000..6fd537e --- /dev/null +++ b/examples/includes/geshi/geshi/vhdl.php @@ -0,0 +1,144 @@ + 'VHDL', + 'COMMENT_SINGLE' => array(1 => '--'), + 'COMMENT_MULTI' => array('%' => '%'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /*keywords*/ + 1 => array( + 'access','after','alias','all','assert','attribute','architecture','begin', + 'block','body','buffer','bus','case','component','configuration','constant', + 'disconnect','downto','else','elsif','end','entity','exit','file','for', + 'function','generate','generic','group','guarded','if','impure','in', + 'inertial','inout','is','label','library','linkage','literal','loop', + 'map','new','next','null','of','on','open','others','out','package', + 'port','postponed','procedure','process','pure','range','record','register', + 'reject','report','return','select','severity','signal','shared','subtype', + 'then','to','transport','type','unaffected','units','until','use','variable', + 'wait','when','while','with','note','warning','error','failure','and', + 'or','xor','not','nor','used','memory','segments','dff','dffe','help_id', + 'mod','info','latch','rising_edge','falling_edge' + ), + /*types*/ + 2 => array( + 'bit','bit_vector','character','boolean','integer','real','time','string', + 'severity_level','positive','natural','signed','unsigned','line','text', + 'std_logic','std_logic_vector','std_ulogic','std_ulogic_vector','qsim_state', + 'qsim_state_vector','qsim_12state','qsim_12state_vector','qsim_strength', + 'mux_bit','mux_vector','reg_bit','reg_vector','wor_bit','wor_vector', + 'work','ieee','std_logic_signed','std_logic_1164','std_logic_arith', + 'numeric_std' + + ), + /*operators*/ + ), + 'SYMBOLS' => array( + '[', ']', '(', ')', + ';',':', + '<','>','=','<=',':=','=>','==' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #000080; font-weight: bold;', + 2 => 'color: #0000ff;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000; font-style: italic;', + 'MULTI' => 'color: #008000; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #000066;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #ff0000;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000066;' + ), + 'REGEXPS' => array( + 0 => 'color: #ff0000;', + 1 => 'color: #ff0000;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Hex numbers and scientific notation for numbers + 0 => '(\b0x[0-9a-fA-F]+|\b\d[0-9a-fA-F]+[hH])|'. + '(\b\d+?(\.\d+?)?E[+\-]?\d+)|(\bns)|'. + "('[0-9a-zA-Z]+(?!'))", + //Number characters? + 1 => "\b(''\d'')" + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/vim.php b/examples/includes/geshi/geshi/vim.php new file mode 100644 index 0000000..94927ea --- /dev/null +++ b/examples/includes/geshi/geshi/vim.php @@ -0,0 +1,185 @@ + 'Vim Script', + 'COMMENT_SINGLE' => array(), + 'COMMENT_REGEXP' => array( + 1 => "/^\".*$/m" + ), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'brea', 'break', 'call', 'cat', 'catc', + 'catch', 'con', 'cont', 'conti', + 'contin', 'continu', 'continue', 'ec', 'echo', + 'echoe', 'echoer', 'echoerr', 'echoh', + 'echohl', 'echom', 'echoms', 'echomsg', 'echon', + 'el', 'els', 'else', 'elsei', 'elseif', + 'en', 'end', 'endi', 'endif', 'endfo', + 'endfor', 'endt', 'endtr', 'endtry', 'endw', + 'endwh', 'endwhi', 'endwhil', 'endwhile', 'exe', 'exec', 'execu', + 'execut', 'execute', 'fina', 'final', 'finall', 'finally', 'for', + 'fun', 'func', 'funct', 'functi', 'functio', 'function', 'if', 'in', + 'let', 'lockv', 'lockva', 'lockvar', 'retu', 'retur', 'return', 'th', + 'thr', 'thro', 'throw', 'try', 'unl', 'unle', 'unlet', 'unlo', 'unloc', + 'unlock', 'unlockv', 'unlockva', 'unlockvar', 'wh', 'whi', 'whil', + 'while' + ), + 2 => array( + 'autocmd', 'com', 'comm', 'comma', 'comman', 'command', 'comc', + 'comcl', 'comcle', 'comclea', 'comclear', 'delc', 'delco', + 'delcom', 'delcomm', 'delcomma', 'delcomman', 'delcommand', + '-nargs' # TODO There are zillions of commands to be added here from http://vimdoc.sourceforge.net/htmldoc/usr_toc.html + ), + 3 => array( + 'abs', 'add', 'append', 'argc', 'argidx', 'argv', 'atan', + 'browse', 'browsedir', 'bufexists', 'buflisted', 'bufloaded', + 'bufname', 'bufnr', 'bufwinnr', 'byte2line', 'byteidx', + 'ceil', 'changenr', 'char2nr', 'cindent', 'clearmatches', + 'col', 'complete', 'complete_add', 'complete_check', 'confirm', + 'copy', 'cos', 'count', 'cscope_connection', 'cursor', + 'deepcopy', 'delete', 'did_filetype', 'diff_filler', + 'diff_hlID', 'empty', 'escape', 'eval', 'eventhandler', + 'executable', 'exists', 'extend', 'expand', 'feedkeys', + 'filereadable', 'filewritable', 'filter', 'finddir', + 'findfile', 'float2nr', 'floor', 'fnameescape', 'fnamemodify', + 'foldclosed', 'foldclosedend', 'foldlevel', 'foldtext', + 'foldtextresult', 'foreground', 'garbagecollect', + 'get', 'getbufline', 'getbufvar', 'getchar', 'getcharmod', + 'getcmdline', 'getcmdpos', 'getcmdtype', 'getcwd', 'getfperm', + 'getfsize', 'getfontname', 'getftime', 'getftype', 'getline', + 'getloclist', 'getmatches', 'getpid', 'getpos', 'getqflist', + 'getreg', 'getregtype', 'gettabwinvar', 'getwinposx', + 'getwinposy', 'getwinvar', 'glob', 'globpath', 'has', + 'has_key', 'haslocaldir', 'hasmapto', 'histadd', 'histdel', + 'histget', 'histnr', 'hlexists', 'hlID', 'hostname', 'iconv', + 'indent', 'index', 'input', 'inputdialog', 'inputlist', + 'inputrestore', 'inputsave', 'inputsecret', 'insert', + 'isdirectory', 'islocked', 'items', 'join', 'keys', 'len', + 'libcall', 'libcallnr', 'line', 'line2byte', 'lispindent', + 'localtime', 'log10', 'map', 'maparg', 'mapcheck', 'match', + 'matchadd', 'matcharg', 'matchdelete', 'matchend', 'matchlist', + 'matchstr', 'max', 'min', 'mkdir', 'mode', 'nextnonblank', + 'nr2char', 'pathshorten', 'pow', 'prevnonblank', 'printf', + 'pumvisible', 'range', 'readfile', 'reltime', 'reltimestr', + 'remote_expr', 'remote_foreground', 'remote_peek', + 'remote_read', 'remote_send', 'remove', 'rename', 'repeat', + 'resolve', 'reverse', 'round', 'search', 'searchdecl', + 'searchpair', 'searchpairpos', 'searchpos', 'server2client', + 'serverlist', 'setbufvar', 'setcmdpos', 'setline', + 'setloclist', 'setmatches', 'setpos', 'setqflist', 'setreg', + 'settabwinvar', 'setwinvar', 'shellescape', 'simplify', 'sin', + 'sort', 'soundfold', 'spellbadword', 'spellsuggest', 'split', + 'sqrt', 'str2float', 'str2nr', 'strftime', 'stridx', 'string', + 'strlen', 'strpart', 'strridx', 'strtrans', 'submatch', + 'substitute', 'synID', 'synIDattr', 'synIDtrans', 'synstack', + 'system', 'tabpagebuflist', 'tabpagenr', 'tabpagewinnr', + 'taglist', 'tagfiles', 'tempname', 'tolower', 'toupper', 'tr', + 'trunc', 'type', 'values', 'virtcol', 'visualmode', 'winbufnr', + 'wincol', 'winheight', 'winline', 'winnr', 'winrestcmd', + 'winrestview', 'winsaveview', 'winwidth', 'writefile' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '%', '&', '*', '|', '/', '<', '>', + '^', '-', '+', '~', '?', ':', '$', '@', '.' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => true, + 2 => true, + 3 => true + ), + 'STYLES' => array( + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => '' + ), + 'KEYWORDS' => array( + 1 => 'color: #804040;', + 2 => 'color: #668080;', + 3 => 'color: #25BB4D;' + ), + 'METHODS' => array( + 0 => 'color: #000000;', + ), + 'NUMBERS' => array( + 0 => 'color: #000000; font-weight:bold;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ), + 'STRINGS' => array( + 0 => 'color: #C5A22D;' + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;' + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, //Save some time as OO identifiers aren't used + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array(), + 'HIGHLIGHT_STRICT_BLOCK' => array() +); + +?> diff --git a/examples/includes/geshi/geshi/visualfoxpro.php b/examples/includes/geshi/geshi/visualfoxpro.php new file mode 100644 index 0000000..4592dd7 --- /dev/null +++ b/examples/includes/geshi/geshi/visualfoxpro.php @@ -0,0 +1,456 @@ + 'Visual Fox Pro', + 'COMMENT_SINGLE' => array(1 => "//", 2 => "\n*"), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'Case', 'Else', '#Else', 'Then', + 'Endcase', 'Enddefine', 'Enddo', 'Endfor', 'Endfunc', 'Endif', 'Endprintjob', + 'Endproc', 'Endscan', 'Endtext', 'Endwith', '#Endif', + '#Elif','#Define','#If','#Include', + '#Itsexpression','#Readclauses','#Region','#Section','#Undef','#Wname', + 'Define','Do', + 'For','Function','Hidden', + 'If','Local','Lparameter','Lparameters','Next','Otherwise', + 'Parameters','Printjob','Procedure','Protected','Public','Scan', + 'Text','While','With','Abs','Accept','Access','Aclass','Acopy', + 'Acos','Adatabases','Adbobjects','Addbs','Addrelationtoenv','Addtabletoenv', + 'Adel','Adir','Aelement','Aerror','Afields','Afont', + 'Agetclass','Agetfileversion','Ains','Ainstance','Alen','Align', + 'Alines','Alltrim','Alter','Amembers','Amouseobj','Anetresources', + 'Ansitooem','Append','Aprinters','Ascan','Aselobj','Asin', + 'Asort','Assert','Asserts','Assist','Asubscript','Asynchronous', + 'At_c','Atan','Atc','Atcc','Atcline','Atline', + 'Atn2','Aused','Autoform','Autoreport','Avcxclasses','Average', + 'BarCount','BarPrompt','BatchMode','BatchUpdateCount','Begin','BellSound', + 'BinToC','Bintoc','Bitand','Bitclear','Bitlshift','Bitnot', + 'Bitor','Bitrshift','Bitset','Bittest','Bitxor','Bof', + 'Browse','BrowseRefresh','Buffering','BuilderLock','COMArray','COMReturnError', + 'CToBin','Calculate','Call','Capslock','Cd','Cdow', + 'Ceiling','Central','Change','Char','Chdir','Chr', + 'Chrsaw','Chrtran','Chrtranc','Close','Cmonth','Cntbar', + 'Cntpad','Col','Comclassinfo','CommandTargetQuery','Compile','Completed', + 'Compobj','Compute','Concat','ConnectBusy','ConnectHandle','ConnectName', + 'ConnectString','ConnectTimeOut','ContainerReleaseType','Continue','Copy','Cos', + 'Cot','Count','Coverage','Cpconvert','Cpcurrent','Cpdbf', + 'Cpnotrans','Create','CreateBinary','Createobject','Createobjectex','Createoffline', + 'CrsBuffering','CrsFetchMemo','CrsFetchSize','CrsMaxRows','CrsMethodUsed','CrsNumBatch', + 'CrsShareConnection','CrsUseMemoSize','CrsWhereClause','Ctobin','Ctod','Ctot', + 'Curdate','Curdir','CurrLeft','CurrSymbol','CursorGetProp','CursorSetProp', + 'Curtime','Curval','DBGetProp','DBSetProp','DB_BufLockRow','DB_BufLockTable', + 'DB_BufOff','DB_BufOptRow','DB_BufOptTable','DB_Complette','DB_DeleteInsert','DB_KeyAndModified', + 'DB_KeyAndTimestamp','DB_KeyAndUpdatable','DB_LocalSQL','DB_NoPrompt','DB_Prompt','DB_RemoteSQL', + 'DB_TransAuto','DB_TransManual','DB_TransNone','DB_Update','Datetime','Day', + 'Dayname','Dayofmonth','Dayofweek','Dayofyear','Dbalias','Dbused', + 'Ddeaborttrans','Ddeadvise','Ddeenabled','Ddeexecute','Ddeinitiate','Ddelasterror', + 'Ddepoke','Dderequest','Ddesetoption','Ddesetservice','Ddesettopic','Ddeterminate', + 'Debugout','Declare','DefOLELCid','DefaultValue','Defaultext','Degrees', + 'DeleteTrigger','Desc','Description','Difference','Dimension','Dir', + 'Directory','Diskspace','DispLogin','DispWarnings','Display','Dll', + 'Dmy','DoDefault','DoEvents','Doc','Doevents','Dow', + 'Drivetype','Drop','Dropoffline','Dtoc','Dtor','Dtos', + 'Dtot','DynamicInputMask','Each','Edit','Eject','Elif', + 'End','Eof','Erase','Evaluate','Event','Eventtracking', + 'Exclude','Exclusive','Exit','Exp','Export','External', + 'FDate','FTime','Fchsize','Fclose','Fcount','Fcreate', + 'Feof','Ferror','FetchMemo','FetchSize','Fflush','Fgets', + 'Filer','Filetostr','Find','Fklabel','Fkmax','Fldlist', + 'Flock','Floor','Flush','Fontmetric','Fopen','Forceext', + 'Forcepath','FormSetClass','FormSetLib','FormsClass','FormsLib','Found', + 'FoxPro','Foxcode','Foxdoc','Foxgen','Foxgraph','Foxview', + 'Fputs','Fread','French','Fseek','Fsize','Fv', + 'Fwrite','Gather','German','GetPem','Getbar','Getcolor', + 'Getcp','Getdir','Getenv','Getexpr','Getfile','Getfldstate', + 'Getfont','Gethost','Getnextmodified','Getobject','Getpad','Getpict', + 'Getprinter','Go','Gomonth','Goto','Graph','GridHorz', + 'GridShow','GridShowPos','GridSnap','GridVert','Help','HelpOn', + 'HelpTo','HighLightRow','Home','Hour','IMEStatus','IdleTimeOut', + 'Idxcollate','Ifdef','Ifndef','Iif','Import','Include', + 'Indbc','Index','Indexseek','Inkey','Inlist','Input', + 'Insert','InsertTrigger','Insmode','IsBlank','IsFLocked','IsLeadByte', + 'IsMouse','IsNull','IsRLocked','Isalpha','Iscolor','Isdigit', + 'Isexclusive','Isflocked','Ishosted','Islower','Isreadonly','Isrlocked', + 'Isupper','Italian','Japan','Join','Justdrive','Justext', + 'Justfname','Justpath','Juststem','KeyField','KeyFieldList','Keyboard' + ), + 2 => array('Keymatch','LastProject','Lastkey','Lcase','Leftc','Len', + 'Lenc','Length','Likec','Lineno','LoadPicture','Loadpicture', + 'Locate','Locfile','Log','Log10','Logout','Lookup', + 'Loop','Lower','Ltrim','Lupdate','Mail','MaxRecords', + 'Mcol','Md','Mdown','Mdx','Mdy','Memlines', + 'Menu','Messagebox','Minute','Mkdir','Mline','Modify', + 'Month','Monthname','Mouse','Mrkbar','Mrkpad','Mrow', + 'Mtdll','Mton','Mwindow','Native','Ndx','Network', + 'NoFilter','Nodefault','Normalize','Note','Now','Ntom', + 'NullString','Numlock','Nvl','ODBChdbc','ODBChstmt','OLEDropTextInsertion', + 'OLELCid','Objnum','Objref','Objtoclient','Objvar','Occurs', + 'Oemtoansi','Oldval','OlePublic','Olereturnerror','On','Open', + 'Oracle','Order','Os','Outer','PCount','Pack', + 'PacketSize','Padc','Padl','Padr','Payment','Pcol', + 'PemStatus','Pi','Pivot','Play','Pop','Popup', + 'Power','PrimaryKey','Printstatus','Private','Prmbar','Prmpad', + 'ProjectClick','Proper','Prow','Prtinfo','Push','Putfile', + 'Pv','Qpr','Quater','QueryTimeOut','Quit','Radians', + 'Rand','Rat','Ratc','Ratline','Rd','Rdlevel', + 'Read','Readkey','Recall','Reccount','RecentlyUsedFiles','Recno', + 'Recsize','Regional','Reindex','RelatedChild','RelatedTable','RelatedTag', + 'Remove','Rename','Repeat','Replace','Replicate','Report', + 'ResHeight','ResWidth','ResourceOn','ResourceTo','Resources','Restore', + 'Resume','Retry','Return','Revertoffline','Rgbscheme','Rightc', + 'Rlock','Rmdir','Rollback','Round','Rtod','Rtrim', + 'RuleExpression','RuleText','Run','Runscript','Rview','SQLAsynchronous', + 'SQLBatchMode','SQLCancel','SQLColumns','SQLConnect','SQLConnectTimeOut','SQLDisconnect', + 'SQLDispLogin','SQLDispWarnings','SQLExec','SQLGetProp','SQLIdleTimeOut','SQLMoreResults', + 'SQLPrepare','SQLQueryTimeOut','SQLSetProp','SQLTables','SQLTransactions','SQLWaitTime', + 'Save','SavePicture','Savepicture','ScaleUnits','Scatter','Scols', + 'Scroll','Sec','Second','Seek','Select','SendUpdates', + 'Set','SetDefault','Setfldstate','Setup','ShareConnection','ShowOLEControls', + 'ShowOLEInsertable','ShowVCXs','Sign','Sin','Size','SizeBox', + 'Skpbar','Skppad','Sort','Soundex','SourceName','Sqlcommit', + 'Sqll','Sqlrollback','Sqlstringconnect','Sqrt','Srows','StatusBar', + 'Store','Str','Strconv','Strtofile','Strtran','Stuff', + 'Stuffc','Substr','Substrc','Substring','Sum','Suspend', + 'Sys','Sysmetric','TabOrdering','Table','TableRefresh','Tablerevert', + 'Tableupdate','TagCount','TagNo','Tan','Target','This', + 'Thisform','Thisformset','Timestamp','Timestampdiff','Total','Transactions', + 'Transform','Trim','Truncate','Ttoc','Ttod','Txnlevel', + 'Txtwidth','Type','Ucase','Undefine','Unlock','Unpack', + 'Updatable','UpdatableFieldList','Update','UpdateName','UpdateNameList','UpdateTrigger', + 'UpdateType','Updated','Upper','Upsizing','Usa','Use', + 'UseMemoSize','Used','Val','Validate','Varread','Vartype', + 'Version','VersionLanguage','Wait','WaitTime','Wborder','Wchild', + 'Wcols','Week','Wexist','Wfont','WhereType','Windcmd', + 'Windhelp','Windmemo','Windmenu','Windmodify','Windquery','Windscreen', + 'Windsnip','Windstproc','WizardPrompt','Wlast','Wlcol','Wlrow', + 'Wmaximum','Wminimum','Wontop','Woutput','Wparent','Wread', + 'Wrows','Wtitle','Wvisible','Year','Zap','_Alignment', + '_Asciicols','_Asciirows','_Assist','_Beautify','_Box','_Browser', + '_Builder','_Calcmem','_Calcvalue','_Cliptext','_Converter','_Coverage', + '_Curobj','_Dblclick','_Diarydate','_Dos','_Foxdoc','_Foxgraph', + '_Gallery','_Gengraph','_Genhtml','_Genmenu','_Genpd','_Genscrn', + '_Genxtab','_Getexpr','_Include','_Indent','_Lmargin','_Mac', + '_Mbr_appnd','_Mbr_cpart','_Mbr_delet','_Mbr_font','_Mbr_goto','_Mbr_grid', + '_Mbr_link','_Mbr_mode','_Mbr_mvfld','_Mbr_mvprt','_Mbr_seek','_Mbr_sp100', + '_Mbr_sp200','_Mbr_szfld','_Mbrowse','_Mda_appnd','_Mda_avg','_Mda_brow', + '_Mda_calc','_Mda_copy','_Mda_count','_Mda_label','_Mda_pack','_Mda_reprt', + '_Mda_rindx','_Mda_setup','_Mda_sort','_Mda_sp100','_Mda_sp200','_Mda_sp300', + '_Mda_sum','_Mda_total','_Mdata','_Mdiary','_Med_clear','_Med_copy', + '_Med_cut','_Med_cvtst','_Med_find','_Med_finda','_Med_goto','_Med_insob', + '_Med_link','_Med_obj','_Med_paste','_Med_pref','_Med_pstlk','_Med_redo', + '_Med_repl','_Med_repla','_Med_slcta','_Med_sp100','_Med_sp200','_Med_sp300', + '_Med_sp400','_Med_sp500','_Med_undo','_Medit','_Mfi_clall','_Mfi_close', + '_Mfi_export','_Mfi_import','_Mfi_new','_Mfi_open','_Mfi_pgset','_Mfi_prevu', + '_Mfi_print','_Mfi_quit','_Mfi_revrt','_Mfi_savas','_Mfi_save','_Mfi_send', + '_Mfi_setup','_Mfi_sp100','_Mfi_sp200','_Mfi_sp300','_Mfi_sp400','_Mfile', + '_Mfiler','_Mfirst','_Mlabel','_Mlast','_Mline','_Mmacro', + '_Mmbldr','_Mpr_beaut','_Mpr_cancl','_Mpr_compl','_Mpr_do','_Mpr_docum', + '_Mpr_formwz','_Mpr_gener','_Mpr_graph','_Mpr_resum','_Mpr_sp100','_Mpr_sp200', + '_Mpr_sp300','_Mpr_suspend','_Mprog','_Mproj','_Mrc_appnd','_Mrc_chnge', + '_Mrc_cont','_Mrc_delet','_Mrc_goto','_Mrc_locat','_Mrc_recal','_Mrc_repl', + '_Mrc_seek','_Mrc_sp100','_Mrc_sp200','_Mrecord','_Mreport','_Mrqbe', + '_Mscreen','_Msm_data','_Msm_edit','_Msm_file','_Msm_format','_Msm_prog', + '_Msm_recrd','_Msm_systm','_Msm_text','_Msm_tools','_Msm_view','_Msm_windo', + '_Mst_about','_Mst_ascii','_Mst_calcu','_Mst_captr','_Mst_dbase','_Mst_diary', + '_Mst_filer','_Mst_help','_Mst_hphow','_Mst_hpsch','_Mst_macro','_Mst_office', + '_Mst_puzzl','_Mst_sp100','_Mst_sp200','_Mst_sp300','_Mst_specl','_Msysmenu', + '_Msystem','_Mtable','_Mtb_appnd','_Mtb_cpart','_Mtb_delet','_Mtb_delrc', + '_Mtb_goto','_Mtb_link','_Mtb_mvfld','_Mtb_mvprt','_Mtb_props','_Mtb_recal', + '_Mtb_sp100','_Mtb_sp200','_Mtb_sp300','_Mtb_sp400','_Mtb_szfld','_Mwi_arran', + '_Mwi_clear','_Mwi_cmd','_Mwi_color','_Mwi_debug','_Mwi_hide','_Mwi_hidea', + '_Mwi_min','_Mwi_move','_Mwi_rotat','_Mwi_showa','_Mwi_size','_Mwi_sp100', + '_Mwi_sp200','_Mwi_toolb','_Mwi_trace','_Mwi_view','_Mwi_zoom','_Mwindow', + '_Mwizards','_Mwz_all','_Mwz_form','_Mwz_foxdoc','_Mwz_import','_Mwz_label', + '_Mwz_mail','_Mwz_pivot','_Mwz_query','_Mwz_reprt','_Mwz_setup','_Mwz_table', + '_Mwz_upsizing','_Netware','_Oracle','_Padvance','_Pageno','_Pbpage', + '_Pcolno','_Pcopies','_Pdparms','_Pdriver','_Pdsetup','_Pecode', + '_Peject','_Pepage','_Pform','_Plength','_Plineno','_Ploffset', + '_Ppitch','_Pquality','_Pretext','_Pscode','_Pspacing','_Pwait', + '_Rmargin','_Runactivedoc','_Samples','_Screen','_Shell','_Spellchk', + '_Sqlserver','_Startup','_Tabs','_Tally','_Text','_Throttle', + '_Transport','_Triggerlevel','_Unix','_WebDevOnly','_WebMenu','_WebMsftHomePage', + '_WebVFPHomePage','_WebVfpOnlineSupport','_Windows','_Wizard','_Wrap','_scctext', + '_vfp','Additive','After','Again','Aindent','Alignright', + 'All','Alt','Alternate','And','Ansi','Any', + 'Aplabout','App','Array','As','Asc','Ascending', + 'Ascii','At','Attributes','Automatic','Autosave','Avg', + 'Bar','Before','Bell','Between','Bitmap','Blank', + 'Blink','Blocksize','Border','Bottom','Brstatus','Bucket', + 'Buffers','By','Candidate','Carry','Cascade','Catalog', + 'Cdx','Center','Century','Cga','Character','Check', + 'Classlib','Clock','Cnt','Codepage','Collate','Color', + 'Com1','Com2','Command','Compact','Compatible','Compress', + 'Confirm','Connection','Connections','Connstring','Console','Copies', + 'Cpcompile','Cpdialog','Csv','Currency','Cycle','Databases', + 'Datasource','Date','Db4','Dbc','Dbf','Dbmemo3', + 'Debug','Decimals','Defaultsource','Deletetables','Delimited','Delimiters', + 'Descending','Design','Development','Device','Dif','Disabled', + 'Distinct','Dlls','Dohistory','Dos','Dosmem','Double', + 'Driver','Duplex','Echo','Editwork','Ega25','Ega43', + 'Ems','Ems64','Encrypt','Encryption','Environment','Escape', + 'Events','Exact','Except','Exe','Exists','Expression', + 'Extended','F','Fdow','Fetch','Field','Fields', + 'File','Files','Fill','Fixed','Float','Foldconst', + 'Font','Footer','Force','Foreign','Fox2x','Foxplus', + 'Free','Freeze','From','Fullpath','Fw2','Fweek', + 'Get','Gets','Global','Group','Grow','Halfheight', + 'Having','Heading','Headings','Helpfilter','History','Hmemory', + 'Hours','Id','In','Indexes','Information','Instruct', + 'Int','Integer','Intensity','Intersect','Into','Is', + 'Isometric','Key','Keycolumns','Keycomp','Keyset','Last', + 'Ledit','Level','Library','Like','Linked','Lock', + 'Logerrors','Long','Lpartition','Mac','Macdesktop','Machelp', + 'Mackey','Macros','Mark','Master','Max','Maxmem', + 'Mdi','Memlimit','Memory','Memos','Memowidth','Memvar', + 'Menus','Messages','Middle','Min','Minimize','Minus', + 'Mod','Modal','Module','Mono43','Movers','Multilocks', + 'Mvarsiz','Mvcount','N','Near','Negotiate','Noalias', + 'Noappend','Noclear','Noclose','Noconsole','Nocptrans','Nodata', + 'Nodebug','Nodelete','Nodup','Noedit','Noeject','Noenvironment', + 'Nofloat','Nofollow','Nogrow','Noinit','Nolgrid','Nolink', + 'Nolock','Nomargin','Nomdi','Nomenu','Nominimize','Nomodify' + ), + 3 => array('Nomouse','None','Nooptimize','Nooverwrite','Noprojecthook','Noprompt', + 'Noread','Norefresh','Norequery','Norgrid','Norm','Normal', + 'Nosave','Noshadow','Noshow','Nospace','Not','Notab', + 'Notify','Noupdate','Novalidate','Noverify','Nowait','Nowindow', + 'Nowrap','Nozoom','Npv','Null','Number','Objects', + 'Odometer','Of','Off','Oleobjects','Only','Optimize', + 'Or','Orientation','Output','Outshow','Overlay','Overwrite', + 'Pad','Palette','Paperlength','Papersize','Paperwidth','Password', + 'Path','Pattern','Pause','Pdox','Pdsetup','Pen', + 'Pfs','Pixels','Plain','Popups','Precision','Preference', + 'Preview','Primary','Printer','Printquality','Procedures','Production', + 'Program','Progwork','Project','Prompt','Query','Random', + 'Range','Readborder','Readerror','Record','Recover','Redit', + 'Reference','References','Relative','Remote','Reprocess','Resource', + 'Rest','Restrict','Rgb','Right','Row','Rowset', + 'Rpd','Runtime','Safety','Same','Sample','Say', + 'Scale','Scheme','Scoreboard','Screen','Sdf','Seconds', + 'Selection','Shadows','Shared','Sheet','Shell','Shift', + 'Shutdown','Single','Some','Sortwork','Space','Sql', + 'Standalone','Status','Std','Step','Sticky','String', + 'Structure','Subclass','Summary','Sylk','Sysformats','Sysmenus', + 'System','T','Tab','Tables','Talk','Tedit', + 'Textmerge','Time','Timeout','Titles','Tmpfiles','To', + 'Topic','Transaction','Trap','Trbetween','Trigger','Ttoption', + 'Typeahead','Udfparms','Union','Unique','Userid','Users', + 'Values','Var','Verb','Vga25','Vga50','Views', + 'Volume','Where','Windows','Wk1','Wk3','Wks', + 'Workarea','Wp','Wr1','Wrap','Wrk','Xcmdfile', + 'Xl5','Xl8','Xls','Y','Yresolution','Zoom', + 'Activate','ActivateCell','Add','AddColumn','AddItem','AddListItem', + 'AddObject','AddProperty','AddToSCC','AfterBuild','AfterCloseTables','AfterDock', + 'AfterRowColChange','BeforeBuild','BeforeDock','BeforeOpenTables','BeforeRowColChange','Box', + 'Build','CheckIn','CheckOut','Circle','Clear','ClearData', + 'Cleanup','Click','CloneObject','CloseEditor','CloseTables','Cls', + 'CommandTargetExec','CommandTargetQueryStas','ContainerRelease','DataToClip','DblClick','Deactivate', + 'Delete','DeleteColumn','Deleted','Destroy','DoCmd','Dock', + 'DoScroll','DoVerb','DownClick','Drag','DragDrop','DragOver', + 'DropDown','Draw','EnterFocus','Error','ErrorMessage','Eval', + 'ExitFocus','FormatChange','GetData','GetFormat','GetLatestVersion','GoBack', + 'GotFocus','GoForward','GridHitTest','Hide','HideDoc','IndexToItemId', + 'Init','InteractiveChange','Item','ItemIdToIndex','KeyPress','Line', + 'Load','LostFocus','Message','MiddleClick','MouseDown','MouseMove', + 'MouseUp','MouseWheel','Move','Moved','NavigateTo','Newobject', + 'OLECompleteDrag','OLEDrag','OLEDragDrop','OLEDragOver','OLEGiveFeedback','OLESetData', + 'OLEStartDrag','OpenEditor','OpenTables','Paint','Point','Print', + 'ProgrammaticChange','PSet','QueryAddFile','QueryModifyFile','QueryRemoveFile','QueryRunFile', + 'QueryUnload','RangeHigh','RangeLow','ReadActivate','ReadExpression','ReadDeactivate', + 'ReadMethod','ReadShow','ReadValid','ReadWhen','Refresh','Release', + 'RemoveFromSCC','RemoveItem','RemoveListItem','RemoveObject','Requery','RequestData', + 'Reset','ResetToDefault','Resize','RightClick','SaveAs','SaveAsClass', + 'Scrolled','SetAll','SetData','SetFocus','SetFormat','SetMain', + 'SetVar','SetViewPort','ShowDoc','ShowWhatsThis','TextHeight','TextWidth', + 'Timer','UIEnable','UnDock','UndoCheckOut','Unload','UpClick', + 'Valid','WhatsThisMode','When','WriteExpression','WriteMethod','ZOrder', + 'ATGetColors','ATListColors','Accelerate','ActiveColumn','ActiveControl','ActiveForm', + 'ActiveObjectId','ActivePage','ActiveProject','ActiveRow','AddLineFeeds','Alias', + 'Alignment','AllowAddNew','AllowHeaderSizing','AllowResize','AllowRowSizing','AllowTabs', + 'AlwaysOnTop','Application','AutoActivate','AutoCenter','AutoCloseTables','AutoIncrement', + 'AutoOpenTables','AutoRelease','AutoSize','AutoVerbMenu','AutoYield','AvailNum', + 'BackColor','BackStyle','BaseClass','BorderColor','BorderStyle','BorderWidth', + 'Bound','BoundColumn','BoundTo','BrowseAlignment','BrowseCellMarg','BrowseDestWidth', + 'BufferMode','BufferModeOverride','BuildDateTime','ButtonCount','ButtonIndex','Buttons', + 'CLSID','CanAccelerate','CanGetFocus','CanLoseFocus','Cancel','Caption', + 'ChildAlias','ChildOrder','Class','ClassLibrary','ClipControls','ClipRect', + 'Closable','ColorScheme','ColorSource','ColumnCount','ColumnHeaders','ColumnLines', + 'ColumnOrder','ColumnWidths','Columns','Comment','ContinuousScroll','ControlBox', + 'ControlCount','ControlIndex','ControlSource','Controls','CurrentControl','CurrentX', + 'CurrentY','CursorSource','Curvature','DataSession','DataSessionId','DataSourceObj', + 'DataType','Database','DateFormat','DateMark','DefButton','DefButtonOrig', + 'DefHeight','DefLeft','DefTop','DefWidth','Default','DefaultFilePath', + 'DefineWindows','DeleteMark','Desktop','Dirty','DisabledBackColor','DisabledByEOF', + 'DisabledForeColor','DisabledItemBackColor','DisabledItemForeColor','DisabledPicture','DispPageHeight','DispPageWidth', + 'DisplayCount','DisplayValue','DoCreate','DockPosition','Docked','DocumentFile', + 'DownPicture','DragIcon','DragMode','DragState','DrawMode','DrawStyle', + 'DrawWidth','DynamicAlignment','DynamicBackColor','DynamicCurrentControl','DynamicFontBold','DynamicFontItalic', + 'DynamicFontName','DynamicFontOutline','DynamicFontShadow','DynamicFontSize','DynamicFontStrikethru','DynamicFontUnderline', + 'DynamicForeColor','EditFlags','Enabled','EnabledByReadLock','Encrypted','EnvLevel', + 'ErasePage','FileClass','FileClassLibrary','FillColor','FillStyle','Filter', + 'FirstElement','FontBold','FontItalic','FontName','FontOutline','FontShadow', + 'FontSize','FontStrikethru','FontUnderline','ForceFocus','ForeColor','FormCount', + 'FormIndex','FormPageCount','FormPageIndex','Format','Forms','FoxFont', + 'FullName','GoFirst','GoLast','GridLineColor','GridLineWidth','GridLines' + ), + 4 => array('HPROJ','HWnd','HalfHeightCaption','HasClip','HeaderGap','HeaderHeight', + 'Height','HelpContextID','HideSelection','Highlight','HomeDir','HostName', + 'HotKey','HscrollSmallChange','IMEMode','Icon','IgnoreInsert','InResize', + 'Increment','IncrementalSearch','InitialSelectedAlias','InputMask','Instancing','IntegralHeight', + 'Interval','ItemBackColor','ItemData','ItemForeColor','ItemIDData','ItemTips', + 'JustReadLocked','KeyPreview','KeyboardHighValue','KeyboardLowValue','LastModified','Left', + 'LeftColumn','LineSlant','LinkMaster','List','ListCount','ListIndex', + 'ListItem','ListItemId','LockDataSource','LockScreen','MDIForm','MainClass', + 'MainFile','Margin','MaxButton','MaxHeight','MaxLeft','MaxLength', + 'MaxTop','MaxWidth','MemoWindow','MinButton','MinHeight','MinWidth', + 'MouseIcon','MousePointer','Movable','MoverBars','MultiSelect','Name', + 'NapTime','NewIndex','NewItemId','NoDataOnLoad','NoDefine','NotifyContainer', + 'NullDisplay','NumberOfElements','OLEDragMode','OLEDragPicture','OLEDropEffects','OLEDropHasData', + 'OLEDropMode','OLERequestPendingTimeOut','OLEServerBusyRaiseError','OLEServerBusyTimeOut','OLETypeAllowed','OleClass', + 'OleClassId','OleControlContainer','OleIDispInValue','OleIDispOutValue','OleIDispatchIncoming','OleIDispatchOutgoing', + 'OnResize','OneToMany','OpenViews','OpenWindow','PageCount','PageHeight', + 'PageOrder','PageWidth','Pages','Panel','PanelLink','Parent', + 'ParentAlias','ParentClass','Partition','PasswordChar','Picture','ProcessID', + 'ProgID','ProjectHookClass','ProjectHookLibrary','Projects','ReadColors','ReadCycle', + 'ReadFiller','ReadLock','ReadMouse','ReadOnly','ReadSave','ReadSize', + 'ReadTimeout','RecordMark','RecordSource','RecordSourceType','Rect','RelationalExpr', + 'RelativeColumn','RelativeRow','ReleaseErase','ReleaseType','ReleaseWindows','Resizable', + 'RightToLeft','RowHeight','RowSource','RowSourceType','SCCProvider','SCCStatus', + 'SDIForm','ScaleMode','ScrollBars','SelLength','SelStart','SelText', + 'SelectOnEntry','Selected','SelectedBackColor','SelectedForeColor','SelectedID','SelectedItemBackColor', + 'SelectedItemForeColor','SelfEdit','ServerClass','ServerClassLibrary','ServerHelpFile','ServerName', + 'ServerProject','ShowTips','ShowWindow','Sizable','Size','Size', + 'Size','Skip','SkipForm','Sorted','SourceType','Sparse', + 'SpecialEffect','SpinnerHighValue','SpinnerLowValue','SplitBar','StartMode','StatusBarText', + 'Stretch','StrictDateEntry','Style','SystemRefCount','TabIndex','TabStop', + 'TabStretch','TabStyle','Tabhit','Tabs','Tag','TerminateRead', + 'ThreadID','TitleBar','ToolTipText','Top','TopIndex','TopItemId', + 'TypeLibCLSID','TypeLibDesc','TypeLibName','UnlockDataSource','Value','ValueDirty', + 'VersionComments','VersionCompany','VersionCopyright','VersionDescription','VersionNumber','VersionProduct', + 'VersionTrademarks','View','ViewPortHeight','ViewPortLeft','ViewPortTop','ViewPortWidth', + 'Visible','VscrollSmallChange','WasActive','WasOpen','WhatsThisButton','WhatsThisHelp', + 'WhatsThisHelpID','Width','WindowList','WindowNTIList','WindowState','WindowType', + 'WordWrap','ZOrderSet','ActiveDoc','Checkbox','Column','ComboBox', + 'CommandButton','CommandGroup','Container','Control','Cursor','Custom', + 'DataEnvironment','EditBox','Empty','FontClass','Form','Formset', + 'General','Grid','Header','HyperLink','Image','Label', + 'ListBox','Memo','OleBaseControl','OleBoundControl','OleClassIDispOut','OleControl', + 'OptionButton','OptionGroup','Page','PageFrame','ProjectHook','RectClass', + 'Relation','Session','Shape','Spinner','TextBox' ,'Toolbar' + ), + ), + 'SYMBOLS' => array( + "!", "@", "$", "%", + "(", ")", "{", "}", "[", "]", + "-", "+", "*", "/", + "=", "<", ">", + ":", ";", ",", ".", "&", + "?", "??", "???" + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: blue;', + 2 => 'color: blue;', + 3 => 'color: blue;', + 4 => 'color: blue;' + ), + 'COMMENTS' => array( + 1 => 'color: green; font-style: italic;', + 2 => 'color: green; font-style: italic;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: blue;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 1 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: blue;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/visualprolog.php b/examples/includes/geshi/geshi/visualprolog.php new file mode 100644 index 0000000..2a5656b --- /dev/null +++ b/examples/includes/geshi/geshi/visualprolog.php @@ -0,0 +1,129 @@ + 'Visual Prolog', + 'COMMENT_SINGLE' => array(1 => '%'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'HARDQUOTE' => array('@"', '"'), + 'HARDESCAPE' => array('""'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( + 'clauses','constants','constructors','delegate','domains','facts', + 'goal','guards','inherits','monitor','namespace','open', + 'predicates','properties','resolve','supports' + ), + 2 => array( + 'align','and','anyflow','as','bitsize','catch','determ','digits', + 'div','do','else','elseif','erroneous','externally','failure', + 'finally','from','language','mod','multi','nondeterm','or', + 'procedure','quot','rem','single','then','to' + ), + 3 => array( + '#bininclude','#else','#elseif','#endif','#error','#export', + '#externally','#if','#import','#include','#message','#options', + '#orrequires','#requires','#then','#warning' + ), + ), + 'SYMBOLS' => array( + '+', '-', '*', '?', '=', '/', '>', '<', '^', '!', ':', '(', ')', '{', '}', '[', ']' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => true, + 1 => true, + 2 => true, + 3 => true + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #808000;', + 2 => 'color: #333399;', + 3 => 'color: #800080;', + ), + 'COMMENTS' => array( + 1 => 'color: #AA77BD', + 'MULTI' => 'color: #AA77BD' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #008080;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #00B7B7;' + ), + 'NUMBERS' => array( + 0 => 'color: #0000FF;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #000000;' + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 0 => 'color: #008000;', + 1 => 'color: #808000;', + 2 => 'color: #333399;', + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => ':', + 2 => '::' + ), + 'REGEXPS' => array( + 0 => "(?)[A-Z_]\w*(?!\w)", + 1 => "\\b(end\\s+)?(implement|class|interface)\\b", + 2 => "\\b(end\\s+)?(foreach|if|try)\\b", + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/whitespace.php b/examples/includes/geshi/geshi/whitespace.php new file mode 100644 index 0000000..dfada78 --- /dev/null +++ b/examples/includes/geshi/geshi/whitespace.php @@ -0,0 +1,121 @@ + 'Whitespace', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'COMMENT_REGEXP' => array( + 3 => "/[^\n\x20\x09]+/s" + ), + 'CASE_KEYWORDS' => GESHI_CAPS_UPPER, + 'QUOTEMARKS' => array(), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + ), + 'COMMENTS' => array( + 3 => 'color: #666666; font-style: italic;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + ), + 'ESCAPE_CHAR' => array( + ), + 'SCRIPT' => array( + ), + 'REGEXPS' => array( + 2 => 'background-color: #FF9999;', + 3 => 'background-color: #9999FF;' + ) + ), + 'URLS' => array( + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 2 => array( + GESHI_SEARCH => "(? " ", + GESHI_MODIFIERS => 's', + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + 3 => array( + GESHI_SEARCH => "\x09", + GESHI_REPLACE => " ", + GESHI_MODIFIERS => 's', + GESHI_BEFORE => "", + GESHI_AFTER => "" + ), + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4, + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'KEYWORDS' => GESHI_NEVER, + 'SYMBOLS' => GESHI_NEVER, + 'STRINGS' => GESHI_NEVER, +// 'REGEXPS' => GESHI_NEVER, + 'NUMBERS' => GESHI_NEVER + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/winbatch.php b/examples/includes/geshi/geshi/winbatch.php new file mode 100644 index 0000000..caa94a4 --- /dev/null +++ b/examples/includes/geshi/geshi/winbatch.php @@ -0,0 +1,369 @@ + 'Winbatch', + 'COMMENT_SINGLE' => array(1 => ';', 2 => ':'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"', '`'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + 1 => array( + 'While', 'To', 'Then', 'Switch', 'Select', 'Return', 'Next', 'IntControl', 'Include', 'In', 'If', + 'Goto', 'GoSub', 'ForEach', 'For', 'Exit', 'Execute', 'ErrorMode', 'EndWhile', 'EndSwitch', '#EndSubRoutine', + 'EndSelect', 'EndIf', '#EEndFunction', 'EndFor', 'End', 'Else', 'DropWild', 'Drop', '#DefineSubRoutine', + '#DefineFunction', 'Debug', 'Continue', 'Case', 'CallExt', 'Call', 'By', 'BreakPoint', 'Break' + ), + 2 => array( + 'ZOOMED', 'YES', 'WORD4', 'WORD2', 'WORD1', 'WHOLESECTION', 'WAIT', 'UNSORTED', 'UNCHECK', 'TRUE', 'TILE', + 'TAB', 'STRING', 'STACK', 'SPC2NET', 'SORTED', 'SOK', 'SNET2PC', 'SINGLE', 'SHIFT', 'SERVER', 'SERRWINSOCK', + 'SERRVOICE', 'SERRSOCKET', 'SERRSERVICE', 'SERRSELECT', 'SERRPARAM', 'SERROUTOFMEM', 'SERRNOTFOUND', 'SERRNOCONN', + 'SERRNOANSWER', 'SERRMUSTWAIT', 'SERRIPADDR', 'SERRHOSTNAME', 'SERRFAILURE', 'SERRBUSY', 'SCROLLLOCK', 'SCANCEL', + 'SAVE', 'SALREADY', 'ROWS', 'REGUSERS', 'REGROOT', 'REGMACHINE', 'REGCURRENT', 'REGCLASSES', 'RDBLCLICK', 'RCLICK', + 'RBUTTON', 'RAD2DEG', 'QSUCCESSINFO', 'QSUCCESS', 'QSTILLEX', 'QROLLBACK', 'QNULL', 'QNODATA', 'QNEXT', 'QNEEDDATA', + 'QFIRST', 'QCOMMIT', 'QBADHANDLE', 'PRINTER', 'PLANCKJOULES', 'PLANCKERGS', 'PI', 'PARSEONLY', 'PARSEC', 'P3ERRREPLY', + 'OPEN', 'ON', 'OFF', 'NUMLOCK', 'NOWAIT', 'NOTIFY', 'NORMAL', 'NORESIZE', 'NONE', 'NO', 'NCSAFORMAT', 'MULTIPLE', + 'MSFORMAT', 'MPLAYRDBLCK', 'MPLAYRCLK', 'MPLAYRBUTTON', 'MPLAYMDBLCK', 'MPLAYMCLK', 'MPLAYMBUTTON', 'MPLAYLDBLCK', + 'MPLAYLCLK', 'MPLAYLBUTTON', 'MINOR', 'MDBLCLICK', 'MCLICK', 'MBYESNO', 'MBUTTON', 'MBOKCANCEL', 'MAJOR', 'MAGFIELD', + 'LOCALGROUP', 'LIGHTMTPS', 'LIGHTMPS', 'LF', 'LDBLCLICK', 'LCLICK', 'LBUTTON', 'LAFFDBERROR', 'ICON', 'HTTPS', 'HTTP', + 'HNOHEADER', 'HMETHODPOST', 'HMETHODGET', 'HIDDEN', 'HHEADERONLY', 'HHEADER', 'GRAVITATION', 'GOPHER', 'GOLDENRATIO', + 'GMTSEC', 'GLOBALGROUP', 'GFTSEC', 'GETPROCID', 'GETEXITCODE', 'FWDSCAN', 'FTPPASSIVE', 'FTP', 'FLOAT8', 'FARADAY', + 'FALSE', 'EXTENDED', 'EULERS', 'ENABLE', 'ELECTRIC', 'DRIVE', 'DISABLE', 'DESCENDING', 'DEG2RAD', 'DEFAULT', 'CTRL', + 'CRLF', 'CR', 'COMMONFORMAT', 'COLUMNS', 'CHECK', 'CAPSLOCK', 'CANCEL', 'BOLTZMANN', 'BACKSCAN', 'AVOGADRO', 'ATTR_X', + 'ATTR_T', 'ATTR_SY', 'ATTR_SH', 'ATTR_RO', 'ATTR_RI', 'ATTR_P', 'ATTR_IC', 'ATTR_H', 'ATTR_DM', 'ATTR_DI', 'ATTR_DC', + 'ATTR_CI', 'ATTR_A', 'ASCENDING', 'ARRANGE', 'AMC', 'ACC_WRITE', 'ACC_READ_NT', 'ACC_READ_95', 'ACC_READ', 'ACC_PRINT_NT', + 'ACC_PMANG_NT', 'ACC_PFULL_NT', 'ACC_LIST', 'ACC_FULL_NT', 'ACC_FULL_95', 'ACC_DELETE', 'ACC_CREATE', 'ACC_CONTROL', + 'ACC_CHNG_NT', 'ACC_ATTRIB', 'ABOVEICONS' + ), + 3 => array( + 'Yields', 'Yield', 'WinZoom', 'WinWaitExist', 'WinWaitClose', 'WinWaitChild', 'WinVersion', 'WinTitle', 'WinSysInfo', + 'WinState', 'WinShow', 'WinResources', 'WinPositionChild', 'WinPosition', 'WinPlaceSet', 'WinPlaceGet', 'WinPlaceChild', + 'WinPlace', 'WinParmSet', 'WinParmGet', 'WinName', 'WinMetrics', 'WinItemProcId', 'WinItemNameId', 'WinItemizeEx', + 'WinItemize', 'WinItemChild', 'WinIsDos', 'WinIdGet', 'WinIconize', 'WinHide', 'WinHelp', 'WinGetactive', 'WinExistchild', + 'WinExist', 'WinExename', 'WinConfig', 'WinClosenot', 'WinClose', 'WinArrange', 'WinActivechild', 'WinActivchild', + 'WinActivate', 'WebVerifyCard', 'WebSetTimeout', 'WebParamSize', 'WebParamNames', 'WebParamFile', 'WebParamData', + 'WebParamBuf', 'WebOutFile', 'WebOutBinary', 'WebOut', 'WebDumpError', 'WebDatData', 'WebCounter', 'WebConSize', 'WebConData', + 'WebConBuf', 'WebCmdData', 'WebBaseConv', 'Wallpaper', 'WaitForKeyEX', 'WaitForKey', 'VersionDLL', 'Version', 'VarType', + 'TimeYmdHms', 'TimeWait', 'TimeSubtract', 'TimeJulToYmd', 'TimeJulianDay', 'TimeDiffSecs', 'TimeDiffDays', 'TimeDiff', 'TimeDelay', + 'TimeDate', 'TimeAdd', 'TextSelect', 'TextBoxSort', 'TextBox', 'Terminate', 'Tanh', 'Tan', 'SysParamInfo', 'SvcWaitForCmd', + 'SvcSetState', 'SvcSetAccept', 'StrUpper', 'StrTrim', 'StrSubWild', 'StrSub', 'StrScan', 'StrReplace', 'StrLower', 'StrLenWild', + 'StrLen', 'StrIndexWild', 'StrIndexNC', 'StrIndex', 'StriCmp', 'StrFixLeft', 'StrFixCharsL', 'StrFixChars', 'StrFix', 'StrFill', + 'StrCnt', 'StrCmp', 'StrClean', 'StrCharCount', 'StrCat', 'StrByteCount', 'Sqrt', 'SoundVolume', 'Sounds', 'Snapshot', 'Sinh', 'Sin', + 'ShortCutMake', 'ShortCutInfo', 'ShortCutExtra', 'ShortCutEdit', 'ShortCutDir', 'ShellExecute', 'SendMenusToEx', 'SendMenusTo', + 'SendKeysTo', 'SendKeysChild', 'SendKey', 'RunZoomWait', 'RunZoom', 'RunWithLogon', 'RunWait', 'RunShell', 'RunIconWait', + 'RunIcon', 'RunHideWait', 'RunHide', 'RunExit', 'RunEnviron', 'Run', 'RtStatus', 'Reload', 'RegUnloadHive', 'RegSetValue', + 'RegSetQword', 'RegSetMulSz', 'RegSetExpSz', 'RegSetEx', 'RegSetDword', 'RegSetBin', 'RegQueryValue', 'RegQueryStr', + 'RegQueryQword', 'RegQueryMulSz', 'RegQueryKeys', 'RegQueryKeyLastWriteTime', 'RegQueryKey', 'RegQueryItem', 'RegQueryExpSz', + 'RegQueryEx', 'RegQueryDword', 'RegQueryBin', 'RegOpenKeyEx', 'RegOpenKey', 'RegOpenFlags', 'RegLoadHive', 'RegExistValue', + 'RegExistKey', 'RegEntryType', 'RegDelValue', 'RegDeleteKey', 'RegCreateKey', 'RegConnect', 'RegCloseKey', 'RegApp', 'Random', + 'PtrPersistent', 'PtrGlobalDefine', 'PtrGlobal', 'Print', 'PlayWaveform', 'PlayMidi', 'PlayMedia', 'PipeServerWrite', 'PipeServerRead', + 'PipeServerCreate', 'PipeServerClose', 'PipeInfo', 'PipeClientSendRecvData', 'PipeClientOpen', 'PipeClientClose', 'Pause', + 'ParseData', 'ObjectTypeGet', 'ObjectType', 'ObjectOpen', 'ObjectGet', 'ObjectEventRemove', 'objecteventremove', 'ObjectEventAdd', + 'objecteventadd', 'ObjectCreate', 'ObjectConstToArray', 'ObjectConstantsGet', 'ObjectCollectionOpen', 'ObjectCollectionNext', + 'ObjectCollectionClose', 'ObjectClose', 'ObjectAccess', 'Num2Char', 'NetInfo', 'MsgTextGet', 'MousePlay', 'MouseMove', 'MouseInfo', + 'MouseDrag', 'MouseCoords', 'MouseClickBtn', 'MouseClick', 'mod', 'Min', 'Message', 'Max', 'Loge', 'LogDisk', 'Log10', 'LastError', + 'KeyToggleSet', 'KeyToggleGet', 'ItemSortNc', 'ItemSort', 'ItemSelect', 'ItemReplace', 'ItemRemove', 'ItemLocate', 'ItemInsert', + 'ItemExtractCSV', 'ItemExtract', 'ItemCountCSV', 'ItemCount', 'IsNumber', 'IsLicensed', 'IsKeyDown', 'IsInt', 'IsFloat', 'IsDefined', + 'Int', 'InstallFile', 'IniWritePvt', 'IniWrite', 'IniReadPvt', 'IniRead', 'IniItemizePvt', 'IniItemize', 'IniDeletePvt', 'IniDelete', + 'IgnoreInput', 'IconReplace', 'IconInfo', 'IconExtract', 'IconArrange', 'GetTickCount', 'GetObject', 'GetExactTime', 'Floor', + 'FindWindow', 'FileYmdHms', 'FileWrite', 'FileVerInfo', 'FileTimeTouch', 'FileTimeSetEx', 'FileTimeSet', 'FileTimeGetEx', + 'FileTimeGet', 'FileTimeCode', 'FileSizeEx', 'FileSize', 'FileRoot', 'FileRename', 'FileRead', 'FilePutW', 'FilePut', 'FilePath', + 'FileOpen', 'FileNameShort', 'FileNameLong', 'FileNameEval2', 'FileNameEval1', 'FileMoveAttr', 'FileMove', 'FileMapName', + 'FileLocate', 'FileItemPath', 'FileItemize', 'FileInfoToArray', 'FileGetW', 'FileGet', 'FileFullname', 'FileExtension', 'FileExist', + 'FileDelete', 'FileCreateTemp', 'FileCopyAttr', 'FileCopy', 'FileCompare', 'FileClose', 'FileBaseName', 'FileAttrSetEx', + 'FileAttrSet', 'FileAttrGetEx', 'FileAttrGet', 'FileAppend', 'Fabs', 'ExtractAttachedFile', 'Exp', 'ExeTypeInfo', 'Exclusive', + 'EnvItemize', 'EnvironSet', 'Environment', 'EndSession', 'DosVersion', 'DllLoad', 'DllLastError', 'DllHwnd', 'DllHinst', + 'DllFree', 'DllCallCDecl', 'DllCall', 'Display', 'DiskVolinfo', 'DiskSize', 'DiskScan', 'DiskInfo', 'DiskFree', 'DiskExist', + 'DirWindows', 'DirSize', 'DirScript', 'DirRename', 'DirRemove', 'DirMake', 'DirItemize', 'DirInfoToArray', 'DirHome', 'DirGet', + 'DirExist', 'DirChange', 'DirAttrSetEx', 'DirAttrSet', 'DirAttrGetEx', 'DirAttrGet', 'DialogProcOptions', 'DialogObject', + 'DialogControlState', 'DialogControlSet', 'DialogControlGet', 'DialogBox', 'Dialog', 'Delay', 'Decimals', 'DebugTrace', + 'DebugData', 'DDETimeout', 'DDETerminate', 'DDERequest', 'DDEPoke', 'DDEInitiate', 'DDEExecute', 'DateTime', 'CurrFilepath', + 'CurrentPath', 'CurrentFile', 'CreateObject', 'Cosh', 'Cos', 'ClipPut', 'ClipHasFormat', 'ClipGetEx', 'ClipGet', 'ClipAppend', + 'ChrUnicodeToString', 'ChrUnicodeToHex', 'ChrStringToUnicode', 'ChrSetCodepage', 'ChrHexToUnicode', 'ChrGetCodepage', + 'Char2Num', 'Ceiling', 'ButtonNames', 'BoxUpdates', 'BoxTitle', 'BoxTextFont', 'BoxTextColor', 'BoxText', 'BoxShut', 'BoxPen', + 'BoxOpen', 'BoxNew', 'BoxMapmode', 'BoxesUp', 'BoxDrawText', 'BoxDrawRect', 'BoxDrawLine', 'BoxDrawCircle', 'BoxDestroy', + 'BoxDataTag', 'BoxDataClear', 'BoxColor', 'BoxCaption', 'BoxButtonWait', 'BoxButtonStat', 'BoxButtonKill', 'BoxButtonDraw', + 'BoxBitMap', 'BinaryXor', 'BinaryXlate', 'BinaryWriteEx', 'BinaryWrite', 'BinaryTagRepl', 'BinaryTagLen', 'BinaryTagInit', + 'BinaryTagIndex', 'BinaryTagFind', 'BinaryTagExtr', 'BinaryStrCnt', 'BinarySort', 'BinaryReplace', 'BinaryReadEx', + 'BinaryRead', 'BinaryPokeStrW', 'BinaryPokeStr', 'BinaryPokeHex', 'BinaryPokeFlt', 'BinaryPoke4', 'BinaryPoke2', 'BinaryPoke', + 'BinaryPeekStrW', 'BinaryPeekStr', 'BinaryPeekHex', 'BinaryPeekFlt', 'BinaryPeek4', 'BinaryPeek2', 'BinaryPeek', 'BinaryOr', + 'BinaryOleType', 'BinaryIndexNc', 'BinaryIndexEx', 'BinaryIndexBin', 'BinaryIndex', 'BinaryIncrFlt', 'BinaryIncr4', + 'BinaryIncr2', 'BinaryIncr', 'BinaryHashRec', 'BinaryFree', 'BinaryEodSet', 'BinaryEodGet', 'BinaryCopy', 'BinaryConvert', + 'BinaryCompare', 'BinaryClipPut', 'BinaryClipGet', 'BinaryChecksum', 'BinaryBufInfo', 'BinaryAnd', 'BinaryAllocArray', + 'BinaryAlloc', 'Beep', 'Average', 'Atan', 'AskYesNo', 'AskTextbox', 'AskPassword', 'AskLine', 'AskItemlist', 'AskFont', + 'AskFiletext', 'AskFilename', 'AskDirectory', 'AskColor', 'Asin', 'ArrInitialize', 'ArrInfo', 'ArrDimension', + 'Arrayize', 'ArrayFilePutCSV', 'ArrayFilePut', 'ArrayFileGetCSV', 'ArrayFileGet', 'AppWaitClose', 'AppExist', 'AddExtender', + 'Acos', 'Abs', 'About' + ), + 4 => array( + 'zZipFiles', 'zVersionInfo', 'zVersion', 'zUnZipFiles', 'zSetPortBit', 'zRPortShift', 'zPortOut', 'zPortIn', 'zNotPortBit', + 'zLPortShift', 'zGetPortBit', 'zClrPortBit', 'xVerifyCCard', 'xSendMessage', 'xMessageBox', 'xMemCompact', 'xHex', 'xGetElapsed', + 'xGetChildHwnd', 'xExtenderInfo', 'xEnumStreams', 'xEjectMedia', 'xDriveReady', 'xDiskLabelGet', 'xCursorSet', 'xBaseConvert', + 'wxPing', 'wxParmSet', 'wxParmGet', 'wxMsgSetHdr', 'wxMsgGetHdr', 'wxMsgGetBody', 'wxHost2Addr', 'wxGetLastErr', 'wxGetInfo', + 'wxGetErrDesc', 'wxAddr2Host', 'wtsWaitSystemEvent', 'wtsVersion', 'wtsTerminateProcess', 'wtsShutdownSystem', 'wtsSendMessage', + 'wtsQuerySessionInfo', 'wtsProcIdToSessId', 'wtsLogoffSession', 'wtsLastErrMsg', 'wtsIsTSEnabled', 'wtsIsCitrixEnabled', + 'wtsGetActiveConsoleSessId', 'wtsEnumSessions', 'wtsEnumProcesses', 'wtsDisconnectSession', 'wnWrkGroups', 'wnVersion', 'wntWtsUserSet', + 'wntWtsUserGet', 'wntVersion', 'wntUserSidChk', 'wntUserSetDat', 'wntUserRename', 'wntUserProps', 'wntUserList', 'wntUserInfo', + 'wntUserGetDat', 'wntUserFiles', 'wntUserExist', 'wntUserDel', 'wntUserAddDat', 'wntUserAdd', 'wntSvcStatus', 'wntSvcStart', + 'wntSvcList', 'wntSvcDelete', 'wntSvcCreate', 'wntSvcControl', 'wntSvcCfgSet', 'wntSvcCfgGet', 'wntShutdown', 'wntShareUsers', + 'wntShareSet', 'wntShareList', 'wntShareInfo', 'wntShareDel', 'wntShareAdd', 'wntServiceInf', 'wntServiceAt', 'wntServerType', + 'wntServerList', 'wntServerInfo', 'wntSecurityGet', 'wntRunAsUser', 'wntResources2', 'wntResources', 'wntRemoteTime', 'wntRasUserSet', + 'wntRasUserGet', 'wntProfileInfo', 'wntProfileDel', 'wntPrivUsers', 'wntPrivList', 'wntPrivGet', 'wntPrivDel', 'wntPrivAdd', + 'wntOwnerSet', 'wntOwnerGet', 'wntMemberSet', 'wntMemberLst2', 'wntMemberList', 'wntMemberGrps', 'wntMemberGet', 'wntMemberDel', + 'wntLsaPolSet', 'wntLsaPolGet', 'wntListGroups', 'wntLastErrMsg', 'wntGroupRen', 'wntGroupInfo', 'wntGroupEdit', 'wntGroupDel', + 'wntGroupAdd', 'wntGetUser', 'wntGetDrive', 'wntGetDc', 'wntGetCon', 'wntFileUsers', 'wntFilesOpen', 'wntFileClose', 'wntEventWrite', + 'wntEventLog', 'wntDomainSync', 'wntDirDialog', 'wntDfsList', 'wntDfsGetInfo', 'wntCurrUsers', 'wntChgPswd', 'wntCancelCon', + 'wntAuditMod', 'wntAuditList', 'wntAuditGet', 'wntAuditDel', 'wntAuditAdd2', 'wntAuditAdd', 'wntAddPrinter', 'wntAddDrive', + 'wntAcctPolSet', 'wntAcctPolGet', 'wntAcctList', 'wntAcctInfo', 'wntAccessMod', 'wntAccessList', 'wntAccessGet', 'wntAccessDel', + 'wntaccessadd2', 'wntAccessAdd', 'wnShares', 'wnSharePath', 'wnShareName', 'wnShareCnt', 'wnServers', 'wnRestore', 'wnNetNames', + 'wnGetUser', 'wnGetCon', 'wnGetCaps', 'wnDlgShare', 'wnDlgNoShare', 'wnDlgDiscon', 'wnDlgCon4', 'wnDlgCon3', 'wnDlgCon2', 'wnDlgCon', + 'wnDlgBrowse', 'wnDialog', 'wnCmptrInfo', 'wnCancelCon', 'wnAddCon', 'WaitSRQ', 'w9xVersion', 'w9xUserSetDat', 'w9xUserRename', + 'w9xUserprops', 'w9xUserList', 'w9xUserinfo', 'w9xUserGetDat', 'w9xUserExist', 'w9xUserDel', 'w9xUserAddDat', 'w9xUserAdd', 'w9xShareSet', + 'w9xShareInfo', 'w9xShareDel', 'w9xShareAdd', 'w9xServiceAt', 'w9xServerList', 'w9xRemoteTime', 'w9xOwnerGet', 'w9xMemberSet', + 'w9xMemberList', 'w9xMemberGrps', 'w9xMemberGet', 'w9xMemberDel', 'w9xListGroups', 'w9xGroupInfo', 'w9xGroupDel', 'w9xGroupAdd', + 'w9xGetDC', 'w9xFileUsers', 'w9xAccessList', 'w9xAccessGet', 'w9xAccessDel', 'w9xAccessAdd', 'w95Version', 'w95ShareUsers', + 'w95ShareSet', 'w95ShareList', 'w95ShareInfo', 'w95ShareDel', 'w95ShareAdd', 'w95ServiceInf', 'w95ServiceAt', 'w95ServerType', + 'w95ServerInfo', 'w95Resources', 'w95GetUser', 'w95GetDrive', 'w95GetCon', 'w95FileUsers', 'w95FileClose', 'w95DirDialog', + 'w95CancelCon', 'w95AddPrinter', 'w95AddDrive', 'w95AccessDel', 'w95AccessAdd', 'w3Version', 'w3PrtBrowse', 'w3NetGetUser', + 'w3NetDialog', 'w3GetCon', 'w3GetCaps', 'w3DirBrowse', 'w3CancelCon', 'w3AddCon', 'urlGetScheme', 'urlEncode', 'urlDecode', + 'tVersion', 'tSetPriority', 'TriggerList', 'Trigger', 'tRemoteConn', 'tOpenProc', 'tListProc', 'tListMod', 'tKillProc', 'tGetProcInfo', + 'tGetPriority', 'tGetModInfo', 'tGetLastError', 'tGetData', 'TestSys', 'TestSRQ', 'tCountProc', 'tCompatible', 'tCloseProc', + 'tBrowseCntrs', 'sSendString', 'sSendNum', 'sSendLine', 'sSendBinary', 'sRecvNum', 'sRecvLine', 'sRecvBinary', 'SrchVersion', + 'SrchNext', 'SrchInit', 'SrchFree', 'sOpen', 'sOK2Send', 'sOK2Recv', 'smtpSendText', 'smtpSendFile', 'sListen', 'SetRWLS', + 'SendSetup', 'SendLLO', 'SendList', 'SendIFC', 'SendDataBytes', 'SendCmds', 'Send', 'sConnect', 'sClose', 'SByteOrder32', + 'sByteOrder16', 'sAccept', 'rRegVersion', 'rRegSearch', 'ResetSys', 'ReceiveSetup', 'Receive', 'ReadStsByte', 'RcvRespMsg', + 'RasVersion', 'RasTypeSize', 'RasRename', 'RasNumCons', 'RasNameValid', 'RasListActCon', 'RasItemize', 'RasHangUp', 'RasGetLastErr', + 'RasGetConStat', 'RasEntrySet', 'RasEntryInfo', 'RasEntryExist', 'RasEntryDel', 'RasEntryAdd', 'RasDialInfo', 'RasDial', + 'RasCopy', 'RasConStatus', 'qVersionInfo', 'qTransact', 'qTables', 'qSpecial', 'qSetConnOpt', 'qNumRsltCol', 'qNativeSql', 'qLastCode', + 'qGetData', 'qFreeStmt', 'qFreeEnv', 'qFreeConnect', 'qFetch', 'qExecDirect', 'qError', 'qDriverList', 'qDriverCon', 'qDisconnect', + 'qDataSources', 'qConnect', 'qConfigError', 'qConfigData', 'qColumns', 'qBindCol', 'qAllocStmt', 'qAllocEnv', 'qAllocConnect', + 'pWaitFor', 'pVersionInfo', 'pTimeout', 'pSetPublish', 'pSetPrtInfo', 'pSetPrtAttrib', 'pSetDefPrtEx', 'pSetDefPrt', 'pSendFile', + 'pRecvFile', 'pPutString', 'pPutLine', 'pPutChar', 'pPutByte', 'pPutBinary', 'PPollUnconfig', 'PPollConfig', 'PPoll', 'pPeekChar', + 'pPeekByte', 'pPaperSizes', 'pPaperBins', 'pModemSReg', 'pModemParams', 'pModemInit', 'pModemHangUp', 'pModemDial', 'pModemControl', + 'pModemConnect', 'pModemCommand', 'pModemAnsRing', 'pModemAnsCall', 'pMediaTypes', 'pGetString', 'pGetPublish', 'pGetPrtList', + 'pGetPrtInfo', 'pGetPrtAttrib', 'pGetLine', 'pGetLastError', 'pGetErrorMsg', 'pGetErrorCode', 'pGetDefPrtInf', 'pGetChar', + 'pGetByte', 'pGetBinary', 'pDelPrtConn', 'pDelPrinter', 'pComOpen', 'pComModify', 'pComInfo', 'pComControl', 'pComClose', + 'pCheckSum', 'pCheckBinary', 'pCaptureOn', 'pCaptureOff', 'pCaptureLog', 'PassControl', 'pAddPrtConn', 'pAddPrinter', 'p3RecvText', + 'p3RecvFile', 'p3Peek', 'p3Open', 'p3GetReply', 'p3Delete', 'p3Count', 'p3Close', 'nwWhoAmI', 'nwVfyPassword', 'nwVersion', + 'nwSrvShutdown', 'nwSrvNLMMgr', 'nwSrvGenGUID', 'nwSrvExecNCF', 'nwSetVolLimit', 'nwSetSrvParam', 'nwSetSrvInfo', 'nwSetPrimServ', + 'nwSetPassword', 'nwSetOptions', 'nwSetFileInfo', 'nwSetDirLimit', 'nwSetDirInfo', 'nwSetContext', 'nwSetBcastMode', 'nwServerList', + 'nwSendBcastMsg', 'nwSearchObjects', 'nwSearchFilter', 'nwRenameObject', 'nwRemoveObject', 'nwReceiveBcastMsg', 'nwNameConvert', + 'nwMutateObject', 'nwMoveObject', 'nwModifyObject', 'nwMapDelete', 'nwMap', 'nwLogout', 'nwLogin', 'nwListUserGroups', + 'nwListObjects', 'nwListGroupMembers', 'nwLastErrMsg', 'nwIsUserInGroup', 'nwGetVolLimit', 'nwGetSrvStats', 'nwGetSrvParam', + 'nwGetSrvInfo', 'nwGetSrvCfg', 'nwGetOptions', 'nwGetObjValue', 'nwGetObjInfo', 'nwGetNLMInfo', 'nwGetMapped', 'nwGetFileInfo', + 'nwGetDirLimit', 'nwGetDirInfo', 'nwGetContext', 'nwGetConnInfo', 'nwGetCapture', 'nwGetBcastMode', 'nwGetAttrInfo', + 'nwDriveStatus', 'nwDrivePath', 'nwDetachFromServer', 'nwDelUserFromGroup', 'nwDelConnNum', 'nwCompareObject', 'nwClientInfo', + 'nwChgPassword', 'nwAttachToServer', 'nwAddUserToGroup', 'nwAddObject', 'netVersion', 'netResources', 'netGetUser', 'netGetCon', + 'netDirDialog', 'netCancelCon', 'netAddPrinter', 'netAddDrive', 'n4Version', 'n4UserGroups', 'n4UserGroupEx', 'n4SetPrimServ', + 'n4SetOptions', 'n4SetContextG', 'n4SetContext', 'n4ServerList', 'n4ServerInfo', 'n4ObjSearch', 'n4ObjRename', 'n4ObjOptions', + 'n4ObjMove', 'n4ObjGetVal', 'n4ObjectProps', 'n4ObjectList', 'n4ObjectInfo', 'n4ObjDelete', 'n4NameConvert', 'n4MsgsEndAll', + 'n4MsgsEnd', 'n4MemberSet', 'n4MemberGet', 'n4MemberDel', 'n4MapRoot', 'n4MapDir', 'n4MapDelete', 'n4Map', 'n4LogoutTree', + 'n4Logout', 'n4Login', 'n4GetUserName', 'n4GetUserId', 'n4GetUser', 'n4GetNetAddr', 'n4GetMapped', 'n4GetContext', + 'n4GetConnNum', 'n4FileUsers', 'n4FileTimeGet', 'n4FileAttrSet', 'n4FileAttrGet', 'n4DriveStatus', 'n4DrivePath', 'n4DirTimeGet', + 'n4DirAttrSet', 'n4DirAttrGet', 'n4Detach', 'n4ChgPassword', 'n4CapturePrt', 'n4CaptureGet', 'n4CaptureEnd', 'n4Attach', + 'n3Version', 'n3UserGroups', 'n3ServerList', 'n3ServerInfo', 'n3MsgsEndAll', 'n3MsgsEnd', 'n3MemberSet', 'n3MemberGet', + 'n3MemberDel', 'n3Maproot', 'n3Mapdir', 'n3Mapdelete', 'n3Map', 'n3Logout', 'n3GetUserId', 'n3GetUser', 'n3GetNetAddr', + 'n3GetMapped', 'n3GetConnNum', 'n3FileTimeGet', 'n3FileAttrSet', 'n3FileAttrGet', 'n3DriveStatus', 'n3DrivePath', + 'n3DirTimeGet', 'n3DirAttrSet', 'n3DirAttrGet', 'n3Detach', 'n3ChgPassword', 'n3CapturePrt', 'n3CaptureGet', + 'n3CaptureEnd', 'n3Attach', 'mVersion', 'mSyncMail', 'mSendMailEx', 'mSendMail', 'mrecvmail', 'mReadNextMsg', 'mLogOn', + 'mLogOff', 'mFindNext', 'mError', 'mCompatible', 'kVerInfo', 'kStatusInfo', 'kSendText', 'kSendFile', 'kManageImap4', + 'kInit', 'kGetMail', 'kExtra', 'kDest', 'kDeletePop3', 'iWriteDataBuf', 'iWriteData', 'iVersion', 'IUrlOpen', 'iUrlEncode', + 'iUrlDecode', 'iReadDataBuf', 'iReadData', 'ipVersion', 'ipPing', 'iPing', 'ipHost2Addr', 'ipGetLastErr', 'ipGetAddress', + 'iParseURL', 'ipAddr2Host', 'iOptionSet', 'iOptionGet', 'ImgWave', 'ImgVersion', 'ImgUnsharpMask', 'ImgThreshold', 'ImgSwirl', + 'ImgSpread', 'ImgSolarize', 'ImgShear', 'ImgSharpen', 'ImgShade', 'ImgScale', 'ImgSample', 'ImgRotate', 'ImgResize', + 'ImgReduceNoise', 'ImgRaise', 'ImgOilPaint', 'ImgNormalize', 'ImgNegate', 'ImgMotionBlur', 'ImgModulate', 'ImgMinify', + 'ImgMedianFilter', 'ImgMagnify', 'ImgLevel', 'ImgIsValid', 'ImgIsPalette', 'ImgIsMono', 'ImgIsGray', 'ImgInfo', 'ImgImplode', + 'ImgGetImageType', 'ImgGetColorCount', 'ImgGaussianBlur', 'ImgGamma', 'ImgFrame', 'ImgFlop', 'ImgFlip', 'ImgEqualize', + 'ImgEnhance', 'ImgEmboss', 'ImgCrop', 'ImgConvert', 'ImgContrast', 'ImgCompare', 'ImgColorize', 'ImgChop', 'ImgCharcoal', + 'ImgBorder', 'ImgBlur', 'ImgAddNoise', 'iLocFindNext', 'iLocFindInit', 'iHttpOpen', 'iHttpInit', 'iHttpHeaders', 'iHttpAccept', + 'iHostConnect', 'iHost2Addr', 'iGetResponse', 'iGetLastError', 'iGetIEVer', 'iGetConStatEx', 'iGetConState', 'iFtpRename', + 'iFtpPut', 'iFtpOpen', 'iFtpGet', 'iFtpFindNext', 'iFtpFindInit', 'iFtpDirRemove', 'iFtpDirMake', 'iFtpDirGet', 'iFtpDirChange', + 'iFtpDialog', 'iFtpDelete', 'iFtpCmd', 'iErrorDialog', 'iDialItemize', 'iDialHangUp', 'iDial', 'iCookieSet', 'iCookieGet', + 'iContentURL', 'iContentFile', 'iContentData', 'iClose', 'ibWrtf', 'ibWrt', 'ibWait', 'ibVersion', 'ibUnlock', 'ibTrg', + 'ibTmo', 'ibStop', 'ibStatus', 'ibSta', 'ibSre', 'ibSic', 'ibSad', 'ibRsv', 'ibRsp', 'ibRsc', 'ibRpp', 'ibRdf', 'ibRd', + 'ibPpc', 'ibPoke', 'ibPct', 'ibPad', 'ibOnl', 'ibMakeAddr', 'ibLock', 'ibLoc', 'ibLn', 'ibLines', 'ibIst', 'ibInit', + 'ibGts', 'ibGetSad', 'ibGetPad', 'ibFind', 'ibEvent', 'ibErr', 'ibEot', 'ibEos', 'iBegin', 'ibDma', 'ibDev', 'ibConfig', + 'ibCntl', 'ibCnt', 'ibCmda', 'ibCmd', 'ibClr', 'ibCac', 'ibBna', 'ibAsk', 'iAddr2Host', 'huge_Thousands', 'huge_Subtract', + 'huge_SetOptions', 'huge_Multiply', 'huge_GetLastError', 'huge_ExtenderInfo', 'huge_Divide', 'huge_Decimal', 'huge_Add', + 'httpStripHTML', 'httpRecvTextF', 'httpRecvText', 'httpRecvQuery', 'httpRecvQryF', 'httpRecvFile', 'httpGetServer', + 'httpGetQuery', 'httpGetPath', 'httpGetFile', 'httpGetDir', 'httpGetAnchor', 'httpFullPath', 'httpFirewall', 'httpAuth', + 'ftpRename', 'ftpQuote', 'ftpPut', 'ftpOpen', 'ftpList', 'ftpGet', 'ftpFirewall', 'ftpDelete', 'ftpClose', 'ftpChDir', + 'FindRQS', 'FindLstn', 'EnvSetVar', 'EnvPathDel', 'EnvPathChk', 'EnvPathAdd', 'EnvListVars', 'EnvGetVar', 'EnvGetInfo', + 'EnableRemote', 'EnableLocal', 'ehllapiWait', 'ehllapiVersion', 'ehllapiUninit', 'ehllapiStopKeyIntercept', 'ehllapiStopHostNotify', + 'ehllapiStopCloseIntercept', 'ehllapiStartKeyIntercept', 'ehllapiStartHostNotify', 'ehllapiStartCloseIntercept', + 'ehllapiSetWindowStatus', 'ehllapiSetSessionParams', 'ehllapiSetPSWindowName', 'ehllapiSetCursorLoc', 'ehllapiSendKey', + 'ehllapiSendFile', 'ehllapiSearchPS', 'ehllapiSearchField', 'ehllapiRunProfile', 'ehllapiResetSystem', 'ehllapiReserve', + 'ehllapiRelease', 'ehllapiReceiveFile', 'ehllapiQuerySystem', 'ehllapiQueryPSStatus', 'ehllapiQueryHostNotify', + 'ehllapiQueryFieldAttr', 'ehllapiQueryCursorLoc', 'ehllapiQueryCloseIntercept', 'ehllapiPostInterceptStatus', + 'ehllapiPause', 'ehllapiLastErrMsg', 'ehllapiInit', 'ehllapiGetWindowStatus', 'ehllapiGetPSHWND', 'ehllapiGetKey', + 'ehllapiFindFieldPos', 'ehllapiFindFieldLen', 'ehllapiDisconnectPS', 'ehllapiCvtRCToPos', 'ehllapiCvtPosToRC', + 'ehllapiCopyTextToPS', 'ehllapiCopyTextToField', 'ehllapiCopyTextFromPS', 'ehllapiCopyTextFromField', 'ehllapiCopyOIA', + 'ehllapiConnectPS', 'dunItemize', 'dunDisconnect', 'dunConnectEx', 'dunConnect', 'dsTestParam', 'dsSIDtoHexStr', 'dsSetSecProp', + 'dsSetProperty', 'dsSetPassword', 'dsSetObj', 'dsSetCredentX', 'dsSetCredent', 'dsRemFromGrp', 'dsRelSecObj', 'dsMoveObj', + 'dsIsObject', 'dsIsMemberGrp', 'dsIsContainer', 'dsGetUsersGrps', 'dsGetSecProp', 'dsGetPropName', 'dsGetProperty', + 'dsGetPrntPath', 'dsGetPrimGrp', 'dsGetMemGrp', 'dsGetInfo', 'dsGetClass', 'dsGetChldPath', 'dsFindPath', 'dsDeleteObj', + 'dsCreatSecObj', 'dsCreateObj', 'dsCopySecObj', 'dsAddToGrp', 'dsAclRemAce', 'dsAclOrderAce', 'dsAclGetAces', 'dsAclAddAce', + 'DevClearList', 'DevClear', 'dbTest', 'dbSwapColumns', 'dbSort', 'dbSetRecordField', 'dbSetOptions', 'dbSetErrorReporting', + 'dbSetEntireRecord', 'dbSetDelimiter', 'dbSave', 'dbOpen', 'dbNameColumn', 'dbMakeNewItem', 'dbInsertColumn', 'dbGetVersion', + 'dbGetSaveStatus', 'dbGetRecordField', 'dbGetRecordCount', 'dbGetNextItem', 'dbGetLastError', 'dbGetEntireRecord', + 'dbGetColumnType', 'dbGetColumnNumber', 'dbGetColumnName', 'dbGetColumnCount', 'dbFindRecord', 'dbExist', 'dbEasterEgg', + 'dbDeleteRecord', 'dbDeleteColumn', 'dbDebug', 'dbCookDatabases', 'dbClose', 'dbCloneRecord', 'dbBindCol', 'cWndState', + 'cWndinfo', 'cWndGetWndSpecName', 'cWndGetWndSpec', 'cWndexist', 'cWndByWndSpecName', 'cWndByWndSpec', 'cWndbyseq', + 'cWndbyname', 'cWndbyid', 'cWndbyclass', 'cWinIDConvert', 'cVersionInfo', 'cVendorId', 'cSetWndText', 'cSetUpDownPos', + 'cSetTvItem', 'cSetTrackPos', 'cSetTabItem', 'cSetLvItem', 'cSetLbItemEx', 'cSetLbItem', 'cSetIpAddr', 'cSetFocus', + 'cSetEditText', 'cSetDtpDate', 'cSetCbItem', 'cSetCalDate', 'cSendMessage', 'cRadioButton', 'cPostMessage', 'cPostButton', + 'cMemStat', 'cGetWndCursor', 'cGetUpDownPos', 'cGetUpDownMin', 'cGetUpDownMax', 'cGetTVItem', 'cGetTrackPos', 'cGetTrackMin', + 'cGetTrackMax', 'cGetTbText', 'cGetSbText', 'cGetLvText', 'cGetLvSelText', 'cGetLvFocText', 'cGetLvDdtText', 'cGetLvColText', + 'cGetLbText', 'cGetLbSelText', 'cGetLbCount', 'cGetIpAddr', 'cGetInfo', 'cGetHrText', 'cGetFocus', 'cGetEditText', 'cGetDtpDate', + 'cGetControlImageCRC', 'cGetCBText', 'cGetCbCount', 'cGetCalDate', 'cFindByName', 'cFindByClass', 'cEnablestate', 'cDblClickItem', + 'cCpuSupt', 'cCpuSpeed', 'cCpuIdExt', 'cCpuId', 'cCpuFeat', 'cCpuBenchmark', 'cCloneCheck', 'cClickToolbar', 'cClickButton', + 'cClearTvItem', 'cClearLvItem', 'cClearLbAll', 'cCheckbox', 'aVersion', 'aStatusbar', 'aShellFolder', 'aMsgTimeout', 'AllSPoll', + 'aGetLastError', 'aFileRename', 'aFileMove', 'aFileDelete', 'aFileCopy' + ), + 5 => array( + 'wWordRight', 'wWordLeft', 'wWinTile', 'wWinRestore', 'wWinNext', 'wWinMinimize', 'wWinMaximize', 'wWinCloseAll', 'wWinClose', + 'wWinCascade', 'wWinArricons', 'wViewOutput', 'wViewOptions', 'wViewHtml', 'wUpperCase', 'wUpline', 'wUndo', 'wTopOfFile', 'wToggleIns', + 'wTab', 'wStatusMsg', 'wStartSel', 'wSpellcheck', 'wSetProject', 'wSetPrefs', 'wSetColblk', 'wSetBookmark', 'wSelWordRight', + 'wSelWordLeft', 'wSelUp', 'wSelTop', 'wSelRight', 'wSelPgUp', 'wSelPgDn', 'wSelLeft', 'wSelInfo', 'wSelHome', 'wSelEnd', 'wSelectAll', + 'wSelDown', 'wSelBottom', 'wRunRebuild', 'wRunMake', 'wRunExecute', 'wRunDebug', 'wRunConfig', 'wRunCompile', 'wRunCommand', 'wRight', + 'wRepeat', 'wRedo', 'wRecord', 'wProperties', 'wPrintDirect', 'wPrinSetup', 'wPrevError', 'wPaste', 'wPageUp', 'wPageDown', 'wNextError', + 'wNewLine', 'wLowerCase', 'wLineCount', 'wLeft', 'wInvertCase', 'wInsString', 'wInsLine', 'wHome', 'wHelpKeyword', 'wHelpKeybrd', + 'wHelpIndex', 'wHelpHelp', 'wHelpCmds', 'wHelpAbout', 'wGotoLine', 'wGotoCol', 'wGetWrap', 'wGetWord', 'wGetUndo', 'wGetSelstate', + 'wGetRedo', 'wGetOutput', 'wGetModified', 'wGetLineNo', 'wGetIns', 'wGetFilename', 'wGetColNo', 'wGetChar', 'wFtpOpen', 'wFindNext', + 'wFindInFiles', 'wFind', 'wFileSaveAs', 'wFileSave', 'wFileRevert', 'wFilePrint', 'wFilePgSetup', 'wFileOpen', 'wFileNew', 'wFileMerge', + 'wFileList', 'wFileExit', 'wEndSel', 'wEndOfFile', 'wEnd', 'wEdWrap', 'wEdWordRight', 'wEdWordLeft', 'wEdUpLine', 'wEdUndo', 'wEdTopOfFile', + 'wEdToggleIns', 'wEdTab', 'wEdStartSel', 'wEdSetColBlk', 'wEdSelectAll', 'wEdRight', 'wEdRedo', 'wEdPaste', 'wEdPageUp', 'wEdPageDown', + 'wEdNewLine', 'wEdLeft', 'wEdInsString', 'wEdHome', 'wEdGoToLine', 'wEdGoToCol', 'wEdGetWord', 'wEdEndSel', 'wEdEndOfFile', 'wEdEnd', + 'wEdDownLine', 'wEdDelete', 'wEdCutLine', 'wEdCut', 'wEdCopyLine', 'wEdCopy', 'wEdClearSel', 'wEdBackTab', 'wEdBackspace', 'wDownLine', + 'wDelete', 'wDelButton', 'wCutMarked', 'wCutLine', 'wCutAppend', 'wCut', 'wCopyMarked', 'wCopyLine', 'wCopyAppend', 'wCopy', 'wCompile', + 'wClearSel', 'wChange', 'wCallMacro', 'wBackTab', 'wBackspace', 'wAutoIndent', 'wAddButton', 'edWindowTile', 'edWindowRestore', + 'edWindowNext', 'edWindowMinimize', 'edWindowMaximize', 'edWindowCloseall', 'edWindowClose', 'edWindowCascade', 'edWindowArrangeIcons', + 'edStatusMsg', 'edSearchViewOutput', 'edSearchRepeat', 'edSearchPrevError', 'edSearchNextError', 'edSearchFind', 'edSearchChange', + 'edRunRebuild', 'edRunMake', 'edRunExecute', 'edRunDebug', 'edRunConfigure', 'edRunCompile', 'edRunCommand', 'edRecord', 'edHelpProcedures', + 'edHelpKeyword', 'edHelpKeyboard', 'edHelpIndex', 'edHelpHelp', 'edHelpCommands', 'edHelpAbout', 'edGetWordWrapState', 'edGetWindowName', + 'edGetUndoState', 'edGetSelectionState', 'edGetRedoState', 'edGetModifiedStatus', 'edGetLineNumber', 'edGetInsertState', 'edGetColumnNumber', + 'edGetChar', 'edFileSetPreferences', 'edFileSaveAs', 'edFileSave', 'edFilePrinterSetup', 'edFilePrint', 'edFilePageSetup', 'edFileOpen', + 'edFileNew', 'edFileMerge', 'edFileList', 'edFileExit', 'edEditWrap', 'edEditWordRight', 'edEditWordLeft', 'edEditUpLine', 'edEditUndo', + 'edEditToggleIns', 'edEditTab', 'edEditStartSelection', 'edEditSetColumnBlock', 'edEditSetBookmark', 'edEditSelectAll', 'edEditRight', + 'edEditRedo', 'edEditPaste', 'edEditPageUp', 'edEditPageDown', 'edEditLeft', 'edEditInsertString', 'edEditGoToLine', 'edEditGoToColumn', + 'edEditGoToBookmark', 'edEditGetCurrentWord', 'edEditEndSelection', 'edEditEndOfLine', 'edEditEndOfFile', 'edEditDownline', 'edEditDelete', + 'edEditCutline', 'edEditCut', 'edEditCopyline', 'edEditCopy', 'edEditClearSelection', 'edEditBeginningOfLine', 'edEditBeginningOfFile', + 'edEditBackTab', 'edEditBackspace', 'edDeleteButton', 'edAddButton' + ) + ), + 'SYMBOLS' => array( + '(', ')', '[', ']', '{', '}', '!', '+', '-', '~', '$', '^', '?', '@', '%', '#', '&', '*', '|', '/', '<', '>' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false, + 5 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #800080;', + 2 => 'color: #0080FF; font-weight: bold;', + 3 => 'color: #0000FF;', + 4 => 'color: #FF00FF;', + 5 => 'color: #008000;' + ), + 'COMMENTS' => array( + 1 => 'color: #008000; font-style: italic;', + 2 => 'color: #FF1010; font-weight: bold;', + 'MULTI' => 'color: #808080; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + 0 => 'color: #006600;' + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'REGEXPS' => array( + 0 => 'color: #0000ff;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array(), + 'REGEXPS' => array(//Variable names + 0 => "[\\$]{1,2}[a-zA-Z_][a-zA-Z0-9_]*" + ), + 'STRICT_MODE_APPLIES' => GESHI_MAYBE, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/xml.php b/examples/includes/geshi/geshi/xml.php new file mode 100644 index 0000000..48b748c --- /dev/null +++ b/examples/includes/geshi/geshi/xml.php @@ -0,0 +1,157 @@ + 'XML', + 'COMMENT_SINGLE' => array(), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + ), + 'COMMENTS' => array( + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #66cc66;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #66cc66;' + ), + 'SCRIPT' => array( + -1 => 'color: #808080; font-style: italic;', // comments + 0 => 'color: #00bbdd;', + 1 => 'color: #ddbb00;', + 2 => 'color: #339933;', + 3 => 'color: #009900;' + ), + 'REGEXPS' => array( + 0 => 'color: #000066;', + 1 => 'color: #000000; font-weight: bold;', + 2 => 'color: #000000; font-weight: bold;' + ) + ), + 'URLS' => array( + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + 0 => array(//attribute names + GESHI_SEARCH => '([a-z_:][\w\-\.:]*)(=)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '\\2' + ), + 1 => array(//Initial header line + GESHI_SEARCH => '(<[\/?|(\?xml)]?[a-z_:][\w\-\.:]*(\??>)?)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + 2 => array(//Tag end markers + GESHI_SEARCH => '(([\/|\?])?>)', + GESHI_REPLACE => '\\1', + GESHI_MODIFIERS => 'i', + GESHI_BEFORE => '', + GESHI_AFTER => '' + ), + ), + 'STRICT_MODE_APPLIES' => GESHI_ALWAYS, + 'SCRIPT_DELIMITERS' => array( + -1 => array( + '' + ), + 0 => array( + ' '>' + ), + 1 => array( + '&' => ';' + ), + 2 => array( + ' ']]>' + ), + 3 => array( + '<' => '>' + ) + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + -1 => false, + 0 => false, + 1 => false, + 2 => false, + 3 => true + ), + 'TAB_WIDTH' => 2, + 'PARSER_CONTROL' => array( + 'ENABLE_FLAGS' => array( + 'NUMBERS' => GESHI_NEVER + ) + ) +); + +?> diff --git a/examples/includes/geshi/geshi/xorg_conf.php b/examples/includes/geshi/geshi/xorg_conf.php new file mode 100644 index 0000000..643d38d --- /dev/null +++ b/examples/includes/geshi/geshi/xorg_conf.php @@ -0,0 +1,124 @@ + 'Xorg configuration', + 'COMMENT_SINGLE' => array(1 => '#'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array('"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + // sections + 1 => array( + 'Section', 'EndSection', 'SubSection', 'EndSubSection' + ), + 2 => array( + // see http://www.x.org/archive/X11R6.9.0/doc/html/xorg.conf.5.html + 'BiosBase', 'Black', 'Boardname', 'BusID', 'ChipID', 'ChipRev', + 'Chipset', 'ClockChip', 'Clocks', 'DacSpeed', + 'DefaultDepth', 'DefaultFbBpp', 'Depth', 'Device', + 'DisplaySize', 'Driver', 'FbBpp', 'Gamma', + 'HorizSync', 'IOBase', 'Identifier', 'InputDevice', + 'Load', 'MemBase', 'Mode', 'Modeline', 'Modelname', + 'Modes', 'Monitor', 'Option', 'Ramdac', 'RgbPath', + 'Screen', 'TextClockFreq', 'UseModes', 'VendorName', + 'VertRefresh', 'VideoAdaptor', 'VideoRam', + 'ViewPort', 'Virtual', 'Visual', 'Weight', 'White' + ), + 3 => array( + // some sub-keywords + // screen position + 'Above', 'Absolute', 'Below', 'LeftOf', 'Relative', 'RightOf', + // modes + 'DotClock', 'Flags', 'HSkew', 'HTimings', 'VScan', 'VTimings' + ), + ), + 'REGEXPS' => array( + ), + 'SYMBOLS' => array( + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #b1b100;', + 2 => 'color: #990000;', + 3 => 'color: #550000;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + ), + 'BRACKETS' => array( + ), + 'STRINGS' => array( + 0 => 'color: #0000ff;', + ), + 'NUMBERS' => array( + 0 => 'color: #cc66cc;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 4 +); + +?> diff --git a/examples/includes/geshi/geshi/xpp.php b/examples/includes/geshi/geshi/xpp.php new file mode 100644 index 0000000..6e7c980 --- /dev/null +++ b/examples/includes/geshi/geshi/xpp.php @@ -0,0 +1,436 @@ + + * + * CHANGES + * ------- + * 2007/02/28 (1.0.0) + * - First Release + * + * TODO (updated 2007/02/27) + * ------------------------- + * + ************************************************************************************* + * + * This file is part of GeSHi. + * + * GeSHi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GeSHi 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 GeSHi; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************************************/ + +$language_data = array ( + 'LANG_NAME' => 'X++', + 'COMMENT_SINGLE' => array(1 => '//'), + 'COMMENT_MULTI' => array('/*' => '*/'), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '\\', + 'KEYWORDS' => array( + 1 => array( // Primitive types + 'void', + 'str', + 'real', + 'int64', + 'int', + 'date', + 'container', + 'boolean', + 'anytype' + ), + 2 => array( // Keywords + 'window', + 'while', + 'try', + 'true', + 'throw', + 'switch', + 'super', + 'static', + 'server', + 'right', + 'return', + 'retry', + 'public', + 'protected', + 'private', + 'print', + 'pause', + 'null', + 'new', + 'mod', + 'left', + 'interface', + 'implements', + 'if', + 'for', + 'final', + 'false', + 'extends', + 'else', + 'edit', + 'do', + 'div', + 'display', + 'default', + 'continue', + 'client', + 'class', + 'changeCompany', + 'case', + 'breakpoint', + 'break', + 'at', + 'abstract' + ), + 3 => array( // Functions within the Axapta kernel + 'year', + 'wkofyr', + 'webwebpartstr', + 'webstaticfilestr', + 'websitetempstr', + 'websitedefstr', + 'webreportstr', + 'webpagedefstr', + 'weboutputcontentitemstr', + 'webmenustr', + 'webletitemstr', + 'webformstr', + 'webdisplaycontentitemstr', + 'webactionitemstr', + 'varstr', + 'utilmoyr', + 'uint2str', + 'typeof', + 'typeid', + 'trunc', + 'today', + 'timenow', + 'time2str', + 'term', + 'tanh', + 'tan', + 'tablestr', + 'tablestaticmethodstr', + 'tablepname', + 'tablenum', + 'tablename2id', + 'tablemethodstr', + 'tableid2pname', + 'tableid2name', + 'tablefieldgroupstr', + 'tablecollectionstr', + 'systemdateset', + 'systemdateget', + 'syd', + 'substr', + 'strupr', + 'strscan', + 'strrtrim', + 'strrep', + 'strrem', + 'strprompt', + 'strpoke', + 'strnfind', + 'strlwr', + 'strltrim', + 'strline', + 'strlen', + 'strkeep', + 'strins', + 'strfmt', + 'strfind', + 'strdel', + 'strcolseq', + 'strcmp', + 'stralpha', + 'str2time', + 'str2num', + 'str2int64', + 'str2int', + 'str2guid', + 'str2enum', + 'str2date', + 'staticmethodstr', + 'sln', + 'sleep', + 'sinh', + 'sin', + 'setprefix', + 'sessionid', + 'securitykeystr', + 'securitykeynum', + 'runbuf', + 'runas', + 'round', + 'resourcestr', + 'reportstr', + 'refprintall', + 'rate', + 'querystr', + 'pv', + 'pt', + 'prmisdefault', + 'primoyr', + 'prevyr', + 'prevqtr', + 'prevmth', + 'power', + 'pmt', + 'num2str', + 'num2date', + 'num2char', + 'nextyr', + 'nextqtr', + 'nextmth', + 'newguid', + 'mthofyr', + 'mthname', + 'mkdate', + 'minint', + 'min', + 'methodstr', + 'menustr', + 'menuitemoutputstr', + 'menuitemdisplaystr', + 'menuitemactionstr', + 'maxint', + 'maxdate', + 'max', + 'match', + 'logn', + 'log10', + 'literalstr', + 'licensecodestr', + 'licensecodenum', + 'intvnorm', + 'intvno', + 'intvname', + 'intvmax', + 'int64str', + 'indexstr', + 'indexnum', + 'indexname2id', + 'indexid2name', + 'idg', + 'identifierstr', + 'helpfilestr', + 'helpdevstr', + 'helpapplstr', + 'guid2str', + 'getprefix', + 'getCurrentUTCTime', + 'fv', + 'funcname', + 'frac', + 'formstr', + 'fieldstr', + 'fieldpname', + 'fieldnum', + 'fieldname2id', + 'fieldid2pname', + 'fieldid2name', + 'extendedTypeStr', + 'extendedTypeNum', + 'exp10', + 'exp', + 'evalbuf', + 'enumstr', + 'enumnum', + 'enumcnt', + 'enum2str', + 'endmth', + 'dimof', + 'dg', + 'decround', + 'ddb', + 'dayofyr', + 'dayofwk', + 'dayofmth', + 'dayname', + 'date2str', + 'date2num', + 'curuserid', + 'curext', + 'cterm', + 'cosh', + 'cos', + 'corrflagset', + 'corrflagget', + 'convertUTCTimeToLocalTime', + 'convertUTCDateToLocalDate', + 'conpoke', + 'conpeek', + 'connull', + 'conlen', + 'conins', + 'confind', + 'configurationkeystr', + 'configurationkeynum', + 'condel', + 'classstr', + 'classnum', + 'classidget', + 'char2num', + 'beep', + 'atan', + 'asin', + 'ascii2ansi', + 'any2str', + 'any2real', + 'any2int64', + 'any2int', + 'any2guid', + 'any2enum', + 'any2date', + 'ansi2ascii', + 'acos', + 'abs' + ), + 4 => array( // X++ SQL stuff + 'where', + 'update_recordset', + 'ttsCommit', + 'ttsBegin', + 'ttsAbort', + 'sum', + 'setting', + 'select', + 'reverse', + 'pessimisticLock', + 'outer', + 'order by', + 'optimisticLock', + 'notExists', + 'noFetch', + 'next', + 'minof', + 'maxof', + 'like', + 'join', + 'insert_recordset', + 'index hint', + 'index', + 'group by', + 'from', + 'forUpdate', + 'forceSelectOrder', + 'forcePlaceholders', + 'forceNestedLoop', + 'forceLiterals', + 'flush', + 'firstOnly', + 'firstFast', + 'exists', + 'desc', + 'delete_from', + 'count', + 'avg', + 'asc' + ) + ), + 'SYMBOLS' => array( // X++ symbols + '!', + '&', + '(', + ')', + '*', + '^', + '|', + '~', + '+', + ',', + '-', + '/', + ':', + '<', + '=', + '>', + '?', + '[', + ']', + '{', + '}' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + 4 => false + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff;', + 2 => 'color: #0000ff;', + 3 => 'color: #0000ff;', + 4 => 'color: #0000ff;' + ), + 'COMMENTS' => array( + 1 => 'color: #007f00;', + 'MULTI' => 'color: #007f00; font-style: italic;' + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000000;' + ), + 'BRACKETS' => array( + 0 => 'color: #000000;' + ), + 'STRINGS' => array( + 0 => 'color: #ff0000;' + ), + 'NUMBERS' => array( + 0 => 'color: #000000;' + ), + 'METHODS' => array( + 1 => 'color: #000000;', + 2 => 'color: #000000;' + ), + 'SYMBOLS' => array( + 0 => 'color: #00007f;' + ), + 'REGEXPS' => array( + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '', + 4 => '' + ), + 'OOLANG' => true, + 'OBJECT_SPLITTERS' => array( + 1 => '.', + 2 => '::' + ), + 'REGEXPS' => array( + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ) +); + +?> diff --git a/examples/includes/geshi/geshi/z80.php b/examples/includes/geshi/geshi/z80.php new file mode 100644 index 0000000..845712f --- /dev/null +++ b/examples/includes/geshi/geshi/z80.php @@ -0,0 +1,144 @@ + 'ZiLOG Z80 Assembler', + 'COMMENT_SINGLE' => array(1 => ';'), + 'COMMENT_MULTI' => array(), + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, + 'QUOTEMARKS' => array("'", '"'), + 'ESCAPE_CHAR' => '', + 'KEYWORDS' => array( + /*CPU*/ + 1 => array( + 'adc','add','and','bit','call','ccf','cp','cpd','cpdr','cpir','cpi', + 'cpl','daa','dec','di','djnz','ei','ex','exx','halt','im','in', + 'in0','inc','ind','indr','inir','ini','jp','jr','ld','ldd','lddr', + 'ldir','ldi','mlt','neg','nop','or','otdm','otdmr','otdr','otim', + 'otimr','otir','out','out0','outd','outi','pop','push','res','ret', + 'reti','retn','rl','rla','rlc','rlca','rld','rr','rra','rrc','rrca', + 'rrd','rst','sbc','scf','set','sla','sl1','sll','slp','sra','srl', + 'sub','tst','tstio','xor' + ), + /*registers*/ + 2 => array( + 'a','b','c','d','e','h','l', + 'af','bc','de','hl','ix','iy','sp', + 'af\'','ixh','ixl','iyh','iyl' + ), + /*Directive*/ + 3 => array( + '#define','#endif','#else','#ifdef','#ifndef','#include','#undef', + '.db','.dd','.df','.dq','.dt','.dw','.end','.org','equ' + ), + ), + 'SYMBOLS' => array( + '[', ']', '(', ')', '?', '+', '-', '*', '/', '%', '$' + ), + 'CASE_SENSITIVE' => array( + GESHI_COMMENTS => false, + 1 => false, + 2 => false, + 3 => false, + ), + 'STYLES' => array( + 'KEYWORDS' => array( + 1 => 'color: #0000ff; font-weight:bold;', + 2 => 'color: #0000ff;', + 3 => 'color: #46aa03; font-weight:bold;' + ), + 'COMMENTS' => array( + 1 => 'color: #adadad; font-style: italic;', + ), + 'ESCAPE_CHAR' => array( + 0 => 'color: #000099; font-weight: bold;' + ), + 'BRACKETS' => array( + 0 => 'color: #0000ff;' + ), + 'STRINGS' => array( + 0 => 'color: #7f007f;' + ), + 'NUMBERS' => array( + 0 => 'color: #dd22dd;' + ), + 'METHODS' => array( + ), + 'SYMBOLS' => array( + 0 => 'color: #008000;' + ), + 'REGEXPS' => array( + 0 => 'color: #22bbff;', + 1 => 'color: #22bbff;', + 2 => 'color: #993333;' + ), + 'SCRIPT' => array( + ) + ), + 'URLS' => array( + 1 => '', + 2 => '', + 3 => '' + ), + 'OOLANG' => false, + 'OBJECT_SPLITTERS' => array( + ), + 'REGEXPS' => array( + //Hex numbers + 0 => '0[0-9a-fA-F]{1,32}[hH]', + //Binary numbers + 1 => '\%[01]{1,64}|[01]{1,64}[bB]?', + //Labels + 2 => '^[_a-zA-Z][_a-zA-Z0-9]?\:' + ), + 'STRICT_MODE_APPLIES' => GESHI_NEVER, + 'SCRIPT_DELIMITERS' => array( + ), + 'HIGHLIGHT_STRICT_BLOCK' => array( + ), + 'TAB_WIDTH' => 8 +); + +?> diff --git a/examples/includes/vp8_doc_tools.php b/examples/includes/vp8_doc_tools.php new file mode 100644 index 0000000..aee2a2e --- /dev/null +++ b/examples/includes/vp8_doc_tools.php @@ -0,0 +1,207 @@ +#!/usr/bin/env php + + * + **********************************************************/ + + +// Includes +include_once('PHP-Markdown-Extra-1.2.3/markdown.php'); +include_once('PHP-SmartyPants-1.5.1e/smartypants.php'); +include_once('ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php'); +require_once('ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php'); +include_once('geshi/geshi.php'); + + +// Paths and Scripts +$geshi_lang = 'geshi/geshi/'; // GeSHi language files +$toc_script = './do_toc.pl'; + + + +/** + * ASCIIMathML parser + * http://tinyurl.com/ASCIIMathPHP + * + * @PARAM mtch_arr array - Array of ASCIIMath expressions + * as returned by preg_replace_callback([pattern]). First + * dimension is the full matched string (with delimiter); + * 2nd dimension is the undelimited contents (typically + * a capture group). + * + **********************************************************/ + +function ASCIIMathPHPCallback($mtch_arr) +{ + $txt = trim($mtch_arr[1]); + + static $asciimath; + + if (!isset($asciimath)) $asciimath = new ASCIIMathPHP($symbol_arr); + + $math_attr_arr = array('displaystyle' => 'true'); + + $asciimath->setExpr($txt); + $asciimath->genMathML($math_attr_arr); + + return($asciimath->getMathML()); +} + +/** + * fix_asciiMath() + * + * ASCIIMath pretty-prints its output, with linefeeds + * and tabs. Causes unexpected behavior in some renderers. + * This flattens blocks. + * + * @PARAM page_body str - The element of an + * XHTML page to transform. + * + **********************************************************/ + +function fix_asciiMath($page_body) +{ + $out = FALSE; + + // Remove linefeeds and whitespace in elements + $tags_bad = array('/()\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mstyle>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mrow>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mo>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mi>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mn>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mtext>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/msqrt>)\n*\s*/' + , '/()\n*\s*/' + , '/(<\/mfrac>)\n*\s*/' + ); + $tags_good = array( '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + , '$1' + ); + $out = preg_replace($tags_bad, $tags_good, $page_body); + + return $out; + +} + +/** + * do_geshi() - Performs GeSHi transforms on XHTML blobs + * + * @param $blob str - The blob to transform + * @param $open str - Opening expression to match + * @param $close str - Closing expression to match + * @param $lang str - Language file to use + * + **********************************************************/ + +function do_geshi($blob, $open = '
        ',
        +                    $close = '
        ', $lang = 'c') +{ + $out = FALSE; + $regexp = '|' . $open . '(.*?)' . $close . '|si'; + echo $regexp . "\n\n"; + + while (preg_match($regexp, $blob, $matches)) + { + $geshi = new GeSHi($matches[1], $lang); + $geshi->set_language_path($geshi_lang); + $blob_new = $geshi->parse_code(); + // Strip annoying final
        + $blob_new = preg_replace('/\n <\/pre>/', '
        ' , $blob_new); + // Fix annoying GeSHI-injected attributes + $blob_new = preg_replace('//i', '
        ' , $blob_new);
        +    $blob  = preg_replace($regexp, $blob_new, $blob, 1);
        +    unset($geshi);
        +  }
        +
        +  return $out;
        +
        +}
        +
        +
        +
        +
        +/**
        + * prep_dd_codeblocks()
        + *
        + * I'm _so_ not proud of this, but don't have time to
        + * write a proper regex.
        + *
        + * @TODO - Write that regex.
        + *
        + **********************************************************/
        +/*
        +function prep_dd_codeblocks($page_body)
        +{
        +  $out = FALSE;
        +  $toggle = 0;
        +  $regexp = '/~{3,}/';
        +
        +  while (preg_match($regexp, $page_body))
        +  {
        +    if ($toggle == 0)
        +    {
        +      $regexp = '/:\s*~{3,}\s*\n/';
        +      $page_body = preg_replace($regexp, ': 
        ', $page_body, 1);
        +      $toggle = 1;
        +    }
        +    else
        +    {
        +      $regexp = '/\n\s*~{3,}/';
        +      $page_body = preg_replace($regexp, '
        ', $page_body, 1); + $toggle = 0; + } + } + + // One more time + $regexp = '/\n\s*~{3,}/'; + $page_body = preg_replace($regexp, '
        ', $page_body, 1); + $out = $page_body; + + return $out; +} +*/ diff --git a/examples/postproc.txt b/examples/postproc.txt new file mode 100644 index 0000000..51b251a --- /dev/null +++ b/examples/postproc.txt @@ -0,0 +1,67 @@ +@TEMPLATE decoder_tmpl.c +Postprocessing Decoder +====================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This example adds postprocessing to the simple decoder loop. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Initializing Postprocessing +--------------------------- +You must inform the codec that you might request postprocessing at +initialization time. This is done by passing the VPX_CODEC_USE_POSTPROC +flag to `vpx_codec_dec_init`. If the codec does not support +postprocessing, this call will return VPX_CODEC_INCAPABLE. For +demonstration purposes, we also fall back to default initialization if +the codec does not provide support. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT +/* Initialize codec */ +res = vpx_codec_dec_init(&codec, interface, NULL, + VPX_CODEC_USE_POSTPROC); +if(res == VPX_CODEC_INCAPABLE) { + printf("NOTICE: Postproc not supported by %s\n", + vpx_codec_iface_name(interface)); + res = vpx_codec_dec_init(&codec, interface, NULL, flags); +} +if(res) + die_codec(&codec, "Failed to initialize decoder"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT + + +Using Adaptive Postprocessing +----------------------------- +VP6 provides "adaptive postprocessing." It will automatically select the +best postprocessing filter on a frame by frame basis based on the amount +of time remaining before the user's specified deadline expires. The +special value 0 indicates that the codec should take as long as +necessary to provide the best quality frame. This example gives the +codec 15ms (15000us) to return a frame. Remember that this is a soft +deadline, and the codec may exceed it doing its regular processing. In +these cases, no additional postprocessing will be done. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE +/* Decode the frame with 15ms deadline */ +if(vpx_codec_decode(&codec, frame, frame_sz, NULL, 15000)) + die_codec(&codec, "Failed to decode frame"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE + + +Codec Specific Postprocessing Controls +-------------------------------------- +Some codecs provide fine grained controls over their built-in +postprocessors. VP8 is one example. The following sample code toggles +postprocessing on and off every 15 frames. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE +#if CONFIG_VP8_DECODER +if(frame_cnt%30 == 1) { + vp8_postproc_cfg_t pp = {0, 0, 0}; + + if(vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) + die_codec(&codec, "Failed to turn off postproc"); +} else if(frame_cnt%30 == 16) { + vp8_postproc_cfg_t pp = {VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE, 4, 0}; + + if(vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) + die_codec(&codec, "Failed to turn on postproc"); +}; +#endif +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE diff --git a/examples/simple_decoder.txt b/examples/simple_decoder.txt new file mode 100644 index 0000000..90d9a68 --- /dev/null +++ b/examples/simple_decoder.txt @@ -0,0 +1,96 @@ +@TEMPLATE decoder_tmpl.c +Simple Decoder +============== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example of a simple decoder loop. It takes an input file +containing the compressed data (in IVF format), passes it through the +decoder, and writes the decompressed frames to disk. Other decoder +examples build upon this one. + +The details of the IVF format have been elided from this example for +simplicity of presentation, as IVF files will not generally be used by +your application. In general, an IVF file consists of a file header, +followed by a variable number of frames. Each frame consists of a frame +header followed by a variable length payload. The length of the payload +is specified in the first four bytes of the frame header. The payload is +the raw compressed data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Standard Includes +----------------- +For decoders, you only have to include `vpx_decoder.h` and then any +header files for the specific codecs you use. In this case, we're using +vp8. The `VPX_CODEC_DISABLE_COMPAT` macro can be defined to ensure +strict compliance with the latest SDK by disabling some backwards +compatibility features. Defining this macro is encouraged. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INCLUDES +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INCLUDES + + +Initializing The Codec +---------------------- +The decoder is initialized by the following code. This is an example for +the VP8 decoder, but the code is analogous for all algorithms. Replace +`vpx_codec_vp8_dx()` with a pointer to the interface exposed by the +algorithm you want to use. The `cfg` argument is left as NULL in this +example, because we want the algorithm to determine the stream +configuration (width/height) and allocate memory automatically. This +parameter is generally only used if you need to preallocate memory, +particularly in External Memory Allocation mode. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT + + +Decoding A Frame +---------------- +Once the frame has been read into memory, it is decoded using the +`vpx_codec_decode` function. The call takes a pointer to the data +(`frame`) and the length of the data (`frame_sz`). No application data +is associated with the frame in this example, so the `user_priv` +parameter is NULL. The `deadline` parameter is left at zero for this +example. This parameter is generally only used when doing adaptive +postprocessing. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE + +Codecs may produce a variable number of output frames for every call to +`vpx_codec_decode`. These frames are retrieved by the +`vpx_codec_get_frame` iterator function. The iterator variable `iter` is +initialized to NULL each time `vpx_codec_decode` is called. +`vpx_codec_get_frame` is called in a loop, returning a pointer to a +decoded image or NULL to indicate the end of list. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GET_FRAME +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GET_FRAME + + +Processing The Decoded Data +--------------------------- +In this example, we simply write the encoded data to disk. It is +important to honor the image's `stride` values. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX + + +Cleanup +------- +The `vpx_codec_destroy` call frees any memory allocated by the codec. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY + + +Error Handling +-------------- +This example does not special case any error return codes. If there was +an error, a descriptive message is printed and the program exits. With +few exeptions, vpx_codec functions return an enumerated error status, +with the value `0` indicating success. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC diff --git a/examples/simple_encoder.txt b/examples/simple_encoder.txt new file mode 100644 index 0000000..44c5b08 --- /dev/null +++ b/examples/simple_encoder.txt @@ -0,0 +1,105 @@ +@TEMPLATE encoder_tmpl.c +Simple Encoder +============== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example of a simple encoder loop. It takes an input file in +YV12 format, passes it through the encoder, and writes the compressed +frames to disk in IVF format. Other decoder examples build upon this +one. + +The details of the IVF format have been elided from this example for +simplicity of presentation, as IVF files will not generally be used by +your application. In general, an IVF file consists of a file header, +followed by a variable number of frames. Each frame consists of a frame +header followed by a variable length payload. The length of the payload +is specified in the first four bytes of the frame header. The payload is +the raw compressed data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Standard Includes +----------------- +For encoders, you only have to include `vpx_encoder.h` and then any +header files for the specific codecs you use. In this case, we're using +vp8. The `VPX_CODEC_DISABLE_COMPAT` macro can be defined to ensure +strict compliance with the latest SDK by disabling some backwards +compatibility features. Defining this macro is encouraged. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INCLUDES +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INCLUDES + + +Getting The Default Configuration +--------------------------------- +Encoders have the notion of "usage profiles." For example, an encoder +may want to publish default configurations for both a video +conferencing appliction and a best quality offline encoder. These +obviously have very different default settings. Consult the +documentation for your codec to see if it provides any default +configurations. All codecs provide a default configuration, number 0, +which is valid for material in the vacinity of QCIF/QVGA. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_DEF_CFG +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_DEF_CFG + + +Updating The Configuration +--------------------------------- +Almost all applications will want to update the default configuration +with settings specific to their usage. Here we set the width and height +of the video file to that specified on the command line. We also scale +the default bitrate based on the ratio between the default resolution +and the resolution specified on the command line. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG + + +Initializing The Codec +---------------------- +The encoder is initialized by the following code. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INIT +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INIT + + +Encoding A Frame +---------------- +The frame is read as a continuous block (size width * height * 3 / 2) +from the input file. If a frame was read (the input file has not hit +EOF) then the frame is passed to the encoder. Otherwise, a NULL +is passed, indicating the End-Of-Stream condition to the encoder. The +`frame_cnt` is reused as the presentation time stamp (PTS) and each +frame is shown for one frame-time in duration. The flags parameter is +unused in this example. The deadline is set to VPX_DL_REALTIME to +make the example run as quickly as possible. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME + +Processing The Encoded Data +--------------------------- +Each packet of type `VPX_CODEC_CX_FRAME_PKT` contains the encoded data +for this frame. We write a IVF frame header, followed by the raw data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_FRAME +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_FRAME + + +Cleanup +------- +The `vpx_codec_destroy` call frees any memory allocated by the codec. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY + + +Error Handling +-------------- +This example does not special case any error return codes. If there was +an error, a descriptive message is printed and the program exits. With +few exeptions, vpx_codec functions return an enumerated error status, +with the value `0` indicating success. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC +@DEFAULT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC diff --git a/examples/twopass_encoder.txt b/examples/twopass_encoder.txt new file mode 100644 index 0000000..4683bc7 --- /dev/null +++ b/examples/twopass_encoder.txt @@ -0,0 +1,75 @@ +@TEMPLATE encoder_tmpl.c +Two Pass Encoder +================ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example of a two pass encoder loop. It takes an input file in +YV12 format, passes it through the encoder twice, and writes the compressed +frames to disk in IVF format. It builds upon the simple_encoder example. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Twopass Variables +----------------- +Twopass mode needs to track the current pass number and the buffer of +statistics packets. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_VARS +int pass; +vpx_fixed_buf_t stats = {0}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_VARS + + +Updating The Configuration +--------------------------------- +In two pass mode, the configuration has to be updated on each pass. The +statistics buffer is passed on the last pass. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_LOOP_BEGIN +for(pass=0; pass<2; pass++) { + frame_cnt = 0; + + if(pass == 0) + cfg.g_pass = VPX_RC_FIRST_PASS; + else { + cfg.g_pass = VPX_RC_LAST_PASS; + cfg.rc_twopass_stats_in = stats; + } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_LOOP_BEGIN + + +Encoding A Frame +---------------- +Encoding a frame in two pass mode is identical to the simple encoder +example, except the deadline is set to VPX_DL_BEST_QUALITY to get the +best quality possible. VPX_DL_GOOD_QUALITY could also be used. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME +frame_avail = read_frame(infile, &raw); +if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, + 1, flags, VPX_DL_BEST_QUALITY)) + die_codec(&codec, "Failed to encode frame"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME + + +Processing Statistics Packets +----------------------------- +Each packet of type `VPX_CODEC_CX_FRAME_PKT` contains the encoded data +for this frame. We write a IVF frame header, followed by the raw data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_STATS +case VPX_CODEC_STATS_PKT: + stats.buf = realloc(stats.buf, stats.sz + + pkt->data.twopass_stats.sz); + if(!stats.buf) + die("Memory reallocation failed.\n"); + memcpy((char*)stats.buf + stats.sz, + pkt->data.twopass_stats.buf, + pkt->data.twopass_stats.sz); + stats.sz += pkt->data.twopass_stats.sz; + break; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_STATS + + +Pass Progress Reporting +----------------------------- +It's sometimes helpful to see when each pass completes. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_LOOP_END + printf("Pass %d complete.\n", pass+1); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_LOOP_END diff --git a/examples/vp8_set_maps.txt b/examples/vp8_set_maps.txt new file mode 100644 index 0000000..ad9ef61 --- /dev/null +++ b/examples/vp8_set_maps.txt @@ -0,0 +1,96 @@ +@TEMPLATE encoder_tmpl.c +VP8 Set Active and ROI Maps +=========================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION +This is an example demonstrating how to control the VP8 encoder's +ROI and Active maps. + +ROI (Reigon of Interest) maps are a way for the application to assign +each macroblock in the image to a region, and then set quantizer and +filtering parameters on that image. + +Active maps are a way for the application to specify on a +macroblock-by-macroblock basis whether there is any activity in that +macroblock. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION + + +Configuration +------------- +An ROI map is set on frame 22. If the width of the image in macroblocks +is evenly divisble by 4, then the output will appear to have distinct +columns, where the quantizer, loopfilter, and static threshold differ +from column to column. + +An active map is set on frame 33. If the width of the image in macroblocks +is evenly divisble by 4, then the output will appear to have distinct +columns, where one column will have motion and the next will not. + +The active map is cleared on frame 44. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PER_FRAME_CFG +if(frame_cnt + 1 == 22) { + vpx_roi_map_t roi; + int i; + + roi.rows = cfg.g_h/16; + roi.cols = cfg.g_w/16; + + roi.delta_q[0] = 0; + roi.delta_q[1] = -2; + roi.delta_q[2] = -4; + roi.delta_q[3] = -6; + + roi.delta_lf[0] = 0; + roi.delta_lf[1] = 1; + roi.delta_lf[2] = 2; + roi.delta_lf[3] = 3; + + roi.static_threshold[0] = 1500; + roi.static_threshold[1] = 1000; + roi.static_threshold[2] = 500; + roi.static_threshold[3] = 0; + + /* generate an ROI map for example */ + roi.roi_map = malloc(roi.rows * roi.cols); + for(i=0;i \n", + argv[0]); + + update_frame_num = atoi(argv[5]); + if(!update_frame_num) + die("Couldn't parse frame number '%s'\n", argv[5]); + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE + + +Extra Variables +--------------- +This example maintains the frame number passed on the command line +in the `update_frame_num` variable: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_VARS +int update_frame_num = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TWOPASS_VARS + + +Configuration +------------- + +The reference frame is updated on the frame specified on the command +line. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME +frame_avail = read_frame(infile, &raw); + +if(frame_cnt + 1 == update_frame_num) { + vpx_ref_frame_t ref; + + ref.frame_type = VP8_LAST_FRAME; + ref.img = raw; + + if(vpx_codec_control(&codec, VP8_SET_REFERENCE, &ref)) + die_codec(&codec, "Failed to set reference frame"); +} + +if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, + 1, flags, VPX_DL_REALTIME)) + die_codec(&codec, "Failed to encode frame"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME + + +Observing The Effects +--------------------- +Use the `simple_encoder` example to encode a sample with a cut scene. +Determine the frame number of the cut scene by looking for a generated +key-frame (indicated by a 'K'). Supply that frame number as an argument +to this example, and observe that no key-frame is generated. diff --git a/keywords.dox b/keywords.dox new file mode 100644 index 0000000..56f5368 --- /dev/null +++ b/keywords.dox @@ -0,0 +1,51 @@ +/*!\page rfc2119 RFC2119 Keywords + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL + NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + RFC 2119. + +Specifically, the following definitions are used: + +\section MUST +\anchor REQUIRED +\anchor SHALL + This word, or the terms "REQUIRED" or "SHALL", mean that the + definition is an absolute requirement of the specification. + +\section MUSTNOT MUST NOT +\anchor SHALLNOT + This phrase, or the phrase "SHALL NOT", mean that the + definition is an absolute prohibition of the specification. + +\section SHOULD +\anchor RECOMMENDED + This word, or the adjective "RECOMMENDED", mean that there + may exist valid reasons in particular circumstances to ignore a + particular item, but the full implications must be understood and + carefully weighed before choosing a different course. + +\section SHOULDNOT SHOULD NOT +\anchor NOTRECOMMENDED + This phrase, or the phrase "NOT RECOMMENDED" mean that + there may exist valid reasons in particular circumstances when the + particular behavior is acceptable or even useful, but the full + implications should be understood and the case carefully weighed + before implementing any behavior described with this label. + +\section MAY +\anchor OPTIONAL + This word, or the adjective "OPTIONAL", mean that an item is + truly optional. One vendor may choose to include the item because a + particular marketplace requires it or because the vendor feels that + it enhances the product while another vendor may omit the same item. + An implementation which does not include a particular option \ref MUST be + prepared to interoperate with another implementation which does + include the option, though perhaps with reduced functionality. In the + same vein an implementation which does include a particular option + \ref MUST be prepared to interoperate with another implementation which + does not include the option (except, of course, for the feature the + option provides.) + + +*/ diff --git a/libmkv/EbmlBufferWriter.c b/libmkv/EbmlBufferWriter.c new file mode 100644 index 0000000..d9b04a8 --- /dev/null +++ b/libmkv/EbmlBufferWriter.c @@ -0,0 +1,60 @@ +//#include +#include "EbmlBufferWriter.h" +#include "EbmlWriter.h" +//#include +//#include +//#include //_alloca +#include +#include +#include + +void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) +{ + unsigned char *src = glob->buf; + src += glob->offset; + memcpy(src, buffer_in, len); + glob->offset += len; +} + +static void _Serialize(EbmlGlobal *glob, const unsigned char *p, const unsigned char *q) +{ + while (q != p) + { + --q; + + unsigned long cbWritten; + memcpy(&(glob->buf[glob->offset]), q, 1); + glob->offset ++; + } +} + +void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len) +{ + //assert(buf); + + const unsigned char *const p = (const unsigned char *)(buffer_in); + const unsigned char *const q = p + len; + + _Serialize(glob, p, q); +} + + +void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id) +{ + Ebml_WriteID(glob, class_id); + ebmlLoc->offset = glob->offset; + //todo this is always taking 8 bytes, this may need later optimization + unsigned long long unknownLen = 0x01FFFFFFFFFFFFFFLLU; + Ebml_Serialize(glob, (void *)&unknownLen, 8); //this is a key that says lenght unknown +} + +void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) +{ + unsigned long long size = glob->offset - ebmlLoc->offset - 8; + unsigned long long curOffset = glob->offset; + glob->offset = ebmlLoc->offset; + size |= 0x0100000000000000LLU; + Ebml_Serialize(glob, &size, 8); + glob->offset = curOffset; +} + diff --git a/libmkv/EbmlBufferWriter.h b/libmkv/EbmlBufferWriter.h new file mode 100644 index 0000000..ba0a9b3 --- /dev/null +++ b/libmkv/EbmlBufferWriter.h @@ -0,0 +1,21 @@ +#ifndef EBMLBUFFERWRITER_HPP +#define EBMLBUFFERWRITER_HPP + +typedef struct +{ + unsigned long long offset; +} EbmlLoc; + +typedef struct +{ + unsigned char *buf; + unsigned int length; + unsigned int offset; +} EbmlGlobal; + + +void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id); +void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc); + + +#endif diff --git a/libmkv/EbmlIDs.h b/libmkv/EbmlIDs.h new file mode 100644 index 0000000..3418e36 --- /dev/null +++ b/libmkv/EbmlIDs.h @@ -0,0 +1,231 @@ +// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. + + +#ifndef MKV_DEFS_HPP +#define MKV_DEFS_HPP 1 + +//Commenting out values not available in webm, but available in matroska + +enum mkv +{ + EBML = 0x1A45DFA3, + EBMLVersion = 0x4286, + EBMLReadVersion = 0x42F7, + EBMLMaxIDLength = 0x42F2, + EBMLMaxSizeLength = 0x42F3, + DocType = 0x4282, + DocTypeVersion = 0x4287, + DocTypeReadVersion = 0x4285, +// CRC_32 = 0xBF, + Void = 0xEC, + SignatureSlot = 0x1B538667, + SignatureAlgo = 0x7E8A, + SignatureHash = 0x7E9A, + SignaturePublicKey = 0x7EA5, + Signature = 0x7EB5, + SignatureElements = 0x7E5B, + SignatureElementList = 0x7E7B, + SignedElement = 0x6532, + //segment + Segment = 0x18538067, + //Meta Seek Information + SeekHead = 0x114D9B74, + Seek = 0x4DBB, + SeekID = 0x53AB, + SeekPosition = 0x53AC, + //Segment Information + Info = 0x1549A966, +// SegmentUID = 0x73A4, +// SegmentFilename = 0x7384, +// PrevUID = 0x3CB923, +// PrevFilename = 0x3C83AB, +// NextUID = 0x3EB923, +// NextFilename = 0x3E83BB, +// SegmentFamily = 0x4444, +// ChapterTranslate = 0x6924, +// ChapterTranslateEditionUID = 0x69FC, +// ChapterTranslateCodec = 0x69BF, +// ChapterTranslateID = 0x69A5, + TimecodeScale = 0x2AD7B1, + Segment_Duration = 0x4489, + DateUTC = 0x4461, +// Title = 0x7BA9, + MuxingApp = 0x4D80, + WritingApp = 0x5741, + //Cluster + Cluster = 0x1F43B675, + Timecode = 0xE7, +// SilentTracks = 0x5854, +// SilentTrackNumber = 0x58D7, +// Position = 0xA7, + PrevSize = 0xAB, + BlockGroup = 0xA0, + Block = 0xA1, +// BlockVirtual = 0xA2, +// BlockAdditions = 0x75A1, +// BlockMore = 0xA6, +// BlockAddID = 0xEE, +// BlockAdditional = 0xA5, + BlockDuration = 0x9B, +// ReferencePriority = 0xFA, + ReferenceBlock = 0xFB, +// ReferenceVirtual = 0xFD, +// CodecState = 0xA4, +// Slices = 0x8E, +// TimeSlice = 0xE8, + LaceNumber = 0xCC, +// FrameNumber = 0xCD, +// BlockAdditionID = 0xCB, +// MkvDelay = 0xCE, +// Cluster_Duration = 0xCF, + SimpleBlock = 0xA3, +// EncryptedBlock = 0xAF, + //Track + Tracks = 0x1654AE6B, + TrackEntry = 0xAE, + TrackNumber = 0xD7, + TrackUID = 0x73C5, + TrackType = 0x83, + FlagEnabled = 0xB9, + FlagDefault = 0x88, + FlagForced = 0x55AA, + FlagLacing = 0x9C, +// MinCache = 0x6DE7, +// MaxCache = 0x6DF8, + DefaultDuration = 0x23E383, +// TrackTimecodeScale = 0x23314F, +// TrackOffset = 0x537F, +// MaxBlockAdditionID = 0x55EE, + Name = 0x536E, + Language = 0x22B59C, + CodecID = 0x86, + CodecPrivate = 0x63A2, + CodecName = 0x258688, +// AttachmentLink = 0x7446, +// CodecSettings = 0x3A9697, +// CodecInfoURL = 0x3B4040, +// CodecDownloadURL = 0x26B240, +// CodecDecodeAll = 0xAA, +// TrackOverlay = 0x6FAB, +// TrackTranslate = 0x6624, +// TrackTranslateEditionUID = 0x66FC, +// TrackTranslateCodec = 0x66BF, +// TrackTranslateTrackID = 0x66A5, + //video + Video = 0xE0, + FlagInterlaced = 0x9A, + StereoMode = 0x53B8, + PixelWidth = 0xB0, + PixelHeight = 0xBA, + PixelCropBottom = 0x54AA, + PixelCropTop = 0x54BB, + PixelCropLeft = 0x54CC, + PixelCropRight = 0x54DD, + DisplayWidth = 0x54B0, + DisplayHeight = 0x54BA, + DisplayUnit = 0x54B2, + AspectRatioType = 0x54B3, +// ColourSpace = 0x2EB524, +// GammaValue = 0x2FB523, + FrameRate = 0x2383E3, + //end video + //audio + Audio = 0xE1, + SamplingFrequency = 0xB5, + OutputSamplingFrequency = 0x78B5, + Channels = 0x9F, +// ChannelPositions = 0x7D7B, + BitDepth = 0x6264, + //end audio + //content encoding +// ContentEncodings = 0x6d80, +// ContentEncoding = 0x6240, +// ContentEncodingOrder = 0x5031, +// ContentEncodingScope = 0x5032, +// ContentEncodingType = 0x5033, +// ContentCompression = 0x5034, +// ContentCompAlgo = 0x4254, +// ContentCompSettings = 0x4255, +// ContentEncryption = 0x5035, +// ContentEncAlgo = 0x47e1, +// ContentEncKeyID = 0x47e2, +// ContentSignature = 0x47e3, +// ContentSigKeyID = 0x47e4, +// ContentSigAlgo = 0x47e5, +// ContentSigHashAlgo = 0x47e6, + //end content encoding + //Cueing Data + Cues = 0x1C53BB6B, + CuePoint = 0xBB, + CueTime = 0xB3, + CueTrackPositions = 0xB7, + CueTrack = 0xF7, + CueClusterPosition = 0xF1, + CueBlockNumber = 0x5378, +// CueCodecState = 0xEA, +// CueReference = 0xDB, +// CueRefTime = 0x96, +// CueRefCluster = 0x97, +// CueRefNumber = 0x535F, +// CueRefCodecState = 0xEB, + //Attachment +// Attachments = 0x1941A469, +// AttachedFile = 0x61A7, +// FileDescription = 0x467E, +// FileName = 0x466E, +// FileMimeType = 0x4660, +// FileData = 0x465C, +// FileUID = 0x46AE, +// FileReferral = 0x4675, + //Chapters +// Chapters = 0x1043A770, +// EditionEntry = 0x45B9, +// EditionUID = 0x45BC, +// EditionFlagHidden = 0x45BD, +// EditionFlagDefault = 0x45DB, +// EditionFlagOrdered = 0x45DD, +// ChapterAtom = 0xB6, +// ChapterUID = 0x73C4, +// ChapterTimeStart = 0x91, +// ChapterTimeEnd = 0x92, +// ChapterFlagHidden = 0x98, +// ChapterFlagEnabled = 0x4598, +// ChapterSegmentUID = 0x6E67, +// ChapterSegmentEditionUID = 0x6EBC, +// ChapterPhysicalEquiv = 0x63C3, +// ChapterTrack = 0x8F, +// ChapterTrackNumber = 0x89, +// ChapterDisplay = 0x80, +// ChapString = 0x85, +// ChapLanguage = 0x437C, +// ChapCountry = 0x437E, +// ChapProcess = 0x6944, +// ChapProcessCodecID = 0x6955, +// ChapProcessPrivate = 0x450D, +// ChapProcessCommand = 0x6911, +// ChapProcessTime = 0x6922, +// ChapProcessData = 0x6933, + //Tagging +// Tags = 0x1254C367, +// Tag = 0x7373, +// Targets = 0x63C0, +// TargetTypeValue = 0x68CA, +// TargetType = 0x63CA, +// Tagging_TrackUID = 0x63C5, +// Tagging_EditionUID = 0x63C9, +// Tagging_ChapterUID = 0x63C4, +// AttachmentUID = 0x63C6, +// SimpleTag = 0x67C8, +// TagName = 0x45A3, +// TagLanguage = 0x447A, +// TagDefault = 0x4484, +// TagString = 0x4487, +// TagBinary = 0x4485, +}; +#endif diff --git a/libmkv/EbmlWriter.c b/libmkv/EbmlWriter.c new file mode 100644 index 0000000..fbf2c66 --- /dev/null +++ b/libmkv/EbmlWriter.c @@ -0,0 +1,171 @@ +// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. + + +#include "EbmlWriter.h" +#include +#include +#include +#include +#if defined(_MSC_VER) +#define LITERALU64(n) n +#else +#define LITERALU64(n) n##LLU +#endif + +void Ebml_WriteLen(EbmlGlobal *glob, long long val) +{ + //TODO check and make sure we are not > than 0x0100000000000000LLU + unsigned char size = 8; //size in bytes to output + unsigned long long minVal = LITERALU64(0x00000000000000ff); //mask to compare for byte size + + for (size = 1; size < 8; size ++) + { + if (val < minVal) + break; + + minVal = (minVal << 7); + } + + val |= (LITERALU64(0x000000000000080) << ((size - 1) * 7)); + + Ebml_Serialize(glob, (void *) &val, sizeof(val), size); +} + +void Ebml_WriteString(EbmlGlobal *glob, const char *str) +{ + const size_t size_ = strlen(str); + const unsigned long long size = size_; + Ebml_WriteLen(glob, size); + //TODO: it's not clear from the spec whether the nul terminator + //should be serialized too. For now we omit the null terminator. + Ebml_Write(glob, str, size); +} + +void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr) +{ + const size_t strlen = wcslen(wstr); + + //TODO: it's not clear from the spec whether the nul terminator + //should be serialized too. For now we include it. + const unsigned long long size = strlen; + + Ebml_WriteLen(glob, size); + Ebml_Write(glob, wstr, size); +} + +void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id) +{ + int len; + + if (class_id >= 0x01000000) + len = 4; + else if (class_id >= 0x00010000) + len = 3; + else if (class_id >= 0x00000100) + len = 2; + else + len = 1; + + Ebml_Serialize(glob, (void *)&class_id, sizeof(class_id), len); +} + +void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) +{ + unsigned char sizeSerialized = 8 | 0x80; + Ebml_WriteID(glob, class_id); + Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); + Ebml_Serialize(glob, &ui, sizeof(ui), 8); +} + +void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui) +{ + unsigned char size = 8; //size in bytes to output + unsigned char sizeSerialized = 0; + unsigned long minVal; + + Ebml_WriteID(glob, class_id); + minVal = 0x7fLU; //mask to compare for byte size + + for (size = 1; size < 4; size ++) + { + if (ui < minVal) + { + break; + } + + minVal <<= 7; + } + + sizeSerialized = 0x80 | size; + Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); + Ebml_Serialize(glob, &ui, sizeof(ui), size); +} +//TODO: perhaps this is a poor name for this id serializer helper function +void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long bin) +{ + int size; + for (size=4; size > 1; size--) + { + if (bin & 0x000000ff << ((size-1) * 8)) + break; + } + Ebml_WriteID(glob, class_id); + Ebml_WriteLen(glob, size); + Ebml_WriteID(glob, bin); +} + +void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d) +{ + unsigned char len = 0x88; + + Ebml_WriteID(glob, class_id); + Ebml_Serialize(glob, &len, sizeof(len), 1); + Ebml_Serialize(glob, &d, sizeof(d), 8); +} + +void Ebml_WriteSigned16(EbmlGlobal *glob, short val) +{ + signed long out = ((val & 0x003FFFFF) | 0x00200000) << 8; + Ebml_Serialize(glob, &out, sizeof(out), 3); +} + +void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s) +{ + Ebml_WriteID(glob, class_id); + Ebml_WriteString(glob, s); +} + +void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s) +{ + Ebml_WriteID(glob, class_id); + Ebml_WriteUTF8(glob, s); +} + +void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length) +{ + Ebml_WriteID(glob, class_id); + Ebml_WriteLen(glob, data_length); + Ebml_Write(glob, data, data_length); +} + +void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize) +{ + unsigned char tmp = 0; + unsigned long i = 0; + + Ebml_WriteID(glob, 0xEC); + Ebml_WriteLen(glob, vSize); + + for (i = 0; i < vSize; i++) + { + Ebml_Write(glob, &tmp, 1); + } +} + +//TODO Serialize Date diff --git a/libmkv/EbmlWriter.h b/libmkv/EbmlWriter.h new file mode 100644 index 0000000..324c9bc --- /dev/null +++ b/libmkv/EbmlWriter.h @@ -0,0 +1,38 @@ +#ifndef EBMLWRITER_HPP +#define EBMLWRITER_HPP + +// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. + +//note: you must define write and serialize functions as well as your own EBML_GLOBAL +//These functions MUST be implemented +#include +#include "vpx/vpx_integer.h" + +typedef struct EbmlGlobal EbmlGlobal; +void Ebml_Serialize(EbmlGlobal *glob, const void *, int, unsigned long); +void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long); +///// + + +void Ebml_WriteLen(EbmlGlobal *glob, long long val); +void Ebml_WriteString(EbmlGlobal *glob, const char *str); +void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr); +void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id); +void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui); +void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui); +void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long ui); +void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d); +//TODO make this more generic to signed +void Ebml_WriteSigned16(EbmlGlobal *glob, short val); +void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s); +void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s); +void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length); +void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize); +//TODO need date function +#endif diff --git a/libmkv/Makefile b/libmkv/Makefile new file mode 100644 index 0000000..b53377b --- /dev/null +++ b/libmkv/Makefile @@ -0,0 +1,25 @@ +#Variables +CC=gcc +LINKER=gcc +FLAGS= + + +#Build Targets +EbmlWriter.o: EbmlWriter.c EbmlWriter.h + $(CC) $(FLAGS) -c EbmlWriter.c + +EbmlBufferWriter.o: EbmlBufferWriter.c EbmlBufferWriter.h + $(CC) $(FLAGS) -c EbmlBufferWriter.c + +MkvElement.o: MkvElement.c WebMElement.h + $(CC) $(FLAGS) -c MkvElement.c + +testlibmkv.o: testlibmkv.c + $(CC) $(FLAGS) -c testlibmkv.c + +testlibmkv: testlibmkv.o MkvElement.o EbmlBufferWriter.o EbmlWriter.o + $(LINKER) $(FLAGS) testlibmkv.o MkvElement.o EbmlBufferWriter.o EbmlWriter.o -o testlibmkv + +clean: + rm -rf *.o testlibmkv + \ No newline at end of file diff --git a/libmkv/WebMElement.c b/libmkv/WebMElement.c new file mode 100644 index 0000000..0ef5100 --- /dev/null +++ b/libmkv/WebMElement.c @@ -0,0 +1,220 @@ +// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. + + +#include "EbmlBufferWriter.h" +#include "EbmlIDs.h" +#include "WebMElement.h" +#include + +#define kVorbisPrivateMaxSize 4000 + +void writeHeader(EbmlGlobal *glob) +{ + EbmlLoc start; + Ebml_StartSubElement(glob, &start, EBML); + Ebml_SerializeUnsigned(glob, EBMLVersion, 1); + Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); //EBML Read Version + Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); //EBML Max ID Length + Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); //EBML Max Size Length + Ebml_SerializeString(glob, DocType, "webm"); //Doc Type + Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); //Doc Type Version + Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); //Doc Type Read Version + Ebml_EndSubElement(glob, &start); +} + +void writeSimpleBlock(EbmlGlobal *glob, unsigned char trackNumber, short timeCode, + int isKeyframe, unsigned char lacingFlag, int discardable, + unsigned char *data, unsigned long dataLength) +{ + Ebml_WriteID(glob, SimpleBlock); + unsigned long blockLength = 4 + dataLength; + blockLength |= 0x10000000; //TODO check length < 0x0FFFFFFFF + Ebml_Serialize(glob, &blockLength, sizeof(blockLength), 4); + trackNumber |= 0x80; //TODO check track nubmer < 128 + Ebml_Write(glob, &trackNumber, 1); + //Ebml_WriteSigned16(glob, timeCode,2); //this is 3 bytes + Ebml_Serialize(glob, &timeCode, sizeof(timeCode), 2); + unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable; + Ebml_Write(glob, &flags, 1); + Ebml_Write(glob, data, dataLength); +} + +static UInt64 generateTrackID(unsigned int trackNumber) +{ + UInt64 t = time(NULL) * trackNumber; + UInt64 r = rand(); + r = r << 32; + r += rand(); + UInt64 rval = t ^ r; + return rval; +} + +void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing, + char *codecId, unsigned int pixelWidth, unsigned int pixelHeight, + double frameRate) +{ + EbmlLoc start; + Ebml_StartSubElement(glob, &start, TrackEntry); + Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); + UInt64 trackID = generateTrackID(trackNumber); + Ebml_SerializeUnsigned(glob, TrackUID, trackID); + Ebml_SerializeString(glob, CodecName, "VP8"); //TODO shouldn't be fixed + + Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1 + Ebml_SerializeString(glob, CodecID, codecId); + { + EbmlLoc videoStart; + Ebml_StartSubElement(glob, &videoStart, Video); + Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); + Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); + Ebml_SerializeFloat(glob, FrameRate, frameRate); + Ebml_EndSubElement(glob, &videoStart); //Video + } + Ebml_EndSubElement(glob, &start); //Track Entry +} +void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing, + char *codecId, double samplingFrequency, unsigned int channels, + unsigned char *private, unsigned long privateSize) +{ + EbmlLoc start; + Ebml_StartSubElement(glob, &start, TrackEntry); + Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); + UInt64 trackID = generateTrackID(trackNumber); + Ebml_SerializeUnsigned(glob, TrackUID, trackID); + Ebml_SerializeUnsigned(glob, TrackType, 2); //audio is always 2 + //I am using defaults for thesed required fields + /* Ebml_SerializeUnsigned(glob, FlagEnabled, 1); + Ebml_SerializeUnsigned(glob, FlagDefault, 1); + Ebml_SerializeUnsigned(glob, FlagForced, 1); + Ebml_SerializeUnsigned(glob, FlagLacing, flagLacing);*/ + Ebml_SerializeString(glob, CodecID, codecId); + Ebml_SerializeData(glob, CodecPrivate, private, privateSize); + + Ebml_SerializeString(glob, CodecName, "VORBIS"); //fixed for now + { + EbmlLoc AudioStart; + Ebml_StartSubElement(glob, &AudioStart, Audio); + Ebml_SerializeFloat(glob, SamplingFrequency, samplingFrequency); + Ebml_SerializeUnsigned(glob, Channels, channels); + Ebml_EndSubElement(glob, &AudioStart); + } + Ebml_EndSubElement(glob, &start); +} +void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc* startInfo, unsigned long timeCodeScale, double duration) +{ + Ebml_StartSubElement(ebml, startInfo, Info); + Ebml_SerializeUnsigned(ebml, TimecodeScale, timeCodeScale); + Ebml_SerializeFloat(ebml, Segment_Duration, duration * 1000.0); //Currently fixed to using milliseconds + Ebml_SerializeString(ebml, 0x4D80, "QTmuxingAppLibWebM-0.0.1"); + Ebml_SerializeString(ebml, 0x5741, "QTwritingAppLibWebM-0.0.1"); + Ebml_EndSubElement(ebml, startInfo); +} + +/* +void Mkv_InitializeSegment(Ebml& ebml_out, EbmlLoc& ebmlLoc) +{ + Ebml_StartSubElement(ebml_out, ebmlLoc, 0x18538067); +} + +void Mkv_InitializeSeek(Ebml& ebml_out, EbmlLoc& ebmlLoc) +{ + Ebml_StartSubElement(ebml_out, ebmlLoc, 0x114d9b74); +} +void Mkv_WriteSeekInformation(Ebml& ebml_out, SeekStruct& seekInformation) +{ + EbmlLoc ebmlLoc; + Ebml_StartSubElement(ebml_out, ebmlLoc, 0x4dbb); + Ebml_SerializeString(ebml_out, 0x53ab, seekInformation.SeekID); + Ebml_SerializeUnsigned(ebml_out, 0x53ac, seekInformation.SeekPosition); + Ebml_EndSubElement(ebml_out, ebmlLoc); +} + +void Mkv_WriteSegmentInformation(Ebml& ebml_out, SegmentInformationStruct& segmentInformation) +{ + Ebml_SerializeUnsigned(ebml_out, 0x73a4, segmentInformation.segmentUID); + if (segmentInformation.filename != 0) + Ebml_SerializeString(ebml_out, 0x7384, segmentInformation.filename); + Ebml_SerializeUnsigned(ebml_out, 0x2AD7B1, segmentInformation.TimecodeScale); + Ebml_SerializeUnsigned(ebml_out, 0x4489, segmentInformation.Duration); + //TODO date + Ebml_SerializeWString(ebml_out, 0x4D80, L"MKVMUX"); + Ebml_SerializeWString(ebml_out, 0x5741, segmentInformation.WritingApp); +} + +void Mkv_InitializeTrack(Ebml& ebml_out, EbmlLoc& ebmlLoc) +{ + Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1654AE6B); +} + +static void Mkv_WriteGenericTrackData(Ebml& ebml_out, TrackStruct& track) +{ + Ebml_SerializeUnsigned(ebml_out, 0xD7, track.TrackNumber); + Ebml_SerializeUnsigned(ebml_out, 0x73C5, track.TrackUID); + Ebml_SerializeUnsigned(ebml_out, 0x83, track.TrackType); + Ebml_SerializeUnsigned(ebml_out, 0xB9, track.FlagEnabled ? 1 :0); + Ebml_SerializeUnsigned(ebml_out, 0x88, track.FlagDefault ? 1 :0); + Ebml_SerializeUnsigned(ebml_out, 0x55AA, track.FlagForced ? 1 :0); + if (track.Language != 0) + Ebml_SerializeString(ebml_out, 0x22B59C, track.Language); + if (track.CodecID != 0) + Ebml_SerializeString(ebml_out, 0x86, track.CodecID); + if (track.CodecPrivate != 0) + Ebml_SerializeData(ebml_out, 0x63A2, track.CodecPrivate, track.CodecPrivateLength); + if (track.CodecName != 0) + Ebml_SerializeWString(ebml_out, 0x258688, track.CodecName); +} + +void Mkv_WriteVideoTrack(Ebml& ebml_out, TrackStruct & track, VideoTrackStruct& video) +{ + EbmlLoc trackHeadLoc, videoHeadLoc; + Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE); //start Track + Mkv_WriteGenericTrackData(ebml_out, track); + Ebml_StartSubElement(ebml_out, videoHeadLoc, 0xE0); //start Video + Ebml_SerializeUnsigned(ebml_out, 0x9A, video.FlagInterlaced ? 1 :0); + Ebml_SerializeUnsigned(ebml_out, 0xB0, video.PixelWidth); + Ebml_SerializeUnsigned(ebml_out, 0xBA, video.PixelHeight); + Ebml_SerializeUnsigned(ebml_out, 0x54B0, video.PixelDisplayWidth); + Ebml_SerializeUnsigned(ebml_out, 0x54BA, video.PixelDisplayHeight); + Ebml_SerializeUnsigned(ebml_out, 0x54B2, video.displayUnit); + Ebml_SerializeFloat(ebml_out, 0x2383E3, video.FrameRate); + Ebml_EndSubElement(ebml_out, videoHeadLoc); + Ebml_EndSubElement(ebml_out, trackHeadLoc); + +} + +void Mkv_WriteAudioTrack(Ebml& ebml_out, TrackStruct & track, AudioTrackStruct& video) +{ + EbmlLoc trackHeadLoc, audioHeadLoc; + Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE); + Mkv_WriteGenericTrackData(ebml_out, track); + Ebml_StartSubElement(ebml_out, audioHeadLoc, 0xE0); //start Audio + Ebml_SerializeFloat(ebml_out, 0xB5, video.SamplingFrequency); + Ebml_SerializeUnsigned(ebml_out, 0x9F, video.Channels); + Ebml_SerializeUnsigned(ebml_out, 0x6264, video.BitDepth); + Ebml_EndSubElement(ebml_out, audioHeadLoc); // end audio + Ebml_EndSubElement(ebml_out, trackHeadLoc); +} + +void Mkv_WriteEbmlClusterHead(Ebml& ebml_out, EbmlLoc& ebmlLoc, ClusterHeadStruct & clusterHead) +{ + Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1F43B675); + Ebml_SerializeUnsigned(ebml_out, 0x6264, clusterHead.TimeCode); +} + +void Mkv_WriteSimpleBlockHead(Ebml& ebml_out, EbmlLoc& ebmlLoc, SimpleBlockStruct& block) +{ + Ebml_StartSubElement(ebml_out, ebmlLoc, 0xA3); + Ebml_Write1UInt(ebml_out, block.TrackNumber); + Ebml_WriteSigned16(ebml_out,block.TimeCode); + unsigned char flags = 0x00 | (block.iskey ? 0x80:0x00) | (block.lacing << 1) | block.discardable; + Ebml_Write1UInt(ebml_out, flags); //TODO this may be the wrong function + Ebml_Serialize(ebml_out, block.data, block.dataLength); + Ebml_EndSubElement(ebml_out,ebmlLoc); +} +*/ diff --git a/libmkv/WebMElement.h b/libmkv/WebMElement.h new file mode 100644 index 0000000..b4208f2 --- /dev/null +++ b/libmkv/WebMElement.h @@ -0,0 +1,35 @@ +// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. + + +#ifndef MKV_CONTEXT_HPP +#define MKV_CONTEXT_HPP 1 + +void writeSimpleBock(EbmlGlobal *ebml, unsigned char trackNumber, unsigned short timeCode, + int isKeyframe, unsigned char lacingFlag, int discardable, + unsigned char *data, unsigned long dataLength); + + +// these are helper functions +void writeHeader(EbmlGlobal *ebml); +void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc* startInfo , unsigned long timeCodeScale, double duration); +//this function is a helper only, it assumes a lot of defaults +void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing, + char *codecId, unsigned int pixelWidth, unsigned int pixelHeight, + double frameRate); +void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing, + char *codecId, double samplingFrequency, unsigned int channels, + unsigned char *private, unsigned long privateSize); + +void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode, + int isKeyframe, unsigned char lacingFlag, int discardable, + unsigned char *data, unsigned long dataLength); + + + +#endif \ No newline at end of file diff --git a/libmkv/testlibmkv.c b/libmkv/testlibmkv.c new file mode 100644 index 0000000..7edfc43 --- /dev/null +++ b/libmkv/testlibmkv.c @@ -0,0 +1,63 @@ +// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. + + + +#include "EbmlIDs.h" +#include "EbmlBufferWriter.h" +#include "WebMElement.h" + +#include +int main(int argc, char *argv[]) +{ + //init the datatype we're using for ebml output + unsigned char data[8192]; + EbmlGlobal ebml; + ebml.buf = data; + ebml.offset = 0; + ebml.length = 8192; + + writeHeader(&ebml); + { + EbmlLoc startSegment; + Ebml_StartSubElement(&ebml, &startSegment, Segment); //segment + { + //segment info + EbmlLoc startInfo; + Ebml_StartSubElement(&ebml, &startInfo, Info); + Ebml_SerializeString(&ebml, 0x4D80, "muxingAppLibMkv"); + Ebml_SerializeString(&ebml, 0x5741, "writingAppLibMkv"); + Ebml_EndSubElement(&ebml, &startInfo); + } + + { + EbmlLoc trackStart; + Ebml_StartSubElement(&ebml, &trackStart, Tracks); + writeVideoTrack(&ebml, 1, 1, "V_MS/VFW/FOURCC", 320, 240, 29.97); + //writeAudioTrack(&ebml,2,1, "A_VORBIS", 32000, 1, NULL, 0); + Ebml_EndSubElement(&ebml, &trackStart); + } + + { + EbmlLoc clusterStart; + Ebml_StartSubElement(&ebml, &clusterStart, Cluster); //cluster + Ebml_SerializeUnsigned(&ebml, Timecode, 0); + + unsigned char someData[4] = {1, 2, 3, 4}; + writeSimpleBlock(&ebml, 1, 0, 1, 0, 0, someData, 4); + Ebml_EndSubElement(&ebml, &clusterStart); + } //end cluster + Ebml_EndSubElement(&ebml, &startSegment); + } + + //dump ebml stuff to the file + FILE *file_out = fopen("test.mkv", "wb"); + size_t bytesWritten = fwrite(data, 1, ebml.offset, file_out); + fclose(file_out); + return 0; +} \ No newline at end of file diff --git a/libs.doxy_template b/libs.doxy_template new file mode 100644 index 0000000..02e2902 --- /dev/null +++ b/libs.doxy_template @@ -0,0 +1,1308 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# Doxyfile 1.5.4 + +# 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 a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "WebM VP8 Codec SDK" + +# 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 = docs + +# 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, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +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 java_doc). +# 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 is your file systems +# 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 java_doc-style +# comment as the brief description. If set to NO, the java_doc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# 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 = 4 + +# 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 = + +# 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 + +# 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 make 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 + +# 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 defqault) 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 TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is +# documented as struct with the name of the typedef. So +# typedef struct type_s {} type_t, will appear in the documentation as a struct +# with name type_t. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named type_s. This can typically +# be useful for C code where the coding convention is that all structs are +# typedef'ed and only the typedef is referenced never the struct's name. + +TYPEDEF_HIDES_STRUCT = NO + +#--------------------------------------------------------------------------- +# 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 = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# 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 namespace 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 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 = NO + +# 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_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 + +# 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 define 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 defines 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 + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# 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 , where is the value of +# the FILE_VERSION_FILTER tag, and 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 = + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 + +# This WARN_NO_PARAMDOC option can be abled 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 = NO + +# 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 = + +# 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++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# 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 +# 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. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem 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 , where +# is the value of the INPUT_FILTER tag, and 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, INPUT_FILTER +# is applied to all files. + +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 + +#--------------------------------------------------------------------------- +# 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. If you have enabled CALL_GRAPH or CALLER_GRAPH +# then you must also enable this option. If you don't then doxygen will produce +# a warning and turn it on anyway + +SOURCE_BROWSER = NO + +# 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 and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# 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 (the default) +# 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 documentstion. + +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 = html + +# 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. + +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 +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# 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 compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# 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. For this to work a browser that supports +# java_script and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = 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 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 + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag 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 +# java_script, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# 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 + +#--------------------------------------------------------------------------- +# configuration options related to the la_te_x output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the la_te_x 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 la_te_x command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for la_te_x. 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 +# la_te_x documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = YES + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of la_te_x +# packages that should be included in the la_te_x output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal la_te_x 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 = + +# If the PDF_HYPERLINKS tag is set to YES, the la_te_x 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 = YES + +# 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 = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated la_te_x files. This will instruct la_te_x 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 + +#--------------------------------------------------------------------------- +# 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 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. + +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 = YES + +#--------------------------------------------------------------------------- +# 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 auto_gen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an auto_gen 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 la_te_x 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 = YES + +# 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 +# in the INCLUDE_PATH (see below) will be search if 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 = *.h + +# 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 = + +# 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. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all 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. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# 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 la_te_x) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. 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 = NO + +# 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 +# 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 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, SOURCE_BROWSER and HAVE_DOT tags 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 = NO + +# If the CALLER_GRAPH, SOURCE_BROWSER 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 graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES 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 png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# 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 MAX_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 +# MAX_DOT_GRAPH_NOTES 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 = 50 + +# 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, which results in a white background. +# 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 = YES + +# 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 = NO + +# 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 + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/libs.mk b/libs.mk new file mode 100644 index 0000000..e2ba737 --- /dev/null +++ b/libs.mk @@ -0,0 +1,437 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +# ARM assembly files are written in RVCT-style. We use some make magic to +# filter those files to allow GCC compilation +ifeq ($(ARCH_ARM),yes) + ASM:=$(if $(filter yes,$(CONFIG_GCC)),.asm.s,.asm) +else + ASM:=.asm +endif + +CODEC_SRCS-yes += CHANGELOG +CODEC_SRCS-yes += libs.mk + +include $(SRC_PATH_BARE)/vpx/vpx_codec.mk +CODEC_SRCS-yes += $(addprefix vpx/,$(call enabled,API_SRCS)) + +include $(SRC_PATH_BARE)/vpx_mem/vpx_mem.mk +CODEC_SRCS-yes += $(addprefix vpx_mem/,$(call enabled,MEM_SRCS)) + +include $(SRC_PATH_BARE)/vpx_scale/vpx_scale.mk +CODEC_SRCS-yes += $(addprefix vpx_scale/,$(call enabled,SCALE_SRCS)) + + +ifeq ($(CONFIG_VP8_ENCODER),yes) + VP8_PREFIX=vp8/ + include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8cx.mk + CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_CX_SRCS)) + CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_CX_EXPORTS)) + CODEC_SRCS-yes += $(VP8_PREFIX)vp8cx.mk vpx/vp8.h vpx/vp8cx.h + CODEC_SRCS-$(ARCH_ARM) += $(VP8_PREFIX)vp8cx_arm.mk + INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h + INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/% + CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h + CODEC_DOC_SECTIONS += vp8 vp8_encoder +endif + +ifeq ($(CONFIG_VP8_DECODER),yes) + VP8_PREFIX=vp8/ + include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8dx.mk + CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_DX_SRCS)) + CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_DX_EXPORTS)) + CODEC_SRCS-yes += $(VP8_PREFIX)vp8dx.mk vpx/vp8.h vpx/vp8dx.h + INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8dx.h + INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/% + CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8dx.h + CODEC_DOC_SECTIONS += vp8 vp8_decoder +endif + + +ifeq ($(CONFIG_ENCODERS),yes) + CODEC_DOC_SECTIONS += encoder +endif +ifeq ($(CONFIG_DECODERS),yes) + CODEC_DOC_SECTIONS += decoder +endif + + +ifeq ($(CONFIG_MSVS),yes) +CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd) +# This variable uses deferred expansion intentionally, since the results of +# $(wildcard) may change during the course of the Make. +VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d)))) +endif + +# The following pairs define a mapping of locations in the distribution +# tree to locations in the source/build trees. +INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/vpx/% +INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/vpx_ports/% +INSTALL_MAPS += $(LIBSUBDIR)/% % +INSTALL_MAPS += src/% $(SRC_PATH_BARE)/% +ifeq ($(CONFIG_MSVS),yes) +INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Release/%) +INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Debug/%) +endif + +# If this is a universal (fat) binary, then all the subarchitectures have +# already been built and our job is to stitch them together. The +# BUILD_LIBVPX variable indicates whether we should be building +# (compiling, linking) the library. The LIPO_LIBVPX variable indicates +# that we're stitching. +$(eval $(if $(filter universal%,$(TOOLCHAIN)),LIPO_LIBVPX,BUILD_LIBVPX):=yes) + +CODEC_SRCS-$(BUILD_LIBVPX) += build/make/version.sh +CODEC_SRCS-$(BUILD_LIBVPX) += build/make/rtcd.sh +CODEC_SRCS-$(BUILD_LIBVPX) += vpx/vpx_integer.h +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/asm_offsets.h +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/vpx_timer.h +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/mem.h +CODEC_SRCS-$(BUILD_LIBVPX) += $(BUILD_PFX)vpx_config.c +INSTALL-SRCS-no += $(BUILD_PFX)vpx_config.c +ifeq ($(ARCH_X86)$(ARCH_X86_64),yes) +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/emms.asm +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/x86.h +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/x86_abi_support.asm +CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/x86_cpuid.c +endif +CODEC_SRCS-$(ARCH_ARM) += vpx_ports/arm_cpudetect.c +CODEC_SRCS-$(ARCH_ARM) += vpx_ports/arm.h +CODEC_EXPORTS-$(BUILD_LIBVPX) += vpx/exports_com +CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc +CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec + +INSTALL-LIBS-yes += include/vpx/vpx_codec.h +INSTALL-LIBS-yes += include/vpx/vpx_image.h +INSTALL-LIBS-yes += include/vpx/vpx_integer.h +INSTALL-LIBS-yes += include/vpx/vpx_codec_impl_top.h +INSTALL-LIBS-yes += include/vpx/vpx_codec_impl_bottom.h +INSTALL-LIBS-$(CONFIG_DECODERS) += include/vpx/vpx_decoder.h +INSTALL-LIBS-$(CONFIG_ENCODERS) += include/vpx/vpx_encoder.h +ifeq ($(CONFIG_EXTERNAL_BUILD),yes) +ifeq ($(CONFIG_MSVS),yes) +INSTALL-LIBS-yes += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/$(CODEC_LIB).lib) +INSTALL-LIBS-$(CONFIG_DEBUG_LIBS) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/$(CODEC_LIB)d.lib) +INSTALL-LIBS-$(CONFIG_SHARED) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/vpx.dll) +INSTALL-LIBS-$(CONFIG_SHARED) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/vpx.exp) +endif +else +INSTALL-LIBS-$(CONFIG_STATIC) += $(LIBSUBDIR)/libvpx.a +INSTALL-LIBS-$(CONFIG_DEBUG_LIBS) += $(LIBSUBDIR)/libvpx_g.a +endif + +CODEC_SRCS=$(filter-out %_test.cc,$(call enabled,CODEC_SRCS)) +INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(CODEC_SRCS) +INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(call enabled,CODEC_EXPORTS) + + +# Generate a list of all enabled sources, in particular for exporting to gyp +# based build systems. +libvpx_srcs.txt: + @echo " [CREATE] $@" + @echo $(CODEC_SRCS) | xargs -n1 echo | sort -u > $@ + + +ifeq ($(CONFIG_EXTERNAL_BUILD),yes) +ifeq ($(CONFIG_MSVS),yes) + +obj_int_extract.vcproj: $(SRC_PATH_BARE)/build/make/obj_int_extract.c + @cp $(SRC_PATH_BARE)/build/x86-msvs/obj_int_extract.bat . + @echo " [CREATE] $@" + $(SRC_PATH_BARE)/build/make/gen_msvs_proj.sh \ + --exe \ + --target=$(TOOLCHAIN) \ + --name=obj_int_extract \ + --ver=$(CONFIG_VS_VERSION) \ + --proj-guid=E1360C65-D375-4335-8057-7ED99CC3F9B2 \ + $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \ + --out=$@ $^ \ + -I. \ + -I"$(SRC_PATH_BARE)" \ + +PROJECTS-$(BUILD_LIBVPX) += obj_int_extract.vcproj +PROJECTS-$(BUILD_LIBVPX) += obj_int_extract.bat + +vpx.def: $(call enabled,CODEC_EXPORTS) + @echo " [CREATE] $@" + $(SRC_PATH_BARE)/build/make/gen_msvs_def.sh\ + --name=vpx\ + --out=$@ $^ +CLEAN-OBJS += vpx.def + +vpx.vcproj: $(CODEC_SRCS) vpx.def + @echo " [CREATE] $@" + $(SRC_PATH_BARE)/build/make/gen_msvs_proj.sh \ + --lib \ + --target=$(TOOLCHAIN) \ + $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \ + --name=vpx \ + --proj-guid=DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74 \ + --module-def=vpx.def \ + --ver=$(CONFIG_VS_VERSION) \ + --out=$@ $(CFLAGS) $^ \ + --src-path-bare="$(SRC_PATH_BARE)" \ + +PROJECTS-$(BUILD_LIBVPX) += vpx.vcproj + +vpx.vcproj: vpx_config.asm +vpx.vcproj: vpx_rtcd.h + +endif +else +LIBVPX_OBJS=$(call objs,$(CODEC_SRCS)) +OBJS-$(BUILD_LIBVPX) += $(LIBVPX_OBJS) +LIBS-$(if $(BUILD_LIBVPX),$(CONFIG_STATIC)) += $(BUILD_PFX)libvpx.a $(BUILD_PFX)libvpx_g.a +$(BUILD_PFX)libvpx_g.a: $(LIBVPX_OBJS) + +BUILD_LIBVPX_SO := $(if $(BUILD_LIBVPX),$(CONFIG_SHARED)) +LIBVPX_SO := libvpx.so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) +LIBS-$(BUILD_LIBVPX_SO) += $(BUILD_PFX)$(LIBVPX_SO)\ + $(notdir $(LIBVPX_SO_SYMLINKS)) +$(BUILD_PFX)$(LIBVPX_SO): $(LIBVPX_OBJS) libvpx.ver +$(BUILD_PFX)$(LIBVPX_SO): extralibs += -lm +$(BUILD_PFX)$(LIBVPX_SO): SONAME = libvpx.so.$(VERSION_MAJOR) +$(BUILD_PFX)$(LIBVPX_SO): SO_VERSION_SCRIPT = libvpx.ver +LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \ + libvpx.so libvpx.so.$(VERSION_MAJOR) \ + libvpx.so.$(VERSION_MAJOR).$(VERSION_MINOR)) + +libvpx.ver: $(call enabled,CODEC_EXPORTS) + @echo " [CREATE] $@" + $(qexec)echo "{ global:" > $@ + $(qexec)for f in $?; do awk '{print $$2";"}' < $$f >>$@; done + $(qexec)echo "local: *; };" >> $@ +CLEAN-OBJS += libvpx.ver + +define libvpx_symlink_template +$(1): $(2) + @echo " [LN] $$@" + $(qexec)ln -sf $(LIBVPX_SO) $$@ +endef + +$(eval $(call libvpx_symlink_template,\ + $(addprefix $(BUILD_PFX),$(notdir $(LIBVPX_SO_SYMLINKS))),\ + $(BUILD_PFX)$(LIBVPX_SO))) +$(eval $(call libvpx_symlink_template,\ + $(addprefix $(DIST_DIR)/,$(LIBVPX_SO_SYMLINKS)),\ + $(DIST_DIR)/$(LIBSUBDIR)/$(LIBVPX_SO))) + +INSTALL-LIBS-$(CONFIG_SHARED) += $(LIBVPX_SO_SYMLINKS) +INSTALL-LIBS-$(CONFIG_SHARED) += $(LIBSUBDIR)/$(LIBVPX_SO) + +LIBS-$(BUILD_LIBVPX) += vpx.pc +vpx.pc: config.mk libs.mk + @echo " [CREATE] $@" + $(qexec)echo '# pkg-config file from libvpx $(VERSION_STRING)' > $@ + $(qexec)echo 'prefix=$(PREFIX)' >> $@ + $(qexec)echo 'exec_prefix=$${prefix}' >> $@ + $(qexec)echo 'libdir=$${prefix}/$(LIBSUBDIR)' >> $@ + $(qexec)echo 'includedir=$${prefix}/include' >> $@ + $(qexec)echo '' >> $@ + $(qexec)echo 'Name: vpx' >> $@ + $(qexec)echo 'Description: WebM Project VPx codec implementation' >> $@ + $(qexec)echo 'Version: $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)' >> $@ + $(qexec)echo 'Requires:' >> $@ + $(qexec)echo 'Conflicts:' >> $@ + $(qexec)echo 'Libs: -L$${libdir} -lvpx' >> $@ + $(qexec)echo 'Cflags: -I$${includedir}' >> $@ +INSTALL-LIBS-yes += $(LIBSUBDIR)/pkgconfig/vpx.pc +INSTALL_MAPS += $(LIBSUBDIR)/pkgconfig/%.pc %.pc +CLEAN-OBJS += vpx.pc +endif + +LIBS-$(LIPO_LIBVPX) += libvpx.a +$(eval $(if $(LIPO_LIBVPX),$(call lipo_lib_template,libvpx.a))) + +# +# Rule to make assembler configuration file from C configuration file +# +ifeq ($(ARCH_X86)$(ARCH_X86_64),yes) +# YASM +$(BUILD_PFX)vpx_config.asm: $(BUILD_PFX)vpx_config.h + @echo " [CREATE] $@" + @egrep "#define [A-Z0-9_]+ [01]" $< \ + | awk '{print $$2 " equ " $$3}' > $@ +else +ADS2GAS=$(if $(filter yes,$(CONFIG_GCC)),| $(ASM_CONVERSION)) +$(BUILD_PFX)vpx_config.asm: $(BUILD_PFX)vpx_config.h + @echo " [CREATE] $@" + @egrep "#define [A-Z0-9_]+ [01]" $< \ + | awk '{print $$2 " EQU " $$3}' $(ADS2GAS) > $@ + @echo " END" $(ADS2GAS) >> $@ +CLEAN-OBJS += $(BUILD_PFX)vpx_config.asm +endif + +# +# Add assembler dependencies for configuration and offsets +# +$(filter %.s.o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm +$(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm + +# +# Calculate platform- and compiler-specific offsets for hand coded assembly +# + +OFFSET_PATTERN:='^[a-zA-Z0-9_]* EQU' + +ifeq ($(filter icc gcc,$(TGT_CC)), $(TGT_CC)) + $(BUILD_PFX)asm_com_offsets.asm: $(BUILD_PFX)$(VP8_PREFIX)common/asm_com_offsets.c.S + LC_ALL=C grep $(OFFSET_PATTERN) $< | tr -d '$$\#' $(ADS2GAS) > $@ + $(BUILD_PFX)$(VP8_PREFIX)common/asm_com_offsets.c.S: $(VP8_PREFIX)common/asm_com_offsets.c + CLEAN-OBJS += $(BUILD_PFX)asm_com_offsets.asm $(BUILD_PFX)$(VP8_PREFIX)common/asm_com_offsets.c.S + + $(BUILD_PFX)asm_enc_offsets.asm: $(BUILD_PFX)$(VP8_PREFIX)encoder/asm_enc_offsets.c.S + LC_ALL=C grep $(OFFSET_PATTERN) $< | tr -d '$$\#' $(ADS2GAS) > $@ + $(BUILD_PFX)$(VP8_PREFIX)encoder/asm_enc_offsets.c.S: $(VP8_PREFIX)encoder/asm_enc_offsets.c + CLEAN-OBJS += $(BUILD_PFX)asm_enc_offsets.asm $(BUILD_PFX)$(VP8_PREFIX)encoder/asm_enc_offsets.c.S + + $(BUILD_PFX)asm_dec_offsets.asm: $(BUILD_PFX)$(VP8_PREFIX)decoder/asm_dec_offsets.c.S + LC_ALL=C grep $(OFFSET_PATTERN) $< | tr -d '$$\#' $(ADS2GAS) > $@ + $(BUILD_PFX)$(VP8_PREFIX)decoder/asm_dec_offsets.c.S: $(VP8_PREFIX)decoder/asm_dec_offsets.c + CLEAN-OBJS += $(BUILD_PFX)asm_dec_offsets.asm $(BUILD_PFX)$(VP8_PREFIX)decoder/asm_dec_offsets.c.S +else + ifeq ($(filter rvct,$(TGT_CC)), $(TGT_CC)) + asm_com_offsets.asm: obj_int_extract + asm_com_offsets.asm: $(VP8_PREFIX)common/asm_com_offsets.c.o + ./obj_int_extract rvds $< $(ADS2GAS) > $@ + OBJS-yes += $(VP8_PREFIX)common/asm_com_offsets.c.o + CLEAN-OBJS += asm_com_offsets.asm + $(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)asm_com_offsets.asm + + asm_enc_offsets.asm: obj_int_extract + asm_enc_offsets.asm: $(VP8_PREFIX)encoder/asm_enc_offsets.c.o + ./obj_int_extract rvds $< $(ADS2GAS) > $@ + OBJS-yes += $(VP8_PREFIX)encoder/asm_enc_offsets.c.o + CLEAN-OBJS += asm_enc_offsets.asm + $(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)asm_enc_offsets.asm + + asm_dec_offsets.asm: obj_int_extract + asm_dec_offsets.asm: $(VP8_PREFIX)decoder/asm_dec_offsets.c.o + ./obj_int_extract rvds $< $(ADS2GAS) > $@ + OBJS-yes += $(VP8_PREFIX)decoder/asm_dec_offsets.c.o + CLEAN-OBJS += asm_dec_offsets.asm + $(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)asm_dec_offsets.asm + endif +endif + +$(shell $(SRC_PATH_BARE)/build/make/version.sh "$(SRC_PATH_BARE)" $(BUILD_PFX)vpx_version.h) +CLEAN-OBJS += $(BUILD_PFX)vpx_version.h + +# +# Rule to generate runtime cpu detection files +# +$(OBJS-yes:.o=.d): $(BUILD_PFX)vpx_rtcd.h +$(BUILD_PFX)vpx_rtcd.h: $(SRC_PATH_BARE)/$(sort $(filter %rtcd_defs.sh,$(CODEC_SRCS))) + @echo " [CREATE] $@" + $(qexec)$(SRC_PATH_BARE)/build/make/rtcd.sh --arch=$(TGT_ISA) \ + --sym=vpx_rtcd \ + --config=$(target)$(if $(FAT_ARCHS),,-$(TOOLCHAIN)).mk \ + $(RTCD_OPTIONS) $^ > $@ +CLEAN-OBJS += $(BUILD_PFX)vpx_rtcd.h + +CODEC_DOC_SRCS += vpx/vpx_codec.h \ + vpx/vpx_decoder.h \ + vpx/vpx_encoder.h \ + vpx/vpx_image.h + +## +## libvpx test directives +## + +ifeq ($(CONFIG_UNIT_TESTS),yes) +ifeq ($(CONFIG_EXTERNAL_BUILD),yes) +ifeq ($(CONFIG_MSVS),yes) + +LIBVPX_TEST_SRCS=$(filter %_test.cc,$(call enabled,CODEC_SRCS)) +LIBVPX_TEST_BINS=$(sort $(LIBVPX_TEST_SRCS:.cc.o=)) + +gtest.vcproj: $(SRC_PATH_BARE)/third_party/googletest/src/src/gtest-all.cc + @echo " [CREATE] $@" + $(SRC_PATH_BARE)/build/make/gen_msvs_proj.sh \ + --lib \ + --target=$(TOOLCHAIN) \ + $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \ + --name=gtest \ + --proj-guid=EC00E1EC-AF68-4D92-A255-181690D1C9B1 \ + --ver=$(CONFIG_VS_VERSION) \ + --src-path-bare="$(SRC_PATH_BARE)" \ + --out=gtest.vcproj $(SRC_PATH_BARE)/third_party/googletest/src/src/gtest-all.cc \ + -I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" -I"$(SRC_PATH_BARE)/third_party/googletest/src" + +PROJECTS-$(CONFIG_MSVS) += gtest.vcproj + +define unit_test_vcproj_template +$(notdir $(1:.cc=.vcproj)): $(SRC_PATH_BARE)/$(1) + @echo " [vcproj] $$@" + $$(SRC_PATH_BARE)/build/make/gen_msvs_proj.sh\ + --exe\ + --target=$$(TOOLCHAIN)\ + --name=$(notdir $(1:.cc=))\ + --ver=$$(CONFIG_VS_VERSION)\ + $$(if $$(CONFIG_STATIC_MSVCRT),--static-crt) \ + --out=$$@ $$(INTERNAL_CFLAGS) $$(CFLAGS) \ + -I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" \ + -L. -lvpxmt -lwinmm -lgtestmt $$^ +endef + +$(foreach proj,$(LIBVPX_TEST_BINS),\ + $(eval $(call unit_test_vcproj_template,$(proj)))) + +PROJECTS-$(CONFIG_MSVS) += $(foreach proj,$(LIBVPX_TEST_BINS),\ + $(notdir $(proj:.cc=.vcproj))) + +test:: + @set -e; for t in $(addprefix Win32/Release/,$(notdir $(LIBVPX_TEST_BINS:.cc=.exe))); do $$t; done +endif +else + +include $(SRC_PATH_BARE)/third_party/googletest/gtest.mk +GTEST_SRCS := $(addprefix third_party/googletest/src/,$(call enabled,GTEST_SRCS)) +GTEST_OBJS=$(call objs,$(GTEST_SRCS)) +$(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src +$(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src/include +OBJS-$(BUILD_LIBVPX) += $(GTEST_OBJS) +LIBS-$(BUILD_LIBVPX) += $(BUILD_PFX)libgtest.a $(BUILD_PFX)libgtest_g.a +$(BUILD_PFX)libgtest_g.a: $(GTEST_OBJS) + +LIBVPX_TEST_SRCS=$(filter %_test.cc,$(call enabled,CODEC_SRCS)) +LIBVPX_TEST_OBJS=$(call objs,$(LIBVPX_TEST_SRCS)) +$(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS:.o=.d): CFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src +$(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS:.o=.d): CFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src/include +LIBVPX_TEST_BINS=$(sort $(LIBVPX_TEST_OBJS:.cc.o=)) +OBJS-$(BUILD_LIBVPX) += $(LIBVPX_TEST_OBJS) + +$(foreach bin,$(LIBVPX_TEST_BINS),\ + $(if $(BUILD_LIBVPX),$(eval $(bin): libvpx.a libgtest.a ))\ + $(if $(BUILD_LIBVPX),$(eval $(call linkerxx_template,$(bin),\ + $(bin).cc.o \ + -L. -lvpx -lgtest -lpthread -lm)\ + )))\ + $(if $(LIPO_LIBS),$(eval $(call lipo_bin_template,$(bin))))\ + +test:: $(LIBVPX_TEST_BINS) + @set -e; for t in $(LIBVPX_TEST_BINS); do $$t; done + +endif +endif + +## +## documentation directives +## +CLEAN-OBJS += libs.doxy +DOCS-yes += libs.doxy +libs.doxy: $(CODEC_DOC_SRCS) + @echo " [CREATE] $@" + @rm -f $@ + @echo "INPUT += $^" >> $@ + @echo "PREDEFINED = VPX_CODEC_DISABLE_COMPAT" >> $@ + @echo "INCLUDE_PATH += ." >> $@; + @echo "ENABLED_SECTIONS += $(sort $(CODEC_DOC_SECTIONS))" >> $@ diff --git a/mainpage.dox b/mainpage.dox new file mode 100644 index 0000000..e2ec280 --- /dev/null +++ b/mainpage.dox @@ -0,0 +1,53 @@ +/*!\mainpage WebM VP8 Codec SDK + + \section main_contents Page Contents + - \ref main_intro + - \ref main_startpoints + - \ref main_support + + \section main_intro Introduction + Welcome to the WebM VP8 Codec SDK. This SDK allows you to integrate your + applications with the VP8 video codec, a high quality, royalty free, open + source codec deployed on millions of computers and devices worldwide. + + This distribution of the WebM VP8 Codec SDK includes the following support: + + \if vp8_encoder + - \ref vp8_encoder + \endif + \if vp8_decoder + - \ref vp8_decoder + \endif + + + \section main_startpoints Starting Points + - Consult the \ref changelog for a complete list of improvements in this + release. + - The \ref readme contains instructions on recompiling the sample applications. + - Read the \ref usage "usage" for a narrative on codec usage. + - Read the \ref samples "sample code" for examples of how to interact with the + codec. + - \ref codec reference + \if encoder + - \ref encoder reference + \endif + \if decoder + - \ref decoder reference + \endif + + \section main_support Support Options & FAQ + The WebM project is an open source project supported by its community. For + questions about this SDK, please mail the apps-devel@webmproject.org list. + To contribute, see http://www.webmproject.org/code/contribute and mail + codec-devel@webmproject.org. +*/ + +/*!\page changelog CHANGELOG + \verbinclude CHANGELOG +*/ + +/*!\page readme README + \verbinclude README +*/ + +/*!\defgroup codecs Supported Codecs */ diff --git a/md5_utils.c b/md5_utils.c new file mode 100644 index 0000000..9a584fa --- /dev/null +++ b/md5_utils.c @@ -0,0 +1,251 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions + * - Ian Jackson . + * Still in the public domain. + */ + +#include /* for memcpy() */ + +#include "md5_utils.h" + +void +byteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p; + + /* Only swap bytes for big endian machines */ + int i = 1; + + if (*(char *)&i == 1) + return; + + p = (md5byte *)buf; + + do + { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } + while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + + if (t > len) + { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(md5byte digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) /* Padding forces an extra block */ + { + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/md5_utils.h b/md5_utils.h new file mode 100644 index 0000000..5ca1b5f --- /dev/null +++ b/md5_utils.h @@ -0,0 +1,42 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef MD5_H +#define MD5_H + +#define md5byte unsigned char +#define UWORD32 unsigned int + +typedef struct MD5Context MD5Context; +struct MD5Context +{ + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +#endif /* !MD5_H */ diff --git a/nestegg/.gitignore b/nestegg/.gitignore new file mode 100644 index 0000000..b2ba99c --- /dev/null +++ b/nestegg/.gitignore @@ -0,0 +1,40 @@ +*.lo +*.o +*.swp +*~ +.deps +.dirstamp +.libs +Makefile +Makefile.in +_stdint.h +aclocal.m4 +autom4te.cache +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +docs/Doxyfile +docs/doxygen-build.stamp +docs/html +install-sh +libtool +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +missing +nestegg-uninstalled.pc +nestegg.pc +src/.dirstamp +src/libnestegg.la +stamp-h1 +test/test +include/nestegg/nestegg-stdint.h diff --git a/nestegg/AUTHORS b/nestegg/AUTHORS new file mode 100644 index 0000000..8204f40 --- /dev/null +++ b/nestegg/AUTHORS @@ -0,0 +1 @@ +Matthew Gregan diff --git a/nestegg/INSTALL b/nestegg/INSTALL new file mode 100644 index 0000000..401df41 --- /dev/null +++ b/nestegg/INSTALL @@ -0,0 +1,8 @@ +Build instructions for libnestegg +================================= + +0. Change directory into the source directory. +1. Run |autoreconf --install| to generate configure. +2. Run |./configure| to configure the build. +3. Run |make| to build. +4. Run |make check| to run the test suite. diff --git a/nestegg/LICENSE b/nestegg/LICENSE new file mode 100644 index 0000000..a67984a --- /dev/null +++ b/nestegg/LICENSE @@ -0,0 +1,13 @@ +Copyright © 2010 Mozilla Foundation + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/nestegg/Makefile.am b/nestegg/Makefile.am new file mode 100644 index 0000000..5006991 --- /dev/null +++ b/nestegg/Makefile.am @@ -0,0 +1,51 @@ +AUTOMAKE_OPTIONS = foreign 1.11 no-dist-gzip dist-bzip2 subdir-objects +ACLOCAL_AMFLAGS = -I m4 + +INCLUDES = -I$(top_srcdir)/include -I. -I$(top_srcdir)/halloc +AM_CFLAGS = -ansi -pedantic -Wall -Wextra -Wno-long-long -O0 -g + +SUBDIRS = docs + +EXTRA_DIST = \ + AUTHORS README LICENSE \ + nestegg-uninstalled.pc.in \ + m4/as-ac-expand.m4 \ + m4/pkg.m4 \ + m4/ax_create_stdint_h.m4 \ + halloc/src/halloc.c \ + halloc/halloc.h \ + halloc/src/align.h \ + halloc/src/hlist.h \ + halloc/src/macros.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = nestegg.pc + +nesteggincludedir = $(includedir)/nestegg +nestegginclude_HEADERS = include/nestegg/nestegg.h include/nestegg/nestegg-stdint.h + +lib_LTLIBRARIES = src/libnestegg.la + +src_libnestegg_la_SOURCES = \ + src/nestegg.c \ + halloc/src/halloc.c \ + halloc/halloc.h \ + halloc/src/align.h \ + halloc/src/hlist.h \ + halloc/src/macros.h + +check_PROGRAMS = test/test + +test_test_SOURCES = test/test.c +test_test_LDADD = src/libnestegg.la + +DISTCLEANFILES = include/nestegg/nestegg-stdint.h + +dist-hook: + find $(distdir) -type d -name '.git' | xargs rm -rf + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" diff --git a/nestegg/README b/nestegg/README new file mode 100644 index 0000000..47c8237 --- /dev/null +++ b/nestegg/README @@ -0,0 +1,6 @@ +See INSTALL for build instructions. + +Licensed under an ISC-style license. See LICENSE for details. + +The source under the halloc/ directory is licensed under a BSD license. See +halloc/halloc.h for details. diff --git a/nestegg/TODO b/nestegg/TODO new file mode 100644 index 0000000..bf0cb04 --- /dev/null +++ b/nestegg/TODO @@ -0,0 +1,21 @@ +- Document when read, seek, tell callbacks are used. +- Add an automated testsuite. +- Test (and fix, if necessary) support for unknown sizes. +- Test (and fix, if necessary) support for large files. +- Read past unknown elements rather than seeking. +- Try to handle unknown elements with unknown sizes. +- Formalize handling of default element values. +- Try to resynchronize stream when read_block fails so that failure to parse + a single block can be treated as non-fatal. +- Make logging more useful to API users. +- Avoid reparsing Cues and ignore any SeekHead at end of file. +- Optionally build a Cue index as Clusters are parsed. +- Support seeking without Cues. +- Avoid building a list of Clusters as they are parsed and retain only the + last one parsed. +- Add an asynchronous error code to struct nestegg and ensure that API calls + continue to fail safely one a fatal error has been returned. +- Modify parser/data structures to provide a clean separation. Perhaps the + parser should return a generic tree of nodes that a second pass uses to + initialize the main data structures. +- Use pool allocator for all allocations. diff --git a/nestegg/configure.ac b/nestegg/configure.ac new file mode 100644 index 0000000..70f6e0d --- /dev/null +++ b/nestegg/configure.ac @@ -0,0 +1,124 @@ +dnl ------------------------------------------------ +dnl Initialization and Versioning +dnl ------------------------------------------------ + +AC_INIT(libnestegg,[0.1git]) + +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +AC_CONFIG_MACRO_DIR([m4]) + +AM_CONFIG_HEADER([config.h]) +AC_CONFIG_SRCDIR([src/nestegg.c]) +AM_INIT_AUTOMAKE + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl Library versioning +dnl CURRENT, REVISION, AGE +dnl - library source changed -> increment REVISION +dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0 +dnl - interfaces added -> increment AGE +dnl - interfaces removed -> AGE = 0 + +NESTEGG_CURRENT=0 +NESTEGG_REVISION=0 +NESTEGG_AGE=1 +AC_SUBST(NESTEGG_CURRENT) +AC_SUBST(NESTEGG_REVISION) +AC_SUBST(NESTEGG_AGE) + + +dnl -------------------------------------------------- +dnl Check for programs +dnl -------------------------------------------------- + +dnl save $CFLAGS since AC_PROG_CC likes to insert "-g -O2" +dnl if $CFLAGS is blank +cflags_save="$CFLAGS" +AC_PROG_CC +AC_PROG_CPP +CFLAGS="$cflags_save" + +AM_PROG_CC_C_O +AC_LIBTOOL_WIN32_DLL +AM_PROG_LIBTOOL + +dnl Check for doxygen +AC_ARG_ENABLE([doc], + AS_HELP_STRING([--enable-doc], [Build API documentation]), + [ac_enable_doc=$enableval], [ac_enable_doc=auto]) + +if test "x$ac_enable_doc" != "xno"; then + AC_CHECK_PROG(HAVE_DOXYGEN, doxygen, true, false) + + if test "x$HAVE_DOXYGEN" = "xfalse" -a "x$ac_enable_doc" = "xyes"; then + AC_MSG_ERROR([*** API documentation explicitly requested but Doxygen not found]) + fi +else + HAVE_DOXYGEN=false +fi +AM_CONDITIONAL(HAVE_DOXYGEN,$HAVE_DOXYGEN) +if test $HAVE_DOXYGEN = "false"; then + AC_MSG_WARN([*** doxygen not found, API documentation will not be built]) +fi + +# Generate portable stdint.h replacement +AX_CREATE_STDINT_H(include/nestegg/nestegg-stdint.h) + +# Test whenever ld supports -version-script +AC_PROG_LD +AC_PROG_LD_GNU +AC_MSG_CHECKING([how to control symbol export]) + +dnl -------------------------------------------------- +dnl Do substitutions +dnl -------------------------------------------------- + +AC_SUBST(DEBUG) +AC_SUBST(PROFILE) + +AC_OUTPUT([ + Makefile + docs/Makefile + docs/Doxyfile + nestegg.pc + nestegg-uninstalled.pc +]) + +AS_AC_EXPAND(LIBDIR, ${libdir}) +AS_AC_EXPAND(INCLUDEDIR, ${includedir}) +AS_AC_EXPAND(BINDIR, ${bindir}) +AS_AC_EXPAND(DOCDIR, ${docdir}) + +if test $HAVE_DOXYGEN = "false"; then + doc_build="no" +else + doc_build="yes" +fi + +AC_MSG_RESULT([ +------------------------------------------------------------------------ + $PACKAGE $VERSION: Automatic configuration OK. + + General configuration: + + API Documentation: .......... ${doc_build} + + Installation paths: + + libnestegg: .................. ${LIBDIR} + C header files: .............. ${INCLUDEDIR}/nestegg + Documentation: ............... ${DOCDIR} + + Building: + + Type 'make' to compile $PACKAGE. + + Type 'make install' to install $PACKAGE. + + Example programs will be built but not installed. +------------------------------------------------------------------------ +]) + diff --git a/nestegg/docs/Doxyfile.in b/nestegg/docs/Doxyfile.in new file mode 100644 index 0000000..e0e9249 --- /dev/null +++ b/nestegg/docs/Doxyfile.in @@ -0,0 +1,1551 @@ +# Doxyfile 1.6.2 + +# 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 a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE@ + +# 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 = @VERSION@ + +# 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-Cyrilic, 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 is your file systems +# 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 = + +# 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, C#, 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 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 make 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 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. + +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 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 penality. +# 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 rougly 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 + +#--------------------------------------------------------------------------- +# 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 = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# 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 namespace 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 = NO + +# 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 = NO + +# 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 + +# 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 define 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 defines 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 + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# 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 , where is the value of +# the FILE_VERSION_FILTER tag, and 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. The 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 = + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 + +# This WARN_NO_PARAMDOC option can be abled 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 = @top_srcdir@/include/nestegg + +# 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++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# 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 +# 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. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem 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 , where +# is the value of the INPUT_FILTER tag, and 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, INPUT_FILTER +# is applied to all files. + +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 + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# 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 = NO + +# 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 = NO + +# 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 = html + +# 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. + +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 +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# 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 = NO + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = 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. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# 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 + +# 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 +# Qt Help Project / Custom Filters. + +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. + +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 at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# 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. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# 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 + +# 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 + +# 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 = YES + +# 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 disadvances is 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, a4wide, 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 = + +# 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 = YES + +# 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 = YES + +# 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 + +#--------------------------------------------------------------------------- +# 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 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. + +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 +# in the INCLUDE_PATH (see below) will be search if 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 = + +# 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. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all 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. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# 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 is superseded by the HAVE_DOT option below. This is only a +# fallback. 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 = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need 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 = FreeSans + +# 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 output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +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 +# 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 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 = NO + +# 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 graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES 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 png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# 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 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 = 50 + +# 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 = NO + +# 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/nestegg/docs/Makefile.am b/nestegg/docs/Makefile.am new file mode 100644 index 0000000..42cf8ee --- /dev/null +++ b/nestegg/docs/Makefile.am @@ -0,0 +1,38 @@ +doc_DATA = doxygen-build.stamp + +EXTRA_DIST = Doxyfile.in + +if HAVE_DOXYGEN +doxygen-build.stamp: Doxyfile + doxygen + touch doxygen-build.stamp +else +doxygen-build.stamp: + echo "*** Warning: Doxygen not found; documentation will not be built." + touch doxygen-build.stamp +endif + +dist_docdir = $(distdir)/libnestegg + +dist-hook: + if test -d html; then \ + mkdir $(dist_docdir); \ + echo -n "copying built documenation..."; \ + cp -rp html $(dist_docdir)/html; \ + echo "OK"; \ + fi + + +install-data-local: doxygen-build.stamp + $(mkinstalldirs) $(DESTDIR)$(docdir) + if test -d html; then \ + cp -rp html $(DESTDIR)$(docdir)/html; \ + fi + +uninstall-local: + rm -rf $(DESTDIR)$(docdir) + +clean-local: + if test -d html; then rm -rf html; fi + if test -f doxygen-build.stamp; then rm -f doxygen-build.stamp; fi + diff --git a/nestegg/halloc/README b/nestegg/halloc/README new file mode 100644 index 0000000..380fba2 --- /dev/null +++ b/nestegg/halloc/README @@ -0,0 +1,45 @@ +halloc 1.2.1 +============ + + Hierarchical memory heap interface - an extension to standard + malloc/free interface that simplifies tasks of memory disposal + when allocated structures exhibit hierarchical properties. + + http://swapped.cc/halloc += + To build libhalloc.a with GNU tools run + make + + To install in /usr/include and /usr/lib + make install + + To cleanup the build files + make clean += + halloc-1.2.1 + * fixed a double-free bug in _set_allocator() as per + Matthew Gregan comments + + * switched to using NULL instead of 0 where applicable + + halloc-1.2.0 + * added missing include to halloc.c + + * improved standard compliance thanks to the feedback + received from Stan Tobias. Two things were fixed - + + - hblock_t structure no longer uses zero-sized 'data' + array, which happened to be common, but non-standard + extension; + + - secondly, added the code to test the behaviour of + realloc(ptr, 0). Standard allows it NOT to act as + free(), in which case halloc will use its own version + of allocator calling free() when neccessary. + + halloc-1.1.0 + * initial public release (rewrite of hhmalloc library) + +============================================================================= +Copyright (c) 2004-2010, Alex Pankratov (ap@swapped.cc). All rights reserved. + diff --git a/nestegg/halloc/halloc.h b/nestegg/halloc/halloc.h new file mode 100644 index 0000000..10af4e8 --- /dev/null +++ b/nestegg/halloc/halloc.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. + * + * Hierarchical memory allocator, 1.2.1 + * http://swapped.cc/halloc + */ + +/* + * The program is distributed under terms of BSD license. + * You can obtain the copy of the license by visiting: + * + * http://www.opensource.org/licenses/bsd-license.php + */ + +#ifndef _LIBP_HALLOC_H_ +#define _LIBP_HALLOC_H_ + +#include /* size_t */ + +/* + * Core API + */ +void * halloc (void * block, size_t len); +void hattach(void * block, void * parent); + +/* + * standard malloc/free api + */ +void * h_malloc (size_t len); +void * h_calloc (size_t n, size_t len); +void * h_realloc(void * p, size_t len); +void h_free (void * p); +char * h_strdup (const char * str); + +/* + * the underlying allocator + */ +typedef void * (* realloc_t)(void * ptr, size_t len); + +extern realloc_t halloc_allocator; + +#endif + diff --git a/nestegg/halloc/src/align.h b/nestegg/halloc/src/align.h new file mode 100644 index 0000000..4c6e183 --- /dev/null +++ b/nestegg/halloc/src/align.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. + * + * Hierarchical memory allocator, 1.2.1 + * http://swapped.cc/halloc + */ + +/* + * The program is distributed under terms of BSD license. + * You can obtain the copy of the license by visiting: + * + * http://www.opensource.org/licenses/bsd-license.php + */ + +#ifndef _LIBP_ALIGN_H_ +#define _LIBP_ALIGN_H_ + +/* + * a type with the most strict alignment requirements + */ +union max_align +{ + char c; + short s; + long l; + int i; + float f; + double d; + void * v; + void (*q)(void); +}; + +typedef union max_align max_align_t; + +#endif + diff --git a/nestegg/halloc/src/halloc.c b/nestegg/halloc/src/halloc.c new file mode 100644 index 0000000..38fd6c1 --- /dev/null +++ b/nestegg/halloc/src/halloc.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2004i-2010 Alex Pankratov. All rights reserved. + * + * Hierarchical memory allocator, 1.2.1 + * http://swapped.cc/halloc + */ + +/* + * The program is distributed under terms of BSD license. + * You can obtain the copy of the license by visiting: + * + * http://www.opensource.org/licenses/bsd-license.php + */ + +#include /* realloc */ +#include /* memset & co */ + +#include "../halloc.h" +#include "align.h" +#include "hlist.h" + +/* + * block control header + */ +typedef struct hblock +{ +#ifndef NDEBUG +#define HH_MAGIC 0x20040518L + long magic; +#endif + hlist_item_t siblings; /* 2 pointers */ + hlist_head_t children; /* 1 pointer */ + max_align_t data[1]; /* not allocated, see below */ + +} hblock_t; + +#define sizeof_hblock offsetof(hblock_t, data) + +/* + * + */ +realloc_t halloc_allocator = NULL; + +#define allocator halloc_allocator + +/* + * static methods + */ +static void _set_allocator(void); +static void * _realloc(void * ptr, size_t n); + +static int _relate(hblock_t * b, hblock_t * p); +static void _free_children(hblock_t * p); + +/* + * Core API + */ +void * halloc(void * ptr, size_t len) +{ + hblock_t * p; + + /* set up default allocator */ + if (! allocator) + { + _set_allocator(); + assert(allocator); + } + + /* calloc */ + if (! ptr) + { + if (! len) + return NULL; + + p = allocator(0, len + sizeof_hblock); + if (! p) + return NULL; +#ifndef NDEBUG + p->magic = HH_MAGIC; +#endif + hlist_init(&p->children); + hlist_init_item(&p->siblings); + + return p->data; + } + + p = structof(ptr, hblock_t, data); + assert(p->magic == HH_MAGIC); + + /* realloc */ + if (len) + { + p = allocator(p, len + sizeof_hblock); + if (! p) + return NULL; + + hlist_relink(&p->siblings); + hlist_relink_head(&p->children); + + return p->data; + } + + /* free */ + _free_children(p); + hlist_del(&p->siblings); + allocator(p, 0); + + return NULL; +} + +void hattach(void * block, void * parent) +{ + hblock_t * b, * p; + + if (! block) + { + assert(! parent); + return; + } + + /* detach */ + b = structof(block, hblock_t, data); + assert(b->magic == HH_MAGIC); + + hlist_del(&b->siblings); + + if (! parent) + return; + + /* attach */ + p = structof(parent, hblock_t, data); + assert(p->magic == HH_MAGIC); + + /* sanity checks */ + assert(b != p); /* trivial */ + assert(! _relate(p, b)); /* heavy ! */ + + hlist_add(&p->children, &b->siblings); +} + +/* + * malloc/free api + */ +void * h_malloc(size_t len) +{ + return halloc(0, len); +} + +void * h_calloc(size_t n, size_t len) +{ + void * ptr = halloc(0, len*=n); + return ptr ? memset(ptr, 0, len) : NULL; +} + +void * h_realloc(void * ptr, size_t len) +{ + return halloc(ptr, len); +} + +void h_free(void * ptr) +{ + halloc(ptr, 0); +} + +char * h_strdup(const char * str) +{ + size_t len = strlen(str); + char * ptr = halloc(0, len + 1); + return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL; +} + +/* + * static stuff + */ +static void _set_allocator(void) +{ + void * p; + assert(! allocator); + + /* + * the purpose of the test below is to check the behaviour + * of realloc(ptr, 0), which is defined in the standard + * as an implementation-specific. if it returns zero, + * then it's equivalent to free(). it can however return + * non-zero, in which case it cannot be used for freeing + * memory blocks and we'll need to supply our own version + * + * Thanks to Stan Tobias for pointing this tricky part out. + */ + allocator = realloc; + if (! (p = malloc(1))) + /* hmm */ + return; + + if ((p = realloc(p, 0))) + { + /* realloc cannot be used as free() */ + allocator = _realloc; + free(p); + } +} + +static void * _realloc(void * ptr, size_t n) +{ + /* + * free'ing realloc() + */ + if (n) + return realloc(ptr, n); + free(ptr); + return NULL; +} + +static int _relate(hblock_t * b, hblock_t * p) +{ + hlist_item_t * i; + + if (!b || !p) + return 0; + + /* + * since there is no 'parent' pointer, which would've allowed + * O(log(n)) upward traversal, the check must use O(n) downward + * iteration of the entire hierarchy; and this can be VERY SLOW + */ + hlist_for_each(i, &p->children) + { + hblock_t * q = structof(i, hblock_t, siblings); + if (q == b || _relate(b, q)) + return 1; + } + return 0; +} + +static void _free_children(hblock_t * p) +{ + hlist_item_t * i, * tmp; + +#ifndef NDEBUG + /* + * this catches loops in hierarchy with almost zero + * overhead (compared to _relate() running time) + */ + assert(p && p->magic == HH_MAGIC); + p->magic = 0; +#endif + hlist_for_each_safe(i, tmp, &p->children) + { + hblock_t * q = structof(i, hblock_t, siblings); + _free_children(q); + allocator(q, 0); + } +} + diff --git a/nestegg/halloc/src/hlist.h b/nestegg/halloc/src/hlist.h new file mode 100644 index 0000000..2791f78 --- /dev/null +++ b/nestegg/halloc/src/hlist.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. + * + * Hierarchical memory allocator, 1.2.1 + * http://swapped.cc/halloc + */ + +/* + * The program is distributed under terms of BSD license. + * You can obtain the copy of the license by visiting: + * + * http://www.opensource.org/licenses/bsd-license.php + */ + +#ifndef _LIBP_HLIST_H_ +#define _LIBP_HLIST_H_ + +#include +#include "macros.h" /* static_inline */ + +/* + * weak double-linked list w/ tail sentinel + */ +typedef struct hlist_head hlist_head_t; +typedef struct hlist_item hlist_item_t; + +/* + * + */ +struct hlist_head +{ + hlist_item_t * next; +}; + +struct hlist_item +{ + hlist_item_t * next; + hlist_item_t ** prev; +}; + +/* + * shared tail sentinel + */ +struct hlist_item hlist_null; + +/* + * + */ +#define __hlist_init(h) { &hlist_null } +#define __hlist_init_item(i) { &hlist_null, &(i).next } + +static_inline void hlist_init(hlist_head_t * h); +static_inline void hlist_init_item(hlist_item_t * i); + +/* static_inline void hlist_purge(hlist_head_t * h); */ + +/* static_inline bool_t hlist_empty(const hlist_head_t * h); */ + +/* static_inline hlist_item_t * hlist_head(const hlist_head_t * h); */ + +/* static_inline hlist_item_t * hlist_next(const hlist_item_t * i); */ +/* static_inline hlist_item_t * hlist_prev(const hlist_item_t * i, + const hlist_head_t * h); */ + +static_inline void hlist_add(hlist_head_t * h, hlist_item_t * i); + +/* static_inline void hlist_add_prev(hlist_item_t * l, hlist_item_t * i); */ +/* static_inline void hlist_add_next(hlist_item_t * l, hlist_item_t * i); */ + +static_inline void hlist_del(hlist_item_t * i); + +static_inline void hlist_relink(hlist_item_t * i); +static_inline void hlist_relink_head(hlist_head_t * h); + +#define hlist_for_each(i, h) \ + for (i = (h)->next; i != &hlist_null; i = i->next) + +#define hlist_for_each_safe(i, tmp, h) \ + for (i = (h)->next, tmp = i->next; \ + i!= &hlist_null; \ + i = tmp, tmp = i->next) + +/* + * static + */ +static_inline void hlist_init(hlist_head_t * h) +{ + assert(h); + h->next = &hlist_null; +} + +static_inline void hlist_init_item(hlist_item_t * i) +{ + assert(i); + i->prev = &i->next; + i->next = &hlist_null; +} + +static_inline void hlist_add(hlist_head_t * h, hlist_item_t * i) +{ + hlist_item_t * next; + assert(h && i); + + next = i->next = h->next; + next->prev = &i->next; + h->next = i; + i->prev = &h->next; +} + +static_inline void hlist_del(hlist_item_t * i) +{ + hlist_item_t * next; + assert(i); + + next = i->next; + next->prev = i->prev; + *i->prev = next; + + hlist_init_item(i); +} + +static_inline void hlist_relink(hlist_item_t * i) +{ + assert(i); + *i->prev = i; + i->next->prev = &i->next; +} + +static_inline void hlist_relink_head(hlist_head_t * h) +{ + assert(h); + h->next->prev = &h->next; +} + +#endif + diff --git a/nestegg/halloc/src/macros.h b/nestegg/halloc/src/macros.h new file mode 100644 index 0000000..c36b516 --- /dev/null +++ b/nestegg/halloc/src/macros.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. + * + * Hierarchical memory allocator, 1.2.1 + * http://swapped.cc/halloc + */ + +/* + * The program is distributed under terms of BSD license. + * You can obtain the copy of the license by visiting: + * + * http://www.opensource.org/licenses/bsd-license.php + */ + +#ifndef _LIBP_MACROS_H_ +#define _LIBP_MACROS_H_ + +#include /* offsetof */ + +/* + restore pointer to the structure by a pointer to its field + */ +#define structof(p,t,f) ((t*)(- offsetof(t,f) + (char*)(p))) + +/* + * redefine for the target compiler + */ +#ifdef _WIN32 +#define static_inline static __inline +#else +#define static_inline static __inline__ +#endif + + +#endif + diff --git a/nestegg/include/nestegg/nestegg.h b/nestegg/include/nestegg/nestegg.h new file mode 100644 index 0000000..7447d14 --- /dev/null +++ b/nestegg/include/nestegg/nestegg.h @@ -0,0 +1,292 @@ +/* + * Copyright © 2010 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ +#ifndef NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 +#define NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 + +#include "vpx/vpx_integer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @mainpage + + @section intro Introduction + + This is the documentation fot the libnestegg C API. + libnestegg is a demultiplexing library for Matroska and WebMedia media files. + + @section example Example code + + @code + nestegg * demux_ctx; + nestegg_init(&demux_ctx, io, NULL); + + nestegg_packet * pkt; + while ((r = nestegg_read_packet(demux_ctx, &pkt)) > 0) { + unsigned int track; + + nestegg_packet_track(pkt, &track); + + // This example decodes the first track only. + if (track == 0) { + unsigned int chunk, chunks; + + nestegg_packet_count(pkt, &chunks); + + // Decode each chunk of data. + for (chunk = 0; chunk < chunks; ++chunk) { + unsigned char * data; + size_t data_size; + + nestegg_packet_data(pkt, chunk, &data, &data_size); + + example_codec_decode(codec_ctx, data, data_size); + } + } + + nestegg_free_packet(pkt); + } + + nestegg_destroy(demux_ctx); + @endcode +*/ + + +/** @file + The libnestegg C API. */ + +#define NESTEGG_TRACK_VIDEO 0 /**< Track is of type video. */ +#define NESTEGG_TRACK_AUDIO 1 /**< Track is of type audio. */ + +#define NESTEGG_CODEC_VP8 0 /**< Track uses Google On2 VP8 codec. */ +#define NESTEGG_CODEC_VORBIS 1 /**< Track uses Xiph Vorbis codec. */ + +#define NESTEGG_SEEK_SET 0 /**< Seek offset relative to beginning of stream. */ +#define NESTEGG_SEEK_CUR 1 /**< Seek offset relative to current position in stream. */ +#define NESTEGG_SEEK_END 2 /**< Seek offset relative to end of stream. */ + +#define NESTEGG_LOG_DEBUG 1 /**< Debug level log message. */ +#define NESTEGG_LOG_INFO 10 /**< Informational level log message. */ +#define NESTEGG_LOG_WARNING 100 /**< Warning level log message. */ +#define NESTEGG_LOG_ERROR 1000 /**< Error level log message. */ +#define NESTEGG_LOG_CRITICAL 10000 /**< Critical level log message. */ + +typedef struct nestegg nestegg; /**< Opaque handle referencing the stream state. */ +typedef struct nestegg_packet nestegg_packet; /**< Opaque handle referencing a packet of data. */ + +/** User supplied IO context. */ +typedef struct { + /** User supplied read callback. + @param buffer Buffer to read data into. + @param length Length of supplied buffer in bytes. + @param userdata The #userdata supplied by the user. + @retval 1 Read succeeded. + @retval 0 End of stream. + @retval -1 Error. */ + int (* read)(void * buffer, size_t length, void * userdata); + + /** User supplied seek callback. + @param offset Offset within the stream to seek to. + @param whence Seek direction. One of #NESTEGG_SEEK_SET, + #NESTEGG_SEEK_CUR, or #NESTEGG_SEEK_END. + @param userdata The #userdata supplied by the user. + @retval 0 Seek succeeded. + @retval -1 Error. */ + int (* seek)(int64_t offset, int whence, void * userdata); + + /** User supplied tell callback. + @param userdata The #userdata supplied by the user. + @returns Current position within the stream. + @retval -1 Error. */ + int64_t (* tell)(void * userdata); + + /** User supplied pointer to be passed to the IO callbacks. */ + void * userdata; +} nestegg_io; + +/** Parameters specific to a video track. */ +typedef struct { + unsigned int width; /**< Width of the video frame in pixels. */ + unsigned int height; /**< Height of the video frame in pixels. */ + unsigned int display_width; /**< Display width of the video frame in pixels. */ + unsigned int display_height; /**< Display height of the video frame in pixels. */ + unsigned int crop_bottom; /**< Pixels to crop from the bottom of the frame. */ + unsigned int crop_top; /**< Pixels to crop from the top of the frame. */ + unsigned int crop_left; /**< Pixels to crop from the left of the frame. */ + unsigned int crop_right; /**< Pixels to crop from the right of the frame. */ +} nestegg_video_params; + +/** Parameters specific to an audio track. */ +typedef struct { + double rate; /**< Sampling rate in Hz. */ + unsigned int channels; /**< Number of audio channels. */ + unsigned int depth; /**< Bits per sample. */ +} nestegg_audio_params; + +/** Logging callback function pointer. */ +typedef void (* nestegg_log)(nestegg * context, unsigned int severity, char const * format, ...); + +/** Initialize a nestegg context. During initialization the parser will + read forward in the stream processing all elements until the first + block of media is reached. All track metadata has been processed at this point. + @param context Storage for the new nestegg context. @see nestegg_destroy + @param io User supplied IO context. + @param callback Optional logging callback function pointer. May be NULL. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback); + +/** Destroy a nestegg context and free associated memory. + @param context #nestegg context to be freed. @see nestegg_init */ +void nestegg_destroy(nestegg * context); + +/** Query the duration of the media stream in nanoseconds. + @param context Stream context initialized by #nestegg_init. + @param duration Storage for the queried duration. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_duration(nestegg * context, uint64_t * duration); + +/** Query the tstamp scale of the media stream in nanoseconds. + Timecodes presented by nestegg have been scaled by this value + before presentation to the caller. + @param context Stream context initialized by #nestegg_init. + @param scale Storage for the queried scale factor. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_tstamp_scale(nestegg * context, uint64_t * scale); + +/** Query the number of tracks in the media stream. + @param context Stream context initialized by #nestegg_init. + @param tracks Storage for the queried track count. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_track_count(nestegg * context, unsigned int * tracks); + +/** Seek @a track to @a tstamp. Stream seek will terminate at the earliest + key point in the stream at or before @a tstamp. Other tracks in the + stream will output packets with unspecified but nearby timestamps. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @param tstamp Absolute timestamp in nanoseconds. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_track_seek(nestegg * context, unsigned int track, uint64_t tstamp); + +/** Query the type specified by @a track. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @retval #NESTEGG_TRACK_VIDEO Track type is video. + @retval #NESTEGG_TRACK_AUDIO Track type is audio. + @retval -1 Error. */ +int nestegg_track_type(nestegg * context, unsigned int track); + +/** Query the codec ID specified by @a track. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @retval #NESTEGG_CODEC_VP8 Track codec is VP8. + @retval #NESTEGG_CODEC_VORBIS Track codec is Vorbis. + @retval -1 Error. */ +int nestegg_track_codec_id(nestegg * context, unsigned int track); + +/** Query the number of codec initialization chunks for @a track. Each + chunk of data should be passed to the codec initialization functions in + the order returned. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @param count Storage for the queried chunk count. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_track_codec_data_count(nestegg * context, unsigned int track, + unsigned int * count); + +/** Get a pointer to chunk number @a item of codec initialization data for + @a track. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @param item Zero based chunk item number. + @param data Storage for the queried data pointer. + The data is owned by the #nestegg context. + @param length Storage for the queried data size. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_track_codec_data(nestegg * context, unsigned int track, unsigned int item, + unsigned char ** data, size_t * length); + +/** Query the video parameters specified by @a track. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @param params Storage for the queried video parameters. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_track_video_params(nestegg * context, unsigned int track, + nestegg_video_params * params); + +/** Query the audio parameters specified by @a track. + @param context Stream context initialized by #nestegg_init. + @param track Zero based track number. + @param params Storage for the queried audio parameters. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_track_audio_params(nestegg * context, unsigned int track, + nestegg_audio_params * params); + +/** Read a packet of media data. A packet consists of one or more chunks of + data associated with a single track. nestegg_read_packet should be + called in a loop while the return value is 1 to drive the stream parser + forward. @see nestegg_free_packet + @param context Context returned by #nestegg_init. + @param packet Storage for the returned nestegg_packet. + @retval 1 Additional packets may be read in subsequent calls. + @retval 0 End of stream. + @retval -1 Error. */ +int nestegg_read_packet(nestegg * context, nestegg_packet ** packet); + +/** Destroy a nestegg_packet and free associated memory. + @param packet #nestegg_packet to be freed. @see nestegg_read_packet */ +void nestegg_free_packet(nestegg_packet * packet); + +/** Query the track number of @a packet. + @param packet Packet initialized by #nestegg_read_packet. + @param track Storage for the queried zero based track index. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_packet_track(nestegg_packet * packet, unsigned int * track); + +/** Query the time stamp in nanoseconds of @a packet. + @param packet Packet initialized by #nestegg_read_packet. + @param tstamp Storage for the queried timestamp in nanoseconds. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_packet_tstamp(nestegg_packet * packet, uint64_t * tstamp); + +/** Query the number of data chunks contained in @a packet. + @param packet Packet initialized by #nestegg_read_packet. + @param count Storage for the queried timestamp in nanoseconds. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_packet_count(nestegg_packet * packet, unsigned int * count); + +/** Get a pointer to chunk number @a item of packet data. + @param packet Packet initialized by #nestegg_read_packet. + @param item Zero based chunk item number. + @param data Storage for the queried data pointer. + The data is owned by the #nestegg_packet packet. + @param length Storage for the queried data size. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_packet_data(nestegg_packet * packet, unsigned int item, + unsigned char ** data, size_t * length); + +#ifdef __cplusplus +} +#endif + +#endif /* NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 */ diff --git a/nestegg/m4/as-ac-expand.m4 b/nestegg/m4/as-ac-expand.m4 new file mode 100644 index 0000000..d6c9e33 --- /dev/null +++ b/nestegg/m4/as-ac-expand.m4 @@ -0,0 +1,43 @@ +dnl as-ac-expand.m4 0.2.0 +dnl autostars m4 macro for expanding directories using configure's prefix +dnl thomas@apestaart.org + +dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) +dnl example +dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) +dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local + +AC_DEFUN([AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) diff --git a/nestegg/m4/ax_create_stdint_h.m4 b/nestegg/m4/ax_create_stdint_h.m4 new file mode 100644 index 0000000..228105b --- /dev/null +++ b/nestegg/m4/ax_create_stdint_h.m4 @@ -0,0 +1,695 @@ +dnl @synopsis AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] +dnl +dnl the "ISO C9X: 7.18 Integer types " section requires the +dnl existence of an include file that defines a set of +dnl typedefs, especially uint8_t,int32_t,uintptr_t. Many older +dnl installations will not provide this file, but some will have the +dnl very same definitions in . In other enviroments we can +dnl use the inet-types in which would define the typedefs +dnl int8_t and u_int8_t respectivly. +dnl +dnl This macros will create a local "_stdint.h" or the headerfile given +dnl as an argument. In many cases that file will just "#include +dnl " or "#include ", while in other environments +dnl it will provide the set of basic 'stdint's definitions/typedefs: +dnl +dnl int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t +dnl int_least32_t.. int_fast32_t.. intmax_t +dnl +dnl which may or may not rely on the definitions of other files, or +dnl using the AC_CHECK_SIZEOF macro to determine the actual sizeof each +dnl type. +dnl +dnl if your header files require the stdint-types you will want to +dnl create an installable file mylib-int.h that all your other +dnl installable header may include. So if you have a library package +dnl named "mylib", just use +dnl +dnl AX_CREATE_STDINT_H(mylib-int.h) +dnl +dnl in configure.ac and go to install that very header file in +dnl Makefile.am along with the other headers (mylib.h) - and the +dnl mylib-specific headers can simply use "#include " to +dnl obtain the stdint-types. +dnl +dnl Remember, if the system already had a valid , the +dnl generated file will include it directly. No need for fuzzy +dnl HAVE_STDINT_H things... (oops, GCC 4.2.x has deliberatly disabled +dnl its stdint.h for non-c99 compilation and the c99-mode is not the +dnl default. Therefore this macro will not use the compiler's stdint.h +dnl - please complain to the GCC developers). +dnl +dnl @category C +dnl @author Guido U. Draheim +dnl @version 2006-10-13 +dnl @license GPLWithACException + +AC_DEFUN([AX_CHECK_DATA_MODEL],[ + AC_CHECK_SIZEOF(char) + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(void*) + ac_cv_char_data_model="" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp" + AC_MSG_CHECKING([data model]) + case "$ac_cv_char_data_model/$ac_cv_long_data_model" in + 122/242) ac_cv_data_model="IP16" ; n="standard 16bit machine" ;; + 122/244) ac_cv_data_model="LP32" ; n="standard 32bit machine" ;; + 122/*) ac_cv_data_model="i16" ; n="unusual int16 model" ;; + 124/444) ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;; + 124/488) ac_cv_data_model="LP64" ; n="standard 64bit unixish" ;; + 124/448) ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;; + 124/*) ac_cv_data_model="i32" ; n="unusual int32 model" ;; + 128/888) ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;; + 128/*) ac_cv_data_model="i64" ; n="unusual int64 model" ;; + 222/*2) ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;; + 333/*3) ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;; + 444/*4) ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;; + 666/*6) ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;; + 888/*8) ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;; + 222/*|333/*|444/*|666/*|888/*) : + ac_cv_data_model="iDSP" ; n="unusual dsptype" ;; + *) ac_cv_data_model="none" ; n="very unusual model" ;; + esac + AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)]) +]) + +dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF]) +AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[ +AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ + ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h sys/types.h]) + do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$1],[$1]) break + done + AC_MSG_CHECKING([for stdint uintptr_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[ +AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ + ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h sys/types.h stdint.h]) + do + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$1],[$1]) break + break; + done + AC_MSG_CHECKING([for stdint uint32_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[ +AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ + ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$1],[$1]) break + break; + done + AC_MSG_CHECKING([for stdint u_int32_t]) + ]) +]) + +AC_DEFUN([AX_CREATE_STDINT_H], +[# ------ AX CREATE STDINT H ------------------------------------- +AC_MSG_CHECKING([for stdint types]) +ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` +# try to shortcircuit - if the default include path of the compiler +# can find a "stdint.h" header then we assume that all compilers can. +AC_CACHE_VAL([ac_cv_header_stdint_t],[ +old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" +old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" +old_CFLAGS="$CFLAGS" ; CFLAGS="" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[ac_cv_stdint_result="(assuming C99 compatible system)" + ac_cv_header_stdint_t="stdint.h"; ], +[ac_cv_header_stdint_t=""]) +if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then +CFLAGS="-std=c99" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[AC_MSG_WARN(your GCC compiler has a defunct stdint.h for its default-mode)]) +fi +CXXFLAGS="$old_CXXFLAGS" +CPPFLAGS="$old_CPPFLAGS" +CFLAGS="$old_CFLAGS" ]) + +v="... $ac_cv_header_stdint_h" +if test "$ac_stdint_h" = "stdint.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) +elif test "$ac_stdint_h" = "inttypes.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) +elif test "_$ac_cv_header_stdint_t" = "_" ; then + AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) +else + ac_cv_header_stdint="$ac_cv_header_stdint_t" + AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) +fi + +if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit.. + +dnl .....intro message done, now do a few system checks..... +dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type, +dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW +dnl instead that is triggered with 3 or more arguments (see types.m4) + +inttype_headers=`echo $2 | sed -e 's/,/ /g'` + +ac_cv_stdint_result="(no helpful system typedefs seen)" +AX_CHECK_HEADER_STDINT_X(dnl + stdint.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen uintptr_t$and64 in $i)") + +if test "_$ac_cv_header_stdint_x" = "_" ; then +AX_CHECK_HEADER_STDINT_O(dnl, + inttypes.h sys/inttypes.h stdint.h $inttype_headers, + ac_cv_stdint_result="(seen uint32_t$and64 in $i)") +fi + +if test "_$ac_cv_header_stdint_x" = "_" ; then +if test "_$ac_cv_header_stdint_o" = "_" ; then +AX_CHECK_HEADER_STDINT_U(dnl, + sys/types.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen u_int32_t$and64 in $i)") +fi fi + +dnl if there was no good C99 header file, do some typedef checks... +if test "_$ac_cv_header_stdint_x" = "_" ; then + AC_MSG_CHECKING([for stdint datatype model]) + AC_MSG_RESULT([(..)]) + AX_CHECK_DATA_MODEL +fi + +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_x" +elif test "_$ac_cv_header_stdint_o" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_o" +elif test "_$ac_cv_header_stdint_u" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_u" +else + ac_cv_header_stdint="stddef.h" +fi + +AC_MSG_CHECKING([for extra inttypes in chosen header]) +AC_MSG_RESULT([($ac_cv_header_stdint)]) +dnl see if int_least and int_fast types are present in _this_ header. +unset ac_cv_type_int_least32_t +unset ac_cv_type_int_fast32_t +AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) +AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) +AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) + +fi # shortcircut to system "stdint.h" +# ------------------ PREPARE VARIABLES ------------------------------ +if test "$GCC" = "yes" ; then +ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1` +else +ac_cv_stdint_message="using $CC" +fi + +AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl +$ac_cv_stdint_result]) + +dnl ----------------------------------------------------------------- +# ----------------- DONE inttypes.h checks START header ------------- +AC_CONFIG_COMMANDS([$ac_stdint_h],[ +AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) +ac_stdint=$tmp/_stdint.h + +echo "#ifndef" $_ac_stdint_h >$ac_stdint +echo "#define" $_ac_stdint_h "1" >>$ac_stdint +echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint +echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint +echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint +if test "_$ac_cv_header_stdint_t" != "_" ; then +echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint +echo "#include " >>$ac_stdint +echo "#endif" >>$ac_stdint +echo "#endif" >>$ac_stdint +else + +cat >>$ac_stdint < +#else +#include + +/* .................... configured part ............................ */ + +STDINT_EOF + +echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_header="$ac_cv_header_stdint_x" + echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint +fi + +echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_o" != "_" ; then + ac_header="$ac_cv_header_stdint_o" + echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint +fi + +echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint +if test "_$ac_cv_header_stdint_u" != "_" ; then + ac_header="$ac_cv_header_stdint_u" + echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint +fi + +echo "" >>$ac_stdint + +if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then + echo "#include <$ac_header>" >>$ac_stdint + echo "" >>$ac_stdint +fi fi + +echo "/* which 64bit typedef has been found */" >>$ac_stdint +if test "$ac_cv_type_uint64_t" = "yes" ; then +echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint +fi +if test "$ac_cv_type_u_int64_t" = "yes" ; then +echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* which type model has been detected */" >>$ac_stdint +if test "_$ac_cv_char_data_model" != "_" ; then +echo "#define _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint +echo "#define _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint +else +echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint +echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* whether int_least types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_least32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint +fi +echo "/* whether int_fast types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_fast32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint +fi +echo "/* whether intmax_t type was detected */" >>$ac_stdint +if test "$ac_cv_type_intmax_t" = "yes"; then +echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + + cat >>$ac_stdint <= 199901L +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#elif !defined __STRICT_ANSI__ +#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ +#define _HAVE_UINT64_T +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ +/* note: all ELF-systems seem to have loff-support which needs 64-bit */ +#if !defined _NO_LONGLONG +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +#elif defined __alpha || (defined __mips && defined _ABIN32) +#if !defined _NO_LONGLONG +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + /* compiler/cpu type to define int64_t */ +#endif +#endif +#endif + +#if defined _STDINT_HAVE_U_INT_TYPES +/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; + +/* glibc compatibility */ +#ifndef __int8_t_defined +#define __int8_t_defined +#endif +#endif + +#ifdef _STDINT_NEED_INT_MODEL_T +/* we must guess all the basic types. Apart from byte-adressable system, */ +/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ +/* (btw, those nibble-addressable systems are way off, or so we assume) */ + +dnl /* have a look at "64bit and data size neutrality" at */ +dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ +dnl /* (the shorthand "ILP" types always have a "P" part) */ + +#if defined _STDINT_BYTE_MODEL +#if _STDINT_LONG_MODEL+0 == 242 +/* 2:4:2 = IP16 = a normal 16-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 +/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ +/* 4:4:4 = ILP32 = a normal 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 +/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ +/* 4:8:8 = LP64 = a normal 64-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* this system has a "long" of 64bit */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +typedef unsigned long uint64_t; +typedef long int64_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 448 +/* LLP64 a 64-bit system derived from a 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* assuming the system has a "long long" */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef unsigned long long uint64_t; +typedef long long int64_t; +#endif +#else +#define _STDINT_NO_INT32_T +#endif +#else +#define _STDINT_NO_INT8_T +#define _STDINT_NO_INT32_T +#endif +#endif + +/* + * quote from SunOS-5.8 sys/inttypes.h: + * Use at your own risk. As of February 1996, the committee is squarely + * behind the fixed sized types; the "least" and "fast" types are still being + * discussed. The probability that the "fast" types may be removed before + * the standard is finalized is high enough that they are not currently + * implemented. + */ + +#if defined _STDINT_NEED_INT_LEAST_T +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_least64_t; +#endif + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_least64_t; +#endif + /* least types */ +#endif + +#if defined _STDINT_NEED_INT_FAST_T +typedef int8_t int_fast8_t; +typedef int int_fast16_t; +typedef int32_t int_fast32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_fast64_t; +#endif + +typedef uint8_t uint_fast8_t; +typedef unsigned uint_fast16_t; +typedef uint32_t uint_fast32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_fast64_t; +#endif + /* fast types */ +#endif + +#ifdef _STDINT_NEED_INTMAX_T +#ifdef _HAVE_UINT64_T +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; +#else +typedef long intmax_t; +typedef unsigned long uintmax_t; +#endif +#endif + +#ifdef _STDINT_NEED_INTPTR_T +#ifndef __intptr_t_defined +#define __intptr_t_defined +/* we encourage using "long" to store pointer values, never use "int" ! */ +#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 +typedef unsigned int uintptr_t; +typedef int intptr_t; +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 +typedef unsigned long uintptr_t; +typedef long intptr_t; +#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T +typedef uint64_t uintptr_t; +typedef int64_t intptr_t; +#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ +typedef unsigned long uintptr_t; +typedef long intptr_t; +#endif +#endif +#endif + +/* The ISO C99 standard specifies that in C++ implementations these + should only be defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS +#ifndef UINT32_C + +/* Signed. */ +# define INT8_C(c) c +# define INT16_C(c) c +# define INT32_C(c) c +# ifdef _HAVE_LONGLONG_UINT64_T +# define INT64_C(c) c ## L +# else +# define INT64_C(c) c ## LL +# endif + +/* Unsigned. */ +# define UINT8_C(c) c ## U +# define UINT16_C(c) c ## U +# define UINT32_C(c) c ## U +# ifdef _HAVE_LONGLONG_UINT64_T +# define UINT64_C(c) c ## UL +# else +# define UINT64_C(c) c ## ULL +# endif + +/* Maximal type. */ +# ifdef _HAVE_LONGLONG_UINT64_T +# define INTMAX_C(c) c ## L +# define UINTMAX_C(c) c ## UL +# else +# define INTMAX_C(c) c ## LL +# define UINTMAX_C(c) c ## ULL +# endif + + /* literalnumbers */ +#endif +#endif + +/* These limits are merily those of a two complement byte-oriented system */ + +/* Minimum of signed integral types. */ +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types. */ +# define UINT8_MAX (255) +# define UINT16_MAX (65535) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (__UINT64_C(18446744073709551615)) + +/* Minimum of signed integral types having a minimum size. */ +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# define INT_LEAST64_MIN INT64_MIN +/* Maximum of signed integral types having a minimum size. */ +# define INT_LEAST8_MAX INT8_MAX +# define INT_LEAST16_MAX INT16_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST64_MAX INT64_MAX + +/* Maximum of unsigned integral types having a minimum size. */ +# define UINT_LEAST8_MAX UINT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define UINT_LEAST64_MAX UINT64_MAX + + /* shortcircuit*/ +#endif + /* once */ +#endif +#endif +STDINT_EOF +fi + if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then + AC_MSG_NOTICE([$ac_stdint_h is unchanged]) + else + ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` + AS_MKDIR_P(["$ac_dir"]) + rm -f $ac_stdint_h + mv $ac_stdint $ac_stdint_h + fi +],[# variables for create stdint.h replacement +PACKAGE="$PACKAGE" +VERSION="$VERSION" +ac_stdint_h="$ac_stdint_h" +_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) +ac_cv_stdint_message="$ac_cv_stdint_message" +ac_cv_header_stdint_t="$ac_cv_header_stdint_t" +ac_cv_header_stdint_x="$ac_cv_header_stdint_x" +ac_cv_header_stdint_o="$ac_cv_header_stdint_o" +ac_cv_header_stdint_u="$ac_cv_header_stdint_u" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_char_data_model="$ac_cv_char_data_model" +ac_cv_long_data_model="$ac_cv_long_data_model" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_type_intmax_t="$ac_cv_type_intmax_t" +]) +]) diff --git a/nestegg/m4/pkg.m4 b/nestegg/m4/pkg.m4 new file mode 100644 index 0000000..996e294 --- /dev/null +++ b/nestegg/m4/pkg.m4 @@ -0,0 +1,157 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + if test -n "$$1"; then + pkg_cv_[]$1="$$1" + else + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + fi +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [AC_MSG_RESULT([no]) + $4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/nestegg/nestegg-uninstalled.pc.in b/nestegg/nestegg-uninstalled.pc.in new file mode 100644 index 0000000..19bb680 --- /dev/null +++ b/nestegg/nestegg-uninstalled.pc.in @@ -0,0 +1,13 @@ +# nestegg uninstalled pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: nestegg +Description: WebM/Matroska demuxer +Version: @VERSION@ +Conflicts: +Libs: -L${libdir} -lnestegg +Cflags: -I${includedir} diff --git a/nestegg/nestegg.pc.in b/nestegg/nestegg.pc.in new file mode 100644 index 0000000..32c09d7 --- /dev/null +++ b/nestegg/nestegg.pc.in @@ -0,0 +1,13 @@ +# nestegg installed pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: nestegg +Description: WebM/Matroska demuxer +Version: @VERSION@ +Conflicts: +Libs: -L${libdir} -lnestegg +Cflags: -I${includedir} diff --git a/nestegg/src/nestegg.c b/nestegg/src/nestegg.c new file mode 100644 index 0000000..63a0e83 --- /dev/null +++ b/nestegg/src/nestegg.c @@ -0,0 +1,1938 @@ +/* + * Copyright © 2010 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ +#include +#include +#include + +#include "nestegg/halloc/halloc.h" +#include "nestegg/include/nestegg/nestegg.h" + +/* EBML Elements */ +#define ID_EBML 0x1a45dfa3 +#define ID_EBML_VERSION 0x4286 +#define ID_EBML_READ_VERSION 0x42f7 +#define ID_EBML_MAX_ID_LENGTH 0x42f2 +#define ID_EBML_MAX_SIZE_LENGTH 0x42f3 +#define ID_DOCTYPE 0x4282 +#define ID_DOCTYPE_VERSION 0x4287 +#define ID_DOCTYPE_READ_VERSION 0x4285 + +/* Global Elements */ +#define ID_VOID 0xec +#define ID_CRC32 0xbf + +/* WebMedia Elements */ +#define ID_SEGMENT 0x18538067 + +/* Seek Head Elements */ +#define ID_SEEK_HEAD 0x114d9b74 +#define ID_SEEK 0x4dbb +#define ID_SEEK_ID 0x53ab +#define ID_SEEK_POSITION 0x53ac + +/* Info Elements */ +#define ID_INFO 0x1549a966 +#define ID_TIMECODE_SCALE 0x2ad7b1 +#define ID_DURATION 0x4489 + +/* Cluster Elements */ +#define ID_CLUSTER 0x1f43b675 +#define ID_TIMECODE 0xe7 +#define ID_BLOCK_GROUP 0xa0 +#define ID_SIMPLE_BLOCK 0xa3 + +/* BlockGroup Elements */ +#define ID_BLOCK 0xa1 +#define ID_BLOCK_DURATION 0x9b +#define ID_REFERENCE_BLOCK 0xfb + +/* Tracks Elements */ +#define ID_TRACKS 0x1654ae6b +#define ID_TRACK_ENTRY 0xae +#define ID_TRACK_NUMBER 0xd7 +#define ID_TRACK_UID 0x73c5 +#define ID_TRACK_TYPE 0x83 +#define ID_FLAG_ENABLED 0xb9 +#define ID_FLAG_DEFAULT 0x88 +#define ID_FLAG_LACING 0x9c +#define ID_TRACK_TIMECODE_SCALE 0x23314f +#define ID_LANGUAGE 0x22b59c +#define ID_CODEC_ID 0x86 +#define ID_CODEC_PRIVATE 0x63a2 + +/* Video Elements */ +#define ID_VIDEO 0xe0 +#define ID_PIXEL_WIDTH 0xb0 +#define ID_PIXEL_HEIGHT 0xba +#define ID_PIXEL_CROP_BOTTOM 0x54aa +#define ID_PIXEL_CROP_TOP 0x54bb +#define ID_PIXEL_CROP_LEFT 0x54cc +#define ID_PIXEL_CROP_RIGHT 0x54dd +#define ID_DISPLAY_WIDTH 0x54b0 +#define ID_DISPLAY_HEIGHT 0x54ba + +/* Audio Elements */ +#define ID_AUDIO 0xe1 +#define ID_SAMPLING_FREQUENCY 0xb5 +#define ID_CHANNELS 0x9f +#define ID_BIT_DEPTH 0x6264 + +/* Cues Elements */ +#define ID_CUES 0x1c53bb6b +#define ID_CUE_POINT 0xbb +#define ID_CUE_TIME 0xb3 +#define ID_CUE_TRACK_POSITIONS 0xb7 +#define ID_CUE_TRACK 0xf7 +#define ID_CUE_CLUSTER_POSITION 0xf1 +#define ID_CUE_BLOCK_NUMBER 0x5378 + +/* EBML Types */ +enum ebml_type_enum { + TYPE_UNKNOWN, + TYPE_MASTER, + TYPE_UINT, + TYPE_FLOAT, + TYPE_INT, + TYPE_STRING, + TYPE_BINARY +}; + +#define LIMIT_STRING (1 << 20) +#define LIMIT_BINARY (1 << 24) +#define LIMIT_BLOCK (1 << 30) +#define LIMIT_FRAME (1 << 28) + +/* Field Flags */ +#define DESC_FLAG_NONE 0 +#define DESC_FLAG_MULTI (1 << 0) +#define DESC_FLAG_SUSPEND (1 << 1) +#define DESC_FLAG_OFFSET (1 << 2) + +/* Block Header Flags */ +#define BLOCK_FLAGS_LACING 6 + +/* Lacing Constants */ +#define LACING_NONE 0 +#define LACING_XIPH 1 +#define LACING_FIXED 2 +#define LACING_EBML 3 + +/* Track Types */ +#define TRACK_TYPE_VIDEO 1 +#define TRACK_TYPE_AUDIO 2 + +/* Track IDs */ +#define TRACK_ID_VP8 "V_VP8" +#define TRACK_ID_VORBIS "A_VORBIS" + +enum vint_mask { + MASK_NONE, + MASK_FIRST_BIT +}; + +struct ebml_binary { + unsigned char * data; + size_t length; +}; + +struct ebml_list_node { + struct ebml_list_node * next; + uint64_t id; + void * data; +}; + +struct ebml_list { + struct ebml_list_node * head; + struct ebml_list_node * tail; +}; + +struct ebml_type { + union ebml_value { + uint64_t u; + double f; + int64_t i; + char * s; + struct ebml_binary b; + } v; + enum ebml_type_enum type; + int read; +}; + +/* EBML Definitions */ +struct ebml { + struct ebml_type ebml_version; + struct ebml_type ebml_read_version; + struct ebml_type ebml_max_id_length; + struct ebml_type ebml_max_size_length; + struct ebml_type doctype; + struct ebml_type doctype_version; + struct ebml_type doctype_read_version; +}; + +/* Matroksa Definitions */ +struct seek { + struct ebml_type id; + struct ebml_type position; +}; + +struct seek_head { + struct ebml_list seek; +}; + +struct info { + struct ebml_type timecode_scale; + struct ebml_type duration; +}; + +struct block_group { + struct ebml_type duration; + struct ebml_type reference_block; +}; + +struct cluster { + struct ebml_type timecode; + struct ebml_list block_group; +}; + +struct video { + struct ebml_type pixel_width; + struct ebml_type pixel_height; + struct ebml_type pixel_crop_bottom; + struct ebml_type pixel_crop_top; + struct ebml_type pixel_crop_left; + struct ebml_type pixel_crop_right; + struct ebml_type display_width; + struct ebml_type display_height; +}; + +struct audio { + struct ebml_type sampling_frequency; + struct ebml_type channels; + struct ebml_type bit_depth; +}; + +struct track_entry { + struct ebml_type number; + struct ebml_type uid; + struct ebml_type type; + struct ebml_type flag_enabled; + struct ebml_type flag_default; + struct ebml_type flag_lacing; + struct ebml_type track_timecode_scale; + struct ebml_type language; + struct ebml_type codec_id; + struct ebml_type codec_private; + struct video video; + struct audio audio; +}; + +struct tracks { + struct ebml_list track_entry; +}; + +struct cue_track_positions { + struct ebml_type track; + struct ebml_type cluster_position; + struct ebml_type block_number; +}; + +struct cue_point { + struct ebml_type time; + struct ebml_list cue_track_positions; +}; + +struct cues { + struct ebml_list cue_point; +}; + +struct segment { + struct ebml_list seek_head; + struct info info; + struct ebml_list cluster; + struct tracks tracks; + struct cues cues; +}; + +/* Misc. */ +struct pool_ctx { + char dummy; +}; + +struct list_node { + struct list_node * previous; + struct ebml_element_desc * node; + unsigned char * data; +}; + +struct saved_state { + int64_t stream_offset; + struct list_node * ancestor; + uint64_t last_id; + uint64_t last_size; +}; + +struct frame { + unsigned char * data; + size_t length; + struct frame * next; +}; + +/* Public (opaque) Structures */ +struct nestegg { + nestegg_io * io; + nestegg_log log; + struct pool_ctx * alloc_pool; + uint64_t last_id; + uint64_t last_size; + struct list_node * ancestor; + struct ebml ebml; + struct segment segment; + int64_t segment_offset; + unsigned int track_count; +}; + +struct nestegg_packet { + uint64_t track; + uint64_t timecode; + struct frame * frame; +}; + +/* Element Descriptor */ +struct ebml_element_desc { + char const * name; + uint64_t id; + enum ebml_type_enum type; + size_t offset; + unsigned int flags; + struct ebml_element_desc * children; + size_t size; + size_t data_offset; +}; + +#define E_FIELD(ID, TYPE, STRUCT, FIELD) \ + { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, NULL, 0, 0 } +#define E_MASTER(ID, TYPE, STRUCT, FIELD) \ + { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_MULTI, ne_ ## FIELD ## _elements, \ + sizeof(struct FIELD), 0 } +#define E_SINGLE_MASTER_O(ID, TYPE, STRUCT, FIELD) \ + { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_OFFSET, ne_ ## FIELD ## _elements, 0, \ + offsetof(STRUCT, FIELD ## _offset) } +#define E_SINGLE_MASTER(ID, TYPE, STRUCT, FIELD) \ + { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, ne_ ## FIELD ## _elements, 0, 0 } +#define E_SUSPEND(ID, TYPE) \ + { #ID, ID, TYPE, 0, DESC_FLAG_SUSPEND, NULL, 0, 0 } +#define E_LAST \ + { NULL, 0, 0, 0, DESC_FLAG_NONE, NULL, 0, 0 } + +/* EBML Element Lists */ +static struct ebml_element_desc ne_ebml_elements[] = { + E_FIELD(ID_EBML_VERSION, TYPE_UINT, struct ebml, ebml_version), + E_FIELD(ID_EBML_READ_VERSION, TYPE_UINT, struct ebml, ebml_read_version), + E_FIELD(ID_EBML_MAX_ID_LENGTH, TYPE_UINT, struct ebml, ebml_max_id_length), + E_FIELD(ID_EBML_MAX_SIZE_LENGTH, TYPE_UINT, struct ebml, ebml_max_size_length), + E_FIELD(ID_DOCTYPE, TYPE_STRING, struct ebml, doctype), + E_FIELD(ID_DOCTYPE_VERSION, TYPE_UINT, struct ebml, doctype_version), + E_FIELD(ID_DOCTYPE_READ_VERSION, TYPE_UINT, struct ebml, doctype_read_version), + E_LAST +}; + +/* WebMedia Element Lists */ +static struct ebml_element_desc ne_seek_elements[] = { + E_FIELD(ID_SEEK_ID, TYPE_BINARY, struct seek, id), + E_FIELD(ID_SEEK_POSITION, TYPE_UINT, struct seek, position), + E_LAST +}; + +static struct ebml_element_desc ne_seek_head_elements[] = { + E_MASTER(ID_SEEK, TYPE_MASTER, struct seek_head, seek), + E_LAST +}; + +static struct ebml_element_desc ne_info_elements[] = { + E_FIELD(ID_TIMECODE_SCALE, TYPE_UINT, struct info, timecode_scale), + E_FIELD(ID_DURATION, TYPE_FLOAT, struct info, duration), + E_LAST +}; + +static struct ebml_element_desc ne_block_group_elements[] = { + E_SUSPEND(ID_BLOCK, TYPE_BINARY), + E_FIELD(ID_BLOCK_DURATION, TYPE_UINT, struct block_group, duration), + E_FIELD(ID_REFERENCE_BLOCK, TYPE_INT, struct block_group, reference_block), + E_LAST +}; + +static struct ebml_element_desc ne_cluster_elements[] = { + E_FIELD(ID_TIMECODE, TYPE_UINT, struct cluster, timecode), + E_MASTER(ID_BLOCK_GROUP, TYPE_MASTER, struct cluster, block_group), + E_SUSPEND(ID_SIMPLE_BLOCK, TYPE_BINARY), + E_LAST +}; + +static struct ebml_element_desc ne_video_elements[] = { + E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width), + E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height), + E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom), + E_FIELD(ID_PIXEL_CROP_TOP, TYPE_UINT, struct video, pixel_crop_top), + E_FIELD(ID_PIXEL_CROP_LEFT, TYPE_UINT, struct video, pixel_crop_left), + E_FIELD(ID_PIXEL_CROP_RIGHT, TYPE_UINT, struct video, pixel_crop_right), + E_FIELD(ID_DISPLAY_WIDTH, TYPE_UINT, struct video, display_width), + E_FIELD(ID_DISPLAY_HEIGHT, TYPE_UINT, struct video, display_height), + E_LAST +}; + +static struct ebml_element_desc ne_audio_elements[] = { + E_FIELD(ID_SAMPLING_FREQUENCY, TYPE_FLOAT, struct audio, sampling_frequency), + E_FIELD(ID_CHANNELS, TYPE_UINT, struct audio, channels), + E_FIELD(ID_BIT_DEPTH, TYPE_UINT, struct audio, bit_depth), + E_LAST +}; + +static struct ebml_element_desc ne_track_entry_elements[] = { + E_FIELD(ID_TRACK_NUMBER, TYPE_UINT, struct track_entry, number), + E_FIELD(ID_TRACK_UID, TYPE_UINT, struct track_entry, uid), + E_FIELD(ID_TRACK_TYPE, TYPE_UINT, struct track_entry, type), + E_FIELD(ID_FLAG_ENABLED, TYPE_UINT, struct track_entry, flag_enabled), + E_FIELD(ID_FLAG_DEFAULT, TYPE_UINT, struct track_entry, flag_default), + E_FIELD(ID_FLAG_LACING, TYPE_UINT, struct track_entry, flag_lacing), + E_FIELD(ID_TRACK_TIMECODE_SCALE, TYPE_FLOAT, struct track_entry, track_timecode_scale), + E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language), + E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id), + E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private), + E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video), + E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio), + E_LAST +}; + +static struct ebml_element_desc ne_tracks_elements[] = { + E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry), + E_LAST +}; + +static struct ebml_element_desc ne_cue_track_positions_elements[] = { + E_FIELD(ID_CUE_TRACK, TYPE_UINT, struct cue_track_positions, track), + E_FIELD(ID_CUE_CLUSTER_POSITION, TYPE_UINT, struct cue_track_positions, cluster_position), + E_FIELD(ID_CUE_BLOCK_NUMBER, TYPE_UINT, struct cue_track_positions, block_number), + E_LAST +}; + +static struct ebml_element_desc ne_cue_point_elements[] = { + E_FIELD(ID_CUE_TIME, TYPE_UINT, struct cue_point, time), + E_MASTER(ID_CUE_TRACK_POSITIONS, TYPE_MASTER, struct cue_point, cue_track_positions), + E_LAST +}; + +static struct ebml_element_desc ne_cues_elements[] = { + E_MASTER(ID_CUE_POINT, TYPE_MASTER, struct cues, cue_point), + E_LAST +}; + +static struct ebml_element_desc ne_segment_elements[] = { + E_MASTER(ID_SEEK_HEAD, TYPE_MASTER, struct segment, seek_head), + E_SINGLE_MASTER(ID_INFO, TYPE_MASTER, struct segment, info), + E_MASTER(ID_CLUSTER, TYPE_MASTER, struct segment, cluster), + E_SINGLE_MASTER(ID_TRACKS, TYPE_MASTER, struct segment, tracks), + E_SINGLE_MASTER(ID_CUES, TYPE_MASTER, struct segment, cues), + E_LAST +}; + +static struct ebml_element_desc ne_top_level_elements[] = { + E_SINGLE_MASTER(ID_EBML, TYPE_MASTER, nestegg, ebml), + E_SINGLE_MASTER_O(ID_SEGMENT, TYPE_MASTER, nestegg, segment), + E_LAST +}; + +#undef E_FIELD +#undef E_MASTER +#undef E_SINGLE_MASTER_O +#undef E_SINGLE_MASTER +#undef E_SUSPEND +#undef E_LAST + +static struct pool_ctx * +ne_pool_init(void) +{ + struct pool_ctx * pool; + + pool = h_malloc(sizeof(*pool)); + if (!pool) + abort(); + return pool; +} + +static void +ne_pool_destroy(struct pool_ctx * pool) +{ + h_free(pool); +} + +static void * +ne_pool_alloc(size_t size, struct pool_ctx * pool) +{ + void * p; + + p = h_malloc(size); + if (!p) + abort(); + hattach(p, pool); + memset(p, 0, size); + return p; +} + +static void * +ne_alloc(size_t size) +{ + void * p; + + p = calloc(1, size); + if (!p) + abort(); + return p; +} + +static int +ne_io_read(nestegg_io * io, void * buffer, size_t length) +{ + return io->read(buffer, length, io->userdata); +} + +static int +ne_io_seek(nestegg_io * io, int64_t offset, int whence) +{ + return io->seek(offset, whence, io->userdata); +} + +static int +ne_io_read_skip(nestegg_io * io, size_t length) +{ + size_t get; + unsigned char buf[8192]; + int r = 1; + + while (length > 0) { + get = length < sizeof(buf) ? length : sizeof(buf); + r = ne_io_read(io, buf, get); + if (r != 1) + break; + length -= get; + } + + return r; +} + +static int64_t +ne_io_tell(nestegg_io * io) +{ + return io->tell(io->userdata); +} + +static int +ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag) +{ + int r; + unsigned char b; + size_t maxlen = 8; + unsigned int count = 1, mask = 1 << 7; + + r = ne_io_read(io, &b, 1); + if (r != 1) + return r; + + while (count < maxlen) { + if ((b & mask) != 0) + break; + mask >>= 1; + count += 1; + } + + if (length) + *length = count; + *value = b; + + if (maskflag == MASK_FIRST_BIT) + *value = b & ~mask; + + while (--count) { + r = ne_io_read(io, &b, 1); + if (r != 1) + return r; + *value <<= 8; + *value |= b; + } + + return 1; +} + +static int +ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length) +{ + return ne_bare_read_vint(io, value, length, MASK_NONE); +} + +static int +ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length) +{ + return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT); +} + +static int +ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length) +{ + int r; + uint64_t uvalue; + uint64_t ulength; + int64_t svint_subtr[] = { + 0x3f, 0x1fff, + 0xfffff, 0x7ffffff, + 0x3ffffffffLL, 0x1ffffffffffLL, + 0xffffffffffffLL, 0x7fffffffffffffLL + }; + + r = ne_bare_read_vint(io, &uvalue, &ulength, MASK_FIRST_BIT); + if (r != 1) + return r; + *value = uvalue - svint_subtr[ulength - 1]; + if (length) + *length = ulength; + return r; +} + +static int +ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length) +{ + unsigned char b; + int r; + + if (length == 0 || length > 8) + return -1; + r = ne_io_read(io, &b, 1); + if (r != 1) + return r; + *val = b; + while (--length) { + r = ne_io_read(io, &b, 1); + if (r != 1) + return r; + *val <<= 8; + *val |= b; + } + return 1; +} + +static int +ne_read_int(nestegg_io * io, int64_t * val, uint64_t length) +{ + int r; + uint64_t uval, base; + + r = ne_read_uint(io, &uval, length); + if (r != 1) + return r; + + if (length < sizeof(int64_t)) { + base = 1; + base <<= length * 8 - 1; + if (uval >= base) { + base = 1; + base <<= length * 8; + } else { + base = 0; + } + *val = uval - base; + } else { + *val = (int64_t) uval; + } + + return 1; +} + +static int +ne_read_float(nestegg_io * io, double * val, uint64_t length) +{ + union { + uint64_t u; + float f; + double d; + } value; + int r; + + /* length == 10 not implemented */ + if (length != 4 && length != 8) + return -1; + r = ne_read_uint(io, &value.u, length); + if (r != 1) + return r; + if (length == 4) + *val = value.f; + else + *val = value.d; + return 1; +} + +static int +ne_read_string(nestegg * ctx, char ** val, uint64_t length) +{ + char * str; + int r; + + if (length == 0 || length > LIMIT_STRING) + return -1; + str = ne_pool_alloc(length + 1, ctx->alloc_pool); + r = ne_io_read(ctx->io, (unsigned char *) str, length); + if (r != 1) + return r; + str[length] = '\0'; + *val = str; + return 1; +} + +static int +ne_read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length) +{ + if (length == 0 || length > LIMIT_BINARY) + return -1; + val->data = ne_pool_alloc(length, ctx->alloc_pool); + val->length = length; + return ne_io_read(ctx->io, val->data, length); +} + +static int +ne_get_uint(struct ebml_type type, uint64_t * value) +{ + if (!type.read) + return -1; + + assert(type.type == TYPE_UINT); + + *value = type.v.u; + + return 0; +} + +static int +ne_get_float(struct ebml_type type, double * value) +{ + if (!type.read) + return -1; + + assert(type.type == TYPE_FLOAT); + + *value = type.v.f; + + return 0; +} + +static int +ne_get_string(struct ebml_type type, char ** value) +{ + if (!type.read) + return -1; + + assert(type.type == TYPE_STRING); + + *value = type.v.s; + + return 0; +} + +static int +ne_get_binary(struct ebml_type type, struct ebml_binary * value) +{ + if (!type.read) + return -1; + + assert(type.type == TYPE_BINARY); + + *value = type.v.b; + + return 0; +} + +static int +ne_is_ancestor_element(uint64_t id, struct list_node * ancestor) +{ + struct ebml_element_desc * element; + + for (; ancestor; ancestor = ancestor->previous) + for (element = ancestor->node; element->id; ++element) + if (element->id == id) + return 1; + + return 0; +} + +static struct ebml_element_desc * +ne_find_element(uint64_t id, struct ebml_element_desc * elements) +{ + struct ebml_element_desc * element; + + for (element = elements; element->id; ++element) + if (element->id == id) + return element; + + return NULL; +} + +static void +ne_ctx_push(nestegg * ctx, struct ebml_element_desc * ancestor, void * data) +{ + struct list_node * item; + + item = ne_alloc(sizeof(*item)); + item->previous = ctx->ancestor; + item->node = ancestor; + item->data = data; + ctx->ancestor = item; +} + +static void +ne_ctx_pop(nestegg * ctx) +{ + struct list_node * item; + + item = ctx->ancestor; + ctx->ancestor = item->previous; + free(item); +} + +static int +ne_ctx_save(nestegg * ctx, struct saved_state * s) +{ + s->stream_offset = ne_io_tell(ctx->io); + if (s->stream_offset < 0) + return -1; + s->ancestor = ctx->ancestor; + s->last_id = ctx->last_id; + s->last_size = ctx->last_size; + return 0; +} + +static int +ne_ctx_restore(nestegg * ctx, struct saved_state * s) +{ + int r; + + r = ne_io_seek(ctx->io, s->stream_offset, NESTEGG_SEEK_SET); + if (r != 0) + return -1; + ctx->ancestor = s->ancestor; + ctx->last_id = s->last_id; + ctx->last_size = s->last_size; + return 0; +} + +static int +ne_peek_element(nestegg * ctx, uint64_t * id, uint64_t * size) +{ + int r; + + if (ctx->last_id && ctx->last_size) { + if (id) + *id = ctx->last_id; + if (size) + *size = ctx->last_size; + return 1; + } + + r = ne_read_id(ctx->io, &ctx->last_id, NULL); + if (r != 1) + return r; + + r = ne_read_vint(ctx->io, &ctx->last_size, NULL); + if (r != 1) + return r; + + if (id) + *id = ctx->last_id; + if (size) + *size = ctx->last_size; + + return 1; +} + +static int +ne_read_element(nestegg * ctx, uint64_t * id, uint64_t * size) +{ + int r; + + r = ne_peek_element(ctx, id, size); + if (r != 1) + return r; + + ctx->last_id = 0; + ctx->last_size = 0; + + return 1; +} + +static void +ne_read_master(nestegg * ctx, struct ebml_element_desc * desc) +{ + struct ebml_list * list; + struct ebml_list_node * node, * oldtail; + + assert(desc->type == TYPE_MASTER && desc->flags & DESC_FLAG_MULTI); + + ctx->log(ctx, NESTEGG_LOG_DEBUG, "multi master element %llx (%s)", + desc->id, desc->name); + + list = (struct ebml_list *) (ctx->ancestor->data + desc->offset); + + node = ne_pool_alloc(sizeof(*node), ctx->alloc_pool); + node->id = desc->id; + node->data = ne_pool_alloc(desc->size, ctx->alloc_pool); + + oldtail = list->tail; + if (oldtail) + oldtail->next = node; + list->tail = node; + if (!list->head) + list->head = node; + + ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p", node->data); + + ne_ctx_push(ctx, desc->children, node->data); +} + +static void +ne_read_single_master(nestegg * ctx, struct ebml_element_desc * desc) +{ + assert(desc->type == TYPE_MASTER && !(desc->flags & DESC_FLAG_MULTI)); + + ctx->log(ctx, NESTEGG_LOG_DEBUG, "single master element %llx (%s)", + desc->id, desc->name); + ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p (%u)", + ctx->ancestor->data + desc->offset, desc->offset); + + ne_ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset); +} + +static int +ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length) +{ + struct ebml_type * storage; + int r; + + storage = (struct ebml_type *) (ctx->ancestor->data + desc->offset); + + if (storage->read) { + ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) already read, skipping", + desc->id, desc->name); + return 0; + } + + storage->type = desc->type; + + ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) -> %p (%u)", + desc->id, desc->name, storage, desc->offset); + + r = -1; + + switch (desc->type) { + case TYPE_UINT: + r = ne_read_uint(ctx->io, &storage->v.u, length); + break; + case TYPE_FLOAT: + r = ne_read_float(ctx->io, &storage->v.f, length); + break; + case TYPE_INT: + r = ne_read_int(ctx->io, &storage->v.i, length); + break; + case TYPE_STRING: + r = ne_read_string(ctx, &storage->v.s, length); + break; + case TYPE_BINARY: + r = ne_read_binary(ctx, &storage->v.b, length); + break; + case TYPE_MASTER: + case TYPE_UNKNOWN: + assert(0); + break; + } + + if (r == 1) + storage->read = 1; + + return r; +} + +static int +ne_parse(nestegg * ctx, struct ebml_element_desc * top_level) +{ + int r; + int64_t * data_offset; + uint64_t id, size; + struct ebml_element_desc * element; + + /* loop until we need to return: + - hit suspend point + - parse complete + - error occurred */ + + /* loop over elements at current level reading them if sublevel found, + push ctx onto stack and continue if sublevel ended, pop ctx off stack + and continue */ + + if (!ctx->ancestor) + return -1; + + for (;;) { + r = ne_peek_element(ctx, &id, &size); + if (r != 1) + break; + + element = ne_find_element(id, ctx->ancestor->node); + if (element) { + if (element->flags & DESC_FLAG_SUSPEND) { + assert(element->type == TYPE_BINARY); + ctx->log(ctx, NESTEGG_LOG_DEBUG, "suspend parse at %llx", id); + r = 1; + break; + } + + r = ne_read_element(ctx, &id, &size); + if (r != 1) + break; + + if (element->flags & DESC_FLAG_OFFSET) { + data_offset = (int64_t *) (ctx->ancestor->data + element->data_offset); + *data_offset = ne_io_tell(ctx->io); + if (*data_offset < 0) { + r = -1; + break; + } + } + + if (element->type == TYPE_MASTER) { + if (element->flags & DESC_FLAG_MULTI) + ne_read_master(ctx, element); + else + ne_read_single_master(ctx, element); + continue; + } else { + r = ne_read_simple(ctx, element, size); + if (r < 0) + break; + } + } else if (ne_is_ancestor_element(id, ctx->ancestor->previous)) { + ctx->log(ctx, NESTEGG_LOG_DEBUG, "parent element %llx", id); + if (top_level && ctx->ancestor->node == top_level) { + ctx->log(ctx, NESTEGG_LOG_DEBUG, "*** parse about to back up past top_level"); + r = 1; + break; + } + ne_ctx_pop(ctx); + } else { + r = ne_read_element(ctx, &id, &size); + if (r != 1) + break; + + if (id != ID_VOID && id != ID_CRC32) + ctx->log(ctx, NESTEGG_LOG_DEBUG, "unknown element %llx", id); + r = ne_io_read_skip(ctx->io, size); + if (r != 1) + break; + } + } + + if (r != 1) + while (ctx->ancestor) + ne_ctx_pop(ctx); + + return r; +} + +static uint64_t +ne_xiph_lace_value(unsigned char ** np) +{ + uint64_t lace; + uint64_t value; + unsigned char * p = *np; + + lace = *p++; + value = lace; + while (lace == 255) { + lace = *p++; + value += lace; + } + + *np = p; + + return value; +} + +static int +ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed) +{ + int r; + uint64_t lace; + + r = ne_read_uint(io, &lace, 1); + if (r != 1) + return r; + *consumed += 1; + + *value = lace; + while (lace == 255) { + r = ne_read_uint(io, &lace, 1); + if (r != 1) + return r; + *consumed += 1; + *value += lace; + } + + return 1; +} + +static int +ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) +{ + int r; + size_t i = 0; + uint64_t sum = 0; + + while (--n) { + r = ne_read_xiph_lace_value(io, &sizes[i], read); + if (r != 1) + return r; + sum += sizes[i]; + i += 1; + } + + if (*read + sum > block) + return -1; + + /* last frame is the remainder of the block */ + sizes[i] = block - *read - sum; + return 1; +} + +static int +ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) +{ + int r; + uint64_t lace, sum, length; + int64_t slace; + size_t i = 0; + + r = ne_read_vint(io, &lace, &length); + if (r != 1) + return r; + *read += length; + + sizes[i] = lace; + sum = sizes[i]; + + i += 1; + n -= 1; + + while (--n) { + r = ne_read_svint(io, &slace, &length); + if (r != 1) + return r; + *read += length; + sizes[i] = sizes[i - 1] + slace; + sum += sizes[i]; + i += 1; + } + + if (*read + sum > block) + return -1; + + /* last frame is the remainder of the block */ + sizes[i] = block - *read - sum; + return 1; +} + +static uint64_t +ne_get_timecode_scale(nestegg * ctx) +{ + uint64_t scale; + + if (ne_get_uint(ctx->segment.info.timecode_scale, &scale) != 0) + scale = 1000000; + + return scale; +} + +static struct track_entry * +ne_find_track_entry(nestegg * ctx, unsigned int track) +{ + struct ebml_list_node * node; + unsigned int tracks = 0; + + node = ctx->segment.tracks.track_entry.head; + while (node) { + assert(node->id == ID_TRACK_ENTRY); + if (track == tracks) + return node->data; + tracks += 1; + node = node->next; + } + + return NULL; +} + +static int +ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_packet ** data) +{ + int r; + int64_t timecode, abs_timecode; + nestegg_packet * pkt; + struct cluster * cluster; + struct frame * f, * last; + struct track_entry * entry; + double track_scale; + uint64_t track, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total; + unsigned int i, lacing; + size_t consumed = 0; + + *data = NULL; + + if (block_size > LIMIT_BLOCK) + return -1; + + r = ne_read_vint(ctx->io, &track, &length); + if (r != 1) + return r; + + if (track == 0 || track > ctx->track_count) + return -1; + + consumed += length; + + r = ne_read_int(ctx->io, &timecode, 2); + if (r != 1) + return r; + + consumed += 2; + + r = ne_read_uint(ctx->io, &flags, 1); + if (r != 1) + return r; + + consumed += 1; + + frames = 0; + + /* flags are different between block and simpleblock, but lacing is + encoded the same way */ + lacing = (flags & BLOCK_FLAGS_LACING) >> 1; + + switch (lacing) { + case LACING_NONE: + frames = 1; + break; + case LACING_XIPH: + case LACING_FIXED: + case LACING_EBML: + r = ne_read_uint(ctx->io, &frames, 1); + if (r != 1) + return r; + consumed += 1; + frames += 1; + } + + if (frames > 256) + return -1; + + switch (lacing) { + case LACING_NONE: + frame_sizes[0] = block_size - consumed; + break; + case LACING_XIPH: + if (frames == 1) + return -1; + r = ne_read_xiph_lacing(ctx->io, block_size, &consumed, frames, frame_sizes); + if (r != 1) + return r; + break; + case LACING_FIXED: + if ((block_size - consumed) % frames) + return -1; + for (i = 0; i < frames; ++i) + frame_sizes[i] = (block_size - consumed) / frames; + break; + case LACING_EBML: + if (frames == 1) + return -1; + r = ne_read_ebml_lacing(ctx->io, block_size, &consumed, frames, frame_sizes); + if (r != 1) + return r; + break; + } + + /* sanity check unlaced frame sizes against total block size. */ + total = consumed; + for (i = 0; i < frames; ++i) + total += frame_sizes[i]; + if (total > block_size) + return -1; + + entry = ne_find_track_entry(ctx, track - 1); + if (!entry) + return -1; + + track_scale = 1.0; + + tc_scale = ne_get_timecode_scale(ctx); + + assert(ctx->segment.cluster.tail->id == ID_CLUSTER); + cluster = ctx->segment.cluster.tail->data; + if (ne_get_uint(cluster->timecode, &cluster_tc) != 0) + return -1; + + abs_timecode = timecode + cluster_tc; + if (abs_timecode < 0) + return -1; + + pkt = ne_alloc(sizeof(*pkt)); + pkt->track = track - 1; + pkt->timecode = abs_timecode * tc_scale * track_scale; + + ctx->log(ctx, NESTEGG_LOG_DEBUG, "%sblock t %lld pts %f f %llx frames: %llu", + block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9, flags, frames); + + last = NULL; + for (i = 0; i < frames; ++i) { + if (frame_sizes[i] > LIMIT_FRAME) { + nestegg_free_packet(pkt); + return -1; + } + f = ne_alloc(sizeof(*f)); + f->data = ne_alloc(frame_sizes[i]); + f->length = frame_sizes[i]; + r = ne_io_read(ctx->io, f->data, frame_sizes[i]); + if (r != 1) { + free(f->data); + free(f); + nestegg_free_packet(pkt); + return -1; + } + + if (!last) + pkt->frame = f; + else + last->next = f; + last = f; + } + + *data = pkt; + + return 1; +} + +static uint64_t +ne_buf_read_id(unsigned char const * p, size_t length) +{ + uint64_t id = 0; + + while (length--) { + id <<= 8; + id |= *p++; + } + + return id; +} + +static struct seek * +ne_find_seek_for_id(struct ebml_list_node * seek_head, uint64_t id) +{ + struct ebml_list * head; + struct ebml_list_node * seek; + struct ebml_binary binary_id; + struct seek * s; + + while (seek_head) { + assert(seek_head->id == ID_SEEK_HEAD); + head = seek_head->data; + seek = head->head; + + while (seek) { + assert(seek->id == ID_SEEK); + s = seek->data; + + if (ne_get_binary(s->id, &binary_id) == 0 && + ne_buf_read_id(binary_id.data, binary_id.length) == id) + return s; + + seek = seek->next; + } + + seek_head = seek_head->next; + } + + return NULL; +} + +static struct cue_point * +ne_find_cue_point_for_tstamp(struct ebml_list_node * cue_point, uint64_t scale, uint64_t tstamp) +{ + uint64_t time; + struct cue_point * c, * prev = NULL; + + while (cue_point) { + assert(cue_point->id == ID_CUE_POINT); + c = cue_point->data; + + if (!prev) + prev = c; + + if (ne_get_uint(c->time, &time) == 0 && time * scale > tstamp) + break; + + prev = cue_point->data; + cue_point = cue_point->next; + } + + return prev; +} + +static int +ne_is_suspend_element(uint64_t id) +{ + /* this could search the tree of elements for DESC_FLAG_SUSPEND */ + if (id == ID_SIMPLE_BLOCK || id == ID_BLOCK) + return 1; + return 0; +} + +static void +ne_null_log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...) +{ + if (ctx && severity && fmt) + return; +} + +int +nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback) +{ + int r; + uint64_t id, version, docversion; + struct ebml_list_node * track; + char * doctype; + nestegg * ctx = NULL; + + if (!(io.read && io.seek && io.tell)) + return -1; + + ctx = ne_alloc(sizeof(*ctx)); + + ctx->io = ne_alloc(sizeof(*ctx->io)); + *ctx->io = io; + ctx->log = callback; + ctx->alloc_pool = ne_pool_init(); + + if (!ctx->log) + ctx->log = ne_null_log_callback; + + r = ne_peek_element(ctx, &id, NULL); + if (r != 1) { + nestegg_destroy(ctx); + return -1; + } + + if (id != ID_EBML) { + nestegg_destroy(ctx); + return -1; + } + + ctx->log(ctx, NESTEGG_LOG_DEBUG, "ctx %p", ctx); + + ne_ctx_push(ctx, ne_top_level_elements, ctx); + + r = ne_parse(ctx, NULL); + + if (r != 1) { + nestegg_destroy(ctx); + return -1; + } + + if (ne_get_uint(ctx->ebml.ebml_read_version, &version) != 0) + version = 1; + if (version != 1) { + nestegg_destroy(ctx); + return -1; + } + + if (ne_get_string(ctx->ebml.doctype, &doctype) != 0) + doctype = "matroska"; + if (strcmp(doctype, "webm") != 0) { + nestegg_destroy(ctx); + return -1; + } + + if (ne_get_uint(ctx->ebml.doctype_read_version, &docversion) != 0) + docversion = 1; + if (docversion < 1 || docversion > 2) { + nestegg_destroy(ctx); + return -1; + } + + if (!ctx->segment.tracks.track_entry.head) { + nestegg_destroy(ctx); + return -1; + } + + track = ctx->segment.tracks.track_entry.head; + ctx->track_count = 0; + + while (track) { + ctx->track_count += 1; + track = track->next; + } + + *context = ctx; + + return 0; +} + +void +nestegg_destroy(nestegg * ctx) +{ + while (ctx->ancestor) + ne_ctx_pop(ctx); + ne_pool_destroy(ctx->alloc_pool); + free(ctx->io); + free(ctx); +} + +int +nestegg_duration(nestegg * ctx, uint64_t * duration) +{ + uint64_t tc_scale; + double unscaled_duration; + + if (ne_get_float(ctx->segment.info.duration, &unscaled_duration) != 0) + return -1; + + tc_scale = ne_get_timecode_scale(ctx); + + *duration = (uint64_t) (unscaled_duration * tc_scale); + return 0; +} + +int +nestegg_tstamp_scale(nestegg * ctx, uint64_t * scale) +{ + *scale = ne_get_timecode_scale(ctx); + return 0; +} + +int +nestegg_track_count(nestegg * ctx, unsigned int * tracks) +{ + *tracks = ctx->track_count; + return 0; +} + +int +nestegg_track_seek(nestegg * ctx, unsigned int track, uint64_t tstamp) +{ + int r; + struct cue_point * cue_point; + struct cue_track_positions * pos; + struct saved_state state; + struct seek * found; + uint64_t seek_pos, tc_scale, t, id; + struct ebml_list_node * node = ctx->segment.cues.cue_point.head; + + /* If there are no cues loaded, check for cues element in the seek head + and load it. */ + if (!node) { + found = ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); + if (!found) + return -1; + + if (ne_get_uint(found->position, &seek_pos) != 0) + return -1; + + /* Save old parser state. */ + r = ne_ctx_save(ctx, &state); + if (r != 0) + return -1; + + /* Seek and set up parser state for segment-level element (Cues). */ + r = ne_io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET); + if (r != 0) + return -1; + ctx->last_id = 0; + ctx->last_size = 0; + + r = ne_read_element(ctx, &id, NULL); + if (r != 1) + return -1; + + if (id != ID_CUES) + return -1; + + ctx->ancestor = NULL; + ne_ctx_push(ctx, ne_top_level_elements, ctx); + ne_ctx_push(ctx, ne_segment_elements, &ctx->segment); + ne_ctx_push(ctx, ne_cues_elements, &ctx->segment.cues); + /* parser will run until end of cues element. */ + ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cue elements"); + r = ne_parse(ctx, ne_cues_elements); + while (ctx->ancestor) + ne_ctx_pop(ctx); + + /* Reset parser state to original state and seek back to old position. */ + if (ne_ctx_restore(ctx, &state) != 0) + return -1; + + if (r < 0) + return -1; + } + + tc_scale = ne_get_timecode_scale(ctx); + + cue_point = ne_find_cue_point_for_tstamp(ctx->segment.cues.cue_point.head, tc_scale, tstamp); + if (!cue_point) + return -1; + + node = cue_point->cue_track_positions.head; + + seek_pos = 0; + + while (node) { + assert(node->id == ID_CUE_TRACK_POSITIONS); + pos = node->data; + if (ne_get_uint(pos->track, &t) == 0 && t - 1 == track) { + if (ne_get_uint(pos->cluster_position, &seek_pos) != 0) + return -1; + break; + } + node = node->next; + } + + /* Seek and set up parser state for segment-level element (Cluster). */ + r = ne_io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET); + if (r != 0) + return -1; + ctx->last_id = 0; + ctx->last_size = 0; + + while (ctx->ancestor) + ne_ctx_pop(ctx); + + ne_ctx_push(ctx, ne_top_level_elements, ctx); + ne_ctx_push(ctx, ne_segment_elements, &ctx->segment); + ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cluster elements"); + r = ne_parse(ctx, NULL); + if (r != 1) + return -1; + + if (!ne_is_suspend_element(ctx->last_id)) + return -1; + + return 0; +} + +int +nestegg_track_type(nestegg * ctx, unsigned int track) +{ + struct track_entry * entry; + uint64_t type; + + entry = ne_find_track_entry(ctx, track); + if (!entry) + return -1; + + if (ne_get_uint(entry->type, &type) != 0) + return -1; + + if (type & TRACK_TYPE_VIDEO) + return NESTEGG_TRACK_VIDEO; + + if (type & TRACK_TYPE_AUDIO) + return NESTEGG_TRACK_AUDIO; + + return -1; +} + +int +nestegg_track_codec_id(nestegg * ctx, unsigned int track) +{ + char * codec_id; + struct track_entry * entry; + + entry = ne_find_track_entry(ctx, track); + if (!entry) + return -1; + + if (ne_get_string(entry->codec_id, &codec_id) != 0) + return -1; + + if (strcmp(codec_id, TRACK_ID_VP8) == 0) + return NESTEGG_CODEC_VP8; + + if (strcmp(codec_id, TRACK_ID_VORBIS) == 0) + return NESTEGG_CODEC_VORBIS; + + return -1; +} + +int +nestegg_track_codec_data_count(nestegg * ctx, unsigned int track, + unsigned int * count) +{ + struct track_entry * entry; + struct ebml_binary codec_private; + unsigned char * p; + + *count = 0; + + entry = ne_find_track_entry(ctx, track); + if (!entry) + return -1; + + if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS) + return -1; + + if (ne_get_binary(entry->codec_private, &codec_private) != 0) + return -1; + + if (codec_private.length < 1) + return -1; + + p = codec_private.data; + *count = *p + 1; + + if (*count > 3) + return -1; + + return 0; +} + +int +nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item, + unsigned char ** data, size_t * length) +{ + struct track_entry * entry; + struct ebml_binary codec_private; + uint64_t sizes[3], total; + unsigned char * p; + unsigned int count, i; + + *data = NULL; + *length = 0; + + entry = ne_find_track_entry(ctx, track); + if (!entry) + return -1; + + if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS) + return -1; + + if (ne_get_binary(entry->codec_private, &codec_private) != 0) + return -1; + + p = codec_private.data; + count = *p++ + 1; + + if (count > 3) + return -1; + + i = 0; + total = 0; + while (--count) { + sizes[i] = ne_xiph_lace_value(&p); + total += sizes[i]; + i += 1; + } + sizes[i] = codec_private.length - total - (p - codec_private.data); + + for (i = 0; i < item; ++i) { + if (sizes[i] > LIMIT_FRAME) + return -1; + p += sizes[i]; + } + *data = p; + *length = sizes[item]; + + return 0; +} + +int +nestegg_track_video_params(nestegg * ctx, unsigned int track, + nestegg_video_params * params) +{ + struct track_entry * entry; + uint64_t value; + + memset(params, 0, sizeof(*params)); + + entry = ne_find_track_entry(ctx, track); + if (!entry) + return -1; + + if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_VIDEO) + return -1; + + if (ne_get_uint(entry->video.pixel_width, &value) != 0) + return -1; + params->width = value; + + if (ne_get_uint(entry->video.pixel_height, &value) != 0) + return -1; + params->height = value; + + value = 0; + ne_get_uint(entry->video.pixel_crop_bottom, &value); + params->crop_bottom = value; + + value = 0; + ne_get_uint(entry->video.pixel_crop_top, &value); + params->crop_top = value; + + value = 0; + ne_get_uint(entry->video.pixel_crop_left, &value); + params->crop_left = value; + + value = 0; + ne_get_uint(entry->video.pixel_crop_right, &value); + params->crop_right = value; + + value = params->width; + ne_get_uint(entry->video.display_width, &value); + params->display_width = value; + + value = params->height; + ne_get_uint(entry->video.display_height, &value); + params->display_height = value; + + return 0; +} + +int +nestegg_track_audio_params(nestegg * ctx, unsigned int track, + nestegg_audio_params * params) +{ + struct track_entry * entry; + uint64_t value; + + memset(params, 0, sizeof(*params)); + + entry = ne_find_track_entry(ctx, track); + if (!entry) + return -1; + + if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_AUDIO) + return -1; + + params->rate = 8000; + ne_get_float(entry->audio.sampling_frequency, ¶ms->rate); + + value = 1; + ne_get_uint(entry->audio.channels, &value); + params->channels = value; + + value = 16; + ne_get_uint(entry->audio.bit_depth, &value); + params->depth = value; + + return 0; +} + +int +nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) +{ + int r; + uint64_t id, size; + + *pkt = NULL; + + for (;;) { + r = ne_peek_element(ctx, &id, &size); + if (r != 1) + return r; + + /* any suspend fields must be handled here */ + if (ne_is_suspend_element(id)) { + r = ne_read_element(ctx, &id, &size); + if (r != 1) + return r; + + /* the only suspend fields are blocks and simple blocks, which we + handle directly. */ + r = ne_read_block(ctx, id, size, pkt); + return r; + } + + r = ne_parse(ctx, NULL); + if (r != 1) + return r; + } + + return 1; +} + +void +nestegg_free_packet(nestegg_packet * pkt) +{ + struct frame * frame; + + while (pkt->frame) { + frame = pkt->frame; + pkt->frame = frame->next; + free(frame->data); + free(frame); + } + + free(pkt); +} + +int +nestegg_packet_track(nestegg_packet * pkt, unsigned int * track) +{ + *track = pkt->track; + return 0; +} + +int +nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp) +{ + *tstamp = pkt->timecode; + return 0; +} + +int +nestegg_packet_count(nestegg_packet * pkt, unsigned int * count) +{ + struct frame * f = pkt->frame; + + *count = 0; + + while (f) { + *count += 1; + f = f->next; + } + + return 0; +} + +int +nestegg_packet_data(nestegg_packet * pkt, unsigned int item, + unsigned char ** data, size_t * length) +{ + struct frame * f = pkt->frame; + unsigned int count = 0; + + *data = NULL; + *length = 0; + + while (f) { + if (count == item) { + *data = f->data; + *length = f->length; + return 0; + } + count += 1; + f = f->next; + } + + return -1; +} diff --git a/nestegg/test/test.c b/nestegg/test/test.c new file mode 100644 index 0000000..210b640 --- /dev/null +++ b/nestegg/test/test.c @@ -0,0 +1,248 @@ +/* + * Copyright © 2010 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ +#include +#include +#include +#include +#include +#include "nestegg/nestegg.h" + +#undef DEBUG +#define SEEK_TEST + +static int +stdio_read(void * p, size_t length, void * fp) +{ + size_t r; + + r = fread(p, length, 1, fp); + if (r == 0 && feof(fp)) + return 0; + return r == 0 ? -1 : 1; +} + +static int +stdio_seek(int64_t offset, int whence, void * fp) +{ + return fseek(fp, offset, whence); +} + +static int64_t +stdio_tell(void * fp) +{ + return ftell(fp); +} + +static void +log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...) +{ + va_list ap; + char const * sev = NULL; + +#ifndef DEBUG + if (severity < NESTEGG_LOG_WARNING) + return; +#endif + + switch (severity) { + case NESTEGG_LOG_DEBUG: + sev = "debug: "; + break; + case NESTEGG_LOG_WARNING: + sev = "warning: "; + break; + case NESTEGG_LOG_CRITICAL: + sev = "critical:"; + break; + default: + sev = "unknown: "; + } + + fprintf(stderr, "%p %s ", (void *) ctx, sev); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); +} + +int +main(int argc, char * argv[]) +{ + FILE * fp; + int r, type; + nestegg * ctx; + nestegg_audio_params aparams; + nestegg_packet * pkt; + nestegg_video_params vparams; + size_t length, size; + uint64_t duration, tstamp, pkt_tstamp; + unsigned char * codec_data, * ptr; + unsigned int cnt, i, j, track, tracks, pkt_cnt, pkt_track; + unsigned int data_items = 0; + nestegg_io io = { + stdio_read, + stdio_seek, + stdio_tell, + NULL + }; + + if (argc != 2) + return EXIT_FAILURE; + + fp = fopen(argv[1], "rb"); + if (!fp) + return EXIT_FAILURE; + + io.userdata = fp; + + ctx = NULL; + r = nestegg_init(&ctx, io, log_callback); + if (r != 0) + return EXIT_FAILURE; + + nestegg_track_count(ctx, &tracks); + nestegg_duration(ctx, &duration); +#ifdef DEBUG + fprintf(stderr, "media has %u tracks and duration %fs\n", tracks, duration / 1e9); +#endif + + for (i = 0; i < tracks; ++i) { + type = nestegg_track_type(ctx, i); +#ifdef DEBUG + fprintf(stderr, "track %u: type: %d codec: %d", i, + type, nestegg_track_codec_id(ctx, i)); +#endif + nestegg_track_codec_data_count(ctx, i, &data_items); + for (j = 0; j < data_items; ++j) { + nestegg_track_codec_data(ctx, i, j, &codec_data, &length); +#ifdef DEBUG + fprintf(stderr, " (%p, %u)", codec_data, (unsigned int) length); +#endif + } + if (type == NESTEGG_TRACK_VIDEO) { + nestegg_track_video_params(ctx, i, &vparams); +#ifdef DEBUG + fprintf(stderr, " video: %ux%u (d: %ux%u %ux%ux%ux%u)", + vparams.width, vparams.height, + vparams.display_width, vparams.display_height, + vparams.crop_top, vparams.crop_left, vparams.crop_bottom, vparams.crop_right); +#endif + } else if (type == NESTEGG_TRACK_AUDIO) { + nestegg_track_audio_params(ctx, i, &aparams); +#ifdef DEBUG + fprintf(stderr, " audio: %.2fhz %u bit %u channels", + aparams.rate, aparams.depth, aparams.channels); +#endif + } +#ifdef DEBUG + fprintf(stderr, "\n"); +#endif + } + +#ifdef SEEK_TEST +#ifdef DEBUG + fprintf(stderr, "seek to middle\n"); +#endif + r = nestegg_track_seek(ctx, 0, duration / 2); + if (r == 0) { +#ifdef DEBUG + fprintf(stderr, "middle "); +#endif + r = nestegg_read_packet(ctx, &pkt); + if (r == 1) { + nestegg_packet_track(pkt, &track); + nestegg_packet_count(pkt, &cnt); + nestegg_packet_tstamp(pkt, &tstamp); +#ifdef DEBUG + fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); +#endif + nestegg_free_packet(pkt); + } else { +#ifdef DEBUG + fprintf(stderr, "middle seek failed\n"); +#endif + } + } + +#ifdef DEBUG + fprintf(stderr, "seek to ~end\n"); +#endif + r = nestegg_track_seek(ctx, 0, duration - (duration / 10)); + if (r == 0) { +#ifdef DEBUG + fprintf(stderr, "end "); +#endif + r = nestegg_read_packet(ctx, &pkt); + if (r == 1) { + nestegg_packet_track(pkt, &track); + nestegg_packet_count(pkt, &cnt); + nestegg_packet_tstamp(pkt, &tstamp); +#ifdef DEBUG + fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); +#endif + nestegg_free_packet(pkt); + } else { +#ifdef DEBUG + fprintf(stderr, "end seek failed\n"); +#endif + } + } + +#ifdef DEBUG + fprintf(stderr, "seek to ~start\n"); +#endif + r = nestegg_track_seek(ctx, 0, duration / 10); + if (r == 0) { +#ifdef DEBUG + fprintf(stderr, "start "); +#endif + r = nestegg_read_packet(ctx, &pkt); + if (r == 1) { + nestegg_packet_track(pkt, &track); + nestegg_packet_count(pkt, &cnt); + nestegg_packet_tstamp(pkt, &tstamp); +#ifdef DEBUG + fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); +#endif + nestegg_free_packet(pkt); + } else { +#ifdef DEBUG + fprintf(stderr, "start seek failed\n"); +#endif + } + } +#endif + + while (nestegg_read_packet(ctx, &pkt) > 0) { + nestegg_packet_track(pkt, &pkt_track); + nestegg_packet_count(pkt, &pkt_cnt); + nestegg_packet_tstamp(pkt, &pkt_tstamp); + +#ifdef DEBUG + fprintf(stderr, "t %u pts %f frames %u: ", pkt_track, pkt_tstamp / 1e9, pkt_cnt); +#endif + + for (i = 0; i < pkt_cnt; ++i) { + nestegg_packet_data(pkt, i, &ptr, &size); +#ifdef DEBUG + fprintf(stderr, "%u ", (unsigned int) size); +#endif + } +#ifdef DEBUG + fprintf(stderr, "\n"); +#endif + + nestegg_free_packet(pkt); + } + + nestegg_destroy(ctx); + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/solution.mk b/solution.mk new file mode 100644 index 0000000..2de1d8d --- /dev/null +++ b/solution.mk @@ -0,0 +1,31 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +vpx.sln: $(wildcard *.vcproj) + @echo " [CREATE] $@" + $(SRC_PATH_BARE)/build/make/gen_msvs_sln.sh \ + $(if $(filter %vpx.vcproj,$^),\ + $(foreach vcp,$(filter-out %vpx.vcproj %gtest.vcproj %obj_int_extract.vcproj,$^),\ + --dep=$(vcp:.vcproj=):vpx) \ + $(foreach vcp,$(filter %_test.vcproj,$^),\ + --dep=$(vcp:.vcproj=):gtest)) \ + --dep=vpx:obj_int_extract \ + --ver=$(CONFIG_VS_VERSION)\ + --out=$@ $^ +vpx.sln.mk: vpx.sln + @true + +PROJECTS-yes += vpx.sln vpx.sln.mk +-include vpx.sln.mk + +# Always install this file, as it is an unconditional post-build rule. +INSTALL_MAPS += src/% $(SRC_PATH_BARE)/% +INSTALL-SRCS-yes += $(target).mk diff --git a/third_party/googletest/README.webm b/third_party/googletest/README.webm new file mode 100644 index 0000000..571d890 --- /dev/null +++ b/third_party/googletest/README.webm @@ -0,0 +1,15 @@ +URL: http://code.google.com/p/googletest/ +Version: 1.6.0 +License: BSD +License File: COPYING + +Description: +Google's framework for writing C++ tests on a variety of platforms +(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the +xUnit architecture. Supports automatic test discovery, a rich set of +assertions, user-defined assertions, death tests, fatal and non-fatal +failures, various options for running the tests, and XML test report +generation. + +Local Modifications: +None. \ No newline at end of file diff --git a/third_party/googletest/gtest.mk b/third_party/googletest/gtest.mk new file mode 100644 index 0000000..0de3113 --- /dev/null +++ b/third_party/googletest/gtest.mk @@ -0,0 +1 @@ +GTEST_SRCS-yes += src/gtest-all.cc diff --git a/third_party/googletest/src/CHANGES b/third_party/googletest/src/CHANGES new file mode 100644 index 0000000..5919245 --- /dev/null +++ b/third_party/googletest/src/CHANGES @@ -0,0 +1,130 @@ +Changes for 1.6.0: + +* New feature: ADD_FAILURE_AT() for reporting a test failure at the + given source location -- useful for writing testing utilities. +* New feature: the universal value printer is moved from Google Mock + to Google Test. +* New feature: type parameters and value parameters are reported in + the XML report now. +* A gtest_disable_pthreads CMake option. +* Colored output works in GNU Screen sessions now. +* Parameters of value-parameterized tests are now printed in the + textual output. +* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are + now correctly reported. +* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to + ostream. +* More complete handling of exceptions. +* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter + name is already used by another library. +* --gtest_catch_exceptions is now true by default, allowing a test + program to continue after an exception is thrown. +* Value-parameterized test fixtures can now derive from Test and + WithParamInterface separately, easing conversion of legacy tests. +* Death test messages are clearly marked to make them more + distinguishable from other messages. +* Compatibility fixes for Android, Google Native Client, MinGW, HP UX, + PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear), + IBM XL C++ (Visual Age C++), and C++0x. +* Bug fixes and implementation clean-ups. +* Potentially incompatible changes: disables the harmful 'make install' + command in autotools. + +Changes for 1.5.0: + + * New feature: assertions can be safely called in multiple threads + where the pthreads library is available. + * New feature: predicates used inside EXPECT_TRUE() and friends + can now generate custom failure messages. + * New feature: Google Test can now be compiled as a DLL. + * New feature: fused source files are included. + * New feature: prints help when encountering unrecognized Google Test flags. + * Experimental feature: CMake build script (requires CMake 2.6.4+). + * Experimental feature: the Pump script for meta programming. + * double values streamed to an assertion are printed with enough precision + to differentiate any two different values. + * Google Test now works on Solaris and AIX. + * Build and test script improvements. + * Bug fixes and implementation clean-ups. + + Potentially breaking changes: + + * Stopped supporting VC++ 7.1 with exceptions disabled. + * Dropped support for 'make install'. + +Changes for 1.4.0: + + * New feature: the event listener API + * New feature: test shuffling + * New feature: the XML report format is closer to junitreport and can + be parsed by Hudson now. + * New feature: when a test runs under Visual Studio, its failures are + integrated in the IDE. + * New feature: /MD(d) versions of VC++ projects. + * New feature: elapsed time for the tests is printed by default. + * New feature: comes with a TR1 tuple implementation such that Boost + is no longer needed for Combine(). + * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends. + * New feature: the Xcode project can now produce static gtest + libraries in addition to a framework. + * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile, + Symbian, gcc, and C++Builder. + * Bug fixes and implementation clean-ups. + +Changes for 1.3.0: + + * New feature: death tests on Windows, Cygwin, and Mac. + * New feature: ability to use Google Test assertions in other testing + frameworks. + * New feature: ability to run disabled test via + --gtest_also_run_disabled_tests. + * New feature: the --help flag for printing the usage. + * New feature: access to Google Test flag values in user code. + * New feature: a script that packs Google Test into one .h and one + .cc file for easy deployment. + * New feature: support for distributing test functions to multiple + machines (requires support from the test runner). + * Bug fixes and implementation clean-ups. + +Changes for 1.2.1: + + * Compatibility fixes for Linux IA-64 and IBM z/OS. + * Added support for using Boost and other TR1 implementations. + * Changes to the build scripts to support upcoming release of Google C++ + Mocking Framework. + * Added Makefile to the distribution package. + * Improved build instructions in README. + +Changes for 1.2.0: + + * New feature: value-parameterized tests. + * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS) + macros. + * Changed the XML report format to match JUnit/Ant's. + * Added tests to the Xcode project. + * Added scons/SConscript for building with SCons. + * Added src/gtest-all.cc for building Google Test from a single file. + * Fixed compatibility with Solaris and z/OS. + * Enabled running Python tests on systems with python 2.3 installed, + e.g. Mac OS X 10.4. + * Bug fixes. + +Changes for 1.1.0: + + * New feature: type-parameterized tests. + * New feature: exception assertions. + * New feature: printing elapsed time of tests. + * Improved the robustness of death tests. + * Added an Xcode project and samples. + * Adjusted the output format on Windows to be understandable by Visual Studio. + * Minor bug fixes. + +Changes for 1.0.1: + + * Added project files for Visual Studio 7.1. + * Fixed issues with compiling on Mac OS X. + * Fixed issues with compiling on Cygwin. + +Changes for 1.0.0: + + * Initial Open Source release of Google Test diff --git a/third_party/googletest/src/CMakeLists.txt b/third_party/googletest/src/CMakeLists.txt new file mode 100644 index 0000000..0fe2654 --- /dev/null +++ b/third_party/googletest/src/CMakeLists.txt @@ -0,0 +1,240 @@ +######################################################################## +# CMake build script for Google Test. +# +# To run the tests for Google Test itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. + +# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to +# make it prominent in the GUI. +option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) + +# When other libraries are using a shared version of runtime libraries, +# Google Test also has to use one. +option( + gtest_force_shared_crt + "Use shared (DLL) run-time lib even when Google Test is built as static lib." + OFF) + +option(gtest_build_tests "Build all of gtest's own tests." OFF) + +option(gtest_build_samples "Build gtest's sample programs." OFF) + +option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF) + +# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). +include(cmake/hermetic_build.cmake OPTIONAL) + +if (COMMAND pre_project_set_up_hermetic_build) + pre_project_set_up_hermetic_build() +endif() + +######################################################################## +# +# Project-wide settings + +# Name of the project. +# +# CMake files in this project can refer to the root source directory +# as ${gtest_SOURCE_DIR} and to the root binary directory as +# ${gtest_BINARY_DIR}. +# Language "C" is required for find_package(Threads). +project(gtest CXX C) +cmake_minimum_required(VERSION 2.6.2) + +if (COMMAND set_up_hermetic_build) + set_up_hermetic_build() +endif() + +# Define helper functions and macros used by Google Test. +include(cmake/internal_utils.cmake) + +config_compiler_and_linker() # Defined in internal_utils.cmake. + +# Where Google Test's .h files can be found. +include_directories( + ${gtest_SOURCE_DIR}/include + ${gtest_SOURCE_DIR}) + +# Where Google Test's libraries can be found. +link_directories(${gtest_BINARY_DIR}/src) + +######################################################################## +# +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. + +# Google Test libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that gtest can be compiled by a user +# aggressive about warnings. +cxx_library(gtest "${cxx_strict}" src/gtest-all.cc) +cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) +target_link_libraries(gtest_main gtest) + +######################################################################## +# +# Samples on how to link user tests with gtest or gtest_main. +# +# They are not built by default. To build them, set the +# gtest_build_samples option to ON. You can do it by running ccmake +# or specifying the -Dbuild_gtest_samples=ON flag when running cmake. + +if (gtest_build_samples) + cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) + cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) + cxx_executable(sample3_unittest samples gtest_main) + cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc) + cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc) + cxx_executable(sample6_unittest samples gtest_main) + cxx_executable(sample7_unittest samples gtest_main) + cxx_executable(sample8_unittest samples gtest_main) + cxx_executable(sample9_unittest samples gtest) + cxx_executable(sample10_unittest samples gtest) +endif() + +######################################################################## +# +# Google Test's own tests. +# +# You can skip this section if you aren't interested in testing +# Google Test itself. +# +# The tests are not built by default. To build them, set the +# gtest_build_tests option to ON. You can do it by running ccmake +# or specifying the -Dgtest_build_tests=ON flag when running cmake. + +if (gtest_build_tests) + # This must be set in the root directory for the tests to be run by + # 'make test' or ctest. + enable_testing() + + ############################################################ + # C++ tests built with standard compiler flags. + + cxx_test(gtest-death-test_test gtest_main) + cxx_test(gtest_environment_test gtest) + cxx_test(gtest-filepath_test gtest_main) + cxx_test(gtest-linked_ptr_test gtest_main) + cxx_test(gtest-listener_test gtest_main) + cxx_test(gtest_main_unittest gtest_main) + cxx_test(gtest-message_test gtest_main) + cxx_test(gtest_no_test_unittest gtest) + cxx_test(gtest-options_test gtest_main) + cxx_test(gtest-param-test_test gtest + test/gtest-param-test2_test.cc) + cxx_test(gtest-port_test gtest_main) + cxx_test(gtest_pred_impl_unittest gtest_main) + cxx_test(gtest-printers_test gtest_main) + cxx_test(gtest_prod_test gtest_main + test/production.cc) + cxx_test(gtest_repeat_test gtest) + cxx_test(gtest_sole_header_test gtest_main) + cxx_test(gtest_stress_test gtest) + cxx_test(gtest-test-part_test gtest_main) + cxx_test(gtest_throw_on_failure_ex_test gtest) + cxx_test(gtest-typed-test_test gtest_main + test/gtest-typed-test2_test.cc) + cxx_test(gtest_unittest gtest_main) + cxx_test(gtest-unittest-api_test gtest) + + ############################################################ + # C++ tests built with non-standard compiler flags. + + cxx_library(gtest_no_exception "${cxx_no_exception}" + src/gtest-all.cc) + cxx_library(gtest_main_no_exception "${cxx_no_exception}" + src/gtest-all.cc src/gtest_main.cc) + cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_test_with_flags(gtest-death-test_ex_nocatch_test + "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0" + gtest test/gtest-death-test_ex_test.cc) + cxx_test_with_flags(gtest-death-test_ex_catch_test + "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1" + gtest test/gtest-death-test_ex_test.cc) + + cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" + gtest_main_no_rtti test/gtest_unittest.cc) + + cxx_shared_library(gtest_dll "${cxx_default}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" + gtest_dll test/gtest_all_test.cc) + set_target_properties(gtest_dll_test_ + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + + if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600) + # The C++ Standard specifies tuple_element. + # Yet MSVC 10's declares tuple_element. + # That declaration conflicts with our own standard-conforming + # tuple implementation. Therefore using our own tuple with + # MSVC 10 doesn't compile. + cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}" + gtest_main_use_own_tuple test/gtest-tuple_test.cc) + + cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}" + gtest_main_use_own_tuple + test/gtest-param-test_test.cc test/gtest-param-test2_test.cc) + endif() + + ############################################################ + # Python tests. + + cxx_executable(gtest_break_on_failure_unittest_ test gtest) + py_test(gtest_break_on_failure_unittest) + + cxx_executable_with_flags( + gtest_catch_exceptions_no_ex_test_ + "${cxx_no_exception}" + gtest_main_no_exception + test/gtest_catch_exceptions_test_.cc) + cxx_executable_with_flags( + gtest_catch_exceptions_ex_test_ + "${cxx_exception}" + gtest_main + test/gtest_catch_exceptions_test_.cc) + py_test(gtest_catch_exceptions_test) + + cxx_executable(gtest_color_test_ test gtest) + py_test(gtest_color_test) + + cxx_executable(gtest_env_var_test_ test gtest) + py_test(gtest_env_var_test) + + cxx_executable(gtest_filter_unittest_ test gtest) + py_test(gtest_filter_unittest) + + cxx_executable(gtest_help_test_ test gtest_main) + py_test(gtest_help_test) + + cxx_executable(gtest_list_tests_unittest_ test gtest) + py_test(gtest_list_tests_unittest) + + cxx_executable(gtest_output_test_ test gtest) + py_test(gtest_output_test) + + cxx_executable(gtest_shuffle_test_ test gtest) + py_test(gtest_shuffle_test) + + cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception) + set_target_properties(gtest_throw_on_failure_test_ + PROPERTIES + COMPILE_FLAGS "${cxx_no_exception}") + py_test(gtest_throw_on_failure_test) + + cxx_executable(gtest_uninitialized_test_ test gtest) + py_test(gtest_uninitialized_test) + + cxx_executable(gtest_xml_outfile1_test_ test gtest_main) + cxx_executable(gtest_xml_outfile2_test_ test gtest_main) + py_test(gtest_xml_outfiles_test) + + cxx_executable(gtest_xml_output_unittest_ test gtest) + py_test(gtest_xml_output_unittest) +endif() diff --git a/third_party/googletest/src/CONTRIBUTORS b/third_party/googletest/src/CONTRIBUTORS new file mode 100644 index 0000000..feae2fc --- /dev/null +++ b/third_party/googletest/src/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This file contains a list of people who've made non-trivial +# contribution to the Google C++ Testing Framework project. People +# who commit code to the project are encouraged to add their names +# here. Please keep the list sorted by first names. + +Ajay Joshi +Balázs Dán +Bharat Mediratta +Chandler Carruth +Chris Prince +Chris Taylor +Dan Egnor +Eric Roman +Hady Zalek +Jeffrey Yasskin +Jói Sigurðsson +Keir Mierle +Keith Ray +Kenton Varda +Manuel Klimek +Markus Heule +Mika Raento +Miklós Fazekas +Pasi Valminen +Patrick Hanna +Patrick Riley +Peter Kaminski +Preston Jackson +Rainer Klaffenboeck +Russ Cox +Russ Rufer +Sean Mcafee +Sigurður Ásgeirsson +Tracy Bialik +Vadim Berman +Vlad Losev +Zhanyong Wan diff --git a/third_party/googletest/src/COPYING b/third_party/googletest/src/COPYING new file mode 100644 index 0000000..1941a11 --- /dev/null +++ b/third_party/googletest/src/COPYING @@ -0,0 +1,28 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/googletest/src/Makefile.am b/third_party/googletest/src/Makefile.am new file mode 100644 index 0000000..cb350b7 --- /dev/null +++ b/third_party/googletest/src/Makefile.am @@ -0,0 +1,302 @@ +# Automake file + +ACLOCAL_AMFLAGS = -I m4 + +# Nonstandard package files for distribution +EXTRA_DIST = \ + CHANGES \ + CONTRIBUTORS \ + include/gtest/gtest-param-test.h.pump \ + include/gtest/internal/gtest-param-util-generated.h.pump \ + include/gtest/internal/gtest-tuple.h.pump \ + include/gtest/internal/gtest-type-util.h.pump \ + make/Makefile \ + scripts/fuse_gtest_files.py \ + scripts/gen_gtest_pred_impl.py \ + scripts/pump.py \ + scripts/test/Makefile + +# gtest source files that we don't compile directly. They are +# #included by gtest-all.cc. +GTEST_SRC = \ + src/gtest-death-test.cc \ + src/gtest-filepath.cc \ + src/gtest-internal-inl.h \ + src/gtest-port.cc \ + src/gtest-printers.cc \ + src/gtest-test-part.cc \ + src/gtest-typed-test.cc \ + src/gtest.cc + +EXTRA_DIST += $(GTEST_SRC) + +# Sample files that we don't compile. +EXTRA_DIST += \ + samples/prime_tables.h \ + samples/sample2_unittest.cc \ + samples/sample3_unittest.cc \ + samples/sample4_unittest.cc \ + samples/sample5_unittest.cc \ + samples/sample6_unittest.cc \ + samples/sample7_unittest.cc \ + samples/sample8_unittest.cc \ + samples/sample9_unittest.cc + +# C++ test files that we don't compile directly. +EXTRA_DIST += \ + test/gtest-death-test_ex_test.cc \ + test/gtest-death-test_test.cc \ + test/gtest-filepath_test.cc \ + test/gtest-linked_ptr_test.cc \ + test/gtest-listener_test.cc \ + test/gtest-message_test.cc \ + test/gtest-options_test.cc \ + test/gtest-param-test2_test.cc \ + test/gtest-param-test2_test.cc \ + test/gtest-param-test_test.cc \ + test/gtest-param-test_test.cc \ + test/gtest-param-test_test.h \ + test/gtest-port_test.cc \ + test/gtest-printers_test.cc \ + test/gtest-test-part_test.cc \ + test/gtest-tuple_test.cc \ + test/gtest-typed-test2_test.cc \ + test/gtest-typed-test_test.cc \ + test/gtest-typed-test_test.h \ + test/gtest-unittest-api_test.cc \ + test/gtest_break_on_failure_unittest_.cc \ + test/gtest_catch_exceptions_test_.cc \ + test/gtest_color_test_.cc \ + test/gtest_env_var_test_.cc \ + test/gtest_environment_test.cc \ + test/gtest_filter_unittest_.cc \ + test/gtest_help_test_.cc \ + test/gtest_list_tests_unittest_.cc \ + test/gtest_main_unittest.cc \ + test/gtest_no_test_unittest.cc \ + test/gtest_output_test_.cc \ + test/gtest_pred_impl_unittest.cc \ + test/gtest_prod_test.cc \ + test/gtest_repeat_test.cc \ + test/gtest_shuffle_test_.cc \ + test/gtest_sole_header_test.cc \ + test/gtest_stress_test.cc \ + test/gtest_throw_on_failure_ex_test.cc \ + test/gtest_throw_on_failure_test_.cc \ + test/gtest_uninitialized_test_.cc \ + test/gtest_unittest.cc \ + test/gtest_unittest.cc \ + test/gtest_xml_outfile1_test_.cc \ + test/gtest_xml_outfile2_test_.cc \ + test/gtest_xml_output_unittest_.cc \ + test/production.cc \ + test/production.h + +# Python tests that we don't run. +EXTRA_DIST += \ + test/gtest_break_on_failure_unittest.py \ + test/gtest_catch_exceptions_test.py \ + test/gtest_color_test.py \ + test/gtest_env_var_test.py \ + test/gtest_filter_unittest.py \ + test/gtest_help_test.py \ + test/gtest_list_tests_unittest.py \ + test/gtest_output_test.py \ + test/gtest_output_test_golden_lin.txt \ + test/gtest_shuffle_test.py \ + test/gtest_test_utils.py \ + test/gtest_throw_on_failure_test.py \ + test/gtest_uninitialized_test.py \ + test/gtest_xml_outfiles_test.py \ + test/gtest_xml_output_unittest.py \ + test/gtest_xml_test_utils.py + +# CMake script +EXTRA_DIST += \ + CMakeLists.txt \ + cmake/internal_utils.cmake + +# MSVC project files +EXTRA_DIST += \ + msvc/gtest-md.sln \ + msvc/gtest-md.vcproj \ + msvc/gtest.sln \ + msvc/gtest.vcproj \ + msvc/gtest_main-md.vcproj \ + msvc/gtest_main.vcproj \ + msvc/gtest_prod_test-md.vcproj \ + msvc/gtest_prod_test.vcproj \ + msvc/gtest_unittest-md.vcproj \ + msvc/gtest_unittest.vcproj + +# xcode project files +EXTRA_DIST += \ + xcode/Config/DebugProject.xcconfig \ + xcode/Config/FrameworkTarget.xcconfig \ + xcode/Config/General.xcconfig \ + xcode/Config/ReleaseProject.xcconfig \ + xcode/Config/StaticLibraryTarget.xcconfig \ + xcode/Config/TestTarget.xcconfig \ + xcode/Resources/Info.plist \ + xcode/Scripts/runtests.sh \ + xcode/Scripts/versiongenerate.py \ + xcode/gtest.xcodeproj/project.pbxproj + +# xcode sample files +EXTRA_DIST += \ + xcode/Samples/FrameworkSample/Info.plist \ + xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \ + xcode/Samples/FrameworkSample/runtests.sh \ + xcode/Samples/FrameworkSample/widget.cc \ + xcode/Samples/FrameworkSample/widget.h \ + xcode/Samples/FrameworkSample/widget_test.cc + +# C++Builder project files +EXTRA_DIST += \ + codegear/gtest.cbproj \ + codegear/gtest.groupproj \ + codegear/gtest_all.cc \ + codegear/gtest_link.cc \ + codegear/gtest_main.cbproj \ + codegear/gtest_unittest.cbproj + +# Distribute and install M4 macro +m4datadir = $(datadir)/aclocal +m4data_DATA = m4/gtest.m4 +EXTRA_DIST += $(m4data_DATA) + +# We define the global AM_CPPFLAGS as everything we compile includes from these +# directories. +AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include + +# Modifies compiler and linker flags for pthreads compatibility. +if HAVE_PTHREADS + AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 + AM_LIBS = @PTHREAD_LIBS@ +else + AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0 +endif + +# Build rules for libraries. +lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la + +lib_libgtest_la_SOURCES = src/gtest-all.cc + +pkginclude_HEADERS = \ + include/gtest/gtest-death-test.h \ + include/gtest/gtest-message.h \ + include/gtest/gtest-param-test.h \ + include/gtest/gtest-printers.h \ + include/gtest/gtest-spi.h \ + include/gtest/gtest-test-part.h \ + include/gtest/gtest-typed-test.h \ + include/gtest/gtest.h \ + include/gtest/gtest_pred_impl.h \ + include/gtest/gtest_prod.h + +pkginclude_internaldir = $(pkgincludedir)/internal +pkginclude_internal_HEADERS = \ + include/gtest/internal/gtest-death-test-internal.h \ + include/gtest/internal/gtest-filepath.h \ + include/gtest/internal/gtest-internal.h \ + include/gtest/internal/gtest-linked_ptr.h \ + include/gtest/internal/gtest-param-util-generated.h \ + include/gtest/internal/gtest-param-util.h \ + include/gtest/internal/gtest-port.h \ + include/gtest/internal/gtest-string.h \ + include/gtest/internal/gtest-tuple.h \ + include/gtest/internal/gtest-type-util.h + +lib_libgtest_main_la_SOURCES = src/gtest_main.cc +lib_libgtest_main_la_LIBADD = lib/libgtest.la + +# Bulid rules for samples and tests. Automake's naming for some of +# these variables isn't terribly obvious, so this is a brief +# reference: +# +# TESTS -- Programs run automatically by "make check" +# check_PROGRAMS -- Programs built by "make check" but not necessarily run + +noinst_LTLIBRARIES = samples/libsamples.la + +samples_libsamples_la_SOURCES = \ + samples/sample1.cc \ + samples/sample1.h \ + samples/sample2.cc \ + samples/sample2.h \ + samples/sample3-inl.h \ + samples/sample4.cc \ + samples/sample4.h + +TESTS= +TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \ + GTEST_BUILD_DIR="$(top_builddir)/test" +check_PROGRAMS= + +# A simple sample on using gtest. +TESTS += samples/sample1_unittest +check_PROGRAMS += samples/sample1_unittest +samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc +samples_sample1_unittest_LDADD = lib/libgtest_main.la \ + lib/libgtest.la \ + samples/libsamples.la + +# Another sample. It also verifies that libgtest works. +TESTS += samples/sample10_unittest +check_PROGRAMS += samples/sample10_unittest +samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc +samples_sample10_unittest_LDADD = lib/libgtest.la + +# This tests most constructs of gtest and verifies that libgtest_main +# and libgtest work. +TESTS += test/gtest_all_test +check_PROGRAMS += test/gtest_all_test +test_gtest_all_test_SOURCES = test/gtest_all_test.cc +test_gtest_all_test_LDADD = lib/libgtest_main.la \ + lib/libgtest.la + +# Tests that fused gtest files compile and work. +FUSED_GTEST_SRC = \ + fused-src/gtest/gtest-all.cc \ + fused-src/gtest/gtest.h \ + fused-src/gtest/gtest_main.cc + +TESTS += test/fused_gtest_test +check_PROGRAMS += test/fused_gtest_test +test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \ + samples/sample1.cc samples/sample1_unittest.cc +test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src" + +# Build rules for putting fused Google Test files into the distribution +# package. The user can also create those files by manually running +# scripts/fuse_gtest_files.py. +$(test_fused_gtest_test_SOURCES): fused-gtest + +fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ + $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \ + scripts/fuse_gtest_files.py + mkdir -p "$(srcdir)/fused-src" + chmod -R u+w "$(srcdir)/fused-src" + rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc" + rm -f "$(srcdir)/fused-src/gtest/gtest.h" + "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src" + cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/" + +maintainer-clean-local: + rm -rf "$(srcdir)/fused-src" + +# Death tests may produce core dumps in the build directory. In case +# this happens, clean them to keep distcleancheck happy. +CLEANFILES = core + +# Disables 'make install' as installing a compiled version of Google +# Test can lead to undefined behavior due to violation of the +# One-Definition Rule. + +install-exec-local: + echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." + false + +install-data-local: + echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." + false diff --git a/third_party/googletest/src/README b/third_party/googletest/src/README new file mode 100644 index 0000000..51a9376 --- /dev/null +++ b/third_party/googletest/src/README @@ -0,0 +1,424 @@ +Google C++ Testing Framework +============================ + +http://code.google.com/p/googletest/ + +Overview +-------- + +Google's framework for writing C++ tests on a variety of platforms +(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the +xUnit architecture. Supports automatic test discovery, a rich set of +assertions, user-defined assertions, death tests, fatal and non-fatal +failures, various options for running the tests, and XML test report +generation. + +Please see the project page above for more information as well as the +mailing list for questions, discussions, and development. There is +also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please +join us! + +Requirements for End Users +-------------------------- + +Google Test is designed to have fairly minimal requirements to build +and use with your projects, but there are some. Currently, we support +Linux, Windows, Mac OS X, and Cygwin. We will also make our best +effort to support other platforms (e.g. Solaris, AIX, and z/OS). +However, since core members of the Google Test project have no access +to these platforms, Google Test may have outstanding issues there. If +you notice any problems on your platform, please notify +googletestframework@googlegroups.com. Patches for fixing them are +even more welcome! + +### Linux Requirements ### + +These are the base requirements to build and use Google Test from a source +package (as described below): + * GNU-compatible Make or gmake + * POSIX-standard shell + * POSIX(-2) Regular Expressions (regex.h) + * A C++98-standard-compliant compiler + +### Windows Requirements ### + + * Microsoft Visual C++ 7.1 or newer + +### Cygwin Requirements ### + + * Cygwin 1.5.25-14 or newer + +### Mac OS X Requirements ### + + * Mac OS X 10.4 Tiger or newer + * Developer Tools Installed + +Also, you'll need CMake 2.6.4 or higher if you want to build the +samples using the provided CMake script, regardless of the platform. + +Requirements for Contributors +----------------------------- + +We welcome patches. If you plan to contribute a patch, you need to +build Google Test and its own tests from an SVN checkout (described +below), which has further requirements: + + * Python version 2.3 or newer (for running some of the tests and + re-generating certain source files from templates) + * CMake 2.6.4 or newer + +Getting the Source +------------------ + +There are two primary ways of getting Google Test's source code: you +can download a stable source release in your preferred archive format, +or directly check out the source from our Subversion (SVN) repositary. +The SVN checkout requires a few extra steps and some extra software +packages on your system, but lets you track the latest development and +make patches much more easily, so we highly encourage it. + +### Source Package ### + +Google Test is released in versioned source packages which can be +downloaded from the download page [1]. Several different archive +formats are provided, but the only difference is the tools used to +manipulate them, and the size of the resulting file. Download +whichever you are most comfortable with. + + [1] http://code.google.com/p/googletest/downloads/list + +Once the package is downloaded, expand it using whichever tools you +prefer for that type. This will result in a new directory with the +name "gtest-X.Y.Z" which contains all of the source code. Here are +some examples on Linux: + + tar -xvzf gtest-X.Y.Z.tar.gz + tar -xvjf gtest-X.Y.Z.tar.bz2 + unzip gtest-X.Y.Z.zip + +### SVN Checkout ### + +To check out the main branch (also known as the "trunk") of Google +Test, run the following Subversion command: + + svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn + +Setting up the Build +-------------------- + +To build Google Test and your tests that use it, you need to tell your +build system where to find its headers and source files. The exact +way to do it depends on which build system you use, and is usually +straightforward. + +### Generic Build Instructions ### + +Suppose you put Google Test in directory ${GTEST_DIR}. To build it, +create a library build target (or a project as called by Visual Studio +and Xcode) to compile + + ${GTEST_DIR}/src/gtest-all.cc + +with + + ${GTEST_DIR}/include and ${GTEST_DIR} + +in the header search path. Assuming a Linux-like system and gcc, +something like the following will do: + + g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc + ar -rv libgtest.a gtest-all.o + +Next, you should compile your test source file with +${GTEST_DIR}/include in the header search path, and link it with gtest +and any other necessary libraries: + + g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test + +As an example, the make/ directory contains a Makefile that you can +use to build Google Test on systems where GNU make is available +(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google +Test's own tests. Instead, it just builds the Google Test library and +a sample test. You can use it as a starting point for your own build +script. + +If the default settings are correct for your environment, the +following commands should succeed: + + cd ${GTEST_DIR}/make + make + ./sample1_unittest + +If you see errors, try to tweak the contents of make/Makefile to make +them go away. There are instructions in make/Makefile on how to do +it. + +### Using CMake ### + +Google Test comes with a CMake build script (CMakeLists.txt) that can +be used on a wide range of platforms ("C" stands for cross-platofrm.). +If you don't have CMake installed already, you can download it for +free from http://www.cmake.org/. + +CMake works by generating native makefiles or build projects that can +be used in the compiler environment of your choice. The typical +workflow starts with: + + mkdir mybuild # Create a directory to hold the build output. + cd mybuild + cmake ${GTEST_DIR} # Generate native build scripts. + +If you want to build Google Test's samples, you should replace the +last command with + + cmake -Dgtest_build_samples=ON ${GTEST_DIR} + +If you are on a *nix system, you should now see a Makefile in the +current directory. Just type 'make' to build gtest. + +If you use Windows and have Vistual Studio installed, a gtest.sln file +and several .vcproj files will be created. You can then build them +using Visual Studio. + +On Mac OS X with Xcode installed, a .xcodeproj file will be generated. + +### Legacy Build Scripts ### + +Before settling on CMake, we have been providing hand-maintained build +projects/scripts for Visual Studio, Xcode, and Autotools. While we +continue to provide them for convenience, they are not actively +maintained any more. We highly recommend that you follow the +instructions in the previous two sections to integrate Google Test +with your existing build system. + +If you still need to use the legacy build scripts, here's how: + +The msvc\ folder contains two solutions with Visual C++ projects. +Open the gtest.sln or gtest-md.sln file using Visual Studio, and you +are ready to build Google Test the same way you build any Visual +Studio project. Files that have names ending with -md use DLL +versions of Microsoft runtime libraries (the /MD or the /MDd compiler +option). Files without that suffix use static versions of the runtime +libraries (the /MT or the /MTd option). Please note that one must use +the same option to compile both gtest and the test code. If you use +Visual Studio 2005 or above, we recommend the -md version as /MD is +the default for new projects in these versions of Visual Studio. + +On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using +Xcode. Build the "gtest" target. The universal binary framework will +end up in your selected build directory (selected in the Xcode +"Preferences..." -> "Building" pane and defaults to xcode/build). +Alternatively, at the command line, enter: + + xcodebuild + +This will build the "Release" configuration of gtest.framework in your +default build location. See the "xcodebuild" man page for more +information about building different configurations and building in +different locations. + +Tweaking Google Test +-------------------- + +Google Test can be used in diverse environments. The default +configuration may not work (or may not work well) out of the box in +some environments. However, you can easily tweak Google Test by +defining control macros on the compiler command line. Generally, +these macros are named like GTEST_XYZ and you define them to either 1 +or 0 to enable or disable a certain feature. + +We list the most frequently used macros below. For a complete list, +see file include/gtest/internal/gtest-port.h. + +### Choosing a TR1 Tuple Library ### + +Some Google Test features require the C++ Technical Report 1 (TR1) +tuple library, which is not yet available with all compilers. The +good news is that Google Test implements a subset of TR1 tuple that's +enough for its own need, and will automatically use this when the +compiler doesn't provide TR1 tuple. + +Usually you don't need to care about which tuple library Google Test +uses. However, if your project already uses TR1 tuple, you need to +tell Google Test to use the same TR1 tuple library the rest of your +project uses, or the two tuple implementations will clash. To do +that, add + + -DGTEST_USE_OWN_TR1_TUPLE=0 + +to the compiler flags while compiling Google Test and your tests. If +you want to force Google Test to use its own tuple library, just add + + -DGTEST_USE_OWN_TR1_TUPLE=1 + +to the compiler flags instead. + +If you don't want Google Test to use tuple at all, add + + -DGTEST_HAS_TR1_TUPLE=0 + +and all features using tuple will be disabled. + +### Multi-threaded Tests ### + +Google Test is thread-safe where the pthread library is available. +After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE +macro to see whether this is the case (yes if the macro is #defined to +1, no if it's undefined.). + +If Google Test doesn't correctly detect whether pthread is available +in your environment, you can force it with + + -DGTEST_HAS_PTHREAD=1 + +or + + -DGTEST_HAS_PTHREAD=0 + +When Google Test uses pthread, you may need to add flags to your +compiler and/or linker to select the pthread library, or you'll get +link errors. If you use the CMake script or the deprecated Autotools +script, this is taken care of for you. If you use your own build +script, you'll need to read your compiler and linker's manual to +figure out what flags to add. + +### As a Shared Library (DLL) ### + +Google Test is compact, so most users can build and link it as a +static library for the simplicity. You can choose to use Google Test +as a shared library (known as a DLL on Windows) if you prefer. + +To compile *gtest* as a shared library, add + + -DGTEST_CREATE_SHARED_LIBRARY=1 + +to the compiler flags. You'll also need to tell the linker to produce +a shared library instead - consult your linker's manual for how to do +it. + +To compile your *tests* that use the gtest shared library, add + + -DGTEST_LINKED_AS_SHARED_LIBRARY=1 + +to the compiler flags. + +Note: while the above steps aren't technically necessary today when +using some compilers (e.g. GCC), they may become necessary in the +future, if we decide to improve the speed of loading the library (see +http://gcc.gnu.org/wiki/Visibility for details). Therefore you are +recommended to always add the above flags when using Google Test as a +shared library. Otherwise a future release of Google Test may break +your build script. + +### Avoiding Macro Name Clashes ### + +In C++, macros don't obey namespaces. Therefore two libraries that +both define a macro of the same name will clash if you #include both +definitions. In case a Google Test macro clashes with another +library, you can force Google Test to rename its macro to avoid the +conflict. + +Specifically, if both Google Test and some other code define macro +FOO, you can add + + -DGTEST_DONT_DEFINE_FOO=1 + +to the compiler flags to tell Google Test to change the macro's name +from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST. +For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write + + GTEST_TEST(SomeTest, DoesThis) { ... } + +instead of + + TEST(SomeTest, DoesThis) { ... } + +in order to define a test. + +Upgrating from an Earlier Version +--------------------------------- + +We strive to keep Google Test releases backward compatible. +Sometimes, though, we have to make some breaking changes for the +users' long-term benefits. This section describes what you'll need to +do if you are upgrading from an earlier version of Google Test. + +### Upgrading from 1.3.0 or Earlier ### + +You may need to explicitly enable or disable Google Test's own TR1 +tuple library. See the instructions in section "Choosing a TR1 Tuple +Library". + +### Upgrading from 1.4.0 or Earlier ### + +The Autotools build script (configure + make) is no longer officially +supportted. You are encouraged to migrate to your own build system or +use CMake. If you still need to use Autotools, you can find +instructions in the README file from Google Test 1.4.0. + +On platforms where the pthread library is available, Google Test uses +it in order to be thread-safe. See the "Multi-threaded Tests" section +for what this means to your build script. + +If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google +Test will no longer compile. This should affect very few people, as a +large portion of STL (including ) doesn't compile in this mode +anyway. We decided to stop supporting it in order to greatly simplify +Google Test's implementation. + +Developing Google Test +---------------------- + +This section discusses how to make your own changes to Google Test. + +### Testing Google Test Itself ### + +To make sure your changes work as intended and don't break existing +functionality, you'll want to compile and run Google Test's own tests. +For that you can use CMake: + + mkdir mybuild + cd mybuild + cmake -Dgtest_build_tests=ON ${GTEST_DIR} + +Make sure you have Python installed, as some of Google Test's tests +are written in Python. If the cmake command complains about not being +able to find Python ("Could NOT find PythonInterp (missing: +PYTHON_EXECUTABLE)"), try telling it explicitly where your Python +executable can be found: + + cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR} + +Next, you can build Google Test and all of its own tests. On *nix, +this is usually done by 'make'. To run the tests, do + + make test + +All tests should pass. + +### Regenerating Source Files ### + +Some of Google Test's source files are generated from templates (not +in the C++ sense) using a script. A template file is named FOO.pump, +where FOO is the name of the file it will generate. For example, the +file include/gtest/internal/gtest-type-util.h.pump is used to generate +gtest-type-util.h in the same directory. + +Normally you don't need to worry about regenerating the source files, +unless you need to modify them. In that case, you should modify the +corresponding .pump files instead and run the pump.py Python script to +regenerate them. You can find pump.py in the scripts/ directory. +Read the Pump manual [2] for how to use it. + + [2] http://code.google.com/p/googletest/wiki/PumpManual + +### Contributing a Patch ### + +We welcome patches. Please read the Google Test developer's guide [3] +for how you can contribute. In particular, make sure you have signed +the Contributor License Agreement, or we won't be able to accept the +patch. + + [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide + +Happy testing! diff --git a/third_party/googletest/src/build-aux/.keep b/third_party/googletest/src/build-aux/.keep new file mode 100644 index 0000000..e69de29 diff --git a/third_party/googletest/src/cmake/internal_utils.cmake b/third_party/googletest/src/cmake/internal_utils.cmake new file mode 100644 index 0000000..7efc2ac --- /dev/null +++ b/third_party/googletest/src/cmake/internal_utils.cmake @@ -0,0 +1,216 @@ +# Defines functions and macros useful for building Google Test and +# Google Mock. +# +# Note: +# +# - This file will be run twice when building Google Mock (once via +# Google Test's CMakeLists.txt, and once via Google Mock's). +# Therefore it shouldn't have any side effects other than defining +# the functions and macros. +# +# - The functions/macros defined in this file may depend on Google +# Test and Google Mock's option() definitions, and thus must be +# called *after* the options have been defined. + +# Tweaks CMake's default compiler/linker settings to suit Google Test's needs. +# +# This must be a macro(), as inside a function string() can only +# update variables in the function scope. +macro(fix_default_compiler_settings_) + if (MSVC) + # For MSVC, CMake sets certain flags to defaults we want to override. + # This replacement code is taken from sample in the CMake Wiki at + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. + foreach (flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) + # When Google Test is built as a shared library, it should also use + # shared runtime libraries. Otherwise, it may end up with multiple + # copies of runtime library data in different modules, resulting in + # hard-to-find crashes. When it is built as a static library, it is + # preferable to use CRT as static libraries, as we don't have to rely + # on CRT DLLs being available. CMake always defaults to using shared + # CRT libraries, so we override that default here. + string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") + endif() + + # We prefer more strict warning checking for building Google Test. + # Replaces /W3 with /W4 in defaults. + string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") + endforeach() + endif() +endmacro() + +# Defines the compiler/linker flags used to build Google Test and +# Google Mock. You can tweak these definitions to suit your need. A +# variable's value is empty before it's explicitly assigned to. +macro(config_compiler_and_linker) + if (NOT gtest_disable_pthreads) + # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. + find_package(Threads) + endif() + + fix_default_compiler_settings_() + if (MSVC) + # Newlines inside flags variables break CMake's NMake generator. + # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. + set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi") + set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") + set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") + set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-GR-") + elseif (CMAKE_COMPILER_IS_GNUCXX) + set(cxx_base_flags "-Wall -Wshadow") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + # Until version 4.3.2, GCC doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") + set(cxx_strict_flags "-Wextra") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") + set(cxx_exception_flags "-features=except") + # Sun Pro doesn't provide macros to indicate whether exceptions and + # RTTI are enabled, so we define GTEST_HAS_* explicitly. + set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR + CMAKE_CXX_COMPILER_ID STREQUAL "XL") + # CMake 2.8 changes Visual Age's compiler ID to "XL". + set(cxx_exception_flags "-qeh") + set(cxx_no_exception_flags "-qnoeh") + # Until version 9.0, Visual Age doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP") + set(cxx_base_flags "-AA -mt") + set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0") + # RTTI can not be disabled in HP aCC compiler. + set(cxx_no_rtti_flags "") + endif() + + if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. + set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") + else() + set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") + endif() + + # For building gtest's own tests and samples. + set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") + set(cxx_no_exception + "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") + set(cxx_default "${cxx_exception}") + set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") + set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") + + # For building the gtest libraries. + set(cxx_strict "${cxx_default} ${cxx_strict_flags}") +endmacro() + +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. +function(cxx_library_with_type name type cxx_flags) + # type can be either STATIC or SHARED to denote a static or shared library. + # ARGN refers to additional arguments after 'cxx_flags'. + add_library(${name} ${type} ${ARGN}) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + endif() + if (CMAKE_USE_PTHREADS_INIT) + target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + endif() +endfunction() + +######################################################################## +# +# Helper functions for creating build targets. + +function(cxx_shared_library name cxx_flags) + cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) +endfunction() + +function(cxx_library name cxx_flags) + cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) +endfunction() + +# cxx_executable_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ executable that depends on the given libraries and +# is built from the given source files with the given compiler flags. +function(cxx_executable_with_flags name cxx_flags libs) + add_executable(${name} ${ARGN}) + if (cxx_flags) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + endif() + if (BUILD_SHARED_LIBS) + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + endif() + # To support mixing linking in static and dynamic libraries, link each + # library in with an extra call to target_link_libraries. + foreach (lib "${libs}") + target_link_libraries(${name} ${lib}) + endforeach() +endfunction() + +# cxx_executable(name dir lib srcs...) +# +# creates a named target that depends on the given libs and is built +# from the given source files. dir/name.cc is implicitly included in +# the source file list. +function(cxx_executable name dir libs) + cxx_executable_with_flags( + ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) +endfunction() + +# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. +find_package(PythonInterp) + +# cxx_test_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ test that depends on the given libs and is built +# from the given source files with the given compiler flags. +function(cxx_test_with_flags name cxx_flags libs) + cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) + add_test(${name} ${name}) +endfunction() + +# cxx_test(name libs srcs...) +# +# creates a named test target that depends on the given libs and is +# built from the given source files. Unlike cxx_test_with_flags, +# test/name.cc is already implicitly included in the source file list. +function(cxx_test name libs) + cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" + "test/${name}.cc" ${ARGN}) +endfunction() + +# py_test(name) +# +# creates a Python test with the given name whose main module is in +# test/name.py. It does nothing if Python is not installed. +function(py_test name) + # We are not supporting Python tests on Linux yet as they consider + # all Linux environments to be google3 and try to use google3 features. + if (PYTHONINTERP_FOUND) + # ${CMAKE_BINARY_DIR} is known at configuration time, so we can + # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known + # only at ctest runtime (by calling ctest -c ), so + # we have to escape $ to delay variable substitution here. + add_test(${name} + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) + endif() +endfunction() diff --git a/third_party/googletest/src/codegear/gtest.cbproj b/third_party/googletest/src/codegear/gtest.cbproj new file mode 100644 index 0000000..95c3054 --- /dev/null +++ b/third_party/googletest/src/codegear/gtest.cbproj @@ -0,0 +1,138 @@ + + + + {bca37a72-5b07-46cf-b44e-89f8e06451a2} + Release + + + true + + + true + true + Base + + + true + true + Base + + + true + lib + JPHNE + NO_STRICT + true + true + CppStaticLibrary + true + rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. + rtl.lib;vcl.lib + 32 + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk + + + false + false + true + _DEBUG;$(Defines) + true + false + true + None + DEBUG + true + Debug + true + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppStaticLibrary + +FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse + + + CodeGear C++Builder Office 2000 Servers Package + CodeGear C++Builder Office XP Servers Package + FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 + + + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 0 + + + 1 + + + 2 + + + 9 + + + 10 + + + 11 + + + 12 + + + 14 + + + 13 + + + 15 + + + 16 + + + 17 + + + 18 + + + Cfg_1 + + + Cfg_2 + + + \ No newline at end of file diff --git a/third_party/googletest/src/codegear/gtest.groupproj b/third_party/googletest/src/codegear/gtest.groupproj new file mode 100644 index 0000000..faf31ca --- /dev/null +++ b/third_party/googletest/src/codegear/gtest.groupproj @@ -0,0 +1,54 @@ + + + {c1d923e0-6cba-4332-9b6f-3420acbf5091} + + + + + + + + + Default.Personality + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/googletest/src/codegear/gtest_all.cc b/third_party/googletest/src/codegear/gtest_all.cc new file mode 100644 index 0000000..121b2d8 --- /dev/null +++ b/third_party/googletest/src/codegear/gtest_all.cc @@ -0,0 +1,38 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Josh Kelley (joshkel@gmail.com) +// +// Google C++ Testing Framework (Google Test) +// +// C++Builder's IDE cannot build a static library from files with hyphens +// in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 . +// This file serves as a workaround. + +#include "src/gtest-all.cc" diff --git a/third_party/googletest/src/codegear/gtest_link.cc b/third_party/googletest/src/codegear/gtest_link.cc new file mode 100644 index 0000000..918eccd --- /dev/null +++ b/third_party/googletest/src/codegear/gtest_link.cc @@ -0,0 +1,40 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Josh Kelley (joshkel@gmail.com) +// +// Google C++ Testing Framework (Google Test) +// +// Links gtest.lib and gtest_main.lib into the current project in C++Builder. +// This means that these libraries can't be renamed, but it's the only way to +// ensure that Debug versus Release test builds are linked against the +// appropriate Debug or Release build of the libraries. + +#pragma link "gtest.lib" +#pragma link "gtest_main.lib" diff --git a/third_party/googletest/src/codegear/gtest_main.cbproj b/third_party/googletest/src/codegear/gtest_main.cbproj new file mode 100644 index 0000000..d76ce13 --- /dev/null +++ b/third_party/googletest/src/codegear/gtest_main.cbproj @@ -0,0 +1,82 @@ + + + + {bca37a72-5b07-46cf-b44e-89f8e06451a2} + Release + + + true + + + true + true + Base + + + true + true + Base + + + true + lib + JPHNE + NO_STRICT + true + true + CppStaticLibrary + true + rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. + rtl.lib;vcl.lib + 32 + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk + + + false + false + true + _DEBUG;$(Defines) + true + false + true + None + DEBUG + true + Debug + true + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppStaticLibrary + +FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse + CodeGear C++Builder Office 2000 Servers Package + CodeGear C++Builder Office XP Servers Package + FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 + + + + + 0 + + + Cfg_1 + + + Cfg_2 + + + diff --git a/third_party/googletest/src/codegear/gtest_unittest.cbproj b/third_party/googletest/src/codegear/gtest_unittest.cbproj new file mode 100644 index 0000000..dc5db8e --- /dev/null +++ b/third_party/googletest/src/codegear/gtest_unittest.cbproj @@ -0,0 +1,88 @@ + + + + {eea63393-5ac5-4b9c-8909-d75fef2daa41} + Release + + + true + + + true + true + Base + + + true + true + Base + + + exe + true + NO_STRICT + JPHNE + true + ..\test + true + CppConsoleApplication + true + true + rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi + false + $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;.. + $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test + true + + + false + false + true + _DEBUG;$(Defines) + true + false + true + None + DEBUG + true + Debug + true + true + true + $(BDS)\lib\debug;$(ILINK_LibraryPath) + Full + true + + + NDEBUG;$(Defines) + Release + $(BDS)\lib\release;$(ILINK_LibraryPath) + None + + + CPlusPlusBuilder.Personality + CppConsoleApplication + +FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse + + + CodeGear C++Builder Office 2000 Servers Package + CodeGear C++Builder Office XP Servers Package + FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test2NO_STRICTSTRICT + + + + + 0 + + + 1 + + + Cfg_1 + + + Cfg_2 + + + \ No newline at end of file diff --git a/third_party/googletest/src/configure.ac b/third_party/googletest/src/configure.ac new file mode 100644 index 0000000..fa66029 --- /dev/null +++ b/third_party/googletest/src/configure.ac @@ -0,0 +1,68 @@ +m4_include(m4/acx_pthread.m4) + +# At this point, the Xcode project assumes the version string will be three +# integers separated by periods and surrounded by square brackets (e.g. +# "[1.0.1]"). It also asumes that there won't be any closing parenthesis +# between "AC_INIT(" and the closing ")" including comments and strings. +AC_INIT([Google C++ Testing Framework], + [1.6.0], + [googletestframework@googlegroups.com], + [gtest]) + +# Provide various options to initialize the Autoconf and configure processes. +AC_PREREQ([2.59]) +AC_CONFIG_SRCDIR([./COPYING]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([build-aux/config.h]) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config]) + +# Initialize Automake with various options. We require at least v1.9, prevent +# pedantic complaints about package files, and enable various distribution +# targets. +AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects]) + +# Check for programs used in building Google Test. +AC_PROG_CC +AC_PROG_CXX +AC_LANG([C++]) +AC_PROG_LIBTOOL + +# TODO(chandlerc@google.com): Currently we aren't running the Python tests +# against the interpreter detected by AM_PATH_PYTHON, and so we condition +# HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's +# version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" +# hashbang. +PYTHON= # We *do not* allow the user to specify a python interpreter +AC_PATH_PROG([PYTHON],[python],[:]) +AS_IF([test "$PYTHON" != ":"], + [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) +AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) + +# Configure pthreads. +AC_ARG_WITH([pthreads], + [AS_HELP_STRING([--with-pthreads], + [use pthreads (default is yes)])], + [with_pthreads=$withval], + [with_pthreads=check]) + +have_pthreads=no +AS_IF([test "x$with_pthreads" != "xno"], + [ACX_PTHREAD( + [], + [AS_IF([test "x$with_pthreads" != "xcheck"], + [AC_MSG_FAILURE( + [--with-pthreads was specified, but unable to be used])])]) + have_pthreads="$acx_pthread_ok"]) +AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"]) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_LIBS) + +# TODO(chandlerc@google.com) Check for the necessary system headers. + +# TODO(chandlerc@google.com) Check the types, structures, and other compiler +# and architecture characteristics. + +# Output the generated files. No further autoconf macros may be used. +AC_OUTPUT diff --git a/third_party/googletest/src/include/gtest/gtest-death-test.h b/third_party/googletest/src/include/gtest/gtest-death-test.h new file mode 100644 index 0000000..a27883f --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-death-test.h @@ -0,0 +1,283 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +#include "gtest/internal/gtest-death-test-internal.h" + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i); +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +# define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +# define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +# define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +# define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-message.h b/third_party/googletest/src/include/gtest/gtest-message.h new file mode 100644 index 0000000..9b7142f --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-message.h @@ -0,0 +1,230 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + +#include "gtest/internal/gtest-string.h" +#include "gtest/internal/gtest-internal.h" + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + // We allocate the stringstream separately because otherwise each use of + // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's + // stack frame leading to huge stack frames in some cases; gcc does not reuse + // the stack space. + Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); + } + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + ::GTestStreamToHelper(ss_.get(), val); + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_.get(), pointer); + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + Message& operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as a String. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::String GetString() const { + return internal::StringStreamToString(ss_.get()); + } + + private: + +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_.get(), pointer); + } + } + template + inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { + ::GTestStreamToHelper(ss_.get(), value); + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + const internal::scoped_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-param-test.h b/third_party/googletest/src/include/gtest/gtest-param-test.h new file mode 100644 index 0000000..6407cfd --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-param-test.h @@ -0,0 +1,1421 @@ +// This file was GENERATED by command: +// pump.py gtest-param-test.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + +#include "gtest/internal/gtest-port.h" + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-param-util-generated.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-param-test.h.pump b/third_party/googletest/src/include/gtest/gtest-param-test.h.pump new file mode 100644 index 0000000..401cb51 --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-param-test.h.pump @@ -0,0 +1,487 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of Values arguments we want to support. +$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + +#include "gtest/internal/gtest-port.h" + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-param-util-generated.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to $n parameters. +// +$range i 1..n +$for i [[ +$range j 1..i + +template <$for j, [[typename T$j]]> +internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) { + return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]); +} + +]] + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to $maxtuple arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +$range i 2..maxtuple +$for i [[ +$range j 1..i + +template <$for j, [[typename Generator$j]]> +internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( + $for j, [[const Generator$j& g$j]]) { + return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>( + $for j, [[g$j]]); +} + +]] +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-printers.h b/third_party/googletest/src/include/gtest/gtest-printers.h new file mode 100644 index 0000000..9cbab3f --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-printers.h @@ -0,0 +1,796 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include // NOLINT +#include +#include +#include +#include +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-internal.h" + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// For selecting which printer to use when a given type has neither << +// nor PrintTo(). +enum TypeKind { + kProtobuf, // a protobuf type + kConvertibleToInteger, // a type implicitly convertible to BiggestInt + // (e.g. a named or unnamed enum type) + kOtherType // anything else +}; + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for T, where kTypeKind is the +// "kind" of T as defined by enum TypeKind. +template +class TypeWithoutFormatter { + public: + // This default version is called when kTypeKind is kOtherType. + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast(&value), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + *os << ("<" + pretty_str + ">"); + } +}; + +template +class TypeWithoutFormatter { + public: + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(const T& value, ::std::ostream* os) { + const internal::BiggestInt kBigInt = value; + *os << kBigInt; + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its debug string is printed; if it's an enum or +// of a type implicitly convertible to BiggestInt, it's printed as an +// integer; otherwise the bytes in the value are printed. This is +// what UniversalPrinter::Print() does when it knows nothing about +// type T and T has neither << operator nor PrintTo(). +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { + TypeWithoutFormatter::value ? kProtobuf : + internal::ImplicitlyConvertible::value ? + kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // C++ doesn't allow casting from a function pointer to any object + // pointer. + // + // IsTrue() silences warnings: "Condition is always true", + // "unreachable code". + if (IsTrue(ImplicitlyConvertible::value)) { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. However, we cannot cast it to const void* directly, + // even using reinterpret_cast, as earlier versions of gcc + // (e.g. 3.4.5) cannot compile the cast when p is a function + // pointer. Casting to UInt64 first solves the problem. + *os << reinterpret_cast( + reinterpret_cast(p)); + } + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os); + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo( + const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_TR1_TUPLE + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray(const char* begin, + size_t len, + ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); +} +inline void UniversalTersePrint(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(string(str), os); + } +} +inline void UniversalTersePrint(char* str, ::std::ostream* os) { + UniversalTersePrint(static_cast(str), os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter::Print(value, os); +} + +#if GTEST_HAS_TR1_TUPLE +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. + +// The inductive case. +template +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +// We have to specialize the entire TuplePrefixPrinter<> class +// template here, even though the definition of +// TersePrintPrefixToStrings() is the same as the generic version, as +// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't +// support specializing a method template of a class template. +template <> +struct TuplePrefixPrinter<1> { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); + } + + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get<0>(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrint(value, &ss); + return ss.str(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-spi.h b/third_party/googletest/src/include/gtest/gtest-spi.h new file mode 100644 index 0000000..b226e55 --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-spi.h @@ -0,0 +1,232 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include "gtest/gtest.h" + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-test-part.h b/third_party/googletest/src/include/gtest/gtest-test-part.h new file mode 100644 index 0000000..8aeea14 --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-test-part.h @@ -0,0 +1,176 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { return file_name_.c_str(); } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static internal::String ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // NULL if the source file is unknown. + internal::String file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + internal::String summary_; // The test failure summary. + internal::String message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/third_party/googletest/src/include/gtest/gtest-typed-test.h b/third_party/googletest/src/include/gtest/gtest-typed-test.h new file mode 100644 index 0000000..fe1e83b --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest-typed-test.h @@ -0,0 +1,259 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-type-util.h" + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +# define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +# define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +# define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ diff --git a/third_party/googletest/src/include/gtest/gtest.h b/third_party/googletest/src/include/gtest/gtest.h new file mode 100644 index 0000000..cd01c7b --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest.h @@ -0,0 +1,2155 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" +#include "gtest/gtest-death-test.h" +#include "gtest/gtest-message.h" +#include "gtest/gtest-param-test.h" +#include "gtest/gtest-printers.h" +#include "gtest/gtest_prod.h" +#include "gtest/gtest-test-part.h" +#include "gtest/gtest-typed-test.h" + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared in gtest-internal.h but defined here, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestCase; +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL ? message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == NULL) + message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr< ::std::string> message_; + + GTEST_DISALLOW_ASSIGN_(AssertionResult); +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test. Only the last value for a given + // key is remembered. + // These are public static so they can be called from utility functions + // that are not members of the test fixture. + // The arguments are const char* instead strings, as Google Test is used + // on platforms where string doesn't compile. + // + // Note that a driving consideration for these RecordProperty methods + // was to produce xml output suited to the Greenspan charting utility, + // which at present will only chart values that fit in a 32-bit int. It + // is the user's responsibility to restrict their values to 32-bit ints + // if they intend them to be used with Greenspan. + static void RecordProperty(const char* key, const char* value); + static void RecordProperty(const char* key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const char* a_key, const char* a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const char* new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + internal::String key_; + // The value supplied by the user. + internal::String value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. + void RecordProperty(const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != NULL) + return value_param_->c_str(); + return NULL; + } + + // Returns true if this test should run, that is if the test is not disabled + // (or it is disabled but the also_run_disabled_tests flag has been specified) + // and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: + +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::UnitTestImpl; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const char* test_case_name, const char* name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_case_name_; // Test case name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const internal::scoped_ptr value_param_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test case. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs SetUpTestCase() for this TestCase. This wrapper is needed + // for catching exceptions thrown from SetUpTestCase(). + void RunSetUpTestCase() { (*set_up_tc_)(); } + + // Runs TearDownTestCase() for this TestCase. This wrapper is + // needed for catching exceptions thrown from TearDownTestCase(). + void RunTearDownTestCase() { (*tear_down_tc_)(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + internal::String name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const; + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const; + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace); + + // Adds a TestProperty to the current TestResult object. If the result already + // contains a property with the same key, the value will be updated. + void RecordPropertyForCurrentTest(const char* key, const char* value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const internal::String& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace(); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char*, and print it as a C string when it is compared against an +// std::string object, for example. +// +// The default implementation ignores the type of the other operand. +// Some specialized versions are used to handle formatting wide or +// narrow C strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +String FormatForComparisonFailureMessage(const T1& value, + const T2& /* other_operand */) { + // C++Builder compiles this incorrectly if the namespace isn't explicitly + // given. + return ::testing::PrintToString(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal, like NULL, false, or 0. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual, + // The following line prevents this overload from being considered if T2 + // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) + // expands to Compare("", "", NULL, my_ptr), which requires a conversion + // to match the Secret* in the other overload, which would otherwise make + // this template match better. + typename EnableIf::value>::type* = 0) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to ASSERT_EQ() is a + // pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + // We used to have a second template parameter instead of Secret*. That + // template parameter would deduce to 'long', making this a better match + // than the first overload even without the first overload's EnableIf. + // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to + // non-pointer argument" (even a deduced integral argument), so the old + // implementation caused warnings in user code. + Secret* /* expected (NULL) */, + T* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, < ); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, > ); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + ::std::stringstream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StringStreamToString(&expected_ss), + StringStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + String const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. This member function is non-static, even though it only + // references static data, to reduce the opportunity for incorrect uses + // like writing 'WithParamInterface::GetParam()' for a test that + // uses a fixture whose parameter type is int. + const ParamType& GetParam() const { return *parameter_; } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = NULL; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. +// +// Examples: +// +// EXPECT_TRUE(server.StatusIsOK()); +// ASSERT_FALSE(server.HasPendingRequest(port)) +// << "There are still pending requests " << "on port " << port; + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +#include "gtest/gtest_pred_impl.h" + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C String Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + (void)internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +// Use this macro in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). + +#define RUN_ALL_TESTS()\ + (::testing::UnitTest::GetInstance()->Run()) + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/third_party/googletest/src/include/gtest/gtest_pred_impl.h b/third_party/googletest/src/include/gtest/gtest_pred_impl.h new file mode 100644 index 0000000..3805f85 --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest_pred_impl.h @@ -0,0 +1,358 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/third_party/googletest/src/include/gtest/gtest_prod.h b/third_party/googletest/src/include/gtest/gtest_prod.h new file mode 100644 index 0000000..da80ddc --- /dev/null +++ b/third_party/googletest/src/include/gtest/gtest_prod.h @@ -0,0 +1,58 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-death-test-internal.h b/third_party/googletest/src/include/gtest/internal/gtest-death-test-internal.h new file mode 100644 index 0000000..1d9f83b --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-death-test-internal.h @@ -0,0 +1,308 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +#include "gtest/internal/gtest-internal.h" + +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const String& message); + + private: + // A string containing a description of the outcome of the last death test. + static String last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const String& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + String file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + String file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-filepath.h b/third_party/googletest/src/include/gtest/internal/gtest-filepath.h new file mode 100644 index 0000000..b36b3cf --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-filepath.h @@ -0,0 +1,210 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + +#include "gtest/internal/gtest-string.h" + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const char* pathname) : pathname_(pathname) { + Normalize(); + } + + explicit FilePath(const String& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + String ToString() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is NULL or "". + bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + String pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-internal.h b/third_party/googletest/src/include/gtest/internal/gtest-internal.h new file mode 100644 index 0000000..7aa1197 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-internal.h @@ -0,0 +1,1226 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-string.h" +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-type-util.h" + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Google Test defines the testing::Message class to allow construction of +// test messages via the << operator. The idea is that anything +// streamable to std::ostream can be streamed to a testing::Message. +// This allows a user to use his own types in Google Test assertions by +// overloading the << operator. +// +// util/gtl/stl_logging-inl.h overloads << for STL containers. These +// overloads cannot be defined in the std namespace, as that will be +// undefined behavior. Therefore, they are defined in the global +// namespace instead. +// +// C++'s symbol lookup rule (i.e. Koenig lookup) says that these +// overloads are visible in either the std namespace or the global +// namespace, but not other namespaces, including the testing +// namespace which Google Test's Message class is in. +// +// To allow STL containers (and other types that has a << operator +// defined in the global namespace) to be used in Google Test assertions, +// testing::Message must access the custom << operator from the global +// namespace. Hence this helper function. +// +// Note: Jeffrey Yasskin suggested an alternative fix by "using +// ::operator<<;" in the definition of Message's operator<<. That fix +// doesn't require a helper function, but unfortunately doesn't +// compile with MSVC. +template +inline void GTestStreamToHelper(std::ostream* os, const T& val) { + *os << val; +} + +class ProtocolMessage; +namespace proto2 { class Message; } + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_IS_NULL_LITERAL_(x) false +#else +# define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ String AppendUserMessage(const String& gtest_msg, + const Message& user_msg); + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +// The Symbian compiler has a bug that prevents it from selecting the +// correct overload of FormatForComparisonFailureMessage (see below) +// unless we pass the first argument by reference. If we do that, +// however, Visual Age C++ 10.1 generates a compiler error. Therefore +// we only apply the work-around for Symbian. +#if defined(__SYMBIAN32__) +# define GTEST_CREF_WORKAROUND_ const& +#else +# define GTEST_CREF_WORKAROUND_ +#endif + +// When this operand is a const char* or char*, if the other operand +// is a ::std::string or ::string, we print this operand as a C string +// rather than a pointer (we do the same for wide strings); otherwise +// we print it as a pointer to be safe. + +// This internal macro is used to avoid duplicated code. +#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ +inline String FormatForComparisonFailureMessage(\ + operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \ + const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +}\ +inline String FormatForComparisonFailureMessage(\ + const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \ + const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +} + +GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) +#if GTEST_HAS_STD_WSTRING +GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_STRING +GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) +#endif // GTEST_HAS_GLOBAL_STRING +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_GLOBAL_WSTRING + +#undef GTEST_FORMAT_IMPL_ + +// The next four overloads handle the case where the operand being +// printed is a char/wchar_t pointer and the other operand is not a +// string/wstring object. In such cases, we just print the operand as +// a pointer to be safe. +#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \ + template \ + String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \ + const T&) { \ + return PrintToString(static_cast(p)); \ + } + +GTEST_FORMAT_CHAR_PTR_IMPL_(char) +GTEST_FORMAT_CHAR_PTR_IMPL_(const char) +GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t) +GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t) + +#undef GTEST_FORMAT_CHAR_PTR_IMPL_ + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ String GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline String GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? String(str) : String(str, comma - str); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", + case_name, index).c_str(), + GetPrefixUntilComma(test_names).c_str(), + GetTypeName().c_str(), + NULL, // No value parameter. + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, + int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Defining a variable of type CompileAssertTypesEqual will cause a +// compiler error iff T1 and T2 are different types. +template +struct CompileAssertTypesEqual; + +template +struct CompileAssertTypesEqual { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template +struct RemoveReference { typedef T type; }; // NOLINT +template +struct RemoveReference { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_REFERENCE_(T) \ + typename ::testing::internal::RemoveReference::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template +struct RemoveConst { typedef T type; }; // NOLINT +template +struct RemoveConst { typedef T type; }; // NOLINT + +// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above +// definition to fail to remove the const in 'const int[3]' and 'const +// char[3][4]'. The following specialization works around the bug. +// However, it causes trouble with GCC and thus needs to be +// conditionally compiled. +#if defined(_MSC_VER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; +#endif + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_CONST_(T) \ + typename ::testing::internal::RemoveConst::type + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) + +// ImplicitlyConvertible::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4244) // Temporarily disables warning 4244. + + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +# pragma warning(pop) // Restores the warning state. +#elif defined(__BORLANDC__) + // C++Builder cannot use member overload resolution during template + // instantiation. The simplest workaround is to use its C++0x type traits + // functions (C++Builder 2009 and above only). + static const bool value = __is_convertible(From, To); +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template +const bool ImplicitlyConvertible::value; + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible::value || + ImplicitlyConvertible::value> { +}; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// Note that we look for both C::iterator and C::const_iterator. The +// reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template +IsContainer IsContainerTest(int /* dummy */, + typename C::iterator* /* it */ = NULL, + typename C::const_iterator* /* const_it */ = NULL) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// EnableIf::type is void when 'Cond' is true, and +// undefined when 'Cond' is false. To use SFINAE to make a function +// overload only apply when a particular expression is true, add +// "typename EnableIf::type* = 0" as the last parameter. +template struct EnableIf; +template<> struct EnableIf { typedef void type; }; // NOLINT + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + static_cast(StaticAssertTypeEqHelper()); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t a_size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + } + size_ = a_size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg.value) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws.") + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, NULL, NULL, \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-linked_ptr.h b/third_party/googletest/src/include/gtest/internal/gtest-linked_ptr.h new file mode 100644 index 0000000..57147b4 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-linked_ptr.h @@ -0,0 +1,233 @@ +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + +#include "gtest/internal/gtest-port.h" + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + // L < g_linked_ptr_mutex + void join(linked_ptr_internal const* ptr) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + // L < g_linked_ptr_mutex + bool depart() { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h b/third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h new file mode 100644 index 0000000..2582675 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h @@ -0,0 +1,4822 @@ +// This file was GENERATED by command: +// pump.py gtest-param-util-generated.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, + v23_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, + v35_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, + v47_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_, v50_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h.pump b/third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h.pump new file mode 100644 index 0000000..dbe9386 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-param-util-generated.h.pump @@ -0,0 +1,301 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of Values arguments we want to support. +$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most $n arguments in Values, +// and at most $maxtuple arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at $maxtuple. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +$range i 2..n +$for i [[ +$range j 1..i + +template <$for j, [[typename T$j]]> +class ValueArray$i { + public: + ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} + + template + operator ParamGenerator() const { + const T array[] = {$for j, [[v$(j)_]]}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray$i& other); + +$for j [[ + + const T$j v$(j)_; +]] + +}; + +]] + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +$range i 2..maxtuple +$for i [[ +$range j 1..i +$range k 2..i + +template <$for j, [[typename T$j]]> +class CartesianProductGenerator$i + : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { + public: + typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; + + CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) + : $for j, [[g$(j)_(g$j)]] {} + virtual ~CartesianProductGenerator$i() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, $for j, [[ + + const ParamGenerator& g$j, + const typename ParamGenerator::iterator& current$(j)]]) + : base_(base), +$for j, [[ + + begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j) +]] { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current$(i)_; + +$for k [[ + if (current$(i+2-k)_ == end$(i+2-k)_) { + current$(i+2-k)_ = begin$(i+2-k)_; + ++current$(i+2-k-1)_; + } + +]] + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ($for j && [[ + + current$(j)_ == typed_other->current$(j)_ +]]); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), $for j, [[ + + begin$(j)_(other.begin$(j)_), + end$(j)_(other.end$(j)_), + current$(j)_(other.current$(j)_) +]] { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType($for j, [[*current$(j)_]]); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return +$for j || [[ + + current$(j)_ == end$(j)_ +]]; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. +$for j [[ + + const typename ParamGenerator::iterator begin$(j)_; + const typename ParamGenerator::iterator end$(j)_; + typename ParamGenerator::iterator current$(j)_; +]] + + ParamType current_value_; + }; // class CartesianProductGenerator$i::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator$i& other); + + +$for j [[ + const ParamGenerator g$(j)_; + +]] +}; // class CartesianProductGenerator$i + + +]] + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +$range i 2..maxtuple +$for i [[ +$range j 1..i + +template <$for j, [[class Generator$j]]> +class CartesianProductHolder$i { + public: +CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) + : $for j, [[g$(j)_(g$j)]] {} + template <$for j, [[typename T$j]]> + operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { + return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( + new CartesianProductGenerator$i<$for j, [[T$j]]>( +$for j,[[ + + static_cast >(g$(j)_) +]])); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder$i& other); + + +$for j [[ + const Generator$j g$(j)_; + +]] +}; // class CartesianProductHolder$i + +]] + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-param-util.h b/third_party/googletest/src/include/gtest/internal/gtest-param-util.h new file mode 100644 index 0000000..0ef9718 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-param-util.h @@ -0,0 +1,619 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-linked_ptr.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-printers.h" + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const string& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const string& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const string& instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const string& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + Message test_case_name_stream; + if ( !instantiation_name.empty() ) + test_case_name_stream << instantiation_name << "/"; + test_case_name_stream << test_info->test_case_base_name; + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name << "/" << i; + MakeAndRegisterTestInfo( + test_case_name_stream.GetString().c_str(), + test_name_stream.GetString().c_str(), + NULL, // No type parameter. + PrintToString(*param_it).c_str(), + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const string test_case_base_name; + const string test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const string test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-port.h b/third_party/googletest/src/include/gtest/internal/gtest-port.h new file mode 100644 index 0000000..157b47f --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-port.h @@ -0,0 +1,1775 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// IteratorTraits - partial implementation of std::iterator_traits, which +// is not available in libCstd when compiled with Sun C++. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like +// platforms, or a reduced regular exception syntax on +// other platforms, including Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +# define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(__MINGW__) || defined(__MINGW32__) +# define GTEST_OS_WINDOWS_MINGW 1 +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# ifdef ANDROID +# define GTEST_OS_LINUX_ANDROID 1 +# endif // ANDROID +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#endif // __CYGWIN__ + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if !GTEST_OS_WINDOWS +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# if !GTEST_OS_NACL +// TODO(vladl@google.com): Remove this condition when Native Client SDK adds +// strings.h (tracked in +// http://code.google.com/p/nativeclient/issues/detail?id=1175). +# include // Native Client doesn't provide strings.h. +# endif +#elif !GTEST_OS_WINDOWS_MOBILE +# include +# include +#endif + +// Defines this to true iff Google Test can use POSIX regular expressions. +#ifndef GTEST_HAS_POSIX_RE +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +#endif + +#if GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_HAS_POSIX_RE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +# define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +# error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +# define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +# define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +# define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +# ifdef __GXX_RTTI +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +// The user didn't tell us not to do it, so we assume it's OK. +# define GTEST_HAS_TR1_TUPLE 1 +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, GCC 4.0.0+ and MSVC +// 2010 are the only mainstream compilers that come with a TR1 tuple +// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by +// defining __GNUC__ and friends, but cannot compile GCC's tuple +// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB +// Feature Pack download, which we cannot assume the user has. +# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ + || _MSC_VER >= 1600 +# define GTEST_USE_OWN_TR1_TUPLE 0 +# else +# define GTEST_USE_OWN_TR1_TUPLE 1 +# endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +# if GTEST_USE_OWN_TR1_TUPLE +# include "gtest/internal/gtest-tuple.h" +# elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +# ifdef BOOST_HAS_TR1_TUPLE +# undef BOOST_HAS_TR1_TUPLE +# endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +# include + +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +# define _TR1_FUNCTIONAL 1 +# include +# undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +# else +# include // NOLINT +# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +# else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +# include // NOLINT +# endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX) +# define GTEST_HAS_DEATH_TEST 1 +# include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +# define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +namespace testing { + +class Message; + +namespace internal { + +class String; + +// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template +struct CompileAssert { +}; + +#define GTEST_COMPILE_ASSERT_(expr, msg) \ + typedef ::testing::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + +// Implementation details of GTEST_COMPILE_ASSERT_: +// +// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// GTEST_COMPILE_ASSERT_(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. +// +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#else +typedef ::std::string string; +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT + +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of a string, as Google Test may be used + // where string is not available. We also do not use Google Test's own + // String type here, in order to simplify dependencies between the + // files. + const char* pattern_; + bool is_valid_; + +#if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +#else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + const To to = NULL; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ String GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ String GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION + + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +// GTEST_HAS_DEATH_TEST implies we have ::std::string. +const ::std::vector& GetArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) {} + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { notified_ = true; } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + while(!notified_) { + SleepMilliseconds(10); + } + } + + private: + volatile bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + } + + // Releases this mutex. + void Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_ = 0; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + owner_ = 0; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +# define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +# define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +# define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +template +struct IteratorTraits { + typedef typename Iterator::value_type value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +# else +inline int IsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +# pragma warning(push) +# pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: + +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-string.h b/third_party/googletest/src/include/gtest/internal/gtest-string.h new file mode 100644 index 0000000..dc3a07b --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-string.h @@ -0,0 +1,350 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include +#include "gtest/internal/gtest-port.h" + +#include + +namespace testing { +namespace internal { + +// String - a UTF-8 string class. +// +// For historic reasons, we don't use std::string. +// +// TODO(wan@google.com): replace this class with std::string or +// implement it in terms of the latter. +// +// Note that String can represent both NULL and the empty string, +// while std::string cannot represent NULL. +// +// NULL and the empty string are considered different. NULL is less +// than anything (including the empty string) except itself. +// +// This class only provides minimum functionality necessary for +// implementing Google Test. We do not intend to implement a full-fledged +// string class here. +// +// Since the purpose of this class is to provide a substitute for +// std::string on platforms where it cannot be used, we define a copy +// constructor and assignment operators such that we don't need +// conditional compilation in a lot of places. +// +// In order to make the representation efficient, the d'tor of String +// is not virtual. Therefore DO NOT INHERIT FROM String. +class GTEST_API_ String { + public: + // Static utility methods + + // Returns the input enclosed in double quotes if it's not NULL; + // otherwise returns "(null)". For example, "\"Hello\"" is returned + // for input "Hello". + // + // This is useful for printing a C string in the syntax of a literal. + // + // Known issue: escape sequences are not handled yet. + static String ShowCStringQuoted(const char* c_str); + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static String ShowWideCString(const wchar_t* wide_c_str); + + // Similar to ShowWideCString(), except that this function encloses + // the converted string in double quotes. + static String ShowWideCStringQuoted(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Formats a list of arguments to a String, using the same format + // spec string as for printf. + // + // We do not use the StringPrintf class as it is not universally + // available. + // + // The result is limited to 4096 characters (including the tailing + // 0). If 4096 characters are not enough to format the input, + // "" is returned. + static String Format(const char* format, ...); + + // C'tors + + // The default c'tor constructs a NULL string. + String() : c_str_(NULL), length_(0) {} + + // Constructs a String by cloning a 0-terminated C string. + String(const char* a_c_str) { // NOLINT + if (a_c_str == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(a_c_str, strlen(a_c_str)); + } + } + + // Constructs a String by copying a given number of chars from a + // buffer. E.g. String("hello", 3) creates the string "hel", + // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", + // and String(NULL, 1) results in access violation. + String(const char* buffer, size_t a_length) { + ConstructNonNull(buffer, a_length); + } + + // The copy c'tor creates a new copy of the string. The two + // String objects do not share content. + String(const String& str) : c_str_(NULL), length_(0) { *this = str; } + + // D'tor. String is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~String() { delete[] c_str_; } + + // Allows a String to be implicitly converted to an ::std::string or + // ::string, and vice versa. Converting a String containing a NULL + // pointer to ::std::string or ::string is undefined behavior. + // Converting a ::std::string or ::string containing an embedded NUL + // character to a String will result in the prefix up to the first + // NUL character. + String(const ::std::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::std::string() const { return ::std::string(c_str(), length()); } + +#if GTEST_HAS_GLOBAL_STRING + String(const ::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::string() const { return ::string(c_str(), length()); } +#endif // GTEST_HAS_GLOBAL_STRING + + // Returns true iff this is an empty string (i.e. ""). + bool empty() const { return (c_str() != NULL) && (length() == 0); } + + // Compares this with another String. + // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 + // if this is greater than rhs. + int Compare(const String& rhs) const; + + // Returns true iff this String equals the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } + + // Returns true iff this String is less than the given String. A + // NULL string is considered less than "". + bool operator<(const String& rhs) const { return Compare(rhs) < 0; } + + // Returns true iff this String doesn't equal the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } + + // Returns true iff this String ends with the given suffix. *Any* + // String is considered to end with a NULL or empty suffix. + bool EndsWith(const char* suffix) const; + + // Returns true iff this String ends with the given suffix, not considering + // case. Any String is considered to end with a NULL or empty suffix. + bool EndsWithCaseInsensitive(const char* suffix) const; + + // Returns the length of the encapsulated string, or 0 if the + // string is NULL. + size_t length() const { return length_; } + + // Gets the 0-terminated C string this String object represents. + // The String object still owns the string. Therefore the caller + // should NOT delete the return value. + const char* c_str() const { return c_str_; } + + // Assigns a C string to this object. Self-assignment works. + const String& operator=(const char* a_c_str) { + return *this = String(a_c_str); + } + + // Assigns a String object to this object. Self-assignment works. + const String& operator=(const String& rhs) { + if (this != &rhs) { + delete[] c_str_; + if (rhs.c_str() == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(rhs.c_str(), rhs.length()); + } + } + + return *this; + } + + private: + // Constructs a non-NULL String from the given content. This + // function can only be called when c_str_ has not been allocated. + // ConstructNonNull(NULL, 0) results in an empty string (""). + // ConstructNonNull(NULL, non_zero) is undefined behavior. + void ConstructNonNull(const char* buffer, size_t a_length) { + char* const str = new char[a_length + 1]; + memcpy(str, buffer, a_length); + str[a_length] = '\0'; + c_str_ = str; + length_ = a_length; + } + + const char* c_str_; + size_t length_; +}; // class String + +// Streams a String to an ostream. Each '\0' character in the String +// is replaced with "\\0". +inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { + if (str.c_str() == NULL) { + os << "(null)"; + } else { + const char* const c_str = str.c_str(); + for (size_t i = 0; i != str.length(); i++) { + if (c_str[i] == '\0') { + os << "\\0"; + } else { + os << c_str[i]; + } + } + } + return os; +} + +// Gets the content of the stringstream's buffer as a String. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ String StringStreamToString(::std::stringstream* stream); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". + +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-tuple.h b/third_party/googletest/src/include/gtest/internal/gtest-tuple.h new file mode 100644 index 0000000..d1af50e --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-tuple.h @@ -0,0 +1,968 @@ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { typedef T0 type; }; + +template +struct TupleElement { typedef T1 type; }; + +template +struct TupleElement { typedef T2 type; }; + +template +struct TupleElement { typedef T3 type; }; + +template +struct TupleElement { typedef T4 type; }; + +template +struct TupleElement { typedef T5 type; }; + +template +struct TupleElement { typedef T6 type; }; + +template +struct TupleElement { typedef T7 type; }; + +template +struct TupleElement { typedef T8 type; }; + +template +struct TupleElement { typedef T9 type; }; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { static const int value = 0; }; + +template +struct tuple_size { static const int value = 1; }; + +template +struct tuple_size { static const int value = 2; }; + +template +struct tuple_size { static const int value = 3; }; + +template +struct tuple_size { static const int value = 4; }; + +template +struct tuple_size { static const int value = 5; }; + +template +struct tuple_size { static const int value = 6; }; + +template +struct tuple_size { static const int value = 7; }; + +template +struct tuple_size { static const int value = 8; }; + +template +struct tuple_size { static const int value = 9; }; + +template +struct tuple_size { static const int value = 10; }; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-tuple.h.pump b/third_party/googletest/src/include/gtest/internal/gtest-tuple.h.pump new file mode 100644 index 0000000..ef51909 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-tuple.h.pump @@ -0,0 +1,336 @@ +$$ -*- mode: c++; -*- +$var n = 10 $$ Maximum number of tuple fields we want to support. +$$ This meta comment fixes auto-indentation in Emacs. }} +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + + +$range i 0..n-1 +$range j 0..n +$range k 1..n +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> + +$for k [[ +$range m 0..k-1 +$range m2 k..n-1 +#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]> + +]] + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. + +$for j [[ +$range m 0..j-1 +#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]] + + +]] + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template <$for i, [[typename T$i = void]]> +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + + +$for i [[ +template +struct TupleElement [[]] +{ typedef T$i type; }; + + +]] +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + + +$for k [[ +$range m 0..k-1 +template +class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { + public: + template friend class gtest_internal::Get; + + tuple() : $for m, [[f$(m)_()]] {} + + explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]] +$for m, [[f$(m)_(f$m)]] {} + + tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} + + template + tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} + +$if k == 2 [[ + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + +]] + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { + return CopyFrom(t); + } + +$if k == 2 [[ + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + +]] + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) { + +$for m [[ + f$(m)_ = t.f$(m)_; + +]] + return *this; + } + + +$for m [[ + T$m f$(m)_; + +]] +}; + + +]] +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +$for k [[ +$range m 0..k-1 + +template +inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) { + return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]); +} + +]] + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + + +$for j [[ +template +struct tuple_size { static const int value = $j; }; + + +]] +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + + +$for i [[ +template <> +class Get<$i> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) + Field(Tuple& t) { return t.f$(i)_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) + ConstField(const Tuple& t) { return t.f$(i)_; } +}; + + +]] +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) +get(GTEST_$(n)_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) +get(const GTEST_$(n)_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, + const GTEST_$(n)_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t, + const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + + +$for j [[ +#undef GTEST_$(j)_TUPLE_ + +]] + + +$for j [[ +#undef GTEST_$(j)_TYPENAMES_ + +]] + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-type-util.h b/third_party/googletest/src/include/gtest/internal/gtest-type-util.h new file mode 100644 index 0000000..b7b01b0 --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-type-util.h @@ -0,0 +1,3330 @@ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-string.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# ifdef __GLIBCXX__ +# include +# elif defined(__HP_aCC) +# include +# endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +String GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if defined(__GLIBCXX__) || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# ifdef __GLIBCXX__ + using abi::__cxa_demangle; +# endif // __GLIBCXX__ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // __GLIBCXX__ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/third_party/googletest/src/include/gtest/internal/gtest-type-util.h.pump b/third_party/googletest/src/include/gtest/internal/gtest-type-util.h.pump new file mode 100644 index 0000000..27f331d --- /dev/null +++ b/third_party/googletest/src/include/gtest/internal/gtest-type-util.h.pump @@ -0,0 +1,296 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of type lists we want to support. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most $n types in a list, and at most $n +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-string.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# ifdef __GLIBCXX__ +# include +# elif defined(__HP_aCC) +# include +# endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +String GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if defined(__GLIBCXX__) || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# ifdef __GLIBCXX__ + using abi::__cxa_demangle; +# endif // __GLIBCXX__ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // __GLIBCXX__ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; + +$range i 2..n + +$for i [[ +$range j 1..i +$range k 2..i +template <$for j, [[typename T$j]]> +struct Types$i { + typedef T1 Head; + typedef Types$(i-1)<$for k, [[T$k]]> Tail; +}; + + +]] + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. + +$range i 1..n +template <$for i, [[typename T$i = internal::None]]> +struct Types { + typedef internal::Types$n<$for i, [[T$i]]> type; +}; + +template <> +struct Types<$for i, [[internal::None]]> { + typedef internal::Types0 type; +}; + +$range i 1..n-1 +$for i [[ +$range j 1..i +$range k i+1..n +template <$for j, [[typename T$j]]> +struct Types<$for j, [[T$j]]$for k[[, internal::None]]> { + typedef internal::Types$i<$for j, [[T$j]]> type; +}; + +]] + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; + +$range i 2..n + +$for i [[ +$range j 1..i +$range k 2..i +template <$for j, [[GTEST_TEMPLATE_ T$j]]> +struct Templates$i { + typedef TemplateSel Head; + typedef Templates$(i-1)<$for k, [[T$k]]> Tail; +}; + + +]] + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. + +$range i 1..n +template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]> +struct Templates { + typedef Templates$n<$for i, [[T$i]]> type; +}; + +template <> +struct Templates<$for i, [[NoneT]]> { + typedef Templates0 type; +}; + +$range i 1..n-1 +$for i [[ +$range j 1..i +$range k i+1..n +template <$for j, [[GTEST_TEMPLATE_ T$j]]> +struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { + typedef Templates$i<$for j, [[T$j]]> type; +}; + +]] + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + + +$range i 1..n +template <$for i, [[typename T$i]]> +struct TypeList > { + typedef typename Types<$for i, [[T$i]]>::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/third_party/googletest/src/m4/acx_pthread.m4 b/third_party/googletest/src/m4/acx_pthread.m4 new file mode 100644 index 0000000..2cf20de --- /dev/null +++ b/third_party/googletest/src/m4/acx_pthread.m4 @@ -0,0 +1,363 @@ +# This was retrieved from +# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi +# See also (perhaps for new versions?) +# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi +# +# We've rewritten the inconsistency check code (from avahi), to work +# more broadly. In particular, it no longer assumes ld accepts -zdefs. +# This caused a restructing of the code, but the functionality has only +# changed a little. + +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl @summary figure out how to build C programs using POSIX threads +dnl +dnl This macro figures out how to build C programs using POSIX threads. +dnl It sets the PTHREAD_LIBS output variable to the threads library and +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special +dnl C compiler flags that are needed. (The user can also force certain +dnl compiler flags/libs to be tested by setting these environment +dnl variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl NOTE: You are assumed to not only compile your program with these +dnl flags, but also link it with them as well. e.g. you should link +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS +dnl $LIBS +dnl +dnl If you are only building threads programs, you may wish to use +dnl these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the +dnl default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, or +dnl if you have any other suggestions or comments. This macro was based +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. +dnl We are also grateful for the helpful feedback of numerous users. +dnl +dnl @category InstalledPackages +dnl @author Steven G. Johnson +dnl @version 2006-05-29 +dnl @license GPLWithACException +dnl +dnl Checks for GCC shared/pthread inconsistency based on work by +dnl Marcin Owsiany + + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr; return attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) + else + PTHREAD_CC=$CC + fi + + # The next part tries to detect GCC inconsistency with -shared on some + # architectures and systems. The problem is that in certain + # configurations, when -shared is specified, GCC "forgets" to + # internally use various flags which are still necessary. + + # + # Prepare the flags + # + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_CC="$CC" + + # Try with the flags determined by the earlier checks. + # + # -Wl,-z,defs forces link-time symbol resolution, so that the + # linking checks with -shared actually have any value + # + # FIXME: -fPIC is required for -shared on many architectures, + # so we specify it here, but the right way would probably be to + # properly detect whether it is actually required. + CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CC="$PTHREAD_CC" + + # In order not to create several levels of indentation, we test + # the value of "$done" until we find the cure or run out of ideas. + done="no" + + # First, make sure the CFLAGS we added are actually accepted by our + # compiler. If not (and OS X's ld, for instance, does not accept -z), + # then we can't do this test. + if test x"$done" = xno; then + AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) + AC_TRY_LINK(,, , [done=yes]) + + if test "x$done" = xyes ; then + AC_MSG_RESULT([no]) + else + AC_MSG_RESULT([yes]) + fi + fi + + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + + # + # Linux gcc on some architectures such as mips/mipsel forgets + # about -lpthread + # + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -lpthread fixes that]) + LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" + else + AC_MSG_RESULT([no]) + fi + fi + # + # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc + # + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -lc_r fixes that]) + LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" + else + AC_MSG_RESULT([no]) + fi + fi + if test x"$done" = xno; then + # OK, we have run out of ideas + AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) + + # so it's not safe to assume that we may use pthreads + acx_pthread_ok=no + fi + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + CC="$save_CC" +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/third_party/googletest/src/m4/gtest.m4 b/third_party/googletest/src/m4/gtest.m4 new file mode 100644 index 0000000..6598ba7 --- /dev/null +++ b/third_party/googletest/src/m4/gtest.m4 @@ -0,0 +1,74 @@ +dnl GTEST_LIB_CHECK([minimum version [, +dnl action if found [,action if not found]]]) +dnl +dnl Check for the presence of the Google Test library, optionally at a minimum +dnl version, and indicate a viable version with the HAVE_GTEST flag. It defines +dnl standard variables for substitution including GTEST_CPPFLAGS, +dnl GTEST_CXXFLAGS, GTEST_LDFLAGS, and GTEST_LIBS. It also defines +dnl GTEST_VERSION as the version of Google Test found. Finally, it provides +dnl optional custom action slots in the event GTEST is found or not. +AC_DEFUN([GTEST_LIB_CHECK], +[ +dnl Provide a flag to enable or disable Google Test usage. +AC_ARG_ENABLE([gtest], + [AS_HELP_STRING([--enable-gtest], + [Enable tests using the Google C++ Testing Framework. + (Default is enabled.)])], + [], + [enable_gtest=]) +AC_ARG_VAR([GTEST_CONFIG], + [The exact path of Google Test's 'gtest-config' script.]) +AC_ARG_VAR([GTEST_CPPFLAGS], + [C-like preprocessor flags for Google Test.]) +AC_ARG_VAR([GTEST_CXXFLAGS], + [C++ compile flags for Google Test.]) +AC_ARG_VAR([GTEST_LDFLAGS], + [Linker path and option flags for Google Test.]) +AC_ARG_VAR([GTEST_LIBS], + [Library linking flags for Google Test.]) +AC_ARG_VAR([GTEST_VERSION], + [The version of Google Test available.]) +HAVE_GTEST="no" +AS_IF([test "x${enable_gtest}" != "xno"], + [AC_MSG_CHECKING([for 'gtest-config']) + AS_IF([test "x${enable_gtest}" != "xyes"], + [AS_IF([test -x "${enable_gtest}/scripts/gtest-config"], + [GTEST_CONFIG="${enable_gtest}/scripts/gtest-config"], + [GTEST_CONFIG="${enable_gtest}/bin/gtest-config"]) + AS_IF([test -x "${GTEST_CONFIG}"], [], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([dnl +Unable to locate either a built or installed Google Test. +The specific location '${enable_gtest}' was provided for a built or installed +Google Test, but no 'gtest-config' script could be found at this location.]) + ])], + [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])]) + AS_IF([test -x "${GTEST_CONFIG}"], + [AC_MSG_RESULT([${GTEST_CONFIG}]) + m4_ifval([$1], + [_gtest_min_version="--min-version=$1" + AC_MSG_CHECKING([for Google Test at least version >= $1])], + [_gtest_min_version="--min-version=0" + AC_MSG_CHECKING([for Google Test])]) + AS_IF([${GTEST_CONFIG} ${_gtest_min_version}], + [AC_MSG_RESULT([yes]) + HAVE_GTEST='yes'], + [AC_MSG_RESULT([no])])], + [AC_MSG_RESULT([no])]) + AS_IF([test "x${HAVE_GTEST}" = "xyes"], + [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags` + GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags` + GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags` + GTEST_LIBS=`${GTEST_CONFIG} --libs` + GTEST_VERSION=`${GTEST_CONFIG} --version` + AC_DEFINE([HAVE_GTEST],[1],[Defined when Google Test is available.])], + [AS_IF([test "x${enable_gtest}" = "xyes"], + [AC_MSG_ERROR([dnl +Google Test was enabled, but no viable version could be found.]) + ])])]) +AC_SUBST([HAVE_GTEST]) +AM_CONDITIONAL([HAVE_GTEST],[test "x$HAVE_GTEST" = "xyes"]) +AS_IF([test "x$HAVE_GTEST" = "xyes"], + [m4_ifval([$2], [$2])], + [m4_ifval([$3], [$3])]) +]) diff --git a/third_party/googletest/src/make/Makefile b/third_party/googletest/src/make/Makefile new file mode 100644 index 0000000..5b27b6a --- /dev/null +++ b/third_party/googletest/src/make/Makefile @@ -0,0 +1,80 @@ +# A sample Makefile for building Google Test and using it in user +# tests. Please tweak it to suit your environment and project. You +# may want to move it to your project's root directory. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. + +# Please tweak the following variable definitions as needed by your +# project, except GTEST_HEADERS, which you can use in your own targets +# but shouldn't modify. + +# Points to the root of Google Test, relative to where this file is. +# Remember to tweak this if you move this file. +GTEST_DIR = .. + +# Where to find user code. +USER_DIR = ../samples + +# Flags passed to the preprocessor. +CPPFLAGS += -I$(GTEST_DIR)/include + +# Flags passed to the C++ compiler. +CXXFLAGS += -g -Wall -Wextra + +# All tests produced by this Makefile. Remember to add new tests you +# created to the list. +TESTS = sample1_unittest + +# All Google Test headers. Usually you shouldn't change this +# definition. +GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ + $(GTEST_DIR)/include/gtest/internal/*.h + +# House-keeping build targets. + +all : $(TESTS) + +clean : + rm -f $(TESTS) gtest.a gtest_main.a *.o + +# Builds gtest.a and gtest_main.a. + +# Usually you shouldn't tweak such internal variables, indicated by a +# trailing _. +GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) + +# For simplicity and to avoid depending on Google Test's +# implementation details, the dependencies specified below are +# conservative and not optimized. This is fine as Google Test +# compiles fast and for ordinary users its source rarely changes. +gtest-all.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ + $(GTEST_DIR)/src/gtest-all.cc + +gtest_main.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ + $(GTEST_DIR)/src/gtest_main.cc + +gtest.a : gtest-all.o + $(AR) $(ARFLAGS) $@ $^ + +gtest_main.a : gtest-all.o gtest_main.o + $(AR) $(ARFLAGS) $@ $^ + +# Builds a sample test. A test should link with either gtest.a or +# gtest_main.a, depending on whether it defines its own main() +# function. + +sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc + +sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \ + $(USER_DIR)/sample1.h $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc + +sample1_unittest : sample1.o sample1_unittest.o gtest_main.a + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ diff --git a/third_party/googletest/src/msvc/gtest-md.sln b/third_party/googletest/src/msvc/gtest-md.sln new file mode 100644 index 0000000..f7908da --- /dev/null +++ b/third_party/googletest/src/msvc/gtest-md.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest-md.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "gtest_main-md.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test-md", "gtest_prod_test-md.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest-md", "gtest_unittest-md.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.ActiveCfg = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.Build.0 = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.ActiveCfg = Release|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.Build.0 = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.ActiveCfg = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.Build.0 = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.ActiveCfg = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.Build.0 = Release|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.ActiveCfg = Debug|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.Build.0 = Debug|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.ActiveCfg = Release|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.Build.0 = Release|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.ActiveCfg = Debug|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.Build.0 = Debug|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.ActiveCfg = Release|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/third_party/googletest/src/msvc/gtest-md.vcproj b/third_party/googletest/src/msvc/gtest-md.vcproj new file mode 100644 index 0000000..1c35c3a --- /dev/null +++ b/third_party/googletest/src/msvc/gtest-md.vcproj @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest.sln b/third_party/googletest/src/msvc/gtest.sln new file mode 100644 index 0000000..ef4b057 --- /dev/null +++ b/third_party/googletest/src/msvc/gtest.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest", "gtest_unittest.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test", "gtest_prod_test.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.ActiveCfg = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.Build.0 = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.ActiveCfg = Release|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.Build.0 = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.ActiveCfg = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.Build.0 = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.ActiveCfg = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.Build.0 = Release|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.ActiveCfg = Debug|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.Build.0 = Debug|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.ActiveCfg = Release|Win32 + {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.Build.0 = Release|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.ActiveCfg = Debug|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.Build.0 = Debug|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.ActiveCfg = Release|Win32 + {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/third_party/googletest/src/msvc/gtest.vcproj b/third_party/googletest/src/msvc/gtest.vcproj new file mode 100644 index 0000000..a8373ce --- /dev/null +++ b/third_party/googletest/src/msvc/gtest.vcproj @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest_main-md.vcproj b/third_party/googletest/src/msvc/gtest_main-md.vcproj new file mode 100644 index 0000000..b5379fe --- /dev/null +++ b/third_party/googletest/src/msvc/gtest_main-md.vcproj @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest_main.vcproj b/third_party/googletest/src/msvc/gtest_main.vcproj new file mode 100644 index 0000000..e8b763c --- /dev/null +++ b/third_party/googletest/src/msvc/gtest_main.vcproj @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest_prod_test-md.vcproj b/third_party/googletest/src/msvc/gtest_prod_test-md.vcproj new file mode 100644 index 0000000..05b05d9 --- /dev/null +++ b/third_party/googletest/src/msvc/gtest_prod_test-md.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest_prod_test.vcproj b/third_party/googletest/src/msvc/gtest_prod_test.vcproj new file mode 100644 index 0000000..6d7a2f0 --- /dev/null +++ b/third_party/googletest/src/msvc/gtest_prod_test.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest_unittest-md.vcproj b/third_party/googletest/src/msvc/gtest_unittest-md.vcproj new file mode 100644 index 0000000..38a5e56 --- /dev/null +++ b/third_party/googletest/src/msvc/gtest_unittest-md.vcproj @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/msvc/gtest_unittest.vcproj b/third_party/googletest/src/msvc/gtest_unittest.vcproj new file mode 100644 index 0000000..cb1f52b --- /dev/null +++ b/third_party/googletest/src/msvc/gtest_unittest.vcproj @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/googletest/src/samples/prime_tables.h b/third_party/googletest/src/samples/prime_tables.h new file mode 100644 index 0000000..92ce16a --- /dev/null +++ b/third_party/googletest/src/samples/prime_tables.h @@ -0,0 +1,123 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// Author: vladl@google.com (Vlad Losev) + +// This provides interface PrimeTable that determines whether a number is a +// prime and determines a next prime number. This interface is used +// in Google Test samples demonstrating use of parameterized tests. + +#ifndef GTEST_SAMPLES_PRIME_TABLES_H_ +#define GTEST_SAMPLES_PRIME_TABLES_H_ + +#include + +// The prime table interface. +class PrimeTable { + public: + virtual ~PrimeTable() {} + + // Returns true iff n is a prime number. + virtual bool IsPrime(int n) const = 0; + + // Returns the smallest prime number greater than p; or returns -1 + // if the next prime is beyond the capacity of the table. + virtual int GetNextPrime(int p) const = 0; +}; + +// Implementation #1 calculates the primes on-the-fly. +class OnTheFlyPrimeTable : public PrimeTable { + public: + virtual bool IsPrime(int n) const { + if (n <= 1) return false; + + for (int i = 2; i*i <= n; i++) { + // n is divisible by an integer other than 1 and itself. + if ((n % i) == 0) return false; + } + + return true; + } + + virtual int GetNextPrime(int p) const { + for (int n = p + 1; n > 0; n++) { + if (IsPrime(n)) return n; + } + + return -1; + } +}; + +// Implementation #2 pre-calculates the primes and stores the result +// in an array. +class PreCalculatedPrimeTable : public PrimeTable { + public: + // 'max' specifies the maximum number the prime table holds. + explicit PreCalculatedPrimeTable(int max) + : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) { + CalculatePrimesUpTo(max); + } + virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; } + + virtual bool IsPrime(int n) const { + return 0 <= n && n < is_prime_size_ && is_prime_[n]; + } + + virtual int GetNextPrime(int p) const { + for (int n = p + 1; n < is_prime_size_; n++) { + if (is_prime_[n]) return n; + } + + return -1; + } + + private: + void CalculatePrimesUpTo(int max) { + ::std::fill(is_prime_, is_prime_ + is_prime_size_, true); + is_prime_[0] = is_prime_[1] = false; + + for (int i = 2; i <= max; i++) { + if (!is_prime_[i]) continue; + + // Marks all multiples of i (except i itself) as non-prime. + for (int j = 2*i; j <= max; j += i) { + is_prime_[j] = false; + } + } + } + + const int is_prime_size_; + bool* const is_prime_; + + // Disables compiler warning "assignment operator could not be generated." + void operator=(const PreCalculatedPrimeTable& rhs); +}; + +#endif // GTEST_SAMPLES_PRIME_TABLES_H_ diff --git a/third_party/googletest/src/samples/sample1.cc b/third_party/googletest/src/samples/sample1.cc new file mode 100644 index 0000000..f171e26 --- /dev/null +++ b/third_party/googletest/src/samples/sample1.cc @@ -0,0 +1,68 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "sample1.h" + +// Returns n! (the factorial of n). For negative n, n! is defined to be 1. +int Factorial(int n) { + int result = 1; + for (int i = 1; i <= n; i++) { + result *= i; + } + + return result; +} + +// Returns true iff n is a prime number. +bool IsPrime(int n) { + // Trivial case 1: small numbers + if (n <= 1) return false; + + // Trivial case 2: even numbers + if (n % 2 == 0) return n == 2; + + // Now, we have that n is odd and n >= 3. + + // Try to divide n by every odd number i, starting from 3 + for (int i = 3; ; i += 2) { + // We only have to try i up to the squre root of n + if (i > n/i) break; + + // Now, we have i <= n/i < n. + // If n is divisible by i, n is not prime. + if (n % i == 0) return false; + } + + // n has no integer factor in the range (1, n), and thus is prime. + return true; +} diff --git a/third_party/googletest/src/samples/sample1.h b/third_party/googletest/src/samples/sample1.h new file mode 100644 index 0000000..3dfeb98 --- /dev/null +++ b/third_party/googletest/src/samples/sample1.h @@ -0,0 +1,43 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_SAMPLES_SAMPLE1_H_ +#define GTEST_SAMPLES_SAMPLE1_H_ + +// Returns n! (the factorial of n). For negative n, n! is defined to be 1. +int Factorial(int n); + +// Returns true iff n is a prime number. +bool IsPrime(int n); + +#endif // GTEST_SAMPLES_SAMPLE1_H_ diff --git a/third_party/googletest/src/samples/sample10_unittest.cc b/third_party/googletest/src/samples/sample10_unittest.cc new file mode 100644 index 0000000..2813d04 --- /dev/null +++ b/third_party/googletest/src/samples/sample10_unittest.cc @@ -0,0 +1,145 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// This sample shows how to use Google Test listener API to implement +// a primitive leak checker. + +#include +#include + +#include "gtest/gtest.h" + +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestCase; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; + +namespace { + +// We will track memory used by this class. +class Water { + public: + // Normal Water declarations go here. + + // operator new and operator delete help us control water allocation. + void* operator new(size_t allocation_size) { + allocated_++; + return malloc(allocation_size); + } + + void operator delete(void* block, size_t /* allocation_size */) { + allocated_--; + free(block); + } + + static int allocated() { return allocated_; } + + private: + static int allocated_; +}; + +int Water::allocated_ = 0; + +// This event listener monitors how many Water objects are created and +// destroyed by each test, and reports a failure if a test leaks some Water +// objects. It does this by comparing the number of live Water objects at +// the beginning of a test and at the end of a test. +class LeakChecker : public EmptyTestEventListener { + private: + // Called before a test starts. + virtual void OnTestStart(const TestInfo& /* test_info */) { + initially_allocated_ = Water::allocated(); + } + + // Called after a test ends. + virtual void OnTestEnd(const TestInfo& /* test_info */) { + int difference = Water::allocated() - initially_allocated_; + + // You can generate a failure in any event handler except + // OnTestPartResult. Just use an appropriate Google Test assertion to do + // it. + EXPECT_TRUE(difference <= 0) + << "Leaked " << difference << " unit(s) of Water!"; + } + + int initially_allocated_; +}; + +TEST(ListenersTest, DoesNotLeak) { + Water* water = new Water; + delete water; +} + +// This should fail when the --check_for_leaks command line flag is +// specified. +TEST(ListenersTest, LeaksWater) { + Water* water = new Water; + EXPECT_TRUE(water != NULL); +} + +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + bool check_for_leaks = false; + if (argc > 1 && strcmp(argv[1], "--check_for_leaks") == 0 ) + check_for_leaks = true; + else + printf("%s\n", "Run this program with --check_for_leaks to enable " + "custom leak checking in the tests."); + + // If we are given the --check_for_leaks command line flag, installs the + // leak checker. + if (check_for_leaks) { + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + + // Adds the leak checker to the end of the test event listener list, + // after the default text output printer and the default XML report + // generator. + // + // The order is important - it ensures that failures generated in the + // leak checker's OnTestEnd() method are processed by the text and XML + // printers *before* their OnTestEnd() methods are called, such that + // they are attributed to the right test. Remember that a listener + // receives an OnXyzStart event *after* listeners preceding it in the + // list received that event, and receives an OnXyzEnd event *before* + // listeners preceding it. + // + // We don't need to worry about deleting the new listener later, as + // Google Test will do it. + listeners.Append(new LeakChecker); + } + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/samples/sample1_unittest.cc b/third_party/googletest/src/samples/sample1_unittest.cc new file mode 100644 index 0000000..a8a7c79 --- /dev/null +++ b/third_party/googletest/src/samples/sample1_unittest.cc @@ -0,0 +1,153 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + + +// This sample shows how to write a simple unit test for a function, +// using Google C++ testing framework. +// +// Writing a unit test using Google C++ testing framework is easy as 1-2-3: + + +// Step 1. Include necessary header files such that the stuff your +// test logic needs is declared. +// +// Don't forget gtest.h, which declares the testing framework. + +#include +#include "sample1.h" +#include "gtest/gtest.h" + + +// Step 2. Use the TEST macro to define your tests. +// +// TEST has two parameters: the test case name and the test name. +// After using the macro, you should define your test logic between a +// pair of braces. You can use a bunch of macros to indicate the +// success or failure of a test. EXPECT_TRUE and EXPECT_EQ are +// examples of such macros. For a complete list, see gtest.h. +// +// +// +// In Google Test, tests are grouped into test cases. This is how we +// keep test code organized. You should put logically related tests +// into the same test case. +// +// The test case name and the test name should both be valid C++ +// identifiers. And you should not use underscore (_) in the names. +// +// Google Test guarantees that each test you define is run exactly +// once, but it makes no guarantee on the order the tests are +// executed. Therefore, you should write your tests in such a way +// that their results don't depend on their order. +// +// + + +// Tests Factorial(). + +// Tests factorial of negative numbers. +TEST(FactorialTest, Negative) { + // This test is named "Negative", and belongs to the "FactorialTest" + // test case. + EXPECT_EQ(1, Factorial(-5)); + EXPECT_EQ(1, Factorial(-1)); + EXPECT_TRUE(Factorial(-10) > 0); + + // + // + // EXPECT_EQ(expected, actual) is the same as + // + // EXPECT_TRUE((expected) == (actual)) + // + // except that it will print both the expected value and the actual + // value when the assertion fails. This is very helpful for + // debugging. Therefore in this case EXPECT_EQ is preferred. + // + // On the other hand, EXPECT_TRUE accepts any Boolean expression, + // and is thus more general. + // + // +} + +// Tests factorial of 0. +TEST(FactorialTest, Zero) { + EXPECT_EQ(1, Factorial(0)); +} + +// Tests factorial of positive numbers. +TEST(FactorialTest, Positive) { + EXPECT_EQ(1, Factorial(1)); + EXPECT_EQ(2, Factorial(2)); + EXPECT_EQ(6, Factorial(3)); + EXPECT_EQ(40320, Factorial(8)); +} + + +// Tests IsPrime() + +// Tests negative input. +TEST(IsPrimeTest, Negative) { + // This test belongs to the IsPrimeTest test case. + + EXPECT_FALSE(IsPrime(-1)); + EXPECT_FALSE(IsPrime(-2)); + EXPECT_FALSE(IsPrime(INT_MIN)); +} + +// Tests some trivial cases. +TEST(IsPrimeTest, Trivial) { + EXPECT_FALSE(IsPrime(0)); + EXPECT_FALSE(IsPrime(1)); + EXPECT_TRUE(IsPrime(2)); + EXPECT_TRUE(IsPrime(3)); +} + +// Tests positive input. +TEST(IsPrimeTest, Positive) { + EXPECT_FALSE(IsPrime(4)); + EXPECT_TRUE(IsPrime(5)); + EXPECT_FALSE(IsPrime(6)); + EXPECT_TRUE(IsPrime(23)); +} + +// Step 3. Call RUN_ALL_TESTS() in main(). +// +// We do this by linking in src/gtest_main.cc file, which consists of +// a main() function which calls RUN_ALL_TESTS() for us. +// +// This runs all the tests you've defined, prints the result, and +// returns 0 if successful, or 1 otherwise. +// +// Did you notice that we didn't register the tests? The +// RUN_ALL_TESTS() macro magically knows about all the tests we +// defined. Isn't this convenient? diff --git a/third_party/googletest/src/samples/sample2.cc b/third_party/googletest/src/samples/sample2.cc new file mode 100644 index 0000000..5f763b9 --- /dev/null +++ b/third_party/googletest/src/samples/sample2.cc @@ -0,0 +1,56 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "sample2.h" + +#include + +// Clones a 0-terminated C string, allocating memory using new. +const char* MyString::CloneCString(const char* a_c_string) { + if (a_c_string == NULL) return NULL; + + const size_t len = strlen(a_c_string); + char* const clone = new char[ len + 1 ]; + memcpy(clone, a_c_string, len + 1); + + return clone; +} + +// Sets the 0-terminated C string this MyString object +// represents. +void MyString::Set(const char* a_c_string) { + // Makes sure this works when c_string == c_string_ + const char* const temp = MyString::CloneCString(a_c_string); + delete[] c_string_; + c_string_ = temp; +} diff --git a/third_party/googletest/src/samples/sample2.h b/third_party/googletest/src/samples/sample2.h new file mode 100644 index 0000000..5b57e60 --- /dev/null +++ b/third_party/googletest/src/samples/sample2.h @@ -0,0 +1,86 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_SAMPLES_SAMPLE2_H_ +#define GTEST_SAMPLES_SAMPLE2_H_ + +#include + + +// A simple string class. +class MyString { + private: + const char* c_string_; + const MyString& operator=(const MyString& rhs); + + public: + + // Clones a 0-terminated C string, allocating memory using new. + static const char* CloneCString(const char* a_c_string); + + //////////////////////////////////////////////////////////// + // + // C'tors + + // The default c'tor constructs a NULL string. + MyString() : c_string_(NULL) {} + + // Constructs a MyString by cloning a 0-terminated C string. + explicit MyString(const char* a_c_string) : c_string_(NULL) { + Set(a_c_string); + } + + // Copy c'tor + MyString(const MyString& string) : c_string_(NULL) { + Set(string.c_string_); + } + + //////////////////////////////////////////////////////////// + // + // D'tor. MyString is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~MyString() { delete[] c_string_; } + + // Gets the 0-terminated C string this MyString object represents. + const char* c_string() const { return c_string_; } + + size_t Length() const { + return c_string_ == NULL ? 0 : strlen(c_string_); + } + + // Sets the 0-terminated C string this MyString object represents. + void Set(const char* c_string); +}; + + +#endif // GTEST_SAMPLES_SAMPLE2_H_ diff --git a/third_party/googletest/src/samples/sample2_unittest.cc b/third_party/googletest/src/samples/sample2_unittest.cc new file mode 100644 index 0000000..3792fa5 --- /dev/null +++ b/third_party/googletest/src/samples/sample2_unittest.cc @@ -0,0 +1,109 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + + +// This sample shows how to write a more complex unit test for a class +// that has multiple member functions. +// +// Usually, it's a good idea to have one test for each method in your +// class. You don't have to do that exactly, but it helps to keep +// your tests organized. You may also throw in additional tests as +// needed. + +#include "sample2.h" +#include "gtest/gtest.h" + +// In this example, we test the MyString class (a simple string). + +// Tests the default c'tor. +TEST(MyString, DefaultConstructor) { + const MyString s; + + // Asserts that s.c_string() returns NULL. + // + // + // + // If we write NULL instead of + // + // static_cast(NULL) + // + // in this assertion, it will generate a warning on gcc 3.4. The + // reason is that EXPECT_EQ needs to know the types of its + // arguments in order to print them when it fails. Since NULL is + // #defined as 0, the compiler will use the formatter function for + // int to print it. However, gcc thinks that NULL should be used as + // a pointer, not an int, and therefore complains. + // + // The root of the problem is C++'s lack of distinction between the + // integer number 0 and the null pointer constant. Unfortunately, + // we have to live with this fact. + // + // + EXPECT_STREQ(NULL, s.c_string()); + + EXPECT_EQ(0u, s.Length()); +} + +const char kHelloString[] = "Hello, world!"; + +// Tests the c'tor that accepts a C string. +TEST(MyString, ConstructorFromCString) { + const MyString s(kHelloString); + EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0); + EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1, + s.Length()); +} + +// Tests the copy c'tor. +TEST(MyString, CopyConstructor) { + const MyString s1(kHelloString); + const MyString s2 = s1; + EXPECT_TRUE(strcmp(s2.c_string(), kHelloString) == 0); +} + +// Tests the Set method. +TEST(MyString, Set) { + MyString s; + + s.Set(kHelloString); + EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0); + + // Set should work when the input pointer is the same as the one + // already in the MyString object. + s.Set(s.c_string()); + EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0); + + // Can we set the MyString to NULL? + s.Set(NULL); + EXPECT_STREQ(NULL, s.c_string()); +} diff --git a/third_party/googletest/src/samples/sample3-inl.h b/third_party/googletest/src/samples/sample3-inl.h new file mode 100644 index 0000000..46369a0 --- /dev/null +++ b/third_party/googletest/src/samples/sample3-inl.h @@ -0,0 +1,173 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_SAMPLES_SAMPLE3_INL_H_ +#define GTEST_SAMPLES_SAMPLE3_INL_H_ + +#include + + +// Queue is a simple queue implemented as a singled-linked list. +// +// The element type must support copy constructor. +template // E is the element type +class Queue; + +// QueueNode is a node in a Queue, which consists of an element of +// type E and a pointer to the next node. +template // E is the element type +class QueueNode { + friend class Queue; + + public: + // Gets the element in this node. + const E& element() const { return element_; } + + // Gets the next node in the queue. + QueueNode* next() { return next_; } + const QueueNode* next() const { return next_; } + + private: + // Creates a node with a given element value. The next pointer is + // set to NULL. + QueueNode(const E& an_element) : element_(an_element), next_(NULL) {} + + // We disable the default assignment operator and copy c'tor. + const QueueNode& operator = (const QueueNode&); + QueueNode(const QueueNode&); + + E element_; + QueueNode* next_; +}; + +template // E is the element type. +class Queue { +public: + + // Creates an empty queue. + Queue() : head_(NULL), last_(NULL), size_(0) {} + + // D'tor. Clears the queue. + ~Queue() { Clear(); } + + // Clears the queue. + void Clear() { + if (size_ > 0) { + // 1. Deletes every node. + QueueNode* node = head_; + QueueNode* next = node->next(); + for (; ;) { + delete node; + node = next; + if (node == NULL) break; + next = node->next(); + } + + // 2. Resets the member variables. + head_ = last_ = NULL; + size_ = 0; + } + } + + // Gets the number of elements. + size_t Size() const { return size_; } + + // Gets the first element of the queue, or NULL if the queue is empty. + QueueNode* Head() { return head_; } + const QueueNode* Head() const { return head_; } + + // Gets the last element of the queue, or NULL if the queue is empty. + QueueNode* Last() { return last_; } + const QueueNode* Last() const { return last_; } + + // Adds an element to the end of the queue. A copy of the element is + // created using the copy constructor, and then stored in the queue. + // Changes made to the element in the queue doesn't affect the source + // object, and vice versa. + void Enqueue(const E& element) { + QueueNode* new_node = new QueueNode(element); + + if (size_ == 0) { + head_ = last_ = new_node; + size_ = 1; + } else { + last_->next_ = new_node; + last_ = new_node; + size_++; + } + } + + // Removes the head of the queue and returns it. Returns NULL if + // the queue is empty. + E* Dequeue() { + if (size_ == 0) { + return NULL; + } + + const QueueNode* const old_head = head_; + head_ = head_->next_; + size_--; + if (size_ == 0) { + last_ = NULL; + } + + E* element = new E(old_head->element()); + delete old_head; + + return element; + } + + // Applies a function/functor on each element of the queue, and + // returns the result in a new queue. The original queue is not + // affected. + template + Queue* Map(F function) const { + Queue* new_queue = new Queue(); + for (const QueueNode* node = head_; node != NULL; node = node->next_) { + new_queue->Enqueue(function(node->element())); + } + + return new_queue; + } + + private: + QueueNode* head_; // The first node of the queue. + QueueNode* last_; // The last node of the queue. + size_t size_; // The number of elements in the queue. + + // We disallow copying a queue. + Queue(const Queue&); + const Queue& operator = (const Queue&); + }; + +#endif // GTEST_SAMPLES_SAMPLE3_INL_H_ diff --git a/third_party/googletest/src/samples/sample3_unittest.cc b/third_party/googletest/src/samples/sample3_unittest.cc new file mode 100644 index 0000000..bf3877d --- /dev/null +++ b/third_party/googletest/src/samples/sample3_unittest.cc @@ -0,0 +1,151 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + + +// In this example, we use a more advanced feature of Google Test called +// test fixture. +// +// A test fixture is a place to hold objects and functions shared by +// all tests in a test case. Using a test fixture avoids duplicating +// the test code necessary to initialize and cleanup those common +// objects for each test. It is also useful for defining sub-routines +// that your tests need to invoke a lot. +// +// +// +// The tests share the test fixture in the sense of code sharing, not +// data sharing. Each test is given its own fresh copy of the +// fixture. You cannot expect the data modified by one test to be +// passed on to another test, which is a bad idea. +// +// The reason for this design is that tests should be independent and +// repeatable. In particular, a test should not fail as the result of +// another test's failure. If one test depends on info produced by +// another test, then the two tests should really be one big test. +// +// The macros for indicating the success/failure of a test +// (EXPECT_TRUE, FAIL, etc) need to know what the current test is +// (when Google Test prints the test result, it tells you which test +// each failure belongs to). Technically, these macros invoke a +// member function of the Test class. Therefore, you cannot use them +// in a global function. That's why you should put test sub-routines +// in a test fixture. +// +// + +#include "sample3-inl.h" +#include "gtest/gtest.h" + +// To use a test fixture, derive a class from testing::Test. +class QueueTest : public testing::Test { + protected: // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() { + q1_.Enqueue(1); + q2_.Enqueue(2); + q2_.Enqueue(3); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + // virtual void TearDown() { + // } + + // A helper function that some test uses. + static int Double(int n) { + return 2*n; + } + + // A helper function for testing Queue::Map(). + void MapTester(const Queue * q) { + // Creates a new queue, where each element is twice as big as the + // corresponding one in q. + const Queue * const new_q = q->Map(Double); + + // Verifies that the new queue has the same size as q. + ASSERT_EQ(q->Size(), new_q->Size()); + + // Verifies the relationship between the elements of the two queues. + for ( const QueueNode * n1 = q->Head(), * n2 = new_q->Head(); + n1 != NULL; n1 = n1->next(), n2 = n2->next() ) { + EXPECT_EQ(2 * n1->element(), n2->element()); + } + + delete new_q; + } + + // Declares the variables your tests want to use. + Queue q0_; + Queue q1_; + Queue q2_; +}; + +// When you have a test fixture, you define a test using TEST_F +// instead of TEST. + +// Tests the default c'tor. +TEST_F(QueueTest, DefaultConstructor) { + // You can access data in the test fixture here. + EXPECT_EQ(0u, q0_.Size()); +} + +// Tests Dequeue(). +TEST_F(QueueTest, Dequeue) { + int * n = q0_.Dequeue(); + EXPECT_TRUE(n == NULL); + + n = q1_.Dequeue(); + ASSERT_TRUE(n != NULL); + EXPECT_EQ(1, *n); + EXPECT_EQ(0u, q1_.Size()); + delete n; + + n = q2_.Dequeue(); + ASSERT_TRUE(n != NULL); + EXPECT_EQ(2, *n); + EXPECT_EQ(1u, q2_.Size()); + delete n; +} + +// Tests the Queue::Map() function. +TEST_F(QueueTest, Map) { + MapTester(&q0_); + MapTester(&q1_); + MapTester(&q2_); +} diff --git a/third_party/googletest/src/samples/sample4.cc b/third_party/googletest/src/samples/sample4.cc new file mode 100644 index 0000000..ae44bda --- /dev/null +++ b/third_party/googletest/src/samples/sample4.cc @@ -0,0 +1,46 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#include + +#include "sample4.h" + +// Returns the current counter value, and increments it. +int Counter::Increment() { + return counter_++; +} + +// Prints the current counter value to STDOUT. +void Counter::Print() const { + printf("%d", counter_); +} diff --git a/third_party/googletest/src/samples/sample4.h b/third_party/googletest/src/samples/sample4.h new file mode 100644 index 0000000..cd60f0d --- /dev/null +++ b/third_party/googletest/src/samples/sample4.h @@ -0,0 +1,53 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_SAMPLES_SAMPLE4_H_ +#define GTEST_SAMPLES_SAMPLE4_H_ + +// A simple monotonic counter. +class Counter { + private: + int counter_; + + public: + // Creates a counter that starts at 0. + Counter() : counter_(0) {} + + // Returns the current counter value, and increments it. + int Increment(); + + // Prints the current counter value to STDOUT. + void Print() const; +}; + +#endif // GTEST_SAMPLES_SAMPLE4_H_ diff --git a/third_party/googletest/src/samples/sample4_unittest.cc b/third_party/googletest/src/samples/sample4_unittest.cc new file mode 100644 index 0000000..fa5afc7 --- /dev/null +++ b/third_party/googletest/src/samples/sample4_unittest.cc @@ -0,0 +1,45 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest.h" +#include "sample4.h" + +// Tests the Increment() method. +TEST(Counter, Increment) { + Counter c; + + // EXPECT_EQ() evaluates its arguments exactly once, so they + // can have side effects. + + EXPECT_EQ(0, c.Increment()); + EXPECT_EQ(1, c.Increment()); + EXPECT_EQ(2, c.Increment()); +} diff --git a/third_party/googletest/src/samples/sample5_unittest.cc b/third_party/googletest/src/samples/sample5_unittest.cc new file mode 100644 index 0000000..e7cab01 --- /dev/null +++ b/third_party/googletest/src/samples/sample5_unittest.cc @@ -0,0 +1,199 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// This sample teaches how to reuse a test fixture in multiple test +// cases by deriving sub-fixtures from it. +// +// When you define a test fixture, you specify the name of the test +// case that will use this fixture. Therefore, a test fixture can +// be used by only one test case. +// +// Sometimes, more than one test cases may want to use the same or +// slightly different test fixtures. For example, you may want to +// make sure that all tests for a GUI library don't leak important +// system resources like fonts and brushes. In Google Test, you do +// this by putting the shared logic in a super (as in "super class") +// test fixture, and then have each test case use a fixture derived +// from this super fixture. + +#include +#include +#include "sample3-inl.h" +#include "gtest/gtest.h" +#include "sample1.h" + +// In this sample, we want to ensure that every test finishes within +// ~5 seconds. If a test takes longer to run, we consider it a +// failure. +// +// We put the code for timing a test in a test fixture called +// "QuickTest". QuickTest is intended to be the super fixture that +// other fixtures derive from, therefore there is no test case with +// the name "QuickTest". This is OK. +// +// Later, we will derive multiple test fixtures from QuickTest. +class QuickTest : public testing::Test { + protected: + // Remember that SetUp() is run immediately before a test starts. + // This is a good place to record the start time. + virtual void SetUp() { + start_time_ = time(NULL); + } + + // TearDown() is invoked immediately after a test finishes. Here we + // check if the test was too slow. + virtual void TearDown() { + // Gets the time when the test finishes + const time_t end_time = time(NULL); + + // Asserts that the test took no more than ~5 seconds. Did you + // know that you can use assertions in SetUp() and TearDown() as + // well? + EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long."; + } + + // The UTC time (in seconds) when the test starts + time_t start_time_; +}; + + +// We derive a fixture named IntegerFunctionTest from the QuickTest +// fixture. All tests using this fixture will be automatically +// required to be quick. +class IntegerFunctionTest : public QuickTest { + // We don't need any more logic than already in the QuickTest fixture. + // Therefore the body is empty. +}; + + +// Now we can write tests in the IntegerFunctionTest test case. + +// Tests Factorial() +TEST_F(IntegerFunctionTest, Factorial) { + // Tests factorial of negative numbers. + EXPECT_EQ(1, Factorial(-5)); + EXPECT_EQ(1, Factorial(-1)); + EXPECT_TRUE(Factorial(-10) > 0); + + // Tests factorial of 0. + EXPECT_EQ(1, Factorial(0)); + + // Tests factorial of positive numbers. + EXPECT_EQ(1, Factorial(1)); + EXPECT_EQ(2, Factorial(2)); + EXPECT_EQ(6, Factorial(3)); + EXPECT_EQ(40320, Factorial(8)); +} + + +// Tests IsPrime() +TEST_F(IntegerFunctionTest, IsPrime) { + // Tests negative input. + EXPECT_TRUE(!IsPrime(-1)); + EXPECT_TRUE(!IsPrime(-2)); + EXPECT_TRUE(!IsPrime(INT_MIN)); + + // Tests some trivial cases. + EXPECT_TRUE(!IsPrime(0)); + EXPECT_TRUE(!IsPrime(1)); + EXPECT_TRUE(IsPrime(2)); + EXPECT_TRUE(IsPrime(3)); + + // Tests positive input. + EXPECT_TRUE(!IsPrime(4)); + EXPECT_TRUE(IsPrime(5)); + EXPECT_TRUE(!IsPrime(6)); + EXPECT_TRUE(IsPrime(23)); +} + + +// The next test case (named "QueueTest") also needs to be quick, so +// we derive another fixture from QuickTest. +// +// The QueueTest test fixture has some logic and shared objects in +// addition to what's in QuickTest already. We define the additional +// stuff inside the body of the test fixture, as usual. +class QueueTest : public QuickTest { + protected: + virtual void SetUp() { + // First, we need to set up the super fixture (QuickTest). + QuickTest::SetUp(); + + // Second, some additional setup for this fixture. + q1_.Enqueue(1); + q2_.Enqueue(2); + q2_.Enqueue(3); + } + + // By default, TearDown() inherits the behavior of + // QuickTest::TearDown(). As we have no additional cleaning work + // for QueueTest, we omit it here. + // + // virtual void TearDown() { + // QuickTest::TearDown(); + // } + + Queue q0_; + Queue q1_; + Queue q2_; +}; + + +// Now, let's write tests using the QueueTest fixture. + +// Tests the default constructor. +TEST_F(QueueTest, DefaultConstructor) { + EXPECT_EQ(0u, q0_.Size()); +} + +// Tests Dequeue(). +TEST_F(QueueTest, Dequeue) { + int* n = q0_.Dequeue(); + EXPECT_TRUE(n == NULL); + + n = q1_.Dequeue(); + EXPECT_TRUE(n != NULL); + EXPECT_EQ(1, *n); + EXPECT_EQ(0u, q1_.Size()); + delete n; + + n = q2_.Dequeue(); + EXPECT_TRUE(n != NULL); + EXPECT_EQ(2, *n); + EXPECT_EQ(1u, q2_.Size()); + delete n; +} + +// If necessary, you can derive further test fixtures from a derived +// fixture itself. For example, you can derive another fixture from +// QueueTest. Google Test imposes no limit on how deep the hierarchy +// can be. In practice, however, you probably don't want it to be too +// deep as to be confusing. diff --git a/third_party/googletest/src/samples/sample6_unittest.cc b/third_party/googletest/src/samples/sample6_unittest.cc new file mode 100644 index 0000000..8f2036a --- /dev/null +++ b/third_party/googletest/src/samples/sample6_unittest.cc @@ -0,0 +1,224 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// This sample shows how to test common properties of multiple +// implementations of the same interface (aka interface tests). + +// The interface and its implementations are in this header. +#include "prime_tables.h" + +#include "gtest/gtest.h" + +// First, we define some factory functions for creating instances of +// the implementations. You may be able to skip this step if all your +// implementations can be constructed the same way. + +template +PrimeTable* CreatePrimeTable(); + +template <> +PrimeTable* CreatePrimeTable() { + return new OnTheFlyPrimeTable; +} + +template <> +PrimeTable* CreatePrimeTable() { + return new PreCalculatedPrimeTable(10000); +} + +// Then we define a test fixture class template. +template +class PrimeTableTest : public testing::Test { + protected: + // The ctor calls the factory function to create a prime table + // implemented by T. + PrimeTableTest() : table_(CreatePrimeTable()) {} + + virtual ~PrimeTableTest() { delete table_; } + + // Note that we test an implementation via the base interface + // instead of the actual implementation class. This is important + // for keeping the tests close to the real world scenario, where the + // implementation is invoked via the base interface. It avoids + // got-yas where the implementation class has a method that shadows + // a method with the same name (but slightly different argument + // types) in the base interface, for example. + PrimeTable* const table_; +}; + +#if GTEST_HAS_TYPED_TEST + +using testing::Types; + +// Google Test offers two ways for reusing tests for different types. +// The first is called "typed tests". You should use it if you +// already know *all* the types you are gonna exercise when you write +// the tests. + +// To write a typed test case, first use +// +// TYPED_TEST_CASE(TestCaseName, TypeList); +// +// to declare it and specify the type parameters. As with TEST_F, +// TestCaseName must match the test fixture name. + +// The list of types we want to test. +typedef Types Implementations; + +TYPED_TEST_CASE(PrimeTableTest, Implementations); + +// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test, +// similar to TEST_F. +TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) { + // Inside the test body, you can refer to the type parameter by + // TypeParam, and refer to the fixture class by TestFixture. We + // don't need them in this example. + + // Since we are in the template world, C++ requires explicitly + // writing 'this->' when referring to members of the fixture class. + // This is something you have to learn to live with. + EXPECT_FALSE(this->table_->IsPrime(-5)); + EXPECT_FALSE(this->table_->IsPrime(0)); + EXPECT_FALSE(this->table_->IsPrime(1)); + EXPECT_FALSE(this->table_->IsPrime(4)); + EXPECT_FALSE(this->table_->IsPrime(6)); + EXPECT_FALSE(this->table_->IsPrime(100)); +} + +TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) { + EXPECT_TRUE(this->table_->IsPrime(2)); + EXPECT_TRUE(this->table_->IsPrime(3)); + EXPECT_TRUE(this->table_->IsPrime(5)); + EXPECT_TRUE(this->table_->IsPrime(7)); + EXPECT_TRUE(this->table_->IsPrime(11)); + EXPECT_TRUE(this->table_->IsPrime(131)); +} + +TYPED_TEST(PrimeTableTest, CanGetNextPrime) { + EXPECT_EQ(2, this->table_->GetNextPrime(0)); + EXPECT_EQ(3, this->table_->GetNextPrime(2)); + EXPECT_EQ(5, this->table_->GetNextPrime(3)); + EXPECT_EQ(7, this->table_->GetNextPrime(5)); + EXPECT_EQ(11, this->table_->GetNextPrime(7)); + EXPECT_EQ(131, this->table_->GetNextPrime(128)); +} + +// That's it! Google Test will repeat each TYPED_TEST for each type +// in the type list specified in TYPED_TEST_CASE. Sit back and be +// happy that you don't have to define them multiple times. + +#endif // GTEST_HAS_TYPED_TEST + +#if GTEST_HAS_TYPED_TEST_P + +using testing::Types; + +// Sometimes, however, you don't yet know all the types that you want +// to test when you write the tests. For example, if you are the +// author of an interface and expect other people to implement it, you +// might want to write a set of tests to make sure each implementation +// conforms to some basic requirements, but you don't know what +// implementations will be written in the future. +// +// How can you write the tests without committing to the type +// parameters? That's what "type-parameterized tests" can do for you. +// It is a bit more involved than typed tests, but in return you get a +// test pattern that can be reused in many contexts, which is a big +// win. Here's how you do it: + +// First, define a test fixture class template. Here we just reuse +// the PrimeTableTest fixture defined earlier: + +template +class PrimeTableTest2 : public PrimeTableTest { +}; + +// Then, declare the test case. The argument is the name of the test +// fixture, and also the name of the test case (as usual). The _P +// suffix is for "parameterized" or "pattern". +TYPED_TEST_CASE_P(PrimeTableTest2); + +// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test, +// similar to what you do with TEST_F. +TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes) { + EXPECT_FALSE(this->table_->IsPrime(-5)); + EXPECT_FALSE(this->table_->IsPrime(0)); + EXPECT_FALSE(this->table_->IsPrime(1)); + EXPECT_FALSE(this->table_->IsPrime(4)); + EXPECT_FALSE(this->table_->IsPrime(6)); + EXPECT_FALSE(this->table_->IsPrime(100)); +} + +TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes) { + EXPECT_TRUE(this->table_->IsPrime(2)); + EXPECT_TRUE(this->table_->IsPrime(3)); + EXPECT_TRUE(this->table_->IsPrime(5)); + EXPECT_TRUE(this->table_->IsPrime(7)); + EXPECT_TRUE(this->table_->IsPrime(11)); + EXPECT_TRUE(this->table_->IsPrime(131)); +} + +TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) { + EXPECT_EQ(2, this->table_->GetNextPrime(0)); + EXPECT_EQ(3, this->table_->GetNextPrime(2)); + EXPECT_EQ(5, this->table_->GetNextPrime(3)); + EXPECT_EQ(7, this->table_->GetNextPrime(5)); + EXPECT_EQ(11, this->table_->GetNextPrime(7)); + EXPECT_EQ(131, this->table_->GetNextPrime(128)); +} + +// Type-parameterized tests involve one extra step: you have to +// enumerate the tests you defined: +REGISTER_TYPED_TEST_CASE_P( + PrimeTableTest2, // The first argument is the test case name. + // The rest of the arguments are the test names. + ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime); + +// At this point the test pattern is done. However, you don't have +// any real test yet as you haven't said which types you want to run +// the tests with. + +// To turn the abstract test pattern into real tests, you instantiate +// it with a list of types. Usually the test pattern will be defined +// in a .h file, and anyone can #include and instantiate it. You can +// even instantiate it more than once in the same program. To tell +// different instances apart, you give each of them a name, which will +// become part of the test case name and can be used in test filters. + +// The list of types we want to test. Note that it doesn't have to be +// defined at the time we write the TYPED_TEST_P()s. +typedef Types + PrimeTableImplementations; +INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name + PrimeTableTest2, // Test case name + PrimeTableImplementations); // Type list + +#endif // GTEST_HAS_TYPED_TEST_P diff --git a/third_party/googletest/src/samples/sample7_unittest.cc b/third_party/googletest/src/samples/sample7_unittest.cc new file mode 100644 index 0000000..1b651a2 --- /dev/null +++ b/third_party/googletest/src/samples/sample7_unittest.cc @@ -0,0 +1,130 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// This sample shows how to test common properties of multiple +// implementations of an interface (aka interface tests) using +// value-parameterized tests. Each test in the test case has +// a parameter that is an interface pointer to an implementation +// tested. + +// The interface and its implementations are in this header. +#include "prime_tables.h" + +#include "gtest/gtest.h" + +#if GTEST_HAS_PARAM_TEST + +using ::testing::TestWithParam; +using ::testing::Values; + +// As a general rule, to prevent a test from affecting the tests that come +// after it, you should create and destroy the tested objects for each test +// instead of reusing them. In this sample we will define a simple factory +// function for PrimeTable objects. We will instantiate objects in test's +// SetUp() method and delete them in TearDown() method. +typedef PrimeTable* CreatePrimeTableFunc(); + +PrimeTable* CreateOnTheFlyPrimeTable() { + return new OnTheFlyPrimeTable(); +} + +template +PrimeTable* CreatePreCalculatedPrimeTable() { + return new PreCalculatedPrimeTable(max_precalculated); +} + +// Inside the test body, fixture constructor, SetUp(), and TearDown() you +// can refer to the test parameter by GetParam(). In this case, the test +// parameter is a factory function which we call in fixture's SetUp() to +// create and store an instance of PrimeTable. +class PrimeTableTest : public TestWithParam { + public: + virtual ~PrimeTableTest() { delete table_; } + virtual void SetUp() { table_ = (*GetParam())(); } + virtual void TearDown() { + delete table_; + table_ = NULL; + } + + protected: + PrimeTable* table_; +}; + +TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { + EXPECT_FALSE(table_->IsPrime(-5)); + EXPECT_FALSE(table_->IsPrime(0)); + EXPECT_FALSE(table_->IsPrime(1)); + EXPECT_FALSE(table_->IsPrime(4)); + EXPECT_FALSE(table_->IsPrime(6)); + EXPECT_FALSE(table_->IsPrime(100)); +} + +TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { + EXPECT_TRUE(table_->IsPrime(2)); + EXPECT_TRUE(table_->IsPrime(3)); + EXPECT_TRUE(table_->IsPrime(5)); + EXPECT_TRUE(table_->IsPrime(7)); + EXPECT_TRUE(table_->IsPrime(11)); + EXPECT_TRUE(table_->IsPrime(131)); +} + +TEST_P(PrimeTableTest, CanGetNextPrime) { + EXPECT_EQ(2, table_->GetNextPrime(0)); + EXPECT_EQ(3, table_->GetNextPrime(2)); + EXPECT_EQ(5, table_->GetNextPrime(3)); + EXPECT_EQ(7, table_->GetNextPrime(5)); + EXPECT_EQ(11, table_->GetNextPrime(7)); + EXPECT_EQ(131, table_->GetNextPrime(128)); +} + +// In order to run value-parameterized tests, you need to instantiate them, +// or bind them to a list of values which will be used as test parameters. +// You can instantiate them in a different translation module, or even +// instantiate them several times. +// +// Here, we instantiate our tests with a list of two PrimeTable object +// factory functions: +INSTANTIATE_TEST_CASE_P( + OnTheFlyAndPreCalculated, + PrimeTableTest, + Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>)); + +#else + +// Google Test may not support value-parameterized tests with some +// compilers. If we use conditional compilation to compile out all +// code referring to the gtest_main library, MSVC linker will not link +// that library at all and consequently complain about missing entry +// point defined in that library (fatal error LNK1561: entry point +// must be defined). This dummy test keeps gtest_main linked in. +TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} + +#endif // GTEST_HAS_PARAM_TEST diff --git a/third_party/googletest/src/samples/sample8_unittest.cc b/third_party/googletest/src/samples/sample8_unittest.cc new file mode 100644 index 0000000..5ad2e2c --- /dev/null +++ b/third_party/googletest/src/samples/sample8_unittest.cc @@ -0,0 +1,173 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// This sample shows how to test code relying on some global flag variables. +// Combine() helps with generating all possible combinations of such flags, +// and each test is given one combination as a parameter. + +// Use class definitions to test from this header. +#include "prime_tables.h" + +#include "gtest/gtest.h" + +#if GTEST_HAS_COMBINE + +// Suppose we want to introduce a new, improved implementation of PrimeTable +// which combines speed of PrecalcPrimeTable and versatility of +// OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both +// PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more +// appropriate under the circumstances. But in low memory conditions, it can be +// told to instantiate without PrecalcPrimeTable instance at all and use only +// OnTheFlyPrimeTable. +class HybridPrimeTable : public PrimeTable { + public: + HybridPrimeTable(bool force_on_the_fly, int max_precalculated) + : on_the_fly_impl_(new OnTheFlyPrimeTable), + precalc_impl_(force_on_the_fly ? NULL : + new PreCalculatedPrimeTable(max_precalculated)), + max_precalculated_(max_precalculated) {} + virtual ~HybridPrimeTable() { + delete on_the_fly_impl_; + delete precalc_impl_; + } + + virtual bool IsPrime(int n) const { + if (precalc_impl_ != NULL && n < max_precalculated_) + return precalc_impl_->IsPrime(n); + else + return on_the_fly_impl_->IsPrime(n); + } + + virtual int GetNextPrime(int p) const { + int next_prime = -1; + if (precalc_impl_ != NULL && p < max_precalculated_) + next_prime = precalc_impl_->GetNextPrime(p); + + return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p); + } + + private: + OnTheFlyPrimeTable* on_the_fly_impl_; + PreCalculatedPrimeTable* precalc_impl_; + int max_precalculated_; +}; + +using ::testing::TestWithParam; +using ::testing::Bool; +using ::testing::Values; +using ::testing::Combine; + +// To test all code paths for HybridPrimeTable we must test it with numbers +// both within and outside PreCalculatedPrimeTable's capacity and also with +// PreCalculatedPrimeTable disabled. We do this by defining fixture which will +// accept different combinations of parameters for instantiating a +// HybridPrimeTable instance. +class PrimeTableTest : public TestWithParam< ::std::tr1::tuple > { + protected: + virtual void SetUp() { + // This can be written as + // + // bool force_on_the_fly; + // int max_precalculated; + // tie(force_on_the_fly, max_precalculated) = GetParam(); + // + // once the Google C++ Style Guide allows use of ::std::tr1::tie. + // + bool force_on_the_fly = ::std::tr1::get<0>(GetParam()); + int max_precalculated = ::std::tr1::get<1>(GetParam()); + table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated); + } + virtual void TearDown() { + delete table_; + table_ = NULL; + } + HybridPrimeTable* table_; +}; + +TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { + // Inside the test body, you can refer to the test parameter by GetParam(). + // In this case, the test parameter is a PrimeTable interface pointer which + // we can use directly. + // Please note that you can also save it in the fixture's SetUp() method + // or constructor and use saved copy in the tests. + + EXPECT_FALSE(table_->IsPrime(-5)); + EXPECT_FALSE(table_->IsPrime(0)); + EXPECT_FALSE(table_->IsPrime(1)); + EXPECT_FALSE(table_->IsPrime(4)); + EXPECT_FALSE(table_->IsPrime(6)); + EXPECT_FALSE(table_->IsPrime(100)); +} + +TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { + EXPECT_TRUE(table_->IsPrime(2)); + EXPECT_TRUE(table_->IsPrime(3)); + EXPECT_TRUE(table_->IsPrime(5)); + EXPECT_TRUE(table_->IsPrime(7)); + EXPECT_TRUE(table_->IsPrime(11)); + EXPECT_TRUE(table_->IsPrime(131)); +} + +TEST_P(PrimeTableTest, CanGetNextPrime) { + EXPECT_EQ(2, table_->GetNextPrime(0)); + EXPECT_EQ(3, table_->GetNextPrime(2)); + EXPECT_EQ(5, table_->GetNextPrime(3)); + EXPECT_EQ(7, table_->GetNextPrime(5)); + EXPECT_EQ(11, table_->GetNextPrime(7)); + EXPECT_EQ(131, table_->GetNextPrime(128)); +} + +// In order to run value-parameterized tests, you need to instantiate them, +// or bind them to a list of values which will be used as test parameters. +// You can instantiate them in a different translation module, or even +// instantiate them several times. +// +// Here, we instantiate our tests with a list of parameters. We must combine +// all variations of the boolean flag suppressing PrecalcPrimeTable and some +// meaningful values for tests. We choose a small value (1), and a value that +// will put some of the tested numbers beyond the capability of the +// PrecalcPrimeTable instance and some inside it (10). Combine will produce all +// possible combinations. +INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters, + PrimeTableTest, + Combine(Bool(), Values(1, 10))); + +#else + +// Google Test may not support Combine() with some compilers. If we +// use conditional compilation to compile out all code referring to +// the gtest_main library, MSVC linker will not link that library at +// all and consequently complain about missing entry point defined in +// that library (fatal error LNK1561: entry point must be +// defined). This dummy test keeps gtest_main linked in. +TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {} + +#endif // GTEST_HAS_COMBINE diff --git a/third_party/googletest/src/samples/sample9_unittest.cc b/third_party/googletest/src/samples/sample9_unittest.cc new file mode 100644 index 0000000..b2e2079 --- /dev/null +++ b/third_party/googletest/src/samples/sample9_unittest.cc @@ -0,0 +1,160 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// This sample shows how to use Google Test listener API to implement +// an alternative console output and how to use the UnitTest reflection API +// to enumerate test cases and tests and to inspect their results. + +#include + +#include "gtest/gtest.h" + +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestCase; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; + +namespace { + +// Provides alternative output mode which produces minimal amount of +// information about tests. +class TersePrinter : public EmptyTestEventListener { + private: + // Called before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& /* unit_test */) {} + + // Called after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) { + fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED"); + fflush(stdout); + } + + // Called before a test starts. + virtual void OnTestStart(const TestInfo& test_info) { + fprintf(stdout, + "*** Test %s.%s starting.\n", + test_info.test_case_name(), + test_info.name()); + fflush(stdout); + } + + // Called after a failed assertion or a SUCCEED() invocation. + virtual void OnTestPartResult(const TestPartResult& test_part_result) { + fprintf(stdout, + "%s in %s:%d\n%s\n", + test_part_result.failed() ? "*** Failure" : "Success", + test_part_result.file_name(), + test_part_result.line_number(), + test_part_result.summary()); + fflush(stdout); + } + + // Called after a test ends. + virtual void OnTestEnd(const TestInfo& test_info) { + fprintf(stdout, + "*** Test %s.%s ending.\n", + test_info.test_case_name(), + test_info.name()); + fflush(stdout); + } +}; // class TersePrinter + +TEST(CustomOutputTest, PrintsMessage) { + printf("Printing something from the test body...\n"); +} + +TEST(CustomOutputTest, Succeeds) { + SUCCEED() << "SUCCEED() has been invoked from here"; +} + +TEST(CustomOutputTest, Fails) { + EXPECT_EQ(1, 2) + << "This test fails in order to demonstrate alternative failure messages"; +} + +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + bool terse_output = false; + if (argc > 1 && strcmp(argv[1], "--terse_output") == 0 ) + terse_output = true; + else + printf("%s\n", "Run this program with --terse_output to change the way " + "it prints its output."); + + UnitTest& unit_test = *UnitTest::GetInstance(); + + // If we are given the --terse_output command line flag, suppresses the + // standard output and attaches own result printer. + if (terse_output) { + TestEventListeners& listeners = unit_test.listeners(); + + // Removes the default console output listener from the list so it will + // not receive events from Google Test and won't print any output. Since + // this operation transfers ownership of the listener to the caller we + // have to delete it as well. + delete listeners.Release(listeners.default_result_printer()); + + // Adds the custom output listener to the list. It will now receive + // events from Google Test and print the alternative output. We don't + // have to worry about deleting it since Google Test assumes ownership + // over it after adding it to the list. + listeners.Append(new TersePrinter); + } + int ret_val = RUN_ALL_TESTS(); + + // This is an example of using the UnitTest reflection API to inspect test + // results. Here we discount failures from the tests we expected to fail. + int unexpectedly_failed_tests = 0; + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + // Counts failed tests that were not meant to fail (those without + // 'Fails' in the name). + if (test_info.result()->Failed() && + strcmp(test_info.name(), "Fails") != 0) { + unexpectedly_failed_tests++; + } + } + } + + // Test that were meant to fail should not affect the test program outcome. + if (unexpectedly_failed_tests == 0) + ret_val = 0; + + return ret_val; +} diff --git a/third_party/googletest/src/scripts/fuse_gtest_files.py b/third_party/googletest/src/scripts/fuse_gtest_files.py new file mode 100755 index 0000000..57ef72f --- /dev/null +++ b/third_party/googletest/src/scripts/fuse_gtest_files.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""fuse_gtest_files.py v0.2.0 +Fuses Google Test source code into a .h file and a .cc file. + +SYNOPSIS + fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR + + Scans GTEST_ROOT_DIR for Google Test source code, and generates + two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc. + Then you can build your tests by adding OUTPUT_DIR to the include + search path and linking with OUTPUT_DIR/gtest/gtest-all.cc. These + two files contain everything you need to use Google Test. Hence + you can "install" Google Test by copying them to wherever you want. + + GTEST_ROOT_DIR can be omitted and defaults to the parent + directory of the directory holding this script. + +EXAMPLES + ./fuse_gtest_files.py fused_gtest + ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest + +This tool is experimental. In particular, it assumes that there is no +conditional inclusion of Google Test headers. Please report any +problems to googletestframework@googlegroups.com. You can read +http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for +more information. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sets +import sys + +# We assume that this file is in the scripts/ directory in the Google +# Test root directory. +DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') + +# Regex for matching '#include "gtest/..."'. +INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gtest/.+)"') + +# Regex for matching '#include "src/..."'. +INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"') + +# Where to find the source seed files. +GTEST_H_SEED = 'include/gtest/gtest.h' +GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h' +GTEST_ALL_CC_SEED = 'src/gtest-all.cc' + +# Where to put the generated files. +GTEST_H_OUTPUT = 'gtest/gtest.h' +GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc' + + +def VerifyFileExists(directory, relative_path): + """Verifies that the given file exists; aborts on failure. + + relative_path is the file path relative to the given directory. + """ + + if not os.path.isfile(os.path.join(directory, relative_path)): + print 'ERROR: Cannot find %s in directory %s.' % (relative_path, + directory) + print ('Please either specify a valid project root directory ' + 'or omit it on the command line.') + sys.exit(1) + + +def ValidateGTestRootDir(gtest_root): + """Makes sure gtest_root points to a valid gtest root directory. + + The function aborts the program on failure. + """ + + VerifyFileExists(gtest_root, GTEST_H_SEED) + VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED) + + +def VerifyOutputFile(output_dir, relative_path): + """Verifies that the given output file path is valid. + + relative_path is relative to the output_dir directory. + """ + + # Makes sure the output file either doesn't exist or can be overwritten. + output_file = os.path.join(output_dir, relative_path) + if os.path.exists(output_file): + # TODO(wan@google.com): The following user-interaction doesn't + # work with automated processes. We should provide a way for the + # Makefile to force overwriting the files. + print ('%s already exists in directory %s - overwrite it? (y/N) ' % + (relative_path, output_dir)) + answer = sys.stdin.readline().strip() + if answer not in ['y', 'Y']: + print 'ABORTED.' + sys.exit(1) + + # Makes sure the directory holding the output file exists; creates + # it and all its ancestors if necessary. + parent_directory = os.path.dirname(output_file) + if not os.path.isdir(parent_directory): + os.makedirs(parent_directory) + + +def ValidateOutputDir(output_dir): + """Makes sure output_dir points to a valid output directory. + + The function aborts the program on failure. + """ + + VerifyOutputFile(output_dir, GTEST_H_OUTPUT) + VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT) + + +def FuseGTestH(gtest_root, output_dir): + """Scans folder gtest_root to generate gtest/gtest.h in output_dir.""" + + output_file = file(os.path.join(output_dir, GTEST_H_OUTPUT), 'w') + processed_files = sets.Set() # Holds all gtest headers we've processed. + + def ProcessFile(gtest_header_path): + """Processes the given gtest header file.""" + + # We don't process the same header twice. + if gtest_header_path in processed_files: + return + + processed_files.add(gtest_header_path) + + # Reads each line in the given gtest header. + for line in file(os.path.join(gtest_root, gtest_header_path), 'r'): + m = INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + # It's '#include "gtest/..."' - let's process it recursively. + ProcessFile('include/' + m.group(1)) + else: + # Otherwise we copy the line unchanged to the output file. + output_file.write(line) + + ProcessFile(GTEST_H_SEED) + output_file.close() + + +def FuseGTestAllCcToFile(gtest_root, output_file): + """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file.""" + + processed_files = sets.Set() + + def ProcessFile(gtest_source_file): + """Processes the given gtest source file.""" + + # We don't process the same #included file twice. + if gtest_source_file in processed_files: + return + + processed_files.add(gtest_source_file) + + # Reads each line in the given gtest source file. + for line in file(os.path.join(gtest_root, gtest_source_file), 'r'): + m = INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + if 'include/' + m.group(1) == GTEST_SPI_H_SEED: + # It's '#include "gtest/gtest-spi.h"'. This file is not + # #included by "gtest/gtest.h", so we need to process it. + ProcessFile(GTEST_SPI_H_SEED) + else: + # It's '#include "gtest/foo.h"' where foo is not gtest-spi. + # We treat it as '#include "gtest/gtest.h"', as all other + # gtest headers are being fused into gtest.h and cannot be + # #included directly. + + # There is no need to #include "gtest/gtest.h" more than once. + if not GTEST_H_SEED in processed_files: + processed_files.add(GTEST_H_SEED) + output_file.write('#include "%s"\n' % (GTEST_H_OUTPUT,)) + else: + m = INCLUDE_SRC_FILE_REGEX.match(line) + if m: + # It's '#include "src/foo"' - let's process it recursively. + ProcessFile(m.group(1)) + else: + output_file.write(line) + + ProcessFile(GTEST_ALL_CC_SEED) + + +def FuseGTestAllCc(gtest_root, output_dir): + """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir.""" + + output_file = file(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w') + FuseGTestAllCcToFile(gtest_root, output_file) + output_file.close() + + +def FuseGTest(gtest_root, output_dir): + """Fuses gtest.h and gtest-all.cc.""" + + ValidateGTestRootDir(gtest_root) + ValidateOutputDir(output_dir) + + FuseGTestH(gtest_root, output_dir) + FuseGTestAllCc(gtest_root, output_dir) + + +def main(): + argc = len(sys.argv) + if argc == 2: + # fuse_gtest_files.py OUTPUT_DIR + FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1]) + elif argc == 3: + # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR + FuseGTest(sys.argv[1], sys.argv[2]) + else: + print __doc__ + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/third_party/googletest/src/scripts/gen_gtest_pred_impl.py b/third_party/googletest/src/scripts/gen_gtest_pred_impl.py new file mode 100755 index 0000000..d35b4f0 --- /dev/null +++ b/third_party/googletest/src/scripts/gen_gtest_pred_impl.py @@ -0,0 +1,730 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""gen_gtest_pred_impl.py v0.1 + +Generates the implementation of Google Test predicate assertions and +accompanying tests. + +Usage: + + gen_gtest_pred_impl.py MAX_ARITY + +where MAX_ARITY is a positive integer. + +The command generates the implementation of up-to MAX_ARITY-ary +predicate assertions, and writes it to file gtest_pred_impl.h in the +directory where the script is. It also generates the accompanying +unit test in file gtest_pred_impl_unittest.cc. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import sys +import time + +# Where this script is. +SCRIPT_DIR = os.path.dirname(sys.argv[0]) + +# Where to store the generated header. +HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h') + +# Where to store the generated unit test. +UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc') + + +def HeaderPreamble(n): + """Returns the preamble for the header file. + + Args: + n: the maximum arity of the predicate macros to be generated. + """ + + # A map that defines the values used in the preamble template. + DEFS = { + 'today' : time.strftime('%m/%d/%Y'), + 'year' : time.strftime('%Y'), + 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n), + 'n' : n + } + + return ( +"""// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on %(today)s by command +// '%(command)s'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most %(n)s. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \\ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\ + if (const ::testing::AssertionResult gtest_ar = (expression)) \\ + ; \\ + else \\ + on_failure(gtest_ar.failure_message()) +""" % DEFS) + + +def Arity(n): + """Returns the English name of the given arity.""" + + if n < 0: + return None + elif n <= 3: + return ['nullary', 'unary', 'binary', 'ternary'][n] + else: + return '%s-ary' % n + + +def Title(word): + """Returns the given word in title case. The difference between + this and string's title() method is that Title('4-ary') is '4-ary' + while '4-ary'.title() is '4-Ary'.""" + + return word[0].upper() + word[1:] + + +def OneTo(n): + """Returns the list [1, 2, 3, ..., n].""" + + return range(1, n + 1) + + +def Iter(n, format, sep=''): + """Given a positive integer n, a format string that contains 0 or + more '%s' format specs, and optionally a separator string, returns + the join of n strings, each formatted with the format string on an + iterator ranged from 1 to n. + + Example: + + Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'. + """ + + # How many '%s' specs are in format? + spec_count = len(format.split('%s')) - 1 + return sep.join([format % (spec_count * (i,)) for i in OneTo(n)]) + + +def ImplementationForArity(n): + """Returns the implementation of n-ary predicate assertions.""" + + # A map the defines the values used in the implementation template. + DEFS = { + 'n' : str(n), + 'vs' : Iter(n, 'v%s', sep=', '), + 'vts' : Iter(n, '#v%s', sep=', '), + 'arity' : Arity(n), + 'Arity' : Title(Arity(n)) + } + + impl = """ + +// Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use +// this in your code. +template +AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS + + impl += Iter(n, """, + const char* e%s""") + + impl += """, + Pred pred""" + + impl += Iter(n, """, + const T%s& v%s""") + + impl += """) { + if (pred(%(vs)s)) return AssertionSuccess(); + +""" % DEFS + + impl += ' return AssertionFailure() << pred_text << "("' + + impl += Iter(n, """ + << e%s""", sep=' << ", "') + + impl += ' << ") evaluates to false, where"' + + impl += Iter(n, """ + << "\\n" << e%s << " evaluates to " << v%s""") + + impl += """; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s. +// Don't use this in your code. +#define GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, on_failure)\\ + GTEST_ASSERT_(pred_format(%(vts)s, %(vs)s),\\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use +// this in your code. +#define GTEST_PRED%(n)s_(pred, %(vs)s, on_failure)\\ + GTEST_ASSERT_(::testing::AssertPred%(n)sHelper(#pred""" % DEFS + + impl += Iter(n, """, \\ + #v%s""") + + impl += """, \\ + pred""" + + impl += Iter(n, """, \\ + v%s""") + + impl += """), on_failure) + +// %(Arity)s predicate assertion macros. +#define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ + GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED%(n)s(pred, %(vs)s) \\ + GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ + GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED%(n)s(pred, %(vs)s) \\ + GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_FATAL_FAILURE_) + +""" % DEFS + + return impl + + +def HeaderPostamble(): + """Returns the postamble for the header file.""" + + return """ + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +""" + + +def GenerateFile(path, content): + """Given a file path and a content string, overwrites it with the + given content.""" + + print 'Updating file %s . . .' % path + + f = file(path, 'w+') + print >>f, content, + f.close() + + print 'File %s has been updated.' % path + + +def GenerateHeader(n): + """Given the maximum arity n, updates the header file that implements + the predicate assertions.""" + + GenerateFile(HEADER, + HeaderPreamble(n) + + ''.join([ImplementationForArity(i) for i in OneTo(n)]) + + HeaderPostamble()) + + +def UnitTestPreamble(): + """Returns the preamble for the unit test file.""" + + # A map that defines the values used in the preamble template. + DEFS = { + 'today' : time.strftime('%m/%d/%Y'), + 'year' : time.strftime('%Y'), + 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]), + } + + return ( +"""// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on %(today)s by command +// '%(command)s'. DO NOT EDIT BY HAND! + +// Regression test for gtest_pred_impl.h +// +// This file is generated by a script and quite long. If you intend to +// learn how Google Test works by reading its unit tests, read +// gtest_unittest.cc instead. +// +// This is intended as a regression test for the Google Test predicate +// assertions. We compile it as part of the gtest_unittest target +// only to keep the implementation tidy and compact, as it is quite +// involved to set up the stage for testing Google Test using Google +// Test itself. +// +// Currently, gtest_unittest takes ~11 seconds to run in the testing +// daemon. In the future, if it grows too large and needs much more +// time to finish, we should consider separating this file into a +// stand-alone regression test. + +#include + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +// A user-defined data type. +struct Bool { + explicit Bool(int val) : value(val != 0) {} + + bool operator>(int n) const { return value > Bool(n).value; } + + Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } + + bool operator==(const Bool& rhs) const { return value == rhs.value; } + + bool value; +}; + +// Enables Bool to be used in assertions. +std::ostream& operator<<(std::ostream& os, const Bool& x) { + return os << (x.value ? "true" : "false"); +} + +""" % DEFS) + + +def TestsForArity(n): + """Returns the tests for n-ary predicate assertions.""" + + # A map that defines the values used in the template for the tests. + DEFS = { + 'n' : n, + 'es' : Iter(n, 'e%s', sep=', '), + 'vs' : Iter(n, 'v%s', sep=', '), + 'vts' : Iter(n, '#v%s', sep=', '), + 'tvs' : Iter(n, 'T%s v%s', sep=', '), + 'int_vs' : Iter(n, 'int v%s', sep=', '), + 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '), + 'types' : Iter(n, 'typename T%s', sep=', '), + 'v_sum' : Iter(n, 'v%s', sep=' + '), + 'arity' : Arity(n), + 'Arity' : Title(Arity(n)), + } + + tests = ( +"""// Sample functions/functors for testing %(arity)s predicate assertions. + +// A %(arity)s predicate function. +template <%(types)s> +bool PredFunction%(n)s(%(tvs)s) { + return %(v_sum)s > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction%(n)sInt(%(int_vs)s) { + return %(v_sum)s > 0; +} +bool PredFunction%(n)sBool(%(Bool_vs)s) { + return %(v_sum)s > 0; +} +""" % DEFS) + + tests += """ +// A %(arity)s predicate functor. +struct PredFunctor%(n)s { + template <%(types)s> + bool operator()(""" % DEFS + + tests += Iter(n, 'const T%s& v%s', sep=""", + """) + + tests += """) { + return %(v_sum)s > 0; + } +}; +""" % DEFS + + tests += """ +// A %(arity)s predicate-formatter function. +template <%(types)s> +testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS + + tests += Iter(n, 'const char* e%s', sep=""", + """) + + tests += Iter(n, """, + const T%s& v%s""") + + tests += """) { + if (PredFunction%(n)s(%(vs)s)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << """ % DEFS + + tests += Iter(n, 'e%s', sep=' << " + " << ') + + tests += """ + << " is expected to be positive, but evaluates to " + << %(v_sum)s << "."; +} +""" % DEFS + + tests += """ +// A %(arity)s predicate-formatter functor. +struct PredFormatFunctor%(n)s { + template <%(types)s> + testing::AssertionResult operator()(""" % DEFS + + tests += Iter(n, 'const char* e%s', sep=""", + """) + + tests += Iter(n, """, + const T%s& v%s""") + + tests += """) const { + return PredFormatFunction%(n)s(%(es)s, %(vs)s); + } +}; +""" % DEFS + + tests += """ +// Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s. + +class Predicate%(n)sTest : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false;""" % DEFS + + tests += """ + """ + Iter(n, 'n%s_ = ') + """0; + } +""" + + tests += """ + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once.""" + + tests += ''.join([""" + EXPECT_EQ(1, n%s_) << + "The predicate assertion didn't evaluate argument %s " + "exactly once.";""" % (i, i + 1) for i in OneTo(n)]) + + tests += """ + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; +""" % DEFS + + tests += Iter(n, """ + static int n%s_;""") + + tests += """ +}; + +bool Predicate%(n)sTest::expected_to_finish_; +bool Predicate%(n)sTest::finished_; +""" % DEFS + + tests += Iter(n, """int Predicate%%(n)sTest::n%s_; +""") % DEFS + + tests += """ +typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest; +typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest; +typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest; +typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest; +""" % DEFS + + def GenTest(use_format, use_assert, expect_failure, + use_functor, use_user_type): + """Returns the test for a predicate assertion macro. + + Args: + use_format: true iff the assertion is a *_PRED_FORMAT*. + use_assert: true iff the assertion is a ASSERT_*. + expect_failure: true iff the assertion is expected to fail. + use_functor: true iff the first argument of the assertion is + a functor (as opposed to a function) + use_user_type: true iff the predicate functor/function takes + argument(s) of a user-defined type. + + Example: + + GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior + of a successful EXPECT_PRED_FORMATn() that takes a functor + whose arguments have built-in types.""" + + if use_assert: + assrt = 'ASSERT' # 'assert' is reserved, so we cannot use + # that identifier here. + else: + assrt = 'EXPECT' + + assertion = assrt + '_PRED' + + if use_format: + pred_format = 'PredFormat' + assertion += '_FORMAT' + else: + pred_format = 'Pred' + + assertion += '%(n)s' % DEFS + + if use_functor: + pred_format_type = 'functor' + pred_format += 'Functor%(n)s()' + else: + pred_format_type = 'function' + pred_format += 'Function%(n)s' + if not use_format: + if use_user_type: + pred_format += 'Bool' + else: + pred_format += 'Int' + + test_name = pred_format_type.title() + + if use_user_type: + arg_type = 'user-defined type (Bool)' + test_name += 'OnUserType' + if expect_failure: + arg = 'Bool(n%s_++)' + else: + arg = 'Bool(++n%s_)' + else: + arg_type = 'built-in type (int)' + test_name += 'OnBuiltInType' + if expect_failure: + arg = 'n%s_++' + else: + arg = '++n%s_' + + if expect_failure: + successful_or_failed = 'failed' + expected_or_not = 'expected.' + test_name += 'Failure' + else: + successful_or_failed = 'successful' + expected_or_not = 'UNEXPECTED!' + test_name += 'Success' + + # A map that defines the values used in the test template. + defs = DEFS.copy() + defs.update({ + 'assert' : assrt, + 'assertion' : assertion, + 'test_name' : test_name, + 'pf_type' : pred_format_type, + 'pf' : pred_format, + 'arg_type' : arg_type, + 'arg' : arg, + 'successful' : successful_or_failed, + 'expected' : expected_or_not, + }) + + test = """ +// Tests a %(successful)s %(assertion)s where the +// predicate-formatter is a %(pf_type)s on a %(arg_type)s. +TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs + + indent = (len(assertion) + 3)*' ' + extra_indent = '' + + if expect_failure: + extra_indent = ' ' + if use_assert: + test += """ + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT""" + else: + test += """ + EXPECT_NONFATAL_FAILURE({ // NOLINT""" + + test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs + + test = test % defs + test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs) + test += ');\n' + extra_indent + ' finished_ = true;\n' + + if expect_failure: + test += ' }, "");\n' + + test += '}\n' + return test + + # Generates tests for all 2**6 = 64 combinations. + tests += ''.join([GenTest(use_format, use_assert, expect_failure, + use_functor, use_user_type) + for use_format in [0, 1] + for use_assert in [0, 1] + for expect_failure in [0, 1] + for use_functor in [0, 1] + for use_user_type in [0, 1] + ]) + + return tests + + +def UnitTestPostamble(): + """Returns the postamble for the tests.""" + + return '' + + +def GenerateUnitTest(n): + """Returns the tests for up-to n-ary predicate assertions.""" + + GenerateFile(UNIT_TEST, + UnitTestPreamble() + + ''.join([TestsForArity(i) for i in OneTo(n)]) + + UnitTestPostamble()) + + +def _Main(): + """The entry point of the script. Generates the header file and its + unit test.""" + + if len(sys.argv) != 2: + print __doc__ + print 'Author: ' + __author__ + sys.exit(1) + + n = int(sys.argv[1]) + GenerateHeader(n) + GenerateUnitTest(n) + + +if __name__ == '__main__': + _Main() diff --git a/third_party/googletest/src/scripts/gtest-config.in b/third_party/googletest/src/scripts/gtest-config.in new file mode 100644 index 0000000..9c72638 --- /dev/null +++ b/third_party/googletest/src/scripts/gtest-config.in @@ -0,0 +1,274 @@ +#!/bin/sh + +# These variables are automatically filled in by the configure script. +name="@PACKAGE_TARNAME@" +version="@PACKAGE_VERSION@" + +show_usage() +{ + echo "Usage: gtest-config [OPTIONS...]" +} + +show_help() +{ + show_usage + cat <<\EOF + +The `gtest-config' script provides access to the necessary compile and linking +flags to connect with Google C++ Testing Framework, both in a build prior to +installation, and on the system proper after installation. The installation +overrides may be issued in combination with any other queries, but will only +affect installation queries if called on a built but not installed gtest. The +installation queries may not be issued with any other types of queries, and +only one installation query may be made at a time. The version queries and +compiler flag queries may be combined as desired but not mixed. Different +version queries are always combined with logical "and" semantics, and only the +last of any particular query is used while all previous ones ignored. All +versions must be specified as a sequence of numbers separated by periods. +Compiler flag queries output the union of the sets of flags when combined. + + Examples: + gtest-config --min-version=1.0 || echo "Insufficient Google Test version." + + g++ $(gtest-config --cppflags --cxxflags) -o foo.o -c foo.cpp + g++ $(gtest-config --ldflags --libs) -o foo foo.o + + # When using a built but not installed Google Test: + g++ $(../../my_gtest_build/scripts/gtest-config ...) ... + + # When using an installed Google Test, but with installation overrides: + export GTEST_PREFIX="/opt" + g++ $(gtest-config --libdir="/opt/lib64" ...) ... + + Help: + --usage brief usage information + --help display this help message + + Installation Overrides: + --prefix= overrides the installation prefix + --exec-prefix= overrides the executable installation prefix + --libdir= overrides the library installation prefix + --includedir= overrides the header file installation prefix + + Installation Queries: + --prefix installation prefix + --exec-prefix executable installation prefix + --libdir library installation directory + --includedir header file installation directory + --version the version of the Google Test installation + + Version Queries: + --min-version=VERSION return 0 if the version is at least VERSION + --exact-version=VERSION return 0 if the version is exactly VERSION + --max-version=VERSION return 0 if the version is at most VERSION + + Compilation Flag Queries: + --cppflags compile flags specific to the C-like preprocessors + --cxxflags compile flags appropriate for C++ programs + --ldflags linker flags + --libs libraries for linking + +EOF +} + +# This function bounds our version with a min and a max. It uses some clever +# POSIX-compliant variable expansion to portably do all the work in the shell +# and avoid any dependency on a particular "sed" or "awk" implementation. +# Notable is that it will only ever compare the first 3 components of versions. +# Further components will be cleanly stripped off. All versions must be +# unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and +# the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should +# investigate expanding this via autom4te from AS_VERSION_COMPARE rather than +# continuing to maintain our own shell version. +check_versions() +{ + major_version=${version%%.*} + minor_version="0" + point_version="0" + if test "${version#*.}" != "${version}"; then + minor_version=${version#*.} + minor_version=${minor_version%%.*} + fi + if test "${version#*.*.}" != "${version}"; then + point_version=${version#*.*.} + point_version=${point_version%%.*} + fi + + min_version="$1" + min_major_version=${min_version%%.*} + min_minor_version="0" + min_point_version="0" + if test "${min_version#*.}" != "${min_version}"; then + min_minor_version=${min_version#*.} + min_minor_version=${min_minor_version%%.*} + fi + if test "${min_version#*.*.}" != "${min_version}"; then + min_point_version=${min_version#*.*.} + min_point_version=${min_point_version%%.*} + fi + + max_version="$2" + max_major_version=${max_version%%.*} + max_minor_version="0" + max_point_version="0" + if test "${max_version#*.}" != "${max_version}"; then + max_minor_version=${max_version#*.} + max_minor_version=${max_minor_version%%.*} + fi + if test "${max_version#*.*.}" != "${max_version}"; then + max_point_version=${max_version#*.*.} + max_point_version=${max_point_version%%.*} + fi + + test $(($major_version)) -lt $(($min_major_version)) && exit 1 + if test $(($major_version)) -eq $(($min_major_version)); then + test $(($minor_version)) -lt $(($min_minor_version)) && exit 1 + if test $(($minor_version)) -eq $(($min_minor_version)); then + test $(($point_version)) -lt $(($min_point_version)) && exit 1 + fi + fi + + test $(($major_version)) -gt $(($max_major_version)) && exit 1 + if test $(($major_version)) -eq $(($max_major_version)); then + test $(($minor_version)) -gt $(($max_minor_version)) && exit 1 + if test $(($minor_version)) -eq $(($max_minor_version)); then + test $(($point_version)) -gt $(($max_point_version)) && exit 1 + fi + fi + + exit 0 +} + +# Show the usage line when no arguments are specified. +if test $# -eq 0; then + show_usage + exit 1 +fi + +while test $# -gt 0; do + case $1 in + --usage) show_usage; exit 0;; + --help) show_help; exit 0;; + + # Installation overrides + --prefix=*) GTEST_PREFIX=${1#--prefix=};; + --exec-prefix=*) GTEST_EXEC_PREFIX=${1#--exec-prefix=};; + --libdir=*) GTEST_LIBDIR=${1#--libdir=};; + --includedir=*) GTEST_INCLUDEDIR=${1#--includedir=};; + + # Installation queries + --prefix|--exec-prefix|--libdir|--includedir|--version) + if test -n "${do_query}"; then + show_usage + exit 1 + fi + do_query=${1#--} + ;; + + # Version checking + --min-version=*) + do_check_versions=yes + min_version=${1#--min-version=} + ;; + --max-version=*) + do_check_versions=yes + max_version=${1#--max-version=} + ;; + --exact-version=*) + do_check_versions=yes + exact_version=${1#--exact-version=} + ;; + + # Compiler flag output + --cppflags) echo_cppflags=yes;; + --cxxflags) echo_cxxflags=yes;; + --ldflags) echo_ldflags=yes;; + --libs) echo_libs=yes;; + + # Everything else is an error + *) show_usage; exit 1;; + esac + shift +done + +# These have defaults filled in by the configure script but can also be +# overridden by environment variables or command line parameters. +prefix="${GTEST_PREFIX:-@prefix@}" +exec_prefix="${GTEST_EXEC_PREFIX:-@exec_prefix@}" +libdir="${GTEST_LIBDIR:-@libdir@}" +includedir="${GTEST_INCLUDEDIR:-@includedir@}" + +# We try and detect if our binary is not located at its installed location. If +# it's not, we provide variables pointing to the source and build tree rather +# than to the install tree. This allows building against a just-built gtest +# rather than an installed gtest. +bindir="@bindir@" +this_relative_bindir=`dirname $0` +this_bindir=`cd ${this_relative_bindir}; pwd -P` +if test "${this_bindir}" = "${this_bindir%${bindir}}"; then + # The path to the script doesn't end in the bindir sequence from Autoconf, + # assume that we are in a build tree. + build_dir=`dirname ${this_bindir}` + src_dir=`cd ${this_bindir}/@top_srcdir@; pwd -P` + + # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we + # should work to remove it, and/or remove libtool altogether, replacing it + # with direct references to the library and a link path. + gtest_libs="${build_dir}/lib/libgtest.la @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" + gtest_ldflags="" + + # We provide hooks to include from either the source or build dir, where the + # build dir is always preferred. This will potentially allow us to write + # build rules for generated headers and have them automatically be preferred + # over provided versions. + gtest_cppflags="-I${build_dir}/include -I${src_dir}/include" + gtest_cxxflags="@PTHREAD_CFLAGS@" +else + # We're using an installed gtest, although it may be staged under some + # prefix. Assume (as our own libraries do) that we can resolve the prefix, + # and are present in the dynamic link paths. + gtest_ldflags="-L${libdir}" + gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" + gtest_cppflags="-I${includedir}" + gtest_cxxflags="@PTHREAD_CFLAGS@" +fi + +# Do an installation query if requested. +if test -n "$do_query"; then + case $do_query in + prefix) echo $prefix; exit 0;; + exec-prefix) echo $exec_prefix; exit 0;; + libdir) echo $libdir; exit 0;; + includedir) echo $includedir; exit 0;; + version) echo $version; exit 0;; + *) show_usage; exit 1;; + esac +fi + +# Do a version check if requested. +if test "$do_check_versions" = "yes"; then + # Make sure we didn't receive a bad combination of parameters. + test "$echo_cppflags" = "yes" && show_usage && exit 1 + test "$echo_cxxflags" = "yes" && show_usage && exit 1 + test "$echo_ldflags" = "yes" && show_usage && exit 1 + test "$echo_libs" = "yes" && show_usage && exit 1 + + if test "$exact_version" != ""; then + check_versions $exact_version $exact_version + # unreachable + else + check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999} + # unreachable + fi +fi + +# Do the output in the correct order so that these can be used in-line of +# a compiler invocation. +output="" +test "$echo_cppflags" = "yes" && output="$output $gtest_cppflags" +test "$echo_cxxflags" = "yes" && output="$output $gtest_cxxflags" +test "$echo_ldflags" = "yes" && output="$output $gtest_ldflags" +test "$echo_libs" = "yes" && output="$output $gtest_libs" +echo $output + +exit 0 diff --git a/third_party/googletest/src/scripts/pump.py b/third_party/googletest/src/scripts/pump.py new file mode 100755 index 0000000..8afe808 --- /dev/null +++ b/third_party/googletest/src/scripts/pump.py @@ -0,0 +1,847 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""pump v0.2.0 - Pretty Useful for Meta Programming. + +A tool for preprocessor meta programming. Useful for generating +repetitive boilerplate code. Especially useful for writing C++ +classes, functions, macros, and templates that need to work with +various number of arguments. + +USAGE: + pump.py SOURCE_FILE + +EXAMPLES: + pump.py foo.cc.pump + Converts foo.cc.pump to foo.cc. + +GRAMMAR: + CODE ::= ATOMIC_CODE* + ATOMIC_CODE ::= $var ID = EXPRESSION + | $var ID = [[ CODE ]] + | $range ID EXPRESSION..EXPRESSION + | $for ID SEPARATOR [[ CODE ]] + | $($) + | $ID + | $(EXPRESSION) + | $if EXPRESSION [[ CODE ]] ELSE_BRANCH + | [[ CODE ]] + | RAW_CODE + SEPARATOR ::= RAW_CODE | EMPTY + ELSE_BRANCH ::= $else [[ CODE ]] + | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH + | EMPTY + EXPRESSION has Python syntax. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sys + + +TOKEN_TABLE = [ + (re.compile(r'\$var\s+'), '$var'), + (re.compile(r'\$elif\s+'), '$elif'), + (re.compile(r'\$else\s+'), '$else'), + (re.compile(r'\$for\s+'), '$for'), + (re.compile(r'\$if\s+'), '$if'), + (re.compile(r'\$range\s+'), '$range'), + (re.compile(r'\$[_A-Za-z]\w*'), '$id'), + (re.compile(r'\$\(\$\)'), '$($)'), + (re.compile(r'\$'), '$'), + (re.compile(r'\[\[\n?'), '[['), + (re.compile(r'\]\]\n?'), ']]'), + ] + + +class Cursor: + """Represents a position (line and column) in a text file.""" + + def __init__(self, line=-1, column=-1): + self.line = line + self.column = column + + def __eq__(self, rhs): + return self.line == rhs.line and self.column == rhs.column + + def __ne__(self, rhs): + return not self == rhs + + def __lt__(self, rhs): + return self.line < rhs.line or ( + self.line == rhs.line and self.column < rhs.column) + + def __le__(self, rhs): + return self < rhs or self == rhs + + def __gt__(self, rhs): + return rhs < self + + def __ge__(self, rhs): + return rhs <= self + + def __str__(self): + if self == Eof(): + return 'EOF' + else: + return '%s(%s)' % (self.line + 1, self.column) + + def __add__(self, offset): + return Cursor(self.line, self.column + offset) + + def __sub__(self, offset): + return Cursor(self.line, self.column - offset) + + def Clone(self): + """Returns a copy of self.""" + + return Cursor(self.line, self.column) + + +# Special cursor to indicate the end-of-file. +def Eof(): + """Returns the special cursor to denote the end-of-file.""" + return Cursor(-1, -1) + + +class Token: + """Represents a token in a Pump source file.""" + + def __init__(self, start=None, end=None, value=None, token_type=None): + if start is None: + self.start = Eof() + else: + self.start = start + if end is None: + self.end = Eof() + else: + self.end = end + self.value = value + self.token_type = token_type + + def __str__(self): + return 'Token @%s: \'%s\' type=%s' % ( + self.start, self.value, self.token_type) + + def Clone(self): + """Returns a copy of self.""" + + return Token(self.start.Clone(), self.end.Clone(), self.value, + self.token_type) + + +def StartsWith(lines, pos, string): + """Returns True iff the given position in lines starts with 'string'.""" + + return lines[pos.line][pos.column:].startswith(string) + + +def FindFirstInLine(line, token_table): + best_match_start = -1 + for (regex, token_type) in token_table: + m = regex.search(line) + if m: + # We found regex in lines + if best_match_start < 0 or m.start() < best_match_start: + best_match_start = m.start() + best_match_length = m.end() - m.start() + best_match_token_type = token_type + + if best_match_start < 0: + return None + + return (best_match_start, best_match_length, best_match_token_type) + + +def FindFirst(lines, token_table, cursor): + """Finds the first occurrence of any string in strings in lines.""" + + start = cursor.Clone() + cur_line_number = cursor.line + for line in lines[start.line:]: + if cur_line_number == start.line: + line = line[start.column:] + m = FindFirstInLine(line, token_table) + if m: + # We found a regex in line. + (start_column, length, token_type) = m + if cur_line_number == start.line: + start_column += start.column + found_start = Cursor(cur_line_number, start_column) + found_end = found_start + length + return MakeToken(lines, found_start, found_end, token_type) + cur_line_number += 1 + # We failed to find str in lines + return None + + +def SubString(lines, start, end): + """Returns a substring in lines.""" + + if end == Eof(): + end = Cursor(len(lines) - 1, len(lines[-1])) + + if start >= end: + return '' + + if start.line == end.line: + return lines[start.line][start.column:end.column] + + result_lines = ([lines[start.line][start.column:]] + + lines[start.line + 1:end.line] + + [lines[end.line][:end.column]]) + return ''.join(result_lines) + + +def StripMetaComments(str): + """Strip meta comments from each line in the given string.""" + + # First, completely remove lines containing nothing but a meta + # comment, including the trailing \n. + str = re.sub(r'^\s*\$\$.*\n', '', str) + + # Then, remove meta comments from contentful lines. + return re.sub(r'\s*\$\$.*', '', str) + + +def MakeToken(lines, start, end, token_type): + """Creates a new instance of Token.""" + + return Token(start, end, SubString(lines, start, end), token_type) + + +def ParseToken(lines, pos, regex, token_type): + line = lines[pos.line][pos.column:] + m = regex.search(line) + if m and not m.start(): + return MakeToken(lines, pos, pos + m.end(), token_type) + else: + print 'ERROR: %s expected at %s.' % (token_type, pos) + sys.exit(1) + + +ID_REGEX = re.compile(r'[_A-Za-z]\w*') +EQ_REGEX = re.compile(r'=') +REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)') +OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*') +WHITE_SPACE_REGEX = re.compile(r'\s') +DOT_DOT_REGEX = re.compile(r'\.\.') + + +def Skip(lines, pos, regex): + line = lines[pos.line][pos.column:] + m = re.search(regex, line) + if m and not m.start(): + return pos + m.end() + else: + return pos + + +def SkipUntil(lines, pos, regex, token_type): + line = lines[pos.line][pos.column:] + m = re.search(regex, line) + if m: + return pos + m.start() + else: + print ('ERROR: %s expected on line %s after column %s.' % + (token_type, pos.line + 1, pos.column)) + sys.exit(1) + + +def ParseExpTokenInParens(lines, pos): + def ParseInParens(pos): + pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX) + pos = Skip(lines, pos, r'\(') + pos = Parse(pos) + pos = Skip(lines, pos, r'\)') + return pos + + def Parse(pos): + pos = SkipUntil(lines, pos, r'\(|\)', ')') + if SubString(lines, pos, pos + 1) == '(': + pos = Parse(pos + 1) + pos = Skip(lines, pos, r'\)') + return Parse(pos) + else: + return pos + + start = pos.Clone() + pos = ParseInParens(pos) + return MakeToken(lines, start, pos, 'exp') + + +def RStripNewLineFromToken(token): + if token.value.endswith('\n'): + return Token(token.start, token.end, token.value[:-1], token.token_type) + else: + return token + + +def TokenizeLines(lines, pos): + while True: + found = FindFirst(lines, TOKEN_TABLE, pos) + if not found: + yield MakeToken(lines, pos, Eof(), 'code') + return + + if found.start == pos: + prev_token = None + prev_token_rstripped = None + else: + prev_token = MakeToken(lines, pos, found.start, 'code') + prev_token_rstripped = RStripNewLineFromToken(prev_token) + + if found.token_type == '$var': + if prev_token_rstripped: + yield prev_token_rstripped + yield found + id_token = ParseToken(lines, found.end, ID_REGEX, 'id') + yield id_token + pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) + + eq_token = ParseToken(lines, pos, EQ_REGEX, '=') + yield eq_token + pos = Skip(lines, eq_token.end, r'\s*') + + if SubString(lines, pos, pos + 2) != '[[': + exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp') + yield exp_token + pos = Cursor(exp_token.end.line + 1, 0) + elif found.token_type == '$for': + if prev_token_rstripped: + yield prev_token_rstripped + yield found + id_token = ParseToken(lines, found.end, ID_REGEX, 'id') + yield id_token + pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX) + elif found.token_type == '$range': + if prev_token_rstripped: + yield prev_token_rstripped + yield found + id_token = ParseToken(lines, found.end, ID_REGEX, 'id') + yield id_token + pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) + + dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..') + yield MakeToken(lines, pos, dots_pos, 'exp') + yield MakeToken(lines, dots_pos, dots_pos + 2, '..') + pos = dots_pos + 2 + new_pos = Cursor(pos.line + 1, 0) + yield MakeToken(lines, pos, new_pos, 'exp') + pos = new_pos + elif found.token_type == '$': + if prev_token: + yield prev_token + yield found + exp_token = ParseExpTokenInParens(lines, found.end) + yield exp_token + pos = exp_token.end + elif (found.token_type == ']]' or found.token_type == '$if' or + found.token_type == '$elif' or found.token_type == '$else'): + if prev_token_rstripped: + yield prev_token_rstripped + yield found + pos = found.end + else: + if prev_token: + yield prev_token + yield found + pos = found.end + + +def Tokenize(s): + """A generator that yields the tokens in the given string.""" + if s != '': + lines = s.splitlines(True) + for token in TokenizeLines(lines, Cursor(0, 0)): + yield token + + +class CodeNode: + def __init__(self, atomic_code_list=None): + self.atomic_code = atomic_code_list + + +class VarNode: + def __init__(self, identifier=None, atomic_code=None): + self.identifier = identifier + self.atomic_code = atomic_code + + +class RangeNode: + def __init__(self, identifier=None, exp1=None, exp2=None): + self.identifier = identifier + self.exp1 = exp1 + self.exp2 = exp2 + + +class ForNode: + def __init__(self, identifier=None, sep=None, code=None): + self.identifier = identifier + self.sep = sep + self.code = code + + +class ElseNode: + def __init__(self, else_branch=None): + self.else_branch = else_branch + + +class IfNode: + def __init__(self, exp=None, then_branch=None, else_branch=None): + self.exp = exp + self.then_branch = then_branch + self.else_branch = else_branch + + +class RawCodeNode: + def __init__(self, token=None): + self.raw_code = token + + +class LiteralDollarNode: + def __init__(self, token): + self.token = token + + +class ExpNode: + def __init__(self, token, python_exp): + self.token = token + self.python_exp = python_exp + + +def PopFront(a_list): + head = a_list[0] + a_list[:1] = [] + return head + + +def PushFront(a_list, elem): + a_list[:0] = [elem] + + +def PopToken(a_list, token_type=None): + token = PopFront(a_list) + if token_type is not None and token.token_type != token_type: + print 'ERROR: %s expected at %s' % (token_type, token.start) + print 'ERROR: %s found instead' % (token,) + sys.exit(1) + + return token + + +def PeekToken(a_list): + if not a_list: + return None + + return a_list[0] + + +def ParseExpNode(token): + python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value) + return ExpNode(token, python_exp) + + +def ParseElseNode(tokens): + def Pop(token_type=None): + return PopToken(tokens, token_type) + + next = PeekToken(tokens) + if not next: + return None + if next.token_type == '$else': + Pop('$else') + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + return code_node + elif next.token_type == '$elif': + Pop('$elif') + exp = Pop('code') + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + inner_else_node = ParseElseNode(tokens) + return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)]) + elif not next.value.strip(): + Pop('code') + return ParseElseNode(tokens) + else: + return None + + +def ParseAtomicCodeNode(tokens): + def Pop(token_type=None): + return PopToken(tokens, token_type) + + head = PopFront(tokens) + t = head.token_type + if t == 'code': + return RawCodeNode(head) + elif t == '$var': + id_token = Pop('id') + Pop('=') + next = PeekToken(tokens) + if next.token_type == 'exp': + exp_token = Pop() + return VarNode(id_token, ParseExpNode(exp_token)) + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + return VarNode(id_token, code_node) + elif t == '$for': + id_token = Pop('id') + next_token = PeekToken(tokens) + if next_token.token_type == 'code': + sep_token = next_token + Pop('code') + else: + sep_token = None + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + return ForNode(id_token, sep_token, code_node) + elif t == '$if': + exp_token = Pop('code') + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + else_node = ParseElseNode(tokens) + return IfNode(ParseExpNode(exp_token), code_node, else_node) + elif t == '$range': + id_token = Pop('id') + exp1_token = Pop('exp') + Pop('..') + exp2_token = Pop('exp') + return RangeNode(id_token, ParseExpNode(exp1_token), + ParseExpNode(exp2_token)) + elif t == '$id': + return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id')) + elif t == '$($)': + return LiteralDollarNode(head) + elif t == '$': + exp_token = Pop('exp') + return ParseExpNode(exp_token) + elif t == '[[': + code_node = ParseCodeNode(tokens) + Pop(']]') + return code_node + else: + PushFront(tokens, head) + return None + + +def ParseCodeNode(tokens): + atomic_code_list = [] + while True: + if not tokens: + break + atomic_code_node = ParseAtomicCodeNode(tokens) + if atomic_code_node: + atomic_code_list.append(atomic_code_node) + else: + break + return CodeNode(atomic_code_list) + + +def ParseToAST(pump_src_text): + """Convert the given Pump source text into an AST.""" + tokens = list(Tokenize(pump_src_text)) + code_node = ParseCodeNode(tokens) + return code_node + + +class Env: + def __init__(self): + self.variables = [] + self.ranges = [] + + def Clone(self): + clone = Env() + clone.variables = self.variables[:] + clone.ranges = self.ranges[:] + return clone + + def PushVariable(self, var, value): + # If value looks like an int, store it as an int. + try: + int_value = int(value) + if ('%s' % int_value) == value: + value = int_value + except Exception: + pass + self.variables[:0] = [(var, value)] + + def PopVariable(self): + self.variables[:1] = [] + + def PushRange(self, var, lower, upper): + self.ranges[:0] = [(var, lower, upper)] + + def PopRange(self): + self.ranges[:1] = [] + + def GetValue(self, identifier): + for (var, value) in self.variables: + if identifier == var: + return value + + print 'ERROR: meta variable %s is undefined.' % (identifier,) + sys.exit(1) + + def EvalExp(self, exp): + try: + result = eval(exp.python_exp) + except Exception, e: + print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e) + print ('ERROR: failed to evaluate meta expression %s at %s' % + (exp.python_exp, exp.token.start)) + sys.exit(1) + return result + + def GetRange(self, identifier): + for (var, lower, upper) in self.ranges: + if identifier == var: + return (lower, upper) + + print 'ERROR: range %s is undefined.' % (identifier,) + sys.exit(1) + + +class Output: + def __init__(self): + self.string = '' + + def GetLastLine(self): + index = self.string.rfind('\n') + if index < 0: + return '' + + return self.string[index + 1:] + + def Append(self, s): + self.string += s + + +def RunAtomicCode(env, node, output): + if isinstance(node, VarNode): + identifier = node.identifier.value.strip() + result = Output() + RunAtomicCode(env.Clone(), node.atomic_code, result) + value = result.string + env.PushVariable(identifier, value) + elif isinstance(node, RangeNode): + identifier = node.identifier.value.strip() + lower = int(env.EvalExp(node.exp1)) + upper = int(env.EvalExp(node.exp2)) + env.PushRange(identifier, lower, upper) + elif isinstance(node, ForNode): + identifier = node.identifier.value.strip() + if node.sep is None: + sep = '' + else: + sep = node.sep.value + (lower, upper) = env.GetRange(identifier) + for i in range(lower, upper + 1): + new_env = env.Clone() + new_env.PushVariable(identifier, i) + RunCode(new_env, node.code, output) + if i != upper: + output.Append(sep) + elif isinstance(node, RawCodeNode): + output.Append(node.raw_code.value) + elif isinstance(node, IfNode): + cond = env.EvalExp(node.exp) + if cond: + RunCode(env.Clone(), node.then_branch, output) + elif node.else_branch is not None: + RunCode(env.Clone(), node.else_branch, output) + elif isinstance(node, ExpNode): + value = env.EvalExp(node) + output.Append('%s' % (value,)) + elif isinstance(node, LiteralDollarNode): + output.Append('$') + elif isinstance(node, CodeNode): + RunCode(env.Clone(), node, output) + else: + print 'BAD' + print node + sys.exit(1) + + +def RunCode(env, code_node, output): + for atomic_code in code_node.atomic_code: + RunAtomicCode(env, atomic_code, output) + + +def IsComment(cur_line): + return '//' in cur_line + + +def IsInPreprocessorDirevative(prev_lines, cur_line): + if cur_line.lstrip().startswith('#'): + return True + return prev_lines != [] and prev_lines[-1].endswith('\\') + + +def WrapComment(line, output): + loc = line.find('//') + before_comment = line[:loc].rstrip() + if before_comment == '': + indent = loc + else: + output.append(before_comment) + indent = len(before_comment) - len(before_comment.lstrip()) + prefix = indent*' ' + '// ' + max_len = 80 - len(prefix) + comment = line[loc + 2:].strip() + segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != ''] + cur_line = '' + for seg in segs: + if len((cur_line + seg).rstrip()) < max_len: + cur_line += seg + else: + if cur_line.strip() != '': + output.append(prefix + cur_line.rstrip()) + cur_line = seg.lstrip() + if cur_line.strip() != '': + output.append(prefix + cur_line.strip()) + + +def WrapCode(line, line_concat, output): + indent = len(line) - len(line.lstrip()) + prefix = indent*' ' # Prefix of the current line + max_len = 80 - indent - len(line_concat) # Maximum length of the current line + new_prefix = prefix + 4*' ' # Prefix of a continuation line + new_max_len = max_len - 4 # Maximum length of a continuation line + # Prefers to wrap a line after a ',' or ';'. + segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != ''] + cur_line = '' # The current line without leading spaces. + for seg in segs: + # If the line is still too long, wrap at a space. + while cur_line == '' and len(seg.strip()) > max_len: + seg = seg.lstrip() + split_at = seg.rfind(' ', 0, max_len) + output.append(prefix + seg[:split_at].strip() + line_concat) + seg = seg[split_at + 1:] + prefix = new_prefix + max_len = new_max_len + + if len((cur_line + seg).rstrip()) < max_len: + cur_line = (cur_line + seg).lstrip() + else: + output.append(prefix + cur_line.rstrip() + line_concat) + prefix = new_prefix + max_len = new_max_len + cur_line = seg.lstrip() + if cur_line.strip() != '': + output.append(prefix + cur_line.strip()) + + +def WrapPreprocessorDirevative(line, output): + WrapCode(line, ' \\', output) + + +def WrapPlainCode(line, output): + WrapCode(line, '', output) + + +def IsHeaderGuardOrInclude(line): + return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or + re.match(r'^#include\s', line)) + + +def WrapLongLine(line, output): + line = line.rstrip() + if len(line) <= 80: + output.append(line) + elif IsComment(line): + if IsHeaderGuardOrInclude(line): + # The style guide made an exception to allow long header guard lines + # and includes. + output.append(line) + else: + WrapComment(line, output) + elif IsInPreprocessorDirevative(output, line): + if IsHeaderGuardOrInclude(line): + # The style guide made an exception to allow long header guard lines + # and includes. + output.append(line) + else: + WrapPreprocessorDirevative(line, output) + else: + WrapPlainCode(line, output) + + +def BeautifyCode(string): + lines = string.splitlines() + output = [] + for line in lines: + WrapLongLine(line, output) + output2 = [line.rstrip() for line in output] + return '\n'.join(output2) + '\n' + + +def ConvertFromPumpSource(src_text): + """Return the text generated from the given Pump source text.""" + ast = ParseToAST(StripMetaComments(src_text)) + output = Output() + RunCode(Env(), ast, output) + return BeautifyCode(output.string) + + +def main(argv): + if len(argv) == 1: + print __doc__ + sys.exit(1) + + file_path = argv[-1] + output_str = ConvertFromPumpSource(file(file_path, 'r').read()) + if file_path.endswith('.pump'): + output_file_path = file_path[:-5] + else: + output_file_path = '-' + if output_file_path == '-': + print output_str, + else: + output_file = file(output_file_path, 'w') + output_file.write('// This file was GENERATED by command:\n') + output_file.write('// %s %s\n' % + (os.path.basename(__file__), os.path.basename(file_path))) + output_file.write('// DO NOT EDIT BY HAND!!!\n\n') + output_file.write(output_str) + output_file.close() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/third_party/googletest/src/scripts/test/Makefile b/third_party/googletest/src/scripts/test/Makefile new file mode 100644 index 0000000..cdff584 --- /dev/null +++ b/third_party/googletest/src/scripts/test/Makefile @@ -0,0 +1,59 @@ +# A Makefile for fusing Google Test and building a sample test against it. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make check - makes everything and runs the built sample test. +# make clean - removes all files generated by make. + +# Points to the root of fused Google Test, relative to where this file is. +FUSED_GTEST_DIR = output + +# Paths to the fused gtest files. +FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h +FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc + +# Where to find the sample test. +SAMPLE_DIR = ../../samples + +# Where to find gtest_main.cc. +GTEST_MAIN_CC = ../../src/gtest_main.cc + +# Flags passed to the preprocessor. +# We have no idea here whether pthreads is available in the system, so +# disable its use. +CPPFLAGS += -I$(FUSED_GTEST_DIR) -DGTEST_HAS_PTHREAD=0 + +# Flags passed to the C++ compiler. +CXXFLAGS += -g + +all : sample1_unittest + +check : all + ./sample1_unittest + +clean : + rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o + +$(FUSED_GTEST_H) : + ../fuse_gtest_files.py $(FUSED_GTEST_DIR) + +$(FUSED_GTEST_ALL_CC) : + ../fuse_gtest_files.py $(FUSED_GTEST_DIR) + +gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc + +gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC) + +sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc + +sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \ + $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc + +sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ diff --git a/third_party/googletest/src/scripts/upload.py b/third_party/googletest/src/scripts/upload.py new file mode 100755 index 0000000..6e6f9a1 --- /dev/null +++ b/third_party/googletest/src/scripts/upload.py @@ -0,0 +1,1387 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tool for uploading diffs from a version control system to the codereview app. + +Usage summary: upload.py [options] [-- diff_options] + +Diff options are passed to the diff command of the underlying system. + +Supported version control systems: + Git + Mercurial + Subversion + +It is important for Git/Mercurial users to specify a tree/node/branch to diff +against by using the '--rev' option. +""" +# This code is derived from appcfg.py in the App Engine SDK (open source), +# and from ASPN recipe #146306. + +import cookielib +import getpass +import logging +import md5 +import mimetypes +import optparse +import os +import re +import socket +import subprocess +import sys +import urllib +import urllib2 +import urlparse + +try: + import readline +except ImportError: + pass + +# The logging verbosity: +# 0: Errors only. +# 1: Status messages. +# 2: Info logs. +# 3: Debug logs. +verbosity = 1 + +# Max size of patch or base file. +MAX_UPLOAD_SIZE = 900 * 1024 + + +def GetEmail(prompt): + """Prompts the user for their email address and returns it. + + The last used email address is saved to a file and offered up as a suggestion + to the user. If the user presses enter without typing in anything the last + used email address is used. If the user enters a new address, it is saved + for next time we prompt. + + """ + last_email_file_name = os.path.expanduser("~/.last_codereview_email_address") + last_email = "" + if os.path.exists(last_email_file_name): + try: + last_email_file = open(last_email_file_name, "r") + last_email = last_email_file.readline().strip("\n") + last_email_file.close() + prompt += " [%s]" % last_email + except IOError, e: + pass + email = raw_input(prompt + ": ").strip() + if email: + try: + last_email_file = open(last_email_file_name, "w") + last_email_file.write(email) + last_email_file.close() + except IOError, e: + pass + else: + email = last_email + return email + + +def StatusUpdate(msg): + """Print a status message to stdout. + + If 'verbosity' is greater than 0, print the message. + + Args: + msg: The string to print. + """ + if verbosity > 0: + print msg + + +def ErrorExit(msg): + """Print an error message to stderr and exit.""" + print >>sys.stderr, msg + sys.exit(1) + + +class ClientLoginError(urllib2.HTTPError): + """Raised to indicate there was an error authenticating with ClientLogin.""" + + def __init__(self, url, code, msg, headers, args): + urllib2.HTTPError.__init__(self, url, code, msg, headers, None) + self.args = args + self.reason = args["Error"] + + +class AbstractRpcServer(object): + """Provides a common interface for a simple RPC server.""" + + def __init__(self, host, auth_function, host_override=None, extra_headers={}, + save_cookies=False): + """Creates a new HttpRpcServer. + + Args: + host: The host to send requests to. + auth_function: A function that takes no arguments and returns an + (email, password) tuple when called. Will be called if authentication + is required. + host_override: The host header to send to the server (defaults to host). + extra_headers: A dict of extra headers to append to every request. + save_cookies: If True, save the authentication cookies to local disk. + If False, use an in-memory cookiejar instead. Subclasses must + implement this functionality. Defaults to False. + """ + self.host = host + self.host_override = host_override + self.auth_function = auth_function + self.authenticated = False + self.extra_headers = extra_headers + self.save_cookies = save_cookies + self.opener = self._GetOpener() + if self.host_override: + logging.info("Server: %s; Host: %s", self.host, self.host_override) + else: + logging.info("Server: %s", self.host) + + def _GetOpener(self): + """Returns an OpenerDirector for making HTTP requests. + + Returns: + A urllib2.OpenerDirector object. + """ + raise NotImplementedError() + + def _CreateRequest(self, url, data=None): + """Creates a new urllib request.""" + logging.debug("Creating request for: '%s' with payload:\n%s", url, data) + req = urllib2.Request(url, data=data) + if self.host_override: + req.add_header("Host", self.host_override) + for key, value in self.extra_headers.iteritems(): + req.add_header(key, value) + return req + + def _GetAuthToken(self, email, password): + """Uses ClientLogin to authenticate the user, returning an auth token. + + Args: + email: The user's email address + password: The user's password + + Raises: + ClientLoginError: If there was an error authenticating with ClientLogin. + HTTPError: If there was some other form of HTTP error. + + Returns: + The authentication token returned by ClientLogin. + """ + account_type = "GOOGLE" + if self.host.endswith(".google.com"): + # Needed for use inside Google. + account_type = "HOSTED" + req = self._CreateRequest( + url="https://www.google.com/accounts/ClientLogin", + data=urllib.urlencode({ + "Email": email, + "Passwd": password, + "service": "ah", + "source": "rietveld-codereview-upload", + "accountType": account_type, + }), + ) + try: + response = self.opener.open(req) + response_body = response.read() + response_dict = dict(x.split("=") + for x in response_body.split("\n") if x) + return response_dict["Auth"] + except urllib2.HTTPError, e: + if e.code == 403: + body = e.read() + response_dict = dict(x.split("=", 1) for x in body.split("\n") if x) + raise ClientLoginError(req.get_full_url(), e.code, e.msg, + e.headers, response_dict) + else: + raise + + def _GetAuthCookie(self, auth_token): + """Fetches authentication cookies for an authentication token. + + Args: + auth_token: The authentication token returned by ClientLogin. + + Raises: + HTTPError: If there was an error fetching the authentication cookies. + """ + # This is a dummy value to allow us to identify when we're successful. + continue_location = "http://localhost/" + args = {"continue": continue_location, "auth": auth_token} + req = self._CreateRequest("http://%s/_ah/login?%s" % + (self.host, urllib.urlencode(args))) + try: + response = self.opener.open(req) + except urllib2.HTTPError, e: + response = e + if (response.code != 302 or + response.info()["location"] != continue_location): + raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg, + response.headers, response.fp) + self.authenticated = True + + def _Authenticate(self): + """Authenticates the user. + + The authentication process works as follows: + 1) We get a username and password from the user + 2) We use ClientLogin to obtain an AUTH token for the user + (see http://code.google.com/apis/accounts/AuthForInstalledApps.html). + 3) We pass the auth token to /_ah/login on the server to obtain an + authentication cookie. If login was successful, it tries to redirect + us to the URL we provided. + + If we attempt to access the upload API without first obtaining an + authentication cookie, it returns a 401 response and directs us to + authenticate ourselves with ClientLogin. + """ + for i in range(3): + credentials = self.auth_function() + try: + auth_token = self._GetAuthToken(credentials[0], credentials[1]) + except ClientLoginError, e: + if e.reason == "BadAuthentication": + print >>sys.stderr, "Invalid username or password." + continue + if e.reason == "CaptchaRequired": + print >>sys.stderr, ( + "Please go to\n" + "https://www.google.com/accounts/DisplayUnlockCaptcha\n" + "and verify you are a human. Then try again.") + break + if e.reason == "NotVerified": + print >>sys.stderr, "Account not verified." + break + if e.reason == "TermsNotAgreed": + print >>sys.stderr, "User has not agreed to TOS." + break + if e.reason == "AccountDeleted": + print >>sys.stderr, "The user account has been deleted." + break + if e.reason == "AccountDisabled": + print >>sys.stderr, "The user account has been disabled." + break + if e.reason == "ServiceDisabled": + print >>sys.stderr, ("The user's access to the service has been " + "disabled.") + break + if e.reason == "ServiceUnavailable": + print >>sys.stderr, "The service is not available; try again later." + break + raise + self._GetAuthCookie(auth_token) + return + + def Send(self, request_path, payload=None, + content_type="application/octet-stream", + timeout=None, + **kwargs): + """Sends an RPC and returns the response. + + Args: + request_path: The path to send the request to, eg /api/appversion/create. + payload: The body of the request, or None to send an empty request. + content_type: The Content-Type header to use. + timeout: timeout in seconds; default None i.e. no timeout. + (Note: for large requests on OS X, the timeout doesn't work right.) + kwargs: Any keyword arguments are converted into query string parameters. + + Returns: + The response body, as a string. + """ + # TODO: Don't require authentication. Let the server say + # whether it is necessary. + if not self.authenticated: + self._Authenticate() + + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + tries = 0 + while True: + tries += 1 + args = dict(kwargs) + url = "http://%s%s" % (self.host, request_path) + if args: + url += "?" + urllib.urlencode(args) + req = self._CreateRequest(url=url, data=payload) + req.add_header("Content-Type", content_type) + try: + f = self.opener.open(req) + response = f.read() + f.close() + return response + except urllib2.HTTPError, e: + if tries > 3: + raise + elif e.code == 401: + self._Authenticate() +## elif e.code >= 500 and e.code < 600: +## # Server Error - try again. +## continue + else: + raise + finally: + socket.setdefaulttimeout(old_timeout) + + +class HttpRpcServer(AbstractRpcServer): + """Provides a simplified RPC-style interface for HTTP requests.""" + + def _Authenticate(self): + """Save the cookie jar after authentication.""" + super(HttpRpcServer, self)._Authenticate() + if self.save_cookies: + StatusUpdate("Saving authentication cookies to %s" % self.cookie_file) + self.cookie_jar.save() + + def _GetOpener(self): + """Returns an OpenerDirector that supports cookies and ignores redirects. + + Returns: + A urllib2.OpenerDirector object. + """ + opener = urllib2.OpenerDirector() + opener.add_handler(urllib2.ProxyHandler()) + opener.add_handler(urllib2.UnknownHandler()) + opener.add_handler(urllib2.HTTPHandler()) + opener.add_handler(urllib2.HTTPDefaultErrorHandler()) + opener.add_handler(urllib2.HTTPSHandler()) + opener.add_handler(urllib2.HTTPErrorProcessor()) + if self.save_cookies: + self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies") + self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file) + if os.path.exists(self.cookie_file): + try: + self.cookie_jar.load() + self.authenticated = True + StatusUpdate("Loaded authentication cookies from %s" % + self.cookie_file) + except (cookielib.LoadError, IOError): + # Failed to load cookies - just ignore them. + pass + else: + # Create an empty cookie file with mode 600 + fd = os.open(self.cookie_file, os.O_CREAT, 0600) + os.close(fd) + # Always chmod the cookie file + os.chmod(self.cookie_file, 0600) + else: + # Don't save cookies across runs of update.py. + self.cookie_jar = cookielib.CookieJar() + opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) + return opener + + +parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]") +parser.add_option("-y", "--assume_yes", action="store_true", + dest="assume_yes", default=False, + help="Assume that the answer to yes/no questions is 'yes'.") +# Logging +group = parser.add_option_group("Logging options") +group.add_option("-q", "--quiet", action="store_const", const=0, + dest="verbose", help="Print errors only.") +group.add_option("-v", "--verbose", action="store_const", const=2, + dest="verbose", default=1, + help="Print info level logs (default).") +group.add_option("--noisy", action="store_const", const=3, + dest="verbose", help="Print all logs.") +# Review server +group = parser.add_option_group("Review server options") +group.add_option("-s", "--server", action="store", dest="server", + default="codereview.appspot.com", + metavar="SERVER", + help=("The server to upload to. The format is host[:port]. " + "Defaults to 'codereview.appspot.com'.")) +group.add_option("-e", "--email", action="store", dest="email", + metavar="EMAIL", default=None, + help="The username to use. Will prompt if omitted.") +group.add_option("-H", "--host", action="store", dest="host", + metavar="HOST", default=None, + help="Overrides the Host header sent with all RPCs.") +group.add_option("--no_cookies", action="store_false", + dest="save_cookies", default=True, + help="Do not save authentication cookies to local disk.") +# Issue +group = parser.add_option_group("Issue options") +group.add_option("-d", "--description", action="store", dest="description", + metavar="DESCRIPTION", default=None, + help="Optional description when creating an issue.") +group.add_option("-f", "--description_file", action="store", + dest="description_file", metavar="DESCRIPTION_FILE", + default=None, + help="Optional path of a file that contains " + "the description when creating an issue.") +group.add_option("-r", "--reviewers", action="store", dest="reviewers", + metavar="REVIEWERS", default=None, + help="Add reviewers (comma separated email addresses).") +group.add_option("--cc", action="store", dest="cc", + metavar="CC", default=None, + help="Add CC (comma separated email addresses).") +# Upload options +group = parser.add_option_group("Patch options") +group.add_option("-m", "--message", action="store", dest="message", + metavar="MESSAGE", default=None, + help="A message to identify the patch. " + "Will prompt if omitted.") +group.add_option("-i", "--issue", type="int", action="store", + metavar="ISSUE", default=None, + help="Issue number to which to add. Defaults to new issue.") +group.add_option("--download_base", action="store_true", + dest="download_base", default=False, + help="Base files will be downloaded by the server " + "(side-by-side diffs may not work on files with CRs).") +group.add_option("--rev", action="store", dest="revision", + metavar="REV", default=None, + help="Branch/tree/revision to diff against (used by DVCS).") +group.add_option("--send_mail", action="store_true", + dest="send_mail", default=False, + help="Send notification email to reviewers.") + + +def GetRpcServer(options): + """Returns an instance of an AbstractRpcServer. + + Returns: + A new AbstractRpcServer, on which RPC calls can be made. + """ + + rpc_server_class = HttpRpcServer + + def GetUserCredentials(): + """Prompts the user for a username and password.""" + email = options.email + if email is None: + email = GetEmail("Email (login for uploading to %s)" % options.server) + password = getpass.getpass("Password for %s: " % email) + return (email, password) + + # If this is the dev_appserver, use fake authentication. + host = (options.host or options.server).lower() + if host == "localhost" or host.startswith("localhost:"): + email = options.email + if email is None: + email = "test@example.com" + logging.info("Using debug user %s. Override with --email" % email) + server = rpc_server_class( + options.server, + lambda: (email, "password"), + host_override=options.host, + extra_headers={"Cookie": + 'dev_appserver_login="%s:False"' % email}, + save_cookies=options.save_cookies) + # Don't try to talk to ClientLogin. + server.authenticated = True + return server + + return rpc_server_class(options.server, GetUserCredentials, + host_override=options.host, + save_cookies=options.save_cookies) + + +def EncodeMultipartFormData(fields, files): + """Encode form fields for multipart/form-data. + + Args: + fields: A sequence of (name, value) elements for regular form fields. + files: A sequence of (name, filename, value) elements for data to be + uploaded as files. + Returns: + (content_type, body) ready for httplib.HTTP instance. + + Source: + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306 + """ + BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-' + CRLF = '\r\n' + lines = [] + for (key, value) in fields: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"' % key) + lines.append('') + lines.append(value) + for (key, filename, value) in files: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)) + lines.append('Content-Type: %s' % GetContentType(filename)) + lines.append('') + lines.append(value) + lines.append('--' + BOUNDARY + '--') + lines.append('') + body = CRLF.join(lines) + content_type = 'multipart/form-data; boundary=%s' % BOUNDARY + return content_type, body + + +def GetContentType(filename): + """Helper to guess the content-type from the filename.""" + return mimetypes.guess_type(filename)[0] or 'application/octet-stream' + + +# Use a shell for subcommands on Windows to get a PATH search. +use_shell = sys.platform.startswith("win") + +def RunShellWithReturnCode(command, print_output=False, + universal_newlines=True): + """Executes a command and returns the output from stdout and the return code. + + Args: + command: Command to execute. + print_output: If True, the output is printed to stdout. + If False, both stdout and stderr are ignored. + universal_newlines: Use universal_newlines flag (default: True). + + Returns: + Tuple (output, return code) + """ + logging.info("Running %s", command) + p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=use_shell, universal_newlines=universal_newlines) + if print_output: + output_array = [] + while True: + line = p.stdout.readline() + if not line: + break + print line.strip("\n") + output_array.append(line) + output = "".join(output_array) + else: + output = p.stdout.read() + p.wait() + errout = p.stderr.read() + if print_output and errout: + print >>sys.stderr, errout + p.stdout.close() + p.stderr.close() + return output, p.returncode + + +def RunShell(command, silent_ok=False, universal_newlines=True, + print_output=False): + data, retcode = RunShellWithReturnCode(command, print_output, + universal_newlines) + if retcode: + ErrorExit("Got error status from %s:\n%s" % (command, data)) + if not silent_ok and not data: + ErrorExit("No output from %s" % command) + return data + + +class VersionControlSystem(object): + """Abstract base class providing an interface to the VCS.""" + + def __init__(self, options): + """Constructor. + + Args: + options: Command line options. + """ + self.options = options + + def GenerateDiff(self, args): + """Return the current diff as a string. + + Args: + args: Extra arguments to pass to the diff command. + """ + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def CheckForUnknownFiles(self): + """Show an "are you sure?" prompt if there are unknown files.""" + unknown_files = self.GetUnknownFiles() + if unknown_files: + print "The following files are not added to version control:" + for line in unknown_files: + print line + prompt = "Are you sure to continue?(y/N) " + answer = raw_input(prompt).strip() + if answer != "y": + ErrorExit("User aborted") + + def GetBaseFile(self, filename): + """Get the content of the upstream version of a file. + + Returns: + A tuple (base_content, new_content, is_binary, status) + base_content: The contents of the base file. + new_content: For text files, this is empty. For binary files, this is + the contents of the new file, since the diff output won't contain + information to reconstruct the current file. + is_binary: True iff the file is binary. + status: The status of the file. + """ + + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + + def GetBaseFiles(self, diff): + """Helper that calls GetBase file for each file in the patch. + + Returns: + A dictionary that maps from filename to GetBaseFile's tuple. Filenames + are retrieved based on lines that start with "Index:" or + "Property changes on:". + """ + files = {} + for line in diff.splitlines(True): + if line.startswith('Index:') or line.startswith('Property changes on:'): + unused, filename = line.split(':', 1) + # On Windows if a file has property changes its filename uses '\' + # instead of '/'. + filename = filename.strip().replace('\\', '/') + files[filename] = self.GetBaseFile(filename) + return files + + + def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, + files): + """Uploads the base files (and if necessary, the current ones as well).""" + + def UploadFile(filename, file_id, content, is_binary, status, is_base): + """Uploads a file to the server.""" + file_too_large = False + if is_base: + type = "base" + else: + type = "current" + if len(content) > MAX_UPLOAD_SIZE: + print ("Not uploading the %s file for %s because it's too large." % + (type, filename)) + file_too_large = True + content = "" + checksum = md5.new(content).hexdigest() + if options.verbose > 0 and not file_too_large: + print "Uploading %s file for %s" % (type, filename) + url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id) + form_fields = [("filename", filename), + ("status", status), + ("checksum", checksum), + ("is_binary", str(is_binary)), + ("is_current", str(not is_base)), + ] + if file_too_large: + form_fields.append(("file_too_large", "1")) + if options.email: + form_fields.append(("user", options.email)) + ctype, body = EncodeMultipartFormData(form_fields, + [("data", filename, content)]) + response_body = rpc_server.Send(url, body, + content_type=ctype) + if not response_body.startswith("OK"): + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + + patches = dict() + [patches.setdefault(v, k) for k, v in patch_list] + for filename in patches.keys(): + base_content, new_content, is_binary, status = files[filename] + file_id_str = patches.get(filename) + if file_id_str.find("nobase") != -1: + base_content = None + file_id_str = file_id_str[file_id_str.rfind("_") + 1:] + file_id = int(file_id_str) + if base_content != None: + UploadFile(filename, file_id, base_content, is_binary, status, True) + if new_content != None: + UploadFile(filename, file_id, new_content, is_binary, status, False) + + def IsImage(self, filename): + """Returns true if the filename has an image extension.""" + mimetype = mimetypes.guess_type(filename)[0] + if not mimetype: + return False + return mimetype.startswith("image/") + + +class SubversionVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Subversion.""" + + def __init__(self, options): + super(SubversionVCS, self).__init__(options) + if self.options.revision: + match = re.match(r"(\d+)(:(\d+))?", self.options.revision) + if not match: + ErrorExit("Invalid Subversion revision %s." % self.options.revision) + self.rev_start = match.group(1) + self.rev_end = match.group(3) + else: + self.rev_start = self.rev_end = None + # Cache output from "svn list -r REVNO dirname". + # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev). + self.svnls_cache = {} + # SVN base URL is required to fetch files deleted in an older revision. + # Result is cached to not guess it over and over again in GetBaseFile(). + required = self.options.download_base or self.options.revision is not None + self.svn_base = self._GuessBase(required) + + def GuessBase(self, required): + """Wrapper for _GuessBase.""" + return self.svn_base + + def _GuessBase(self, required): + """Returns the SVN base URL. + + Args: + required: If true, exits if the url can't be guessed, otherwise None is + returned. + """ + info = RunShell(["svn", "info"]) + for line in info.splitlines(): + words = line.split() + if len(words) == 2 and words[0] == "URL:": + url = words[1] + scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) + username, netloc = urllib.splituser(netloc) + if username: + logging.info("Removed username from base URL") + if netloc.endswith("svn.python.org"): + if netloc == "svn.python.org": + if path.startswith("/projects/"): + path = path[9:] + elif netloc != "pythondev@svn.python.org": + ErrorExit("Unrecognized Python URL: %s" % url) + base = "http://svn.python.org/view/*checkout*%s/" % path + logging.info("Guessed Python base = %s", base) + elif netloc.endswith("svn.collab.net"): + if path.startswith("/repos/"): + path = path[6:] + base = "http://svn.collab.net/viewvc/*checkout*%s/" % path + logging.info("Guessed CollabNet base = %s", base) + elif netloc.endswith(".googlecode.com"): + path = path + "/" + base = urlparse.urlunparse(("http", netloc, path, params, + query, fragment)) + logging.info("Guessed Google Code base = %s", base) + else: + path = path + "/" + base = urlparse.urlunparse((scheme, netloc, path, params, + query, fragment)) + logging.info("Guessed base = %s", base) + return base + if required: + ErrorExit("Can't find URL in output from svn info") + return None + + def GenerateDiff(self, args): + cmd = ["svn", "diff"] + if self.options.revision: + cmd += ["-r", self.options.revision] + cmd.extend(args) + data = RunShell(cmd) + count = 0 + for line in data.splitlines(): + if line.startswith("Index:") or line.startswith("Property changes on:"): + count += 1 + logging.info(line) + if not count: + ErrorExit("No valid patches found in output from svn diff") + return data + + def _CollapseKeywords(self, content, keyword_str): + """Collapses SVN keywords.""" + # svn cat translates keywords but svn diff doesn't. As a result of this + # behavior patching.PatchChunks() fails with a chunk mismatch error. + # This part was originally written by the Review Board development team + # who had the same problem (http://reviews.review-board.org/r/276/). + # Mapping of keywords to known aliases + svn_keywords = { + # Standard keywords + 'Date': ['Date', 'LastChangedDate'], + 'Revision': ['Revision', 'LastChangedRevision', 'Rev'], + 'Author': ['Author', 'LastChangedBy'], + 'HeadURL': ['HeadURL', 'URL'], + 'Id': ['Id'], + + # Aliases + 'LastChangedDate': ['LastChangedDate', 'Date'], + 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'], + 'LastChangedBy': ['LastChangedBy', 'Author'], + 'URL': ['URL', 'HeadURL'], + } + + def repl(m): + if m.group(2): + return "$%s::%s$" % (m.group(1), " " * len(m.group(3))) + return "$%s$" % m.group(1) + keywords = [keyword + for name in keyword_str.split(" ") + for keyword in svn_keywords.get(name, [])] + return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content) + + def GetUnknownFiles(self): + status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True) + unknown_files = [] + for line in status.split("\n"): + if line and line[0] == "?": + unknown_files.append(line) + return unknown_files + + def ReadFile(self, filename): + """Returns the contents of a file.""" + file = open(filename, 'rb') + result = "" + try: + result = file.read() + finally: + file.close() + return result + + def GetStatus(self, filename): + """Returns the status of a file.""" + if not self.options.revision: + status = RunShell(["svn", "status", "--ignore-externals", filename]) + if not status: + ErrorExit("svn status returned no output for %s" % filename) + status_lines = status.splitlines() + # If file is in a cl, the output will begin with + # "\n--- Changelist 'cl_name':\n". See + # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt + if (len(status_lines) == 3 and + not status_lines[0] and + status_lines[1].startswith("--- Changelist")): + status = status_lines[2] + else: + status = status_lines[0] + # If we have a revision to diff against we need to run "svn list" + # for the old and the new revision and compare the results to get + # the correct status for a file. + else: + dirname, relfilename = os.path.split(filename) + if dirname not in self.svnls_cache: + cmd = ["svn", "list", "-r", self.rev_start, dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to get status for %s." % filename) + old_files = out.splitlines() + args = ["svn", "list"] + if self.rev_end: + args += ["-r", self.rev_end] + cmd = args + [dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to run command %s" % cmd) + self.svnls_cache[dirname] = (old_files, out.splitlines()) + old_files, new_files = self.svnls_cache[dirname] + if relfilename in old_files and relfilename not in new_files: + status = "D " + elif relfilename in old_files and relfilename in new_files: + status = "M " + else: + status = "A " + return status + + def GetBaseFile(self, filename): + status = self.GetStatus(filename) + base_content = None + new_content = None + + # If a file is copied its status will be "A +", which signifies + # "addition-with-history". See "svn st" for more information. We need to + # upload the original file or else diff parsing will fail if the file was + # edited. + if status[0] == "A" and status[3] != "+": + # We'll need to upload the new content if we're adding a binary file + # since diff's output won't contain it. + mimetype = RunShell(["svn", "propget", "svn:mime-type", filename], + silent_ok=True) + base_content = "" + is_binary = mimetype and not mimetype.startswith("text/") + if is_binary and self.IsImage(filename): + new_content = self.ReadFile(filename) + elif (status[0] in ("M", "D", "R") or + (status[0] == "A" and status[3] == "+") or # Copied file. + (status[0] == " " and status[1] == "M")): # Property change. + args = [] + if self.options.revision: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + # Don't change filename, it's needed later. + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:mime-type", url] + mimetype, returncode = RunShellWithReturnCode(cmd) + if returncode: + # File does not exist in the requested revision. + # Reset mimetype, it contains an error message. + mimetype = "" + get_base = False + is_binary = mimetype and not mimetype.startswith("text/") + if status[0] == " ": + # Empty base content just to force an upload. + base_content = "" + elif is_binary: + if self.IsImage(filename): + get_base = True + if status[0] == "M": + if not self.rev_end: + new_content = self.ReadFile(filename) + else: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end) + new_content = RunShell(["svn", "cat", url], + universal_newlines=True, silent_ok=True) + else: + base_content = "" + else: + get_base = True + + if get_base: + if is_binary: + universal_newlines = False + else: + universal_newlines = True + if self.rev_start: + # "svn cat -r REV delete_file.txt" doesn't work. cat requires + # the full URL with "@REV" appended instead of using "-r" option. + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + base_content = RunShell(["svn", "cat", url], + universal_newlines=universal_newlines, + silent_ok=True) + else: + base_content = RunShell(["svn", "cat", filename], + universal_newlines=universal_newlines, + silent_ok=True) + if not is_binary: + args = [] + if self.rev_start: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:keywords", url] + keywords, returncode = RunShellWithReturnCode(cmd) + if keywords and not returncode: + base_content = self._CollapseKeywords(base_content, keywords) + else: + StatusUpdate("svn status returned unexpected output: %s" % status) + sys.exit(1) + return base_content, new_content, is_binary, status[0:5] + + +class GitVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Git.""" + + def __init__(self, options): + super(GitVCS, self).__init__(options) + # Map of filename -> hash of base file. + self.base_hashes = {} + + def GenerateDiff(self, extra_args): + # This is more complicated than svn's GenerateDiff because we must convert + # the diff output to include an svn-style "Index:" line as well as record + # the hashes of the base files, so we can upload them along with our diff. + if self.options.revision: + extra_args = [self.options.revision] + extra_args + gitdiff = RunShell(["git", "diff", "--full-index"] + extra_args) + svndiff = [] + filecount = 0 + filename = None + for line in gitdiff.splitlines(): + match = re.match(r"diff --git a/(.*) b/.*$", line) + if match: + filecount += 1 + filename = match.group(1) + svndiff.append("Index: %s\n" % filename) + else: + # The "index" line in a git diff looks like this (long hashes elided): + # index 82c0d44..b2cee3f 100755 + # We want to save the left hash, as that identifies the base file. + match = re.match(r"index (\w+)\.\.", line) + if match: + self.base_hashes[filename] = match.group(1) + svndiff.append(line + "\n") + if not filecount: + ErrorExit("No valid patches found in output from git diff") + return "".join(svndiff) + + def GetUnknownFiles(self): + status = RunShell(["git", "ls-files", "--exclude-standard", "--others"], + silent_ok=True) + return status.splitlines() + + def GetBaseFile(self, filename): + hash = self.base_hashes[filename] + base_content = None + new_content = None + is_binary = False + if hash == "0" * 40: # All-zero hash indicates no base file. + status = "A" + base_content = "" + else: + status = "M" + base_content, returncode = RunShellWithReturnCode(["git", "show", hash]) + if returncode: + ErrorExit("Got error status from 'git show %s'" % hash) + return (base_content, new_content, is_binary, status) + + +class MercurialVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Mercurial.""" + + def __init__(self, options, repo_dir): + super(MercurialVCS, self).__init__(options) + # Absolute path to repository (we can be in a subdir) + self.repo_dir = os.path.normpath(repo_dir) + # Compute the subdir + cwd = os.path.normpath(os.getcwd()) + assert cwd.startswith(self.repo_dir) + self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") + if self.options.revision: + self.base_rev = self.options.revision + else: + self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip() + + def _GetRelPath(self, filename): + """Get relative path of a file according to the current directory, + given its logical path in the repo.""" + assert filename.startswith(self.subdir), filename + return filename[len(self.subdir):].lstrip(r"\/") + + def GenerateDiff(self, extra_args): + # If no file specified, restrict to the current subdir + extra_args = extra_args or ["."] + cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args + data = RunShell(cmd, silent_ok=True) + svndiff = [] + filecount = 0 + for line in data.splitlines(): + m = re.match("diff --git a/(\S+) b/(\S+)", line) + if m: + # Modify line to make it look like as it comes from svn diff. + # With this modification no changes on the server side are required + # to make upload.py work with Mercurial repos. + # NOTE: for proper handling of moved/copied files, we have to use + # the second filename. + filename = m.group(2) + svndiff.append("Index: %s" % filename) + svndiff.append("=" * 67) + filecount += 1 + logging.info(line) + else: + svndiff.append(line) + if not filecount: + ErrorExit("No valid patches found in output from hg diff") + return "\n".join(svndiff) + "\n" + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + args = [] + status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], + silent_ok=True) + unknown_files = [] + for line in status.splitlines(): + st, fn = line.split(" ", 1) + if st == "?": + unknown_files.append(fn) + return unknown_files + + def GetBaseFile(self, filename): + # "hg status" and "hg cat" both take a path relative to the current subdir + # rather than to the repo root, but "hg diff" has given us the full path + # to the repo root. + base_content = "" + new_content = None + is_binary = False + oldrelpath = relpath = self._GetRelPath(filename) + # "hg status -C" returns two lines for moved/copied files, one otherwise + out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) + out = out.splitlines() + # HACK: strip error message about missing file/directory if it isn't in + # the working copy + if out[0].startswith('%s: ' % relpath): + out = out[1:] + if len(out) > 1: + # Moved/copied => considered as modified, use old filename to + # retrieve base contents + oldrelpath = out[1].strip() + status = "M" + else: + status, _ = out[0].split(' ', 1) + if status != "A": + base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath], + silent_ok=True) + is_binary = "\0" in base_content # Mercurial's heuristic + if status != "R": + new_content = open(relpath, "rb").read() + is_binary = is_binary or "\0" in new_content + if is_binary and base_content: + # Fetch again without converting newlines + base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath], + silent_ok=True, universal_newlines=False) + if not is_binary or not self.IsImage(relpath): + new_content = None + return base_content, new_content, is_binary, status + + +# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync. +def SplitPatch(data): + """Splits a patch into separate pieces for each file. + + Args: + data: A string containing the output of svn diff. + + Returns: + A list of 2-tuple (filename, text) where text is the svn diff output + pertaining to filename. + """ + patches = [] + filename = None + diff = [] + for line in data.splitlines(True): + new_filename = None + if line.startswith('Index:'): + unused, new_filename = line.split(':', 1) + new_filename = new_filename.strip() + elif line.startswith('Property changes on:'): + unused, temp_filename = line.split(':', 1) + # When a file is modified, paths use '/' between directories, however + # when a property is modified '\' is used on Windows. Make them the same + # otherwise the file shows up twice. + temp_filename = temp_filename.strip().replace('\\', '/') + if temp_filename != filename: + # File has property changes but no modifications, create a new diff. + new_filename = temp_filename + if new_filename: + if filename and diff: + patches.append((filename, ''.join(diff))) + filename = new_filename + diff = [line] + continue + if diff is not None: + diff.append(line) + if filename and diff: + patches.append((filename, ''.join(diff))) + return patches + + +def UploadSeparatePatches(issue, rpc_server, patchset, data, options): + """Uploads a separate patch for each file in the diff output. + + Returns a list of [patch_key, filename] for each file. + """ + patches = SplitPatch(data) + rv = [] + for patch in patches: + if len(patch[1]) > MAX_UPLOAD_SIZE: + print ("Not uploading the patch for " + patch[0] + + " because the file is too large.") + continue + form_fields = [("filename", patch[0])] + if not options.download_base: + form_fields.append(("content_upload", "1")) + files = [("data", "data.diff", patch[1])] + ctype, body = EncodeMultipartFormData(form_fields, files) + url = "/%d/upload_patch/%d" % (int(issue), int(patchset)) + print "Uploading patch for " + patch[0] + response_body = rpc_server.Send(url, body, content_type=ctype) + lines = response_body.splitlines() + if not lines or lines[0] != "OK": + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + rv.append([lines[1], patch[0]]) + return rv + + +def GuessVCS(options): + """Helper to guess the version control system. + + This examines the current directory, guesses which VersionControlSystem + we're using, and returns an instance of the appropriate class. Exit with an + error if we can't figure it out. + + Returns: + A VersionControlSystem instance. Exits if the VCS can't be guessed. + """ + # Mercurial has a command to get the base directory of a repository + # Try running it, but don't die if we don't have hg installed. + # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. + try: + out, returncode = RunShellWithReturnCode(["hg", "root"]) + if returncode == 0: + return MercurialVCS(options, out.strip()) + except OSError, (errno, message): + if errno != 2: # ENOENT -- they don't have hg installed. + raise + + # Subversion has a .svn in all working directories. + if os.path.isdir('.svn'): + logging.info("Guessed VCS = Subversion") + return SubversionVCS(options) + + # Git has a command to test if you're in a git tree. + # Try running it, but don't die if we don't have git installed. + try: + out, returncode = RunShellWithReturnCode(["git", "rev-parse", + "--is-inside-work-tree"]) + if returncode == 0: + return GitVCS(options) + except OSError, (errno, message): + if errno != 2: # ENOENT -- they don't have git installed. + raise + + ErrorExit(("Could not guess version control system. " + "Are you in a working copy directory?")) + + +def RealMain(argv, data=None): + """The real main function. + + Args: + argv: Command line arguments. + data: Diff contents. If None (default) the diff is generated by + the VersionControlSystem implementation returned by GuessVCS(). + + Returns: + A 2-tuple (issue id, patchset id). + The patchset id is None if the base files are not uploaded by this + script (applies only to SVN checkouts). + """ + logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" + "%(lineno)s %(message)s ")) + os.environ['LC_ALL'] = 'C' + options, args = parser.parse_args(argv[1:]) + global verbosity + verbosity = options.verbose + if verbosity >= 3: + logging.getLogger().setLevel(logging.DEBUG) + elif verbosity >= 2: + logging.getLogger().setLevel(logging.INFO) + vcs = GuessVCS(options) + if isinstance(vcs, SubversionVCS): + # base field is only allowed for Subversion. + # Note: Fetching base files may become deprecated in future releases. + base = vcs.GuessBase(options.download_base) + else: + base = None + if not base and options.download_base: + options.download_base = True + logging.info("Enabled upload of base file") + if not options.assume_yes: + vcs.CheckForUnknownFiles() + if data is None: + data = vcs.GenerateDiff(args) + files = vcs.GetBaseFiles(data) + if verbosity >= 1: + print "Upload server:", options.server, "(change with -s/--server)" + if options.issue: + prompt = "Message describing this patch set: " + else: + prompt = "New issue subject: " + message = options.message or raw_input(prompt).strip() + if not message: + ErrorExit("A non-empty message is required") + rpc_server = GetRpcServer(options) + form_fields = [("subject", message)] + if base: + form_fields.append(("base", base)) + if options.issue: + form_fields.append(("issue", str(options.issue))) + if options.email: + form_fields.append(("user", options.email)) + if options.reviewers: + for reviewer in options.reviewers.split(','): + if "@" in reviewer and not reviewer.split("@")[1].count(".") == 1: + ErrorExit("Invalid email address: %s" % reviewer) + form_fields.append(("reviewers", options.reviewers)) + if options.cc: + for cc in options.cc.split(','): + if "@" in cc and not cc.split("@")[1].count(".") == 1: + ErrorExit("Invalid email address: %s" % cc) + form_fields.append(("cc", options.cc)) + description = options.description + if options.description_file: + if options.description: + ErrorExit("Can't specify description and description_file") + file = open(options.description_file, 'r') + description = file.read() + file.close() + if description: + form_fields.append(("description", description)) + # Send a hash of all the base file so the server can determine if a copy + # already exists in an earlier patchset. + base_hashes = "" + for file, info in files.iteritems(): + if not info[0] is None: + checksum = md5.new(info[0]).hexdigest() + if base_hashes: + base_hashes += "|" + base_hashes += checksum + ":" + file + form_fields.append(("base_hashes", base_hashes)) + # If we're uploading base files, don't send the email before the uploads, so + # that it contains the file status. + if options.send_mail and options.download_base: + form_fields.append(("send_mail", "1")) + if not options.download_base: + form_fields.append(("content_upload", "1")) + if len(data) > MAX_UPLOAD_SIZE: + print "Patch is large, so uploading file patches separately." + uploaded_diff_file = [] + form_fields.append(("separate_patches", "1")) + else: + uploaded_diff_file = [("data", "data.diff", data)] + ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) + response_body = rpc_server.Send("/upload", body, content_type=ctype) + patchset = None + if not options.download_base or not uploaded_diff_file: + lines = response_body.splitlines() + if len(lines) >= 2: + msg = lines[0] + patchset = lines[1].strip() + patches = [x.split(" ", 1) for x in lines[2:]] + else: + msg = response_body + else: + msg = response_body + StatusUpdate(msg) + if not response_body.startswith("Issue created.") and \ + not response_body.startswith("Issue updated."): + sys.exit(0) + issue = msg[msg.rfind("/")+1:] + + if not uploaded_diff_file: + result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) + if not options.download_base: + patches = result + + if not options.download_base: + vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) + if options.send_mail: + rpc_server.Send("/" + issue + "/mail", payload="") + return issue, patchset + + +def main(): + try: + RealMain(sys.argv) + except KeyboardInterrupt: + print + StatusUpdate("Interrupted.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/third_party/googletest/src/scripts/upload_gtest.py b/third_party/googletest/src/scripts/upload_gtest.py new file mode 100755 index 0000000..be19ae8 --- /dev/null +++ b/third_party/googletest/src/scripts/upload_gtest.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""upload_gtest.py v0.1.0 -- uploads a Google Test patch for review. + +This simple wrapper passes all command line flags and +--cc=googletestframework@googlegroups.com to upload.py. + +USAGE: upload_gtest.py [options for upload.py] +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import sys + +CC_FLAG = '--cc=' +GTEST_GROUP = 'googletestframework@googlegroups.com' + + +def main(): + # Finds the path to upload.py, assuming it is in the same directory + # as this file. + my_dir = os.path.dirname(os.path.abspath(__file__)) + upload_py_path = os.path.join(my_dir, 'upload.py') + + # Adds Google Test discussion group to the cc line if it's not there + # already. + upload_py_argv = [upload_py_path] + found_cc_flag = False + for arg in sys.argv[1:]: + if arg.startswith(CC_FLAG): + found_cc_flag = True + cc_line = arg[len(CC_FLAG):] + cc_list = [addr for addr in cc_line.split(',') if addr] + if GTEST_GROUP not in cc_list: + cc_list.append(GTEST_GROUP) + upload_py_argv.append(CC_FLAG + ','.join(cc_list)) + else: + upload_py_argv.append(arg) + + if not found_cc_flag: + upload_py_argv.append(CC_FLAG + GTEST_GROUP) + + # Invokes upload.py with the modified command line flags. + os.execv(upload_py_path, upload_py_argv) + + +if __name__ == '__main__': + main() diff --git a/third_party/googletest/src/src/gtest-all.cc b/third_party/googletest/src/src/gtest-all.cc new file mode 100644 index 0000000..0a9cee5 --- /dev/null +++ b/third_party/googletest/src/src/gtest-all.cc @@ -0,0 +1,48 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +#include "src/gtest.cc" +#include "src/gtest-death-test.cc" +#include "src/gtest-filepath.cc" +#include "src/gtest-port.cc" +#include "src/gtest-printers.cc" +#include "src/gtest-test-part.cc" +#include "src/gtest-typed-test.cc" diff --git a/third_party/googletest/src/src/gtest-death-test.cc b/third_party/googletest/src/src/gtest-death-test.cc new file mode 100644 index 0000000..8b2e413 --- /dev/null +++ b/third_party/googletest/src/src/gtest-death-test.cc @@ -0,0 +1,1234 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + +#include "gtest/gtest-death-test.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +#endif // GTEST_HAS_DEATH_TEST + +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-string.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS +} + +# if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { + return String(errno == 0 ? "" : posix::StrError(errno)); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; +} + +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const String error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +# else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; +bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index())); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str())); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + write_handle_as_size_t, parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + write_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing diff --git a/third_party/googletest/src/src/gtest-filepath.cc b/third_party/googletest/src/src/gtest-filepath.cc new file mode 100644 index 0000000..91b2571 --- /dev/null +++ b/third_party/googletest/src/src/gtest-filepath.cc @@ -0,0 +1,380 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-port.h" + +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL +// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + +#include "gtest/internal/gtest-string.h" + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing diff --git a/third_party/googletest/src/src/gtest-internal-inl.h b/third_party/googletest/src/src/gtest-internal-inl.h new file mode 100644 index 0000000..65a2101 --- /dev/null +++ b/third_party/googletest/src/src/gtest-internal-inl.h @@ -0,0 +1,1038 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + +#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest-spi.h" + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + bool death_test_use_fork_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool print_time_; + bool pretty_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + String stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->type_param(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ String GetLastErrnoDescription(); + +# if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +# endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/third_party/googletest/src/src/gtest-port.cc b/third_party/googletest/src/src/gtest-port.cc new file mode 100644 index 0000000..b860d48 --- /dev/null +++ b/third_party/googletest/src/src/gtest-port.cc @@ -0,0 +1,746 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/internal/gtest-port.h" + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + +#include "gtest/gtest-spi.h" +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) { + return String::Format("%s:", file_name).c_str(); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line).c_str(); +#else + return String::Format("%s:%d:", file_name, line).c_str(); +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) + return file_name; + else + return String::Format("%s:%d", file_name, line).c_str(); +} + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { + +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +# else + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stream.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +String CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const String content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // GTEST_HAS_STREAM_REDIRECTION + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing diff --git a/third_party/googletest/src/src/gtest-printers.cc b/third_party/googletest/src/src/gtest-printers.cc new file mode 100644 index 0000000..ed63c7b --- /dev/null +++ b/third_party/googletest/src/src/gtest-printers.cc @@ -0,0 +1,356 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include "gtest/gtest-printers.h" +#include +#include +#include // NOLINT +#include +#include "gtest/internal/gtest-port.h" + +namespace testing { + +namespace { + +using ::std::ostream; + +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. +# define snprintf _snprintf +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +# define snprintf _snprintf_s +#elif _MSC_VER +# define snprintf _snprintf +#endif // GTEST_OS_WINDOWS_MOBILE + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(c)) { + *os << static_cast(c); + return kAsIs; + } else { + *os << String::Format("\\x%X", static_cast(c)); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { + return PrintAsWideStringLiteralTo(static_cast(c), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << String::Format("%d", c).c_str(); + + // For more convenience, we print c's code again in hexidecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << String::Format(", 0x%X", + static_cast(c)).c_str(); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const char cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" \""; + } + is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const wchar_t cur = begin[index]; + if (is_previous_hex && isascii(cur) && IsXDigit(static_cast(cur))) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" L\""; + } + is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing diff --git a/third_party/googletest/src/src/gtest-test-part.cc b/third_party/googletest/src/src/gtest-test-part.cc new file mode 100644 index 0000000..5ddc67c --- /dev/null +++ b/third_party/googletest/src/src/gtest-test-part.cc @@ -0,0 +1,110 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + +#include "gtest/gtest-test-part.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing diff --git a/third_party/googletest/src/src/gtest-typed-test.cc b/third_party/googletest/src/src/gtest-typed-test.cc new file mode 100644 index 0000000..a5cc88f --- /dev/null +++ b/third_party/googletest/src/src/gtest-typed-test.cc @@ -0,0 +1,110 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest-typed-test.h" +#include "gtest/gtest.h" + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/third_party/googletest/src/src/gtest.cc b/third_party/googletest/src/src/gtest.cc new file mode 100644 index 0000000..904d9d7 --- /dev/null +++ b/third_party/googletest/src/src/gtest.cc @@ -0,0 +1,4898 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_SYMBIAN +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).ToString() ); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive = String(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const string& substr) { + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + +# ifdef _MSC_VER + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +# pragma warning(pop) // Restores the warning state. +# else + + _ftime64(&now); + +# endif // _MSC_VER + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String + +// Returns the input enclosed in double quotes if it's not NULL; +// otherwise returns "(null)". For example, "\"Hello\"" is returned +// for input "Hello". +// +// This is useful for printing a C string in the syntax of a literal. +// +// Known issue: escape sequences are not handled yet. +String String::ShowCStringQuoted(const char* c_str) { + return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); +} + +// Copies at most length characters from str into a newly-allocated +// piece of memory of size length+1. The memory is allocated with new[]. +// A terminating null byte is written to the memory, and a pointer to it +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + posix::StrNCpy(clone, str, length); + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const String error_hex(String::Format("0x%08X ", hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } else { + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + posix::StrNCpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); +} + +// Similar to ShowWideCString(), except that this function encloses +// the converted string in double quotes. +String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String::Format("L\"%s\"", + String::ShowWideCString(wide_c_str).c_str()); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; + } + + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef _MSC_VER // We are using MSVC. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + + const int size = vsnprintf(buffer, kBufferSize, format, args); + +# pragma warning(pop) // Restores the warning state. +#else // We are not using MSVC. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#endif // _MSC_VER + va_end(args); + + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } +} + +// Converts the buffer in a stringstream to a String, converting NUL +// bytes to "\\0" along the way. +String StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + // We need to use a helper stringstream to do this transformation + // because String doesn't support push_back(). + ::std::stringstream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + + return String(helper.str().c_str()); +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + internal::String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static internal::String* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new internal::String(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static internal::String FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result); + +// A failed Google Test assertion will throw an exception of this type when +// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We +// derive it from std::runtime_error, which is for errors presumably +// detectable only at run time. Since std::runtime_error inherits from +// std::exception, many testing frameworks know how to extract and print the +// message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + internal::String* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s +// to signify they cannot be NULLs. +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, type_param, value_param, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && internal::String(test_info->name()).Compare(name_) == 0; + } + + private: + internal::String name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + default: + return "Unknown result type"; + } +} + +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("TypeParam = %s", type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("GetParam() = %s", value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + + internal::String test_case_name_; +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case.type_param() == NULL) { + printf("\n"); + } else { + printf(", where TypeParam = %s\n", test_case.type_param()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static String EscapeXml(const char* str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static string RemoveInvalidXmlCharacters(const string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static String TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { + string output; + output.reserve(str.size()); + for (string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + *stream << " \n"; + *stream << " "; + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string message = location + "\n" + part.message(); + OutputXmlCDataSection(stream, + RemoveInvalidXmlCharacters(message).c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase& test_case) { + fprintf(out, + " \n", + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); + for (int i = 0; i < test_case.total_test_count(); ++i) { + ::std::stringstream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StringStreamToString(&stream).c_str()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest& unit_test) { + fprintf(out, "\n"); + fprintf(out, + "\n"); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + Send("gtest_streaming_protocol_version=1.0\n"); + } + + virtual ~StreamingListener() { + if (sockfd_ != -1) + CloseConnection(); + } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + Send("event=TestProgramStart\n"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + Send(String::Format("event=TestProgramEnd&passed=%d\n", + unit_test.Passed())); + + // Notify the streaming server to stop. + CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + Send(String::Format("event=TestIterationStart&iteration=%d\n", + iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", + unit_test.Passed(), + StreamableToString(unit_test.elapsed_time()).c_str())); + } + + void OnTestCaseStart(const TestCase& test_case) { + Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); + } + + void OnTestCaseEnd(const TestCase& test_case) { + Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", + test_case.Passed(), + StreamableToString(test_case.elapsed_time()).c_str())); + } + + void OnTestStart(const TestInfo& test_info) { + Send(String::Format("event=TestStart&name=%s\n", test_info.name())); + } + + void OnTestEnd(const TestInfo& test_info) { + Send(String::Format( + "event=TestEnd&passed=%d&elapsed_time=%sms\n", + (test_info.result())->Passed(), + StreamableToString((test_info.result())->elapsed_time()).c_str())); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", + UrlEncode(file_name).c_str(), + test_part_result.line_number())); + Send(UrlEncode(test_part_result.message()) + "\n"); + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + // Sends a string to the socket. + void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append(String::Format("%%%02x", static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + // Dereference NULL through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: Symbian doesn't implement abort() well, and some debuggers + // don't correctly trap abort(). + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_HAS_SEH + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { + +# if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + + } +#endif // GTEST_HAS_SEH + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +# pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in String form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return false; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + &(current_test_info_->result_) : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing diff --git a/third_party/googletest/src/src/gtest_main.cc b/third_party/googletest/src/src/gtest_main.cc new file mode 100644 index 0000000..a09bbe0 --- /dev/null +++ b/third_party/googletest/src/src/gtest_main.cc @@ -0,0 +1,39 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "gtest/gtest.h" + +GTEST_API_ int main(int argc, char **argv) { + std::cout << "Running main() from gtest_main.cc\n"; + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest-death-test_ex_test.cc b/third_party/googletest/src/test/gtest-death-test_ex_test.cc new file mode 100644 index 0000000..b50a13d --- /dev/null +++ b/third_party/googletest/src/test/gtest-death-test_ex_test.cc @@ -0,0 +1,93 @@ +// Copyright 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) +// +// Tests that verify interaction of exceptions and death tests. + +#include "gtest/gtest-death-test.h" +#include "gtest/gtest.h" + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_HAS_SEH +# include // For RaiseException(). +# endif + +# include "gtest/gtest-spi.h" + +# if GTEST_HAS_EXCEPTIONS + +# include // For std::exception. + +// Tests that death tests report thrown exceptions as failures and that the +// exceptions do not escape death test macros. +TEST(CxxExceptionDeathTest, ExceptionIsFailure) { + try { + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception"); + } catch (...) { // NOLINT + FAIL() << "An exception escaped a death test macro invocation " + << "with catch_exceptions " + << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); + } +} + +class TestException : public std::exception { + public: + virtual const char* what() const throw() { return "exceptional message"; } +}; + +TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions) { + // Verifies that the exception message is quoted in the failure text. + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), + "exceptional message"); + // Verifies that the location is mentioned in the failure text. + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), + "gtest-death-test_ex_test.cc"); +} +# endif // GTEST_HAS_EXCEPTIONS + +# if GTEST_HAS_SEH +// Tests that enabling interception of SEH exceptions with the +// catch_exceptions flag does not interfere with SEH exceptions being +// treated as death by death tests. +TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere) { + EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "") + << "with catch_exceptions " + << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); +} +# endif + +#endif // GTEST_HAS_DEATH_TEST + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0; + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest-death-test_test.cc b/third_party/googletest/src/test/gtest-death-test_test.cc new file mode 100644 index 0000000..bcf8e2a --- /dev/null +++ b/third_party/googletest/src/test/gtest-death-test_test.cc @@ -0,0 +1,1296 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Tests for death tests. + +#include "gtest/gtest-death-test.h" +#include "gtest/gtest.h" +#include "gtest/internal/gtest-filepath.h" + +using testing::internal::AlwaysFalse; +using testing::internal::AlwaysTrue; + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_WINDOWS +# include // For chdir(). +# else +# include +# include // For waitpid. +# include // For std::numeric_limits. +# endif // GTEST_OS_WINDOWS + +# include +# include +# include + +# include "gtest/gtest-spi.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +# define GTEST_IMPLEMENTATION_ 1 +# include "src/gtest-internal-inl.h" +# undef GTEST_IMPLEMENTATION_ + +namespace posix = ::testing::internal::posix; + +using testing::Message; +using testing::internal::DeathTest; +using testing::internal::DeathTestFactory; +using testing::internal::FilePath; +using testing::internal::GetLastErrnoDescription; +using testing::internal::GetUnitTestImpl; +using testing::internal::ParseNaturalNumber; +using testing::internal::String; + +namespace testing { +namespace internal { + +// A helper class whose objects replace the death test factory for a +// single UnitTest object during their lifetimes. +class ReplaceDeathTestFactory { + public: + explicit ReplaceDeathTestFactory(DeathTestFactory* new_factory) + : unit_test_impl_(GetUnitTestImpl()) { + old_factory_ = unit_test_impl_->death_test_factory_.release(); + unit_test_impl_->death_test_factory_.reset(new_factory); + } + + ~ReplaceDeathTestFactory() { + unit_test_impl_->death_test_factory_.release(); + unit_test_impl_->death_test_factory_.reset(old_factory_); + } + private: + // Prevents copying ReplaceDeathTestFactory objects. + ReplaceDeathTestFactory(const ReplaceDeathTestFactory&); + void operator=(const ReplaceDeathTestFactory&); + + UnitTestImpl* unit_test_impl_; + DeathTestFactory* old_factory_; +}; + +} // namespace internal +} // namespace testing + +void DieWithMessage(const ::std::string& message) { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); // Make sure the text is printed before the process exits. + + // We call _exit() instead of exit(), as the former is a direct + // system call and thus safer in the presence of threads. exit() + // will invoke user-defined exit-hooks, which may do dangerous + // things that conflict with death tests. + // + // Some compilers can recognize that _exit() never returns and issue the + // 'unreachable code' warning for code following this function, unless + // fooled by a fake condition. + if (AlwaysTrue()) + _exit(1); +} + +void DieInside(const ::std::string& function) { + DieWithMessage("death inside " + function + "()."); +} + +// Tests that death tests work. + +class TestForDeathTest : public testing::Test { + protected: + TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {} + + virtual ~TestForDeathTest() { + posix::ChDir(original_dir_.c_str()); + } + + // A static member function that's expected to die. + static void StaticMemberFunction() { DieInside("StaticMemberFunction"); } + + // A method of the test fixture that may die. + void MemberFunction() { + if (should_die_) + DieInside("MemberFunction"); + } + + // True iff MemberFunction() should die. + bool should_die_; + const FilePath original_dir_; +}; + +// A class with a member function that may die. +class MayDie { + public: + explicit MayDie(bool should_die) : should_die_(should_die) {} + + // A member function that may die. + void MemberFunction() const { + if (should_die_) + DieInside("MayDie::MemberFunction"); + } + + private: + // True iff MemberFunction() should die. + bool should_die_; +}; + +// A global function that's expected to die. +void GlobalFunction() { DieInside("GlobalFunction"); } + +// A non-void function that's expected to die. +int NonVoidFunction() { + DieInside("NonVoidFunction"); + return 1; +} + +// A unary function that may die. +void DieIf(bool should_die) { + if (should_die) + DieInside("DieIf"); +} + +// A binary function that may die. +bool DieIfLessThan(int x, int y) { + if (x < y) { + DieInside("DieIfLessThan"); + } + return true; +} + +// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. +void DeathTestSubroutine() { + EXPECT_DEATH(GlobalFunction(), "death.*GlobalFunction"); + ASSERT_DEATH(GlobalFunction(), "death.*GlobalFunction"); +} + +// Death in dbg, not opt. +int DieInDebugElse12(int* sideeffect) { + if (sideeffect) *sideeffect = 12; + +# ifndef NDEBUG + + DieInside("DieInDebugElse12"); + +# endif // NDEBUG + + return 12; +} + +# if GTEST_OS_WINDOWS + +// Tests the ExitedWithCode predicate. +TEST(ExitStatusPredicateTest, ExitedWithCode) { + // On Windows, the process's exit code is the same as its exit status, + // so the predicate just compares the its input with its parameter. + EXPECT_TRUE(testing::ExitedWithCode(0)(0)); + EXPECT_TRUE(testing::ExitedWithCode(1)(1)); + EXPECT_TRUE(testing::ExitedWithCode(42)(42)); + EXPECT_FALSE(testing::ExitedWithCode(0)(1)); + EXPECT_FALSE(testing::ExitedWithCode(1)(0)); +} + +# else + +// Returns the exit status of a process that calls _exit(2) with a +// given exit code. This is a helper function for the +// ExitStatusPredicateTest test suite. +static int NormalExitStatus(int exit_code) { + pid_t child_pid = fork(); + if (child_pid == 0) { + _exit(exit_code); + } + int status; + waitpid(child_pid, &status, 0); + return status; +} + +// Returns the exit status of a process that raises a given signal. +// If the signal does not cause the process to die, then it returns +// instead the exit status of a process that exits normally with exit +// code 1. This is a helper function for the ExitStatusPredicateTest +// test suite. +static int KilledExitStatus(int signum) { + pid_t child_pid = fork(); + if (child_pid == 0) { + raise(signum); + _exit(1); + } + int status; + waitpid(child_pid, &status, 0); + return status; +} + +// Tests the ExitedWithCode predicate. +TEST(ExitStatusPredicateTest, ExitedWithCode) { + const int status0 = NormalExitStatus(0); + const int status1 = NormalExitStatus(1); + const int status42 = NormalExitStatus(42); + const testing::ExitedWithCode pred0(0); + const testing::ExitedWithCode pred1(1); + const testing::ExitedWithCode pred42(42); + EXPECT_PRED1(pred0, status0); + EXPECT_PRED1(pred1, status1); + EXPECT_PRED1(pred42, status42); + EXPECT_FALSE(pred0(status1)); + EXPECT_FALSE(pred42(status0)); + EXPECT_FALSE(pred1(status42)); +} + +// Tests the KilledBySignal predicate. +TEST(ExitStatusPredicateTest, KilledBySignal) { + const int status_segv = KilledExitStatus(SIGSEGV); + const int status_kill = KilledExitStatus(SIGKILL); + const testing::KilledBySignal pred_segv(SIGSEGV); + const testing::KilledBySignal pred_kill(SIGKILL); + EXPECT_PRED1(pred_segv, status_segv); + EXPECT_PRED1(pred_kill, status_kill); + EXPECT_FALSE(pred_segv(status_kill)); + EXPECT_FALSE(pred_kill(status_segv)); +} + +# endif // GTEST_OS_WINDOWS + +// Tests that the death test macros expand to code which may or may not +// be followed by operator<<, and that in either case the complete text +// comprises only a single C++ statement. +TEST_F(TestForDeathTest, SingleStatement) { + if (AlwaysFalse()) + // This would fail if executed; this is a compilation test only + ASSERT_DEATH(return, ""); + + if (AlwaysTrue()) + EXPECT_DEATH(_exit(1), ""); + else + // This empty "else" branch is meant to ensure that EXPECT_DEATH + // doesn't expand into an "if" statement without an "else" + ; + + if (AlwaysFalse()) + ASSERT_DEATH(return, "") << "did not die"; + + if (AlwaysFalse()) + ; + else + EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; +} + +void DieWithEmbeddedNul() { + fprintf(stderr, "Hello%cmy null world.\n", '\0'); + fflush(stderr); + _exit(1); +} + +# if GTEST_USES_PCRE +// Tests that EXPECT_DEATH and ASSERT_DEATH work when the error +// message has a NUL character in it. +TEST_F(TestForDeathTest, EmbeddedNulInMessage) { + // TODO(wan@google.com): doesn't support matching strings + // with embedded NUL characters - find a way to workaround it. + EXPECT_DEATH(DieWithEmbeddedNul(), "my null world"); + ASSERT_DEATH(DieWithEmbeddedNul(), "my null world"); +} +# endif // GTEST_USES_PCRE + +// Tests that death test macros expand to code which interacts well with switch +// statements. +TEST_F(TestForDeathTest, SwitchStatement) { +// Microsoft compiler usually complains about switch statements without +// case labels. We suppress that warning for this test. +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4065) +# endif // _MSC_VER + + switch (0) + default: + ASSERT_DEATH(_exit(1), "") << "exit in default switch handler"; + + switch (0) + case 0: + EXPECT_DEATH(_exit(1), "") << "exit in switch case"; + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER +} + +// Tests that a static member function can be used in a "fast" style +// death test. +TEST_F(TestForDeathTest, StaticMemberFunctionFastStyle) { + testing::GTEST_FLAG(death_test_style) = "fast"; + ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); +} + +// Tests that a method of the test fixture can be used in a "fast" +// style death test. +TEST_F(TestForDeathTest, MemberFunctionFastStyle) { + testing::GTEST_FLAG(death_test_style) = "fast"; + should_die_ = true; + EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); +} + +void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); } + +// Tests that death tests work even if the current directory has been +// changed. +TEST_F(TestForDeathTest, FastDeathTestInChangedDir) { + testing::GTEST_FLAG(death_test_style) = "fast"; + + ChangeToRootDir(); + EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); + + ChangeToRootDir(); + ASSERT_DEATH(_exit(1), ""); +} + +// Repeats a representative sample of death tests in the "threadsafe" style: + +TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); +} + +TEST_F(TestForDeathTest, MemberFunctionThreadsafeStyle) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + should_die_ = true; + EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); +} + +TEST_F(TestForDeathTest, ThreadsafeDeathTestInLoop) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + + for (int i = 0; i < 3; ++i) + EXPECT_EXIT(_exit(i), testing::ExitedWithCode(i), "") << ": i = " << i; +} + +TEST_F(TestForDeathTest, ThreadsafeDeathTestInChangedDir) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + + ChangeToRootDir(); + EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); + + ChangeToRootDir(); + ASSERT_DEATH(_exit(1), ""); +} + +TEST_F(TestForDeathTest, MixedStyles) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + EXPECT_DEATH(_exit(1), ""); + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_DEATH(_exit(1), ""); +} + +namespace { + +bool pthread_flag; + +void SetPthreadFlag() { + pthread_flag = true; +} + +} // namespace + +# if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD + +TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { + if (!testing::GTEST_FLAG(death_test_use_fork)) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + pthread_flag = false; + ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL)); + ASSERT_DEATH(_exit(1), ""); + ASSERT_FALSE(pthread_flag); + } +} + +# endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD + +// Tests that a method of another class can be used in a death test. +TEST_F(TestForDeathTest, MethodOfAnotherClass) { + const MayDie x(true); + ASSERT_DEATH(x.MemberFunction(), "MayDie\\:\\:MemberFunction"); +} + +// Tests that a global function can be used in a death test. +TEST_F(TestForDeathTest, GlobalFunction) { + EXPECT_DEATH(GlobalFunction(), "GlobalFunction"); +} + +// Tests that any value convertible to an RE works as a second +// argument to EXPECT_DEATH. +TEST_F(TestForDeathTest, AcceptsAnythingConvertibleToRE) { + static const char regex_c_str[] = "GlobalFunction"; + EXPECT_DEATH(GlobalFunction(), regex_c_str); + + const testing::internal::RE regex(regex_c_str); + EXPECT_DEATH(GlobalFunction(), regex); + +# if GTEST_HAS_GLOBAL_STRING + + const string regex_str(regex_c_str); + EXPECT_DEATH(GlobalFunction(), regex_str); + +# endif // GTEST_HAS_GLOBAL_STRING + + const ::std::string regex_std_str(regex_c_str); + EXPECT_DEATH(GlobalFunction(), regex_std_str); +} + +// Tests that a non-void function can be used in a death test. +TEST_F(TestForDeathTest, NonVoidFunction) { + ASSERT_DEATH(NonVoidFunction(), "NonVoidFunction"); +} + +// Tests that functions that take parameter(s) can be used in a death test. +TEST_F(TestForDeathTest, FunctionWithParameter) { + EXPECT_DEATH(DieIf(true), "DieIf\\(\\)"); + EXPECT_DEATH(DieIfLessThan(2, 3), "DieIfLessThan"); +} + +// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. +TEST_F(TestForDeathTest, OutsideFixture) { + DeathTestSubroutine(); +} + +// Tests that death tests can be done inside a loop. +TEST_F(TestForDeathTest, InsideLoop) { + for (int i = 0; i < 5; i++) { + EXPECT_DEATH(DieIfLessThan(-1, i), "DieIfLessThan") << "where i == " << i; + } +} + +// Tests that a compound statement can be used in a death test. +TEST_F(TestForDeathTest, CompoundStatement) { + EXPECT_DEATH({ // NOLINT + const int x = 2; + const int y = x + 1; + DieIfLessThan(x, y); + }, + "DieIfLessThan"); +} + +// Tests that code that doesn't die causes a death test to fail. +TEST_F(TestForDeathTest, DoesNotDie) { + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieIf(false), "DieIf"), + "failed to die"); +} + +// Tests that a death test fails when the error message isn't expected. +TEST_F(TestForDeathTest, ErrorMessageMismatch) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_DEATH(DieIf(true), "DieIfLessThan") << "End of death test message."; + }, "died but not with expected error"); +} + +// On exit, *aborted will be true iff the EXPECT_DEATH() statement +// aborted the function. +void ExpectDeathTestHelper(bool* aborted) { + *aborted = true; + EXPECT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. + *aborted = false; +} + +// Tests that EXPECT_DEATH doesn't abort the test on failure. +TEST_F(TestForDeathTest, EXPECT_DEATH) { + bool aborted = true; + EXPECT_NONFATAL_FAILURE(ExpectDeathTestHelper(&aborted), + "failed to die"); + EXPECT_FALSE(aborted); +} + +// Tests that ASSERT_DEATH does abort the test on failure. +TEST_F(TestForDeathTest, ASSERT_DEATH) { + static bool aborted; + EXPECT_FATAL_FAILURE({ // NOLINT + aborted = true; + ASSERT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. + aborted = false; + }, "failed to die"); + EXPECT_TRUE(aborted); +} + +// Tests that EXPECT_DEATH evaluates the arguments exactly once. +TEST_F(TestForDeathTest, SingleEvaluation) { + int x = 3; + EXPECT_DEATH(DieIf((++x) == 4), "DieIf"); + + const char* regex = "DieIf"; + const char* regex_save = regex; + EXPECT_DEATH(DieIfLessThan(3, 4), regex++); + EXPECT_EQ(regex_save + 1, regex); +} + +// Tests that run-away death tests are reported as failures. +TEST_F(TestForDeathTest, RunawayIsFailure) { + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast(0), "Foo"), + "failed to die."); +} + +// Tests that death tests report executing 'return' in the statement as +// failure. +TEST_F(TestForDeathTest, ReturnIsFailure) { + EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"), + "illegal return in test statement."); +} + +// Tests that EXPECT_DEBUG_DEATH works as expected, +// that is, in debug mode, it: +// 1. Asserts on death. +// 2. Has no side effect. +// +// And in opt mode, it: +// 1. Has side effects but does not assert. +TEST_F(TestForDeathTest, TestExpectDebugDeath) { + int sideeffect = 0; + + EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), + "death.*DieInDebugElse12"); + +# ifdef NDEBUG + + // Checks that the assignment occurs in opt mode (sideeffect). + EXPECT_EQ(12, sideeffect); + +# else + + // Checks that the assignment does not occur in dbg mode (no sideeffect). + EXPECT_EQ(0, sideeffect); + +# endif +} + +// Tests that ASSERT_DEBUG_DEATH works as expected +// In debug mode: +// 1. Asserts on debug death. +// 2. Has no side effect. +// +// In opt mode: +// 1. Has side effects and returns the expected value (12). +TEST_F(TestForDeathTest, TestAssertDebugDeath) { + int sideeffect = 0; + + ASSERT_DEBUG_DEATH({ // NOLINT + // Tests that the return value is 12 in opt mode. + EXPECT_EQ(12, DieInDebugElse12(&sideeffect)); + // Tests that the side effect occurred in opt mode. + EXPECT_EQ(12, sideeffect); + }, "death.*DieInDebugElse12"); + +# ifdef NDEBUG + + // Checks that the assignment occurs in opt mode (sideeffect). + EXPECT_EQ(12, sideeffect); + +# else + + // Checks that the assignment does not occur in dbg mode (no sideeffect). + EXPECT_EQ(0, sideeffect); + +# endif +} + +# ifndef NDEBUG + +void ExpectDebugDeathHelper(bool* aborted) { + *aborted = true; + EXPECT_DEBUG_DEATH(return, "") << "This is expected to fail."; + *aborted = false; +} + +# if GTEST_OS_WINDOWS +TEST(PopUpDeathTest, DoesNotShowPopUpOnAbort) { + printf("This test should be considered failing if it shows " + "any pop-up dialogs.\n"); + fflush(stdout); + + EXPECT_DEATH({ + testing::GTEST_FLAG(catch_exceptions) = false; + abort(); + }, ""); +} +# endif // GTEST_OS_WINDOWS + +// Tests that EXPECT_DEBUG_DEATH in debug mode does not abort +// the function. +TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) { + bool aborted = true; + EXPECT_NONFATAL_FAILURE(ExpectDebugDeathHelper(&aborted), ""); + EXPECT_FALSE(aborted); +} + +void AssertDebugDeathHelper(bool* aborted) { + *aborted = true; + ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail."; + *aborted = false; +} + +// Tests that ASSERT_DEBUG_DEATH in debug mode aborts the function on +// failure. +TEST_F(TestForDeathTest, AssertDebugDeathAborts) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +# endif // _NDEBUG + +// Tests the *_EXIT family of macros, using a variety of predicates. +static void TestExitMacros() { + EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); + ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), ""); + +# if GTEST_OS_WINDOWS + + // Of all signals effects on the process exit code, only those of SIGABRT + // are documented on Windows. + // See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx. + EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), ""); + +# else + + EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo"; + ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar"; + + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_EXIT(_exit(0), testing::KilledBySignal(SIGSEGV), "") + << "This failure is expected, too."; + }, "This failure is expected, too."); + +# endif // GTEST_OS_WINDOWS + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_EXIT(raise(SIGSEGV), testing::ExitedWithCode(0), "") + << "This failure is expected."; + }, "This failure is expected."); +} + +TEST_F(TestForDeathTest, ExitMacros) { + TestExitMacros(); +} + +TEST_F(TestForDeathTest, ExitMacrosUsingFork) { + testing::GTEST_FLAG(death_test_use_fork) = true; + TestExitMacros(); +} + +TEST_F(TestForDeathTest, InvalidStyle) { + testing::GTEST_FLAG(death_test_style) = "rococo"; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_DEATH(_exit(0), "") << "This failure is expected."; + }, "This failure is expected."); +} + +TEST_F(TestForDeathTest, DeathTestFailedOutput) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH(DieWithMessage("death\n"), + "expected message"), + "Actual msg:\n" + "[ DEATH ] death\n"); +} + +TEST_F(TestForDeathTest, DeathTestUnexpectedReturnOutput) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH({ + fprintf(stderr, "returning\n"); + fflush(stderr); + return; + }, ""), + " Result: illegal return in test statement.\n" + " Error msg:\n" + "[ DEATH ] returning\n"); +} + +TEST_F(TestForDeathTest, DeathTestBadExitCodeOutput) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_EXIT(DieWithMessage("exiting with rc 1\n"), + testing::ExitedWithCode(3), + "expected message"), + " Result: died but not with expected exit code:\n" + " Exited with exit status 1\n" + "Actual msg:\n" + "[ DEATH ] exiting with rc 1\n"); +} + +TEST_F(TestForDeathTest, DeathTestMultiLineMatchFail) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), + "line 1\nxyz\nline 3\n"), + "Actual msg:\n" + "[ DEATH ] line 1\n" + "[ DEATH ] line 2\n" + "[ DEATH ] line 3\n"); +} + +TEST_F(TestForDeathTest, DeathTestMultiLineMatchPass) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), + "line 1\nline 2\nline 3\n"); +} + +// A DeathTestFactory that returns MockDeathTests. +class MockDeathTestFactory : public DeathTestFactory { + public: + MockDeathTestFactory(); + virtual bool Create(const char* statement, + const ::testing::internal::RE* regex, + const char* file, int line, DeathTest** test); + + // Sets the parameters for subsequent calls to Create. + void SetParameters(bool create, DeathTest::TestRole role, + int status, bool passed); + + // Accessors. + int AssumeRoleCalls() const { return assume_role_calls_; } + int WaitCalls() const { return wait_calls_; } + int PassedCalls() const { return passed_args_.size(); } + bool PassedArgument(int n) const { return passed_args_[n]; } + int AbortCalls() const { return abort_args_.size(); } + DeathTest::AbortReason AbortArgument(int n) const { + return abort_args_[n]; + } + bool TestDeleted() const { return test_deleted_; } + + private: + friend class MockDeathTest; + // If true, Create will return a MockDeathTest; otherwise it returns + // NULL. + bool create_; + // The value a MockDeathTest will return from its AssumeRole method. + DeathTest::TestRole role_; + // The value a MockDeathTest will return from its Wait method. + int status_; + // The value a MockDeathTest will return from its Passed method. + bool passed_; + + // Number of times AssumeRole was called. + int assume_role_calls_; + // Number of times Wait was called. + int wait_calls_; + // The arguments to the calls to Passed since the last call to + // SetParameters. + std::vector passed_args_; + // The arguments to the calls to Abort since the last call to + // SetParameters. + std::vector abort_args_; + // True if the last MockDeathTest returned by Create has been + // deleted. + bool test_deleted_; +}; + + +// A DeathTest implementation useful in testing. It returns values set +// at its creation from its various inherited DeathTest methods, and +// reports calls to those methods to its parent MockDeathTestFactory +// object. +class MockDeathTest : public DeathTest { + public: + MockDeathTest(MockDeathTestFactory *parent, + TestRole role, int status, bool passed) : + parent_(parent), role_(role), status_(status), passed_(passed) { + } + virtual ~MockDeathTest() { + parent_->test_deleted_ = true; + } + virtual TestRole AssumeRole() { + ++parent_->assume_role_calls_; + return role_; + } + virtual int Wait() { + ++parent_->wait_calls_; + return status_; + } + virtual bool Passed(bool exit_status_ok) { + parent_->passed_args_.push_back(exit_status_ok); + return passed_; + } + virtual void Abort(AbortReason reason) { + parent_->abort_args_.push_back(reason); + } + private: + MockDeathTestFactory* const parent_; + const TestRole role_; + const int status_; + const bool passed_; +}; + + +// MockDeathTestFactory constructor. +MockDeathTestFactory::MockDeathTestFactory() + : create_(true), + role_(DeathTest::OVERSEE_TEST), + status_(0), + passed_(true), + assume_role_calls_(0), + wait_calls_(0), + passed_args_(), + abort_args_() { +} + + +// Sets the parameters for subsequent calls to Create. +void MockDeathTestFactory::SetParameters(bool create, + DeathTest::TestRole role, + int status, bool passed) { + create_ = create; + role_ = role; + status_ = status; + passed_ = passed; + + assume_role_calls_ = 0; + wait_calls_ = 0; + passed_args_.clear(); + abort_args_.clear(); +} + + +// Sets test to NULL (if create_ is false) or to the address of a new +// MockDeathTest object with parameters taken from the last call +// to SetParameters (if create_ is true). Always returns true. +bool MockDeathTestFactory::Create(const char* /*statement*/, + const ::testing::internal::RE* /*regex*/, + const char* /*file*/, + int /*line*/, + DeathTest** test) { + test_deleted_ = false; + if (create_) { + *test = new MockDeathTest(this, role_, status_, passed_); + } else { + *test = NULL; + } + return true; +} + +// A test fixture for testing the logic of the GTEST_DEATH_TEST_ macro. +// It installs a MockDeathTestFactory that is used for the duration +// of the test case. +class MacroLogicDeathTest : public testing::Test { + protected: + static testing::internal::ReplaceDeathTestFactory* replacer_; + static MockDeathTestFactory* factory_; + + static void SetUpTestCase() { + factory_ = new MockDeathTestFactory; + replacer_ = new testing::internal::ReplaceDeathTestFactory(factory_); + } + + static void TearDownTestCase() { + delete replacer_; + replacer_ = NULL; + delete factory_; + factory_ = NULL; + } + + // Runs a death test that breaks the rules by returning. Such a death + // test cannot be run directly from a test routine that uses a + // MockDeathTest, or the remainder of the routine will not be executed. + static void RunReturningDeathTest(bool* flag) { + ASSERT_DEATH({ // NOLINT + *flag = true; + return; + }, ""); + } +}; + +testing::internal::ReplaceDeathTestFactory* MacroLogicDeathTest::replacer_ + = NULL; +MockDeathTestFactory* MacroLogicDeathTest::factory_ = NULL; + + +// Test that nothing happens when the factory doesn't return a DeathTest: +TEST_F(MacroLogicDeathTest, NothingHappens) { + bool flag = false; + factory_->SetParameters(false, DeathTest::OVERSEE_TEST, 0, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_FALSE(flag); + EXPECT_EQ(0, factory_->AssumeRoleCalls()); + EXPECT_EQ(0, factory_->WaitCalls()); + EXPECT_EQ(0, factory_->PassedCalls()); + EXPECT_EQ(0, factory_->AbortCalls()); + EXPECT_FALSE(factory_->TestDeleted()); +} + +// Test that the parent process doesn't run the death test code, +// and that the Passed method returns false when the (simulated) +// child process exits with status 0: +TEST_F(MacroLogicDeathTest, ChildExitsSuccessfully) { + bool flag = false; + factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 0, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_FALSE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(1, factory_->WaitCalls()); + ASSERT_EQ(1, factory_->PassedCalls()); + EXPECT_FALSE(factory_->PassedArgument(0)); + EXPECT_EQ(0, factory_->AbortCalls()); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that the Passed method was given the argument "true" when +// the (simulated) child process exits with status 1: +TEST_F(MacroLogicDeathTest, ChildExitsUnsuccessfully) { + bool flag = false; + factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 1, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_FALSE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(1, factory_->WaitCalls()); + ASSERT_EQ(1, factory_->PassedCalls()); + EXPECT_TRUE(factory_->PassedArgument(0)); + EXPECT_EQ(0, factory_->AbortCalls()); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that the (simulated) child process executes the death test +// code, and is aborted with the correct AbortReason if it +// executes a return statement. +TEST_F(MacroLogicDeathTest, ChildPerformsReturn) { + bool flag = false; + factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); + RunReturningDeathTest(&flag); + EXPECT_TRUE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(0, factory_->WaitCalls()); + EXPECT_EQ(0, factory_->PassedCalls()); + EXPECT_EQ(1, factory_->AbortCalls()); + EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, + factory_->AbortArgument(0)); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that the (simulated) child process is aborted with the +// correct AbortReason if it does not die. +TEST_F(MacroLogicDeathTest, ChildDoesNotDie) { + bool flag = false; + factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_TRUE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(0, factory_->WaitCalls()); + EXPECT_EQ(0, factory_->PassedCalls()); + // This time there are two calls to Abort: one since the test didn't + // die, and another from the ReturnSentinel when it's destroyed. The + // sentinel normally isn't destroyed if a test doesn't die, since + // _exit(2) is called in that case by ForkingDeathTest, but not by + // our MockDeathTest. + ASSERT_EQ(2, factory_->AbortCalls()); + EXPECT_EQ(DeathTest::TEST_DID_NOT_DIE, + factory_->AbortArgument(0)); + EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, + factory_->AbortArgument(1)); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that a successful death test does not register a successful +// test part. +TEST(SuccessRegistrationDeathTest, NoSuccessPart) { + EXPECT_DEATH(_exit(1), ""); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +TEST(StreamingAssertionsDeathTest, DeathTest) { + EXPECT_DEATH(_exit(1), "") << "unexpected failure"; + ASSERT_DEATH(_exit(1), "") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_DEATH(_exit(0), "") << "expected failure"; + }, "expected failure"); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_DEATH(_exit(0), "") << "expected failure"; + }, "expected failure"); +} + +// Tests that GetLastErrnoDescription returns an empty string when the +// last error is 0 and non-empty string when it is non-zero. +TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks) { + errno = ENOENT; + EXPECT_STRNE("", GetLastErrnoDescription().c_str()); + errno = 0; + EXPECT_STREQ("", GetLastErrnoDescription().c_str()); +} + +# if GTEST_OS_WINDOWS +TEST(AutoHandleTest, AutoHandleWorks) { + HANDLE handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + // Tests that the AutoHandle is correctly initialized with a handle. + testing::internal::AutoHandle auto_handle(handle); + EXPECT_EQ(handle, auto_handle.Get()); + + // Tests that Reset assigns INVALID_HANDLE_VALUE. + // Note that this cannot verify whether the original handle is closed. + auto_handle.Reset(); + EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle.Get()); + + // Tests that Reset assigns the new handle. + // Note that this cannot verify whether the original handle is closed. + handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + auto_handle.Reset(handle); + EXPECT_EQ(handle, auto_handle.Get()); + + // Tests that AutoHandle contains INVALID_HANDLE_VALUE by default. + testing::internal::AutoHandle auto_handle2; + EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle2.Get()); +} +# endif // GTEST_OS_WINDOWS + +# if GTEST_OS_WINDOWS +typedef unsigned __int64 BiggestParsable; +typedef signed __int64 BiggestSignedParsable; +const BiggestParsable kBiggestParsableMax = ULLONG_MAX; +const BiggestSignedParsable kBiggestSignedParsableMax = LLONG_MAX; +# else +typedef unsigned long long BiggestParsable; +typedef signed long long BiggestSignedParsable; +const BiggestParsable kBiggestParsableMax = + ::std::numeric_limits::max(); +const BiggestSignedParsable kBiggestSignedParsableMax = + ::std::numeric_limits::max(); +# endif // GTEST_OS_WINDOWS + +TEST(ParseNaturalNumberTest, RejectsInvalidFormat) { + BiggestParsable result = 0; + + // Rejects non-numbers. + EXPECT_FALSE(ParseNaturalNumber(String("non-number string"), &result)); + + // Rejects numbers with whitespace prefix. + EXPECT_FALSE(ParseNaturalNumber(String(" 123"), &result)); + + // Rejects negative numbers. + EXPECT_FALSE(ParseNaturalNumber(String("-123"), &result)); + + // Rejects numbers starting with a plus sign. + EXPECT_FALSE(ParseNaturalNumber(String("+123"), &result)); + errno = 0; +} + +TEST(ParseNaturalNumberTest, RejectsOverflownNumbers) { + BiggestParsable result = 0; + + EXPECT_FALSE(ParseNaturalNumber(String("99999999999999999999999"), &result)); + + signed char char_result = 0; + EXPECT_FALSE(ParseNaturalNumber(String("200"), &char_result)); + errno = 0; +} + +TEST(ParseNaturalNumberTest, AcceptsValidNumbers) { + BiggestParsable result = 0; + + result = 0; + ASSERT_TRUE(ParseNaturalNumber(String("123"), &result)); + EXPECT_EQ(123U, result); + + // Check 0 as an edge case. + result = 1; + ASSERT_TRUE(ParseNaturalNumber(String("0"), &result)); + EXPECT_EQ(0U, result); + + result = 1; + ASSERT_TRUE(ParseNaturalNumber(String("00000"), &result)); + EXPECT_EQ(0U, result); +} + +TEST(ParseNaturalNumberTest, AcceptsTypeLimits) { + Message msg; + msg << kBiggestParsableMax; + + BiggestParsable result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg.GetString(), &result)); + EXPECT_EQ(kBiggestParsableMax, result); + + Message msg2; + msg2 << kBiggestSignedParsableMax; + + BiggestSignedParsable signed_result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg2.GetString(), &signed_result)); + EXPECT_EQ(kBiggestSignedParsableMax, signed_result); + + Message msg3; + msg3 << INT_MAX; + + int int_result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg3.GetString(), &int_result)); + EXPECT_EQ(INT_MAX, int_result); + + Message msg4; + msg4 << UINT_MAX; + + unsigned int uint_result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg4.GetString(), &uint_result)); + EXPECT_EQ(UINT_MAX, uint_result); +} + +TEST(ParseNaturalNumberTest, WorksForShorterIntegers) { + short short_result = 0; + ASSERT_TRUE(ParseNaturalNumber(String("123"), &short_result)); + EXPECT_EQ(123, short_result); + + signed char char_result = 0; + ASSERT_TRUE(ParseNaturalNumber(String("123"), &char_result)); + EXPECT_EQ(123, char_result); +} + +# if GTEST_OS_WINDOWS +TEST(EnvironmentTest, HandleFitsIntoSizeT) { + // TODO(vladl@google.com): Remove this test after this condition is verified + // in a static assertion in gtest-death-test.cc in the function + // GetStatusFileDescriptor. + ASSERT_TRUE(sizeof(HANDLE) <= sizeof(size_t)); +} +# endif // GTEST_OS_WINDOWS + +// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED trigger +// failures when death tests are available on the system. +TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable) { + EXPECT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestExpectMacro"), + "death inside CondDeathTestExpectMacro"); + ASSERT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestAssertMacro"), + "death inside CondDeathTestAssertMacro"); + + // Empty statement will not crash, which must trigger a failure. + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH_IF_SUPPORTED(;, ""), ""); + EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(;, ""), ""); +} + +#else + +using testing::internal::CaptureStderr; +using testing::internal::GetCapturedStderr; +using testing::internal::String; + +// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still +// defined but do not trigger failures when death tests are not available on +// the system. +TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) { + // Empty statement will not crash, but that should not trigger a failure + // when death tests are not supported. + CaptureStderr(); + EXPECT_DEATH_IF_SUPPORTED(;, ""); + String output = GetCapturedStderr(); + ASSERT_TRUE(NULL != strstr(output.c_str(), + "Death tests are not supported on this platform")); + ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); + + // The streamed message should not be printed as there is no test failure. + CaptureStderr(); + EXPECT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; + output = GetCapturedStderr(); + ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); + + CaptureStderr(); + ASSERT_DEATH_IF_SUPPORTED(;, ""); // NOLINT + output = GetCapturedStderr(); + ASSERT_TRUE(NULL != strstr(output.c_str(), + "Death tests are not supported on this platform")); + ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); + + CaptureStderr(); + ASSERT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; // NOLINT + output = GetCapturedStderr(); + ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); +} + +void FuncWithAssert(int* n) { + ASSERT_DEATH_IF_SUPPORTED(return;, ""); + (*n)++; +} + +// Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current +// function (as ASSERT_DEATH does) if death tests are not supported. +TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { + int n = 0; + FuncWithAssert(&n); + EXPECT_EQ(1, n); +} +#endif // GTEST_HAS_DEATH_TEST + +// Tests that the death test macros expand to code which may or may not +// be followed by operator<<, and that in either case the complete text +// comprises only a single C++ statement. +// +// The syntax should work whether death tests are available or not. +TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { + if (AlwaysFalse()) + // This would fail if executed; this is a compilation test only + ASSERT_DEATH_IF_SUPPORTED(return, ""); + + if (AlwaysTrue()) + EXPECT_DEATH_IF_SUPPORTED(_exit(1), ""); + else + // This empty "else" branch is meant to ensure that EXPECT_DEATH + // doesn't expand into an "if" statement without an "else" + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die"; + + if (AlwaysFalse()) + ; // NOLINT + else + EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; +} + +// Tests that conditional death test macros expand to code which interacts +// well with switch statements. +TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { +// Microsoft compiler usually complains about switch statements without +// case labels. We suppress that warning for this test. +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4065) +#endif // _MSC_VER + + switch (0) + default: + ASSERT_DEATH_IF_SUPPORTED(_exit(1), "") + << "exit in default switch handler"; + + switch (0) + case 0: + EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case"; + +#ifdef _MSC_VER +# pragma warning(pop) +#endif // _MSC_VER +} + +// Tests that a test case whose name ends with "DeathTest" works fine +// on Windows. +TEST(NotADeathTest, Test) { + SUCCEED(); +} diff --git a/third_party/googletest/src/test/gtest-filepath_test.cc b/third_party/googletest/src/test/gtest-filepath_test.cc new file mode 100644 index 0000000..66d4118 --- /dev/null +++ b/third_party/googletest/src/test/gtest-filepath_test.cc @@ -0,0 +1,696 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This file tests classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included from gtest_unittest.cc, to avoid changing +// build or make-files for some existing Google Test clients. Do not +// #include this file anywhere else! + +#include "gtest/internal/gtest-filepath.h" +#include "gtest/gtest.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS_MOBILE +# include // NOLINT +#elif GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS_MOBILE + +namespace testing { +namespace internal { +namespace { + +#if GTEST_OS_WINDOWS_MOBILE +// TODO(wan@google.com): Move these to the POSIX adapter section in +// gtest-port.h. + +// Windows CE doesn't have the remove C function. +int remove(const char* path) { + LPCWSTR wpath = String::AnsiToUtf16(path); + int ret = DeleteFile(wpath) ? 0 : -1; + delete [] wpath; + return ret; +} +// Windows CE doesn't have the _rmdir C function. +int _rmdir(const char* path) { + FilePath filepath(path); + LPCWSTR wpath = String::AnsiToUtf16( + filepath.RemoveTrailingPathSeparator().c_str()); + int ret = RemoveDirectory(wpath) ? 0 : -1; + delete [] wpath; + return ret; +} + +#else + +TEST(GetCurrentDirTest, ReturnsCurrentDir) { + const FilePath original_dir = FilePath::GetCurrentDir(); + EXPECT_FALSE(original_dir.IsEmpty()); + + posix::ChDir(GTEST_PATH_SEP_); + const FilePath cwd = FilePath::GetCurrentDir(); + posix::ChDir(original_dir.c_str()); + +# if GTEST_OS_WINDOWS + + // Skips the ":". + const char* const cwd_without_drive = strchr(cwd.c_str(), ':'); + ASSERT_TRUE(cwd_without_drive != NULL); + EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1); + +# else + + EXPECT_STREQ(GTEST_PATH_SEP_, cwd.c_str()); + +# endif +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +TEST(IsEmptyTest, ReturnsTrueForEmptyPath) { + EXPECT_TRUE(FilePath("").IsEmpty()); + EXPECT_TRUE(FilePath(NULL).IsEmpty()); +} + +TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) { + EXPECT_FALSE(FilePath("a").IsEmpty()); + EXPECT_FALSE(FilePath(".").IsEmpty()); + EXPECT_FALSE(FilePath("a/b").IsEmpty()); + EXPECT_FALSE(FilePath("a\\b\\").IsEmpty()); +} + +// RemoveDirectoryName "" -> "" +TEST(RemoveDirectoryNameTest, WhenEmptyName) { + EXPECT_STREQ("", FilePath("").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName "afile" -> "afile" +TEST(RemoveDirectoryNameTest, ButNoDirectory) { + EXPECT_STREQ("afile", + FilePath("afile").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName "/afile" -> "afile" +TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) { + EXPECT_STREQ("afile", + FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName "adir/" -> "" +TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) { + EXPECT_STREQ("", + FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName "adir/afile" -> "afile" +TEST(RemoveDirectoryNameTest, ShouldGiveFileName) { + EXPECT_STREQ("afile", + FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName "adir/subdir/afile" -> "afile" +TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { + EXPECT_STREQ("afile", + FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") + .RemoveDirectoryName().c_str()); +} + +#if GTEST_HAS_ALT_PATH_SEP_ + +// Tests that RemoveDirectoryName() works with the alternate separator +// on Windows. + +// RemoveDirectoryName("/afile") -> "afile" +TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) { + EXPECT_STREQ("afile", + FilePath("/afile").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName("adir/") -> "" +TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) { + EXPECT_STREQ("", + FilePath("adir/").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName("adir/afile") -> "afile" +TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) { + EXPECT_STREQ("afile", + FilePath("adir/afile").RemoveDirectoryName().c_str()); +} + +// RemoveDirectoryName("adir/subdir/afile") -> "afile" +TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) { + EXPECT_STREQ("afile", + FilePath("adir/subdir/afile").RemoveDirectoryName().c_str()); +} + +#endif + +// RemoveFileName "" -> "./" +TEST(RemoveFileNameTest, EmptyName) { +#if GTEST_OS_WINDOWS_MOBILE + // On Windows CE, we use the root as the current directory. + EXPECT_STREQ(GTEST_PATH_SEP_, + FilePath("").RemoveFileName().c_str()); +#else + EXPECT_STREQ("." GTEST_PATH_SEP_, + FilePath("").RemoveFileName().c_str()); +#endif +} + +// RemoveFileName "adir/" -> "adir/" +TEST(RemoveFileNameTest, ButNoFile) { + EXPECT_STREQ("adir" GTEST_PATH_SEP_, + FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().c_str()); +} + +// RemoveFileName "adir/afile" -> "adir/" +TEST(RemoveFileNameTest, GivesDirName) { + EXPECT_STREQ("adir" GTEST_PATH_SEP_, + FilePath("adir" GTEST_PATH_SEP_ "afile") + .RemoveFileName().c_str()); +} + +// RemoveFileName "adir/subdir/afile" -> "adir/subdir/" +TEST(RemoveFileNameTest, GivesDirAndSubDirName) { + EXPECT_STREQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, + FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") + .RemoveFileName().c_str()); +} + +// RemoveFileName "/afile" -> "/" +TEST(RemoveFileNameTest, GivesRootDir) { + EXPECT_STREQ(GTEST_PATH_SEP_, + FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().c_str()); +} + +#if GTEST_HAS_ALT_PATH_SEP_ + +// Tests that RemoveFileName() works with the alternate separator on +// Windows. + +// RemoveFileName("adir/") -> "adir/" +TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) { + EXPECT_STREQ("adir" GTEST_PATH_SEP_, + FilePath("adir/").RemoveFileName().c_str()); +} + +// RemoveFileName("adir/afile") -> "adir/" +TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) { + EXPECT_STREQ("adir" GTEST_PATH_SEP_, + FilePath("adir/afile").RemoveFileName().c_str()); +} + +// RemoveFileName("adir/subdir/afile") -> "adir/subdir/" +TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) { + EXPECT_STREQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, + FilePath("adir/subdir/afile").RemoveFileName().c_str()); +} + +// RemoveFileName("/afile") -> "\" +TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) { + EXPECT_STREQ(GTEST_PATH_SEP_, + FilePath("/afile").RemoveFileName().c_str()); +} + +#endif + +TEST(MakeFileNameTest, GenerateWhenNumberIsZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), + 0, "xml"); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); +} + +TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), + 12, "xml"); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.c_str()); +} + +TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar"), 0, "xml"); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); +} + +TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar"), 12, "xml"); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.c_str()); +} + +TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) { + FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), + 0, "xml"); + EXPECT_STREQ("bar.xml", actual.c_str()); +} + +TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) { + FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), + 14, "xml"); + EXPECT_STREQ("bar_14.xml", actual.c_str()); +} + +TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo"), + FilePath("bar.xml")); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); +} + +TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar.xml")); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); +} + +TEST(ConcatPathsTest, Path1BeingEmpty) { + FilePath actual = FilePath::ConcatPaths(FilePath(""), + FilePath("bar.xml")); + EXPECT_STREQ("bar.xml", actual.c_str()); +} + +TEST(ConcatPathsTest, Path2BeingEmpty) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo"), + FilePath("")); + EXPECT_STREQ("foo" GTEST_PATH_SEP_, actual.c_str()); +} + +TEST(ConcatPathsTest, BothPathBeingEmpty) { + FilePath actual = FilePath::ConcatPaths(FilePath(""), + FilePath("")); + EXPECT_STREQ("", actual.c_str()); +} + +TEST(ConcatPathsTest, Path1ContainsPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"), + FilePath("foobar.xml")); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml", + actual.c_str()); +} + +TEST(ConcatPathsTest, Path2ContainsPathSep) { + FilePath actual = FilePath::ConcatPaths( + FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar" GTEST_PATH_SEP_ "bar.xml")); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml", + actual.c_str()); +} + +TEST(ConcatPathsTest, Path2EndsWithPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo"), + FilePath("bar" GTEST_PATH_SEP_)); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.c_str()); +} + +// RemoveTrailingPathSeparator "" -> "" +TEST(RemoveTrailingPathSeparatorTest, EmptyString) { + EXPECT_STREQ("", + FilePath("").RemoveTrailingPathSeparator().c_str()); +} + +// RemoveTrailingPathSeparator "foo" -> "foo" +TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) { + EXPECT_STREQ("foo", + FilePath("foo").RemoveTrailingPathSeparator().c_str()); +} + +// RemoveTrailingPathSeparator "foo/" -> "foo" +TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) { + EXPECT_STREQ( + "foo", + FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().c_str()); +#if GTEST_HAS_ALT_PATH_SEP_ + EXPECT_STREQ("foo", + FilePath("foo/").RemoveTrailingPathSeparator().c_str()); +#endif +} + +// RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/" +TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) { + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_) + .RemoveTrailingPathSeparator().c_str()); +} + +// RemoveTrailingPathSeparator "foo/bar" -> "foo/bar" +TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) { + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ "bar") + .RemoveTrailingPathSeparator().c_str()); +} + +TEST(DirectoryTest, RootDirectoryExists) { +#if GTEST_OS_WINDOWS // We are on Windows. + char current_drive[_MAX_PATH]; // NOLINT + current_drive[0] = static_cast(_getdrive() + 'A' - 1); + current_drive[1] = ':'; + current_drive[2] = '\\'; + current_drive[3] = '\0'; + EXPECT_TRUE(FilePath(current_drive).DirectoryExists()); +#else + EXPECT_TRUE(FilePath("/").DirectoryExists()); +#endif // GTEST_OS_WINDOWS +} + +#if GTEST_OS_WINDOWS +TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) { + const int saved_drive_ = _getdrive(); + // Find a drive that doesn't exist. Start with 'Z' to avoid common ones. + for (char drive = 'Z'; drive >= 'A'; drive--) + if (_chdrive(drive - 'A' + 1) == -1) { + char non_drive[_MAX_PATH]; // NOLINT + non_drive[0] = drive; + non_drive[1] = ':'; + non_drive[2] = '\\'; + non_drive[3] = '\0'; + EXPECT_FALSE(FilePath(non_drive).DirectoryExists()); + break; + } + _chdrive(saved_drive_); +} +#endif // GTEST_OS_WINDOWS + +#if !GTEST_OS_WINDOWS_MOBILE +// Windows CE _does_ consider an empty directory to exist. +TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) { + EXPECT_FALSE(FilePath("").DirectoryExists()); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +TEST(DirectoryTest, CurrentDirectoryExists) { +#if GTEST_OS_WINDOWS // We are on Windows. +# ifndef _WIN32_CE // Windows CE doesn't have a current directory. + + EXPECT_TRUE(FilePath(".").DirectoryExists()); + EXPECT_TRUE(FilePath(".\\").DirectoryExists()); + +# endif // _WIN32_CE +#else + EXPECT_TRUE(FilePath(".").DirectoryExists()); + EXPECT_TRUE(FilePath("./").DirectoryExists()); +#endif // GTEST_OS_WINDOWS +} + +TEST(NormalizeTest, NullStringsEqualEmptyDirectory) { + EXPECT_STREQ("", FilePath(NULL).c_str()); + EXPECT_STREQ("", FilePath(String(NULL)).c_str()); +} + +// "foo/bar" == foo//bar" == "foo///bar" +TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) { + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ "bar").c_str()); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); + EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ + GTEST_PATH_SEP_ "bar").c_str()); +} + +// "/bar" == //bar" == "///bar" +TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) { + EXPECT_STREQ(GTEST_PATH_SEP_ "bar", + FilePath(GTEST_PATH_SEP_ "bar").c_str()); + EXPECT_STREQ(GTEST_PATH_SEP_ "bar", + FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); + EXPECT_STREQ(GTEST_PATH_SEP_ "bar", + FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); +} + +// "foo/" == foo//" == "foo///" +TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) { + EXPECT_STREQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_).c_str()); + EXPECT_STREQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).c_str()); + EXPECT_STREQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).c_str()); +} + +#if GTEST_HAS_ALT_PATH_SEP_ + +// Tests that separators at the end of the string are normalized +// regardless of their combination (e.g. "foo\" =="foo/\" == +// "foo\\/"). +TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd) { + EXPECT_STREQ("foo" GTEST_PATH_SEP_, + FilePath("foo/").c_str()); + EXPECT_STREQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_ "/").c_str()); + EXPECT_STREQ("foo" GTEST_PATH_SEP_, + FilePath("foo//" GTEST_PATH_SEP_).c_str()); +} + +#endif + +TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) { + FilePath default_path; + FilePath non_default_path("path"); + non_default_path = default_path; + EXPECT_STREQ("", non_default_path.c_str()); + EXPECT_STREQ("", default_path.c_str()); // RHS var is unchanged. +} + +TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) { + FilePath non_default_path("path"); + FilePath default_path; + default_path = non_default_path; + EXPECT_STREQ("path", default_path.c_str()); + EXPECT_STREQ("path", non_default_path.c_str()); // RHS var is unchanged. +} + +TEST(AssignmentOperatorTest, ConstAssignedToNonConst) { + const FilePath const_default_path("const_path"); + FilePath non_default_path("path"); + non_default_path = const_default_path; + EXPECT_STREQ("const_path", non_default_path.c_str()); +} + +class DirectoryCreationTest : public Test { + protected: + virtual void SetUp() { + testdata_path_.Set(FilePath(String::Format("%s%s%s", + TempDir().c_str(), GetCurrentExecutableName().c_str(), + "_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_))); + testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator()); + + unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), + 0, "txt")); + unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), + 1, "txt")); + + remove(testdata_file_.c_str()); + remove(unique_file0_.c_str()); + remove(unique_file1_.c_str()); + posix::RmDir(testdata_path_.c_str()); + } + + virtual void TearDown() { + remove(testdata_file_.c_str()); + remove(unique_file0_.c_str()); + remove(unique_file1_.c_str()); + posix::RmDir(testdata_path_.c_str()); + } + + String TempDir() const { +#if GTEST_OS_WINDOWS_MOBILE + return String("\\temp\\"); +#elif GTEST_OS_WINDOWS + const char* temp_dir = posix::GetEnv("TEMP"); + if (temp_dir == NULL || temp_dir[0] == '\0') + return String("\\temp\\"); + else if (String(temp_dir).EndsWith("\\")) + return String(temp_dir); + else + return String::Format("%s\\", temp_dir); +#else + return String("/tmp/"); +#endif // GTEST_OS_WINDOWS_MOBILE + } + + void CreateTextFile(const char* filename) { + FILE* f = posix::FOpen(filename, "w"); + fprintf(f, "text\n"); + fclose(f); + } + + // Strings representing a directory and a file, with identical paths + // except for the trailing separator character that distinquishes + // a directory named 'test' from a file named 'test'. Example names: + FilePath testdata_path_; // "/tmp/directory_creation/test/" + FilePath testdata_file_; // "/tmp/directory_creation/test" + FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt" + FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt" +}; + +TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively) { + EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.c_str(); + EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); + EXPECT_TRUE(testdata_path_.DirectoryExists()); +} + +TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) { + EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.c_str(); + EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); + // Call 'create' again... should still succeed. + EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); +} + +TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename) { + FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_, + FilePath("unique"), "txt")); + EXPECT_STREQ(unique_file0_.c_str(), file_path.c_str()); + EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there + + testdata_path_.CreateDirectoriesRecursively(); + EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there + CreateTextFile(file_path.c_str()); + EXPECT_TRUE(file_path.FileOrDirectoryExists()); + + FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_, + FilePath("unique"), "txt")); + EXPECT_STREQ(unique_file1_.c_str(), file_path2.c_str()); + EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there + CreateTextFile(file_path2.c_str()); + EXPECT_TRUE(file_path2.FileOrDirectoryExists()); +} + +TEST_F(DirectoryCreationTest, CreateDirectoriesFail) { + // force a failure by putting a file where we will try to create a directory. + CreateTextFile(testdata_file_.c_str()); + EXPECT_TRUE(testdata_file_.FileOrDirectoryExists()); + EXPECT_FALSE(testdata_file_.DirectoryExists()); + EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively()); +} + +TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile) { + const FilePath test_detail_xml("test_detail.xml"); + EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively()); +} + +TEST(FilePathTest, DefaultConstructor) { + FilePath fp; + EXPECT_STREQ("", fp.c_str()); +} + +TEST(FilePathTest, CharAndCopyConstructors) { + const FilePath fp("spicy"); + EXPECT_STREQ("spicy", fp.c_str()); + + const FilePath fp_copy(fp); + EXPECT_STREQ("spicy", fp_copy.c_str()); +} + +TEST(FilePathTest, StringConstructor) { + const FilePath fp(String("cider")); + EXPECT_STREQ("cider", fp.c_str()); +} + +TEST(FilePathTest, Set) { + const FilePath apple("apple"); + FilePath mac("mac"); + mac.Set(apple); // Implement Set() since overloading operator= is forbidden. + EXPECT_STREQ("apple", mac.c_str()); + EXPECT_STREQ("apple", apple.c_str()); +} + +TEST(FilePathTest, ToString) { + const FilePath file("drink"); + String str(file.ToString()); + EXPECT_STREQ("drink", str.c_str()); +} + +TEST(FilePathTest, RemoveExtension) { + EXPECT_STREQ("app", FilePath("app.exe").RemoveExtension("exe").c_str()); + EXPECT_STREQ("APP", FilePath("APP.EXE").RemoveExtension("exe").c_str()); +} + +TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) { + EXPECT_STREQ("app", FilePath("app").RemoveExtension("exe").c_str()); +} + +TEST(FilePathTest, IsDirectory) { + EXPECT_FALSE(FilePath("cola").IsDirectory()); + EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory()); +#if GTEST_HAS_ALT_PATH_SEP_ + EXPECT_TRUE(FilePath("koala/").IsDirectory()); +#endif +} + +TEST(FilePathTest, IsAbsolutePath) { + EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); + EXPECT_FALSE(FilePath("").IsAbsolutePath()); +#if GTEST_OS_WINDOWS + EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not" + GTEST_PATH_SEP_ "relative").IsAbsolutePath()); + EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath()); + EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not" + GTEST_PATH_SEP_ "relative").IsAbsolutePath()); +#else + EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative") + .IsAbsolutePath()); +#endif // GTEST_OS_WINDOWS +} + +TEST(FilePathTest, IsRootDirectory) { +#if GTEST_OS_WINDOWS + EXPECT_TRUE(FilePath("a:\\").IsRootDirectory()); + EXPECT_TRUE(FilePath("Z:/").IsRootDirectory()); + EXPECT_TRUE(FilePath("e://").IsRootDirectory()); + EXPECT_FALSE(FilePath("").IsRootDirectory()); + EXPECT_FALSE(FilePath("b:").IsRootDirectory()); + EXPECT_FALSE(FilePath("b:a").IsRootDirectory()); + EXPECT_FALSE(FilePath("8:/").IsRootDirectory()); + EXPECT_FALSE(FilePath("c|/").IsRootDirectory()); +#else + EXPECT_TRUE(FilePath("/").IsRootDirectory()); + EXPECT_TRUE(FilePath("//").IsRootDirectory()); + EXPECT_FALSE(FilePath("").IsRootDirectory()); + EXPECT_FALSE(FilePath("\\").IsRootDirectory()); + EXPECT_FALSE(FilePath("/x").IsRootDirectory()); +#endif +} + +} // namespace +} // namespace internal +} // namespace testing diff --git a/third_party/googletest/src/test/gtest-linked_ptr_test.cc b/third_party/googletest/src/test/gtest-linked_ptr_test.cc new file mode 100644 index 0000000..0d5508a --- /dev/null +++ b/third_party/googletest/src/test/gtest-linked_ptr_test.cc @@ -0,0 +1,155 @@ +// Copyright 2003, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// Ported to Windows: Vadim Berman (vadimb@google.com) + +#include "gtest/internal/gtest-linked_ptr.h" + +#include +#include "gtest/gtest.h" + +namespace { + +using testing::Message; +using testing::internal::linked_ptr; + +int num; +Message* history = NULL; + +// Class which tracks allocation/deallocation +class A { + public: + A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; } + virtual ~A() { *history << "A" << mynum << " dtor\n"; } + virtual void Use() { *history << "A" << mynum << " use\n"; } + protected: + int mynum; +}; + +// Subclass +class B : public A { + public: + B() { *history << "B" << mynum << " ctor\n"; } + ~B() { *history << "B" << mynum << " dtor\n"; } + virtual void Use() { *history << "B" << mynum << " use\n"; } +}; + +class LinkedPtrTest : public testing::Test { + public: + LinkedPtrTest() { + num = 0; + history = new Message; + } + + virtual ~LinkedPtrTest() { + delete history; + history = NULL; + } +}; + +TEST_F(LinkedPtrTest, GeneralTest) { + { + linked_ptr a0, a1, a2; + // Use explicit function call notation here to suppress self-assign warning. + a0.operator=(a0); + a1 = a2; + ASSERT_EQ(a0.get(), static_cast(NULL)); + ASSERT_EQ(a1.get(), static_cast(NULL)); + ASSERT_EQ(a2.get(), static_cast(NULL)); + ASSERT_TRUE(a0 == NULL); + ASSERT_TRUE(a1 == NULL); + ASSERT_TRUE(a2 == NULL); + + { + linked_ptr a3(new A); + a0 = a3; + ASSERT_TRUE(a0 == a3); + ASSERT_TRUE(a0 != NULL); + ASSERT_TRUE(a0.get() == a3); + ASSERT_TRUE(a0 == a3.get()); + linked_ptr a4(a0); + a1 = a4; + linked_ptr a5(new A); + ASSERT_TRUE(a5.get() != a3); + ASSERT_TRUE(a5 != a3.get()); + a2 = a5; + linked_ptr b0(new B); + linked_ptr a6(b0); + ASSERT_TRUE(b0 == a6); + ASSERT_TRUE(a6 == b0); + ASSERT_TRUE(b0 != NULL); + a5 = b0; + a5 = b0; + a3->Use(); + a4->Use(); + a5->Use(); + a6->Use(); + b0->Use(); + (*b0).Use(); + b0.get()->Use(); + } + + a0->Use(); + a1->Use(); + a2->Use(); + + a1 = a2; + a2.reset(new A); + a0.reset(); + + linked_ptr a7; + } + + ASSERT_STREQ( + "A0 ctor\n" + "A1 ctor\n" + "A2 ctor\n" + "B2 ctor\n" + "A0 use\n" + "A0 use\n" + "B2 use\n" + "B2 use\n" + "B2 use\n" + "B2 use\n" + "B2 use\n" + "B2 dtor\n" + "A2 dtor\n" + "A0 use\n" + "A0 use\n" + "A1 use\n" + "A3 ctor\n" + "A0 dtor\n" + "A3 dtor\n" + "A1 dtor\n", + history->GetString().c_str() + ); +} + +} // Unnamed namespace diff --git a/third_party/googletest/src/test/gtest-listener_test.cc b/third_party/googletest/src/test/gtest-listener_test.cc new file mode 100644 index 0000000..2aa08ef --- /dev/null +++ b/third_party/googletest/src/test/gtest-listener_test.cc @@ -0,0 +1,313 @@ +// Copyright 2009 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) +// +// The Google C++ Testing Framework (Google Test) +// +// This file verifies Google Test event listeners receive events at the +// right times. + +#include "gtest/gtest.h" +#include + +using ::testing::AddGlobalTestEnvironment; +using ::testing::Environment; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestCase; +using ::testing::TestEventListener; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; +using ::testing::internal::String; + +// Used by tests to register their events. +std::vector* g_events = NULL; + +namespace testing { +namespace internal { + +class EventRecordingListener : public TestEventListener { + public: + EventRecordingListener(const char* name) : name_(name) {} + + protected: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { + g_events->push_back(GetFullMethodName("OnTestProgramStart")); + } + + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int iteration) { + Message message; + message << GetFullMethodName("OnTestIterationStart") + << "(" << iteration << ")"; + g_events->push_back(message.GetString()); + } + + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) { + g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart")); + } + + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) { + g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd")); + } + + virtual void OnTestCaseStart(const TestCase& /*test_case*/) { + g_events->push_back(GetFullMethodName("OnTestCaseStart")); + } + + virtual void OnTestStart(const TestInfo& /*test_info*/) { + g_events->push_back(GetFullMethodName("OnTestStart")); + } + + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) { + g_events->push_back(GetFullMethodName("OnTestPartResult")); + } + + virtual void OnTestEnd(const TestInfo& /*test_info*/) { + g_events->push_back(GetFullMethodName("OnTestEnd")); + } + + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) { + g_events->push_back(GetFullMethodName("OnTestCaseEnd")); + } + + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) { + g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart")); + } + + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) { + g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd")); + } + + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int iteration) { + Message message; + message << GetFullMethodName("OnTestIterationEnd") + << "(" << iteration << ")"; + g_events->push_back(message.GetString()); + } + + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { + g_events->push_back(GetFullMethodName("OnTestProgramEnd")); + } + + private: + String GetFullMethodName(const char* name) { + Message message; + message << name_ << "." << name; + return message.GetString(); + } + + String name_; +}; + +class EnvironmentInvocationCatcher : public Environment { + protected: + virtual void SetUp() { + g_events->push_back(String("Environment::SetUp")); + } + + virtual void TearDown() { + g_events->push_back(String("Environment::TearDown")); + } +}; + +class ListenerTest : public Test { + protected: + static void SetUpTestCase() { + g_events->push_back(String("ListenerTest::SetUpTestCase")); + } + + static void TearDownTestCase() { + g_events->push_back(String("ListenerTest::TearDownTestCase")); + } + + virtual void SetUp() { + g_events->push_back(String("ListenerTest::SetUp")); + } + + virtual void TearDown() { + g_events->push_back(String("ListenerTest::TearDown")); + } +}; + +TEST_F(ListenerTest, DoesFoo) { + // Test execution order within a test case is not guaranteed so we are not + // recording the test name. + g_events->push_back(String("ListenerTest::* Test Body")); + SUCCEED(); // Triggers OnTestPartResult. +} + +TEST_F(ListenerTest, DoesBar) { + g_events->push_back(String("ListenerTest::* Test Body")); + SUCCEED(); // Triggers OnTestPartResult. +} + +} // namespace internal + +} // namespace testing + +using ::testing::internal::EnvironmentInvocationCatcher; +using ::testing::internal::EventRecordingListener; + +void VerifyResults(const std::vector& data, + const char* const* expected_data, + int expected_data_size) { + const int actual_size = data.size(); + // If the following assertion fails, a new entry will be appended to + // data. Hence we save data.size() first. + EXPECT_EQ(expected_data_size, actual_size); + + // Compares the common prefix. + const int shorter_size = expected_data_size <= actual_size ? + expected_data_size : actual_size; + int i = 0; + for (; i < shorter_size; ++i) { + ASSERT_STREQ(expected_data[i], data[i].c_str()) + << "at position " << i; + } + + // Prints extra elements in the actual data. + for (; i < actual_size; ++i) { + printf(" Actual event #%d: %s\n", i, data[i].c_str()); + } +} + +int main(int argc, char **argv) { + std::vector events; + g_events = &events; + InitGoogleTest(&argc, argv); + + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener("1st")); + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener("2nd")); + + AddGlobalTestEnvironment(new EnvironmentInvocationCatcher); + + GTEST_CHECK_(events.size() == 0) + << "AddGlobalTestEnvironment should not generate any events itself."; + + ::testing::GTEST_FLAG(repeat) = 2; + int ret_val = RUN_ALL_TESTS(); + + const char* const expected_events[] = { + "1st.OnTestProgramStart", + "2nd.OnTestProgramStart", + "1st.OnTestIterationStart(0)", + "2nd.OnTestIterationStart(0)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "1st.OnTestCaseStart", + "2nd.OnTestCaseStart", + "ListenerTest::SetUpTestCase", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestCase", + "2nd.OnTestCaseEnd", + "1st.OnTestCaseEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "2nd.OnTestIterationEnd(0)", + "1st.OnTestIterationEnd(0)", + "1st.OnTestIterationStart(1)", + "2nd.OnTestIterationStart(1)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "1st.OnTestCaseStart", + "2nd.OnTestCaseStart", + "ListenerTest::SetUpTestCase", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "ListenerTest::TearDown", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestCase", + "2nd.OnTestCaseEnd", + "1st.OnTestCaseEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "2nd.OnTestIterationEnd(1)", + "1st.OnTestIterationEnd(1)", + "2nd.OnTestProgramEnd", + "1st.OnTestProgramEnd" + }; + VerifyResults(events, + expected_events, + sizeof(expected_events)/sizeof(expected_events[0])); + + // We need to check manually for ad hoc test failures that happen after + // RUN_ALL_TESTS finishes. + if (UnitTest::GetInstance()->Failed()) + ret_val = 1; + + return ret_val; +} diff --git a/third_party/googletest/src/test/gtest-message_test.cc b/third_party/googletest/src/test/gtest-message_test.cc new file mode 100644 index 0000000..c09c6a8 --- /dev/null +++ b/third_party/googletest/src/test/gtest-message_test.cc @@ -0,0 +1,166 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Tests for the Message class. + +#include "gtest/gtest-message.h" + +#include "gtest/gtest.h" + +namespace { + +using ::testing::Message; + +// A helper function that turns a Message into a C string. +const char* ToCString(const Message& msg) { + static testing::internal::String result; + result = msg.GetString(); + return result.c_str(); +} + +// Tests the testing::Message class + +// Tests the default constructor. +TEST(MessageTest, DefaultConstructor) { + const Message msg; + EXPECT_STREQ("", ToCString(msg)); +} + +// Tests the copy constructor. +TEST(MessageTest, CopyConstructor) { + const Message msg1("Hello"); + const Message msg2(msg1); + EXPECT_STREQ("Hello", ToCString(msg2)); +} + +// Tests constructing a Message from a C-string. +TEST(MessageTest, ConstructsFromCString) { + Message msg("Hello"); + EXPECT_STREQ("Hello", ToCString(msg)); +} + +// Tests streaming a float. +TEST(MessageTest, StreamsFloat) { + const char* const s = ToCString(Message() << 1.23456F << " " << 2.34567F); + // Both numbers should be printed with enough precision. + EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s); + EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s); +} + +// Tests streaming a double. +TEST(MessageTest, StreamsDouble) { + const char* const s = ToCString(Message() << 1260570880.4555497 << " " + << 1260572265.1954534); + // Both numbers should be printed with enough precision. + EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s); + EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s); +} + +// Tests streaming a non-char pointer. +TEST(MessageTest, StreamsPointer) { + int n = 0; + int* p = &n; + EXPECT_STRNE("(null)", ToCString(Message() << p)); +} + +// Tests streaming a NULL non-char pointer. +TEST(MessageTest, StreamsNullPointer) { + int* p = NULL; + EXPECT_STREQ("(null)", ToCString(Message() << p)); +} + +// Tests streaming a C string. +TEST(MessageTest, StreamsCString) { + EXPECT_STREQ("Foo", ToCString(Message() << "Foo")); +} + +// Tests streaming a NULL C string. +TEST(MessageTest, StreamsNullCString) { + char* p = NULL; + EXPECT_STREQ("(null)", ToCString(Message() << p)); +} + +// Tests streaming std::string. +TEST(MessageTest, StreamsString) { + const ::std::string str("Hello"); + EXPECT_STREQ("Hello", ToCString(Message() << str)); +} + +// Tests that we can output strings containing embedded NULs. +TEST(MessageTest, StreamsStringWithEmbeddedNUL) { + const char char_array_with_nul[] = + "Here's a NUL\0 and some more string"; + const ::std::string string_with_nul(char_array_with_nul, + sizeof(char_array_with_nul) - 1); + EXPECT_STREQ("Here's a NUL\\0 and some more string", + ToCString(Message() << string_with_nul)); +} + +// Tests streaming a NUL char. +TEST(MessageTest, StreamsNULChar) { + EXPECT_STREQ("\\0", ToCString(Message() << '\0')); +} + +// Tests streaming int. +TEST(MessageTest, StreamsInt) { + EXPECT_STREQ("123", ToCString(Message() << 123)); +} + +// Tests that basic IO manipulators (endl, ends, and flush) can be +// streamed to Message. +TEST(MessageTest, StreamsBasicIoManip) { + EXPECT_STREQ("Line 1.\nA NUL char \\0 in line 2.", + ToCString(Message() << "Line 1." << std::endl + << "A NUL char " << std::ends << std::flush + << " in line 2.")); +} + +// Tests Message::GetString() +TEST(MessageTest, GetString) { + Message msg; + msg << 1 << " lamb"; + EXPECT_STREQ("1 lamb", msg.GetString().c_str()); +} + +// Tests streaming a Message object to an ostream. +TEST(MessageTest, StreamsToOStream) { + Message msg("Hello"); + ::std::stringstream ss; + ss << msg; + EXPECT_STREQ("Hello", testing::internal::StringStreamToString(&ss).c_str()); +} + +// Tests that a Message object doesn't take up too much stack space. +TEST(MessageTest, DoesNotTakeUpMuchStackSpace) { + EXPECT_LE(sizeof(Message), 16U); +} + +} // namespace diff --git a/third_party/googletest/src/test/gtest-options_test.cc b/third_party/googletest/src/test/gtest-options_test.cc new file mode 100644 index 0000000..9e98f3f --- /dev/null +++ b/third_party/googletest/src/test/gtest-options_test.cc @@ -0,0 +1,212 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) +// +// Google Test UnitTestOptions tests +// +// This file tests classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included from gtest.cc, to avoid changing build or +// make-files on Windows and other platforms. Do not #include this file +// anywhere else! + +#include "gtest/gtest.h" + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { +namespace { + +// Turns the given relative path into an absolute path. +FilePath GetAbsolutePathOf(const FilePath& relative_path) { + return FilePath::ConcatPaths(FilePath::GetCurrentDir(), relative_path); +} + +// Testing UnitTestOptions::GetOutputFormat/GetOutputFile. + +TEST(XmlOutputTest, GetOutputFormatDefault) { + GTEST_FLAG(output) = ""; + EXPECT_STREQ("", UnitTestOptions::GetOutputFormat().c_str()); +} + +TEST(XmlOutputTest, GetOutputFormat) { + GTEST_FLAG(output) = "xml:filename"; + EXPECT_STREQ("xml", UnitTestOptions::GetOutputFormat().c_str()); +} + +TEST(XmlOutputTest, GetOutputFileDefault) { + GTEST_FLAG(output) = ""; + EXPECT_STREQ(GetAbsolutePathOf(FilePath("test_detail.xml")).c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +} + +TEST(XmlOutputTest, GetOutputFileSingleFile) { + GTEST_FLAG(output) = "xml:filename.abc"; + EXPECT_STREQ(GetAbsolutePathOf(FilePath("filename.abc")).c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +} + +TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { + GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; + const std::string expected_output_file = + GetAbsolutePathOf( + FilePath(std::string("path") + GTEST_PATH_SEP_ + + GetCurrentExecutableName().c_str() + ".xml")).c_str(); + const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); +#if GTEST_OS_WINDOWS + EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); +#else + EXPECT_EQ(expected_output_file, output_file.c_str()); +#endif +} + +TEST(OutputFileHelpersTest, GetCurrentExecutableName) { + const std::string exe_str = GetCurrentExecutableName().c_str(); +#if GTEST_OS_WINDOWS + const bool success = + _strcmpi("gtest-options_test", exe_str.c_str()) == 0 || + _strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 || + _strcmpi("gtest_all_test", exe_str.c_str()) == 0 || + _strcmpi("gtest_dll_test", exe_str.c_str()) == 0; +#else + // TODO(wan@google.com): remove the hard-coded "lt-" prefix when + // Chandler Carruth's libtool replacement is ready. + const bool success = + exe_str == "gtest-options_test" || + exe_str == "gtest_all_test" || + exe_str == "lt-gtest_all_test" || + exe_str == "gtest_dll_test"; +#endif // GTEST_OS_WINDOWS + if (!success) + FAIL() << "GetCurrentExecutableName() returns " << exe_str; +} + +class XmlOutputChangeDirTest : public Test { + protected: + virtual void SetUp() { + original_working_dir_ = FilePath::GetCurrentDir(); + posix::ChDir(".."); + // This will make the test fail if run from the root directory. + EXPECT_STRNE(original_working_dir_.c_str(), + FilePath::GetCurrentDir().c_str()); + } + + virtual void TearDown() { + posix::ChDir(original_working_dir_.c_str()); + } + + FilePath original_working_dir_; +}; + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault) { + GTEST_FLAG(output) = ""; + EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_, + FilePath("test_detail.xml")).c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML) { + GTEST_FLAG(output) = "xml"; + EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_, + FilePath("test_detail.xml")).c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile) { + GTEST_FLAG(output) = "xml:filename.abc"; + EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_, + FilePath("filename.abc")).c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) { + GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; + const std::string expected_output_file = + FilePath::ConcatPaths( + original_working_dir_, + FilePath(std::string("path") + GTEST_PATH_SEP_ + + GetCurrentExecutableName().c_str() + ".xml")).c_str(); + const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); +#if GTEST_OS_WINDOWS + EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); +#else + EXPECT_EQ(expected_output_file, output_file.c_str()); +#endif +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsoluteFile) { +#if GTEST_OS_WINDOWS + GTEST_FLAG(output) = "xml:c:\\tmp\\filename.abc"; + EXPECT_STREQ(FilePath("c:\\tmp\\filename.abc").c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +#else + GTEST_FLAG(output) ="xml:/tmp/filename.abc"; + EXPECT_STREQ(FilePath("/tmp/filename.abc").c_str(), + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); +#endif +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) { +#if GTEST_OS_WINDOWS + const std::string path = "c:\\tmp\\"; +#else + const std::string path = "/tmp/"; +#endif + + GTEST_FLAG(output) = "xml:" + path; + const std::string expected_output_file = + path + GetCurrentExecutableName().c_str() + ".xml"; + const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); + +#if GTEST_OS_WINDOWS + EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); +#else + EXPECT_EQ(expected_output_file, output_file.c_str()); +#endif +} + +} // namespace +} // namespace internal +} // namespace testing diff --git a/third_party/googletest/src/test/gtest-param-test2_test.cc b/third_party/googletest/src/test/gtest-param-test2_test.cc new file mode 100644 index 0000000..4a782fe --- /dev/null +++ b/third_party/googletest/src/test/gtest-param-test2_test.cc @@ -0,0 +1,65 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) +// +// Tests for Google Test itself. This verifies that the basic constructs of +// Google Test work. + +#include "gtest/gtest.h" + +#include "test/gtest-param-test_test.h" + +#if GTEST_HAS_PARAM_TEST + +using ::testing::Values; +using ::testing::internal::ParamGenerator; + +// Tests that generators defined in a different translation unit +// are functional. The test using extern_gen is defined +// in gtest-param-test_test.cc. +ParamGenerator extern_gen = Values(33); + +// Tests that a parameterized test case can be defined in one translation unit +// and instantiated in another. The test is defined in gtest-param-test_test.cc +// and ExternalInstantiationTest fixture class is defined in +// gtest-param-test_test.h. +INSTANTIATE_TEST_CASE_P(MultiplesOf33, + ExternalInstantiationTest, + Values(33, 66)); + +// Tests that a parameterized test case can be instantiated +// in multiple translation units. Another instantiation is defined +// in gtest-param-test_test.cc and InstantiationInMultipleTranslaionUnitsTest +// fixture is defined in gtest-param-test_test.h +INSTANTIATE_TEST_CASE_P(Sequence2, + InstantiationInMultipleTranslaionUnitsTest, + Values(42*3, 42*4, 42*5)); + +#endif // GTEST_HAS_PARAM_TEST diff --git a/third_party/googletest/src/test/gtest-param-test_test.cc b/third_party/googletest/src/test/gtest-param-test_test.cc new file mode 100644 index 0000000..94a53d9 --- /dev/null +++ b/third_party/googletest/src/test/gtest-param-test_test.cc @@ -0,0 +1,895 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) +// +// Tests for Google Test itself. This file verifies that the parameter +// generators objects produce correct parameter sequences and that +// Google Test runtime instantiates correct tests from those sequences. + +#include "gtest/gtest.h" + +#if GTEST_HAS_PARAM_TEST + +# include +# include +# include +# include +# include +# include + +// To include gtest-internal-inl.h. +# define GTEST_IMPLEMENTATION_ 1 +# include "src/gtest-internal-inl.h" // for UnitTestOptions +# undef GTEST_IMPLEMENTATION_ + +# include "test/gtest-param-test_test.h" + +using ::std::vector; +using ::std::sort; + +using ::testing::AddGlobalTestEnvironment; +using ::testing::Bool; +using ::testing::Message; +using ::testing::Range; +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::ValuesIn; + +# if GTEST_HAS_COMBINE +using ::testing::Combine; +using ::std::tr1::get; +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +# endif // GTEST_HAS_COMBINE + +using ::testing::internal::ParamGenerator; +using ::testing::internal::UnitTestOptions; + +// Prints a value to a string. +// +// TODO(wan@google.com): remove PrintValue() when we move matchers and +// EXPECT_THAT() from Google Mock to Google Test. At that time, we +// can write EXPECT_THAT(x, Eq(y)) to compare two tuples x and y, as +// EXPECT_THAT() and the matchers know how to print tuples. +template +::std::string PrintValue(const T& value) { + ::std::stringstream stream; + stream << value; + return stream.str(); +} + +# if GTEST_HAS_COMBINE + +// These overloads allow printing tuples in our tests. We cannot +// define an operator<< for tuples, as that definition needs to be in +// the std namespace in order to be picked up by Google Test via +// Argument-Dependent Lookup, yet defining anything in the std +// namespace in non-STL code is undefined behavior. + +template +::std::string PrintValue(const tuple& value) { + ::std::stringstream stream; + stream << "(" << get<0>(value) << ", " << get<1>(value) << ")"; + return stream.str(); +} + +template +::std::string PrintValue(const tuple& value) { + ::std::stringstream stream; + stream << "(" << get<0>(value) << ", " << get<1>(value) + << ", "<< get<2>(value) << ")"; + return stream.str(); +} + +template +::std::string PrintValue( + const tuple& value) { + ::std::stringstream stream; + stream << "(" << get<0>(value) << ", " << get<1>(value) + << ", "<< get<2>(value) << ", " << get<3>(value) + << ", "<< get<4>(value) << ", " << get<5>(value) + << ", "<< get<6>(value) << ", " << get<7>(value) + << ", "<< get<8>(value) << ", " << get<9>(value) << ")"; + return stream.str(); +} + +# endif // GTEST_HAS_COMBINE + +// Verifies that a sequence generated by the generator and accessed +// via the iterator object matches the expected one using Google Test +// assertions. +template +void VerifyGenerator(const ParamGenerator& generator, + const T (&expected_values)[N]) { + typename ParamGenerator::iterator it = generator.begin(); + for (size_t i = 0; i < N; ++i) { + ASSERT_FALSE(it == generator.end()) + << "At element " << i << " when accessing via an iterator " + << "created with the copy constructor.\n"; + // We cannot use EXPECT_EQ() here as the values may be tuples, + // which don't support <<. + EXPECT_TRUE(expected_values[i] == *it) + << "where i is " << i + << ", expected_values[i] is " << PrintValue(expected_values[i]) + << ", *it is " << PrintValue(*it) + << ", and 'it' is an iterator created with the copy constructor.\n"; + it++; + } + EXPECT_TRUE(it == generator.end()) + << "At the presumed end of sequence when accessing via an iterator " + << "created with the copy constructor.\n"; + + // Test the iterator assignment. The following lines verify that + // the sequence accessed via an iterator initialized via the + // assignment operator (as opposed to a copy constructor) matches + // just the same. + it = generator.begin(); + for (size_t i = 0; i < N; ++i) { + ASSERT_FALSE(it == generator.end()) + << "At element " << i << " when accessing via an iterator " + << "created with the assignment operator.\n"; + EXPECT_TRUE(expected_values[i] == *it) + << "where i is " << i + << ", expected_values[i] is " << PrintValue(expected_values[i]) + << ", *it is " << PrintValue(*it) + << ", and 'it' is an iterator created with the copy constructor.\n"; + it++; + } + EXPECT_TRUE(it == generator.end()) + << "At the presumed end of sequence when accessing via an iterator " + << "created with the assignment operator.\n"; +} + +template +void VerifyGeneratorIsEmpty(const ParamGenerator& generator) { + typename ParamGenerator::iterator it = generator.begin(); + EXPECT_TRUE(it == generator.end()); + + it = generator.begin(); + EXPECT_TRUE(it == generator.end()); +} + +// Generator tests. They test that each of the provided generator functions +// generates an expected sequence of values. The general test pattern +// instantiates a generator using one of the generator functions, +// checks the sequence produced by the generator using its iterator API, +// and then resets the iterator back to the beginning of the sequence +// and checks the sequence again. + +// Tests that iterators produced by generator functions conform to the +// ForwardIterator concept. +TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { + const ParamGenerator gen = Range(0, 10); + ParamGenerator::iterator it = gen.begin(); + + // Verifies that iterator initialization works as expected. + ParamGenerator::iterator it2 = it; + EXPECT_TRUE(*it == *it2) << "Initialized iterators must point to the " + << "element same as its source points to"; + + // Verifies that iterator assignment works as expected. + it++; + EXPECT_FALSE(*it == *it2); + it2 = it; + EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the " + << "element same as its source points to"; + + // Verifies that prefix operator++() returns *this. + EXPECT_EQ(&it, &(++it)) << "Result of the prefix operator++ must be " + << "refer to the original object"; + + // Verifies that the result of the postfix operator++ points to the value + // pointed to by the original iterator. + int original_value = *it; // Have to compute it outside of macro call to be + // unaffected by the parameter evaluation order. + EXPECT_EQ(original_value, *(it++)); + + // Verifies that prefix and postfix operator++() advance an iterator + // all the same. + it2 = it; + it++; + ++it2; + EXPECT_TRUE(*it == *it2); +} + +// Tests that Range() generates the expected sequence. +TEST(RangeTest, IntRangeWithDefaultStep) { + const ParamGenerator gen = Range(0, 3); + const int expected_values[] = {0, 1, 2}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that Range() generates the single element sequence +// as expected when provided with range limits that are equal. +TEST(RangeTest, IntRangeSingleValue) { + const ParamGenerator gen = Range(0, 1); + const int expected_values[] = {0}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that Range() with generates empty sequence when +// supplied with an empty range. +TEST(RangeTest, IntRangeEmpty) { + const ParamGenerator gen = Range(0, 0); + VerifyGeneratorIsEmpty(gen); +} + +// Tests that Range() with custom step (greater then one) generates +// the expected sequence. +TEST(RangeTest, IntRangeWithCustomStep) { + const ParamGenerator gen = Range(0, 9, 3); + const int expected_values[] = {0, 3, 6}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Range() with custom step (greater then one) generates +// the expected sequence when the last element does not fall on the +// upper range limit. Sequences generated by Range() must not have +// elements beyond the range limits. +TEST(RangeTest, IntRangeWithCustomStepOverUpperBound) { + const ParamGenerator gen = Range(0, 4, 3); + const int expected_values[] = {0, 3}; + VerifyGenerator(gen, expected_values); +} + +// Verifies that Range works with user-defined types that define +// copy constructor, operator=(), operator+(), and operator<(). +class DogAdder { + public: + explicit DogAdder(const char* a_value) : value_(a_value) {} + DogAdder(const DogAdder& other) : value_(other.value_.c_str()) {} + + DogAdder operator=(const DogAdder& other) { + if (this != &other) + value_ = other.value_; + return *this; + } + DogAdder operator+(const DogAdder& other) const { + Message msg; + msg << value_.c_str() << other.value_.c_str(); + return DogAdder(msg.GetString().c_str()); + } + bool operator<(const DogAdder& other) const { + return value_ < other.value_; + } + const ::testing::internal::String& value() const { return value_; } + + private: + ::testing::internal::String value_; +}; + +TEST(RangeTest, WorksWithACustomType) { + const ParamGenerator gen = + Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog")); + ParamGenerator::iterator it = gen.begin(); + + ASSERT_FALSE(it == gen.end()); + EXPECT_STREQ("cat", it->value().c_str()); + + ASSERT_FALSE(++it == gen.end()); + EXPECT_STREQ("catdog", it->value().c_str()); + + EXPECT_TRUE(++it == gen.end()); +} + +class IntWrapper { + public: + explicit IntWrapper(int a_value) : value_(a_value) {} + IntWrapper(const IntWrapper& other) : value_(other.value_) {} + + IntWrapper operator=(const IntWrapper& other) { + value_ = other.value_; + return *this; + } + // operator+() adds a different type. + IntWrapper operator+(int other) const { return IntWrapper(value_ + other); } + bool operator<(const IntWrapper& other) const { + return value_ < other.value_; + } + int value() const { return value_; } + + private: + int value_; +}; + +TEST(RangeTest, WorksWithACustomTypeWithDifferentIncrementType) { + const ParamGenerator gen = Range(IntWrapper(0), IntWrapper(2)); + ParamGenerator::iterator it = gen.begin(); + + ASSERT_FALSE(it == gen.end()); + EXPECT_EQ(0, it->value()); + + ASSERT_FALSE(++it == gen.end()); + EXPECT_EQ(1, it->value()); + + EXPECT_TRUE(++it == gen.end()); +} + +// Tests that ValuesIn() with an array parameter generates +// the expected sequence. +TEST(ValuesInTest, ValuesInArray) { + int array[] = {3, 5, 8}; + const ParamGenerator gen = ValuesIn(array); + VerifyGenerator(gen, array); +} + +// Tests that ValuesIn() with a const array parameter generates +// the expected sequence. +TEST(ValuesInTest, ValuesInConstArray) { + const int array[] = {3, 5, 8}; + const ParamGenerator gen = ValuesIn(array); + VerifyGenerator(gen, array); +} + +// Edge case. Tests that ValuesIn() with an array parameter containing a +// single element generates the single element sequence. +TEST(ValuesInTest, ValuesInSingleElementArray) { + int array[] = {42}; + const ParamGenerator gen = ValuesIn(array); + VerifyGenerator(gen, array); +} + +// Tests that ValuesIn() generates the expected sequence for an STL +// container (vector). +TEST(ValuesInTest, ValuesInVector) { + typedef ::std::vector ContainerType; + ContainerType values; + values.push_back(3); + values.push_back(5); + values.push_back(8); + const ParamGenerator gen = ValuesIn(values); + + const int expected_values[] = {3, 5, 8}; + VerifyGenerator(gen, expected_values); +} + +// Tests that ValuesIn() generates the expected sequence. +TEST(ValuesInTest, ValuesInIteratorRange) { + typedef ::std::vector ContainerType; + ContainerType values; + values.push_back(3); + values.push_back(5); + values.push_back(8); + const ParamGenerator gen = ValuesIn(values.begin(), values.end()); + + const int expected_values[] = {3, 5, 8}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that ValuesIn() provided with an iterator range specifying a +// single value generates a single-element sequence. +TEST(ValuesInTest, ValuesInSingleElementIteratorRange) { + typedef ::std::vector ContainerType; + ContainerType values; + values.push_back(42); + const ParamGenerator gen = ValuesIn(values.begin(), values.end()); + + const int expected_values[] = {42}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that ValuesIn() provided with an empty iterator range +// generates an empty sequence. +TEST(ValuesInTest, ValuesInEmptyIteratorRange) { + typedef ::std::vector ContainerType; + ContainerType values; + const ParamGenerator gen = ValuesIn(values.begin(), values.end()); + + VerifyGeneratorIsEmpty(gen); +} + +// Tests that the Values() generates the expected sequence. +TEST(ValuesTest, ValuesWorks) { + const ParamGenerator gen = Values(3, 5, 8); + + const int expected_values[] = {3, 5, 8}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Values() generates the expected sequences from elements of +// different types convertible to ParamGenerator's parameter type. +TEST(ValuesTest, ValuesWorksForValuesOfCompatibleTypes) { + const ParamGenerator gen = Values(3, 5.0f, 8.0); + + const double expected_values[] = {3.0, 5.0, 8.0}; + VerifyGenerator(gen, expected_values); +} + +TEST(ValuesTest, ValuesWorksForMaxLengthList) { + const ParamGenerator gen = Values( + 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, + 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, + 410, 420, 430, 440, 450, 460, 470, 480, 490, 500); + + const int expected_values[] = { + 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, + 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, + 410, 420, 430, 440, 450, 460, 470, 480, 490, 500}; + VerifyGenerator(gen, expected_values); +} + +// Edge case test. Tests that single-parameter Values() generates the sequence +// with the single value. +TEST(ValuesTest, ValuesWithSingleParameter) { + const ParamGenerator gen = Values(42); + + const int expected_values[] = {42}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Bool() generates sequence (false, true). +TEST(BoolTest, BoolWorks) { + const ParamGenerator gen = Bool(); + + const bool expected_values[] = {false, true}; + VerifyGenerator(gen, expected_values); +} + +# if GTEST_HAS_COMBINE + +// Tests that Combine() with two parameters generates the expected sequence. +TEST(CombineTest, CombineWithTwoParameters) { + const char* foo = "foo"; + const char* bar = "bar"; + const ParamGenerator > gen = + Combine(Values(foo, bar), Values(3, 4)); + + tuple expected_values[] = { + make_tuple(foo, 3), make_tuple(foo, 4), + make_tuple(bar, 3), make_tuple(bar, 4)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Combine() with three parameters generates the expected sequence. +TEST(CombineTest, CombineWithThreeParameters) { + const ParamGenerator > gen = Combine(Values(0, 1), + Values(3, 4), + Values(5, 6)); + tuple expected_values[] = { + make_tuple(0, 3, 5), make_tuple(0, 3, 6), + make_tuple(0, 4, 5), make_tuple(0, 4, 6), + make_tuple(1, 3, 5), make_tuple(1, 3, 6), + make_tuple(1, 4, 5), make_tuple(1, 4, 6)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that the Combine() with the first parameter generating a single value +// sequence generates a sequence with the number of elements equal to the +// number of elements in the sequence generated by the second parameter. +TEST(CombineTest, CombineWithFirstParameterSingleValue) { + const ParamGenerator > gen = Combine(Values(42), + Values(0, 1)); + + tuple expected_values[] = {make_tuple(42, 0), make_tuple(42, 1)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that the Combine() with the second parameter generating a single value +// sequence generates a sequence with the number of elements equal to the +// number of elements in the sequence generated by the first parameter. +TEST(CombineTest, CombineWithSecondParameterSingleValue) { + const ParamGenerator > gen = Combine(Values(0, 1), + Values(42)); + + tuple expected_values[] = {make_tuple(0, 42), make_tuple(1, 42)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that when the first parameter produces an empty sequence, +// Combine() produces an empty sequence, too. +TEST(CombineTest, CombineWithFirstParameterEmptyRange) { + const ParamGenerator > gen = Combine(Range(0, 0), + Values(0, 1)); + VerifyGeneratorIsEmpty(gen); +} + +// Tests that when the second parameter produces an empty sequence, +// Combine() produces an empty sequence, too. +TEST(CombineTest, CombineWithSecondParameterEmptyRange) { + const ParamGenerator > gen = Combine(Values(0, 1), + Range(1, 1)); + VerifyGeneratorIsEmpty(gen); +} + +// Edge case. Tests that combine works with the maximum number +// of parameters supported by Google Test (currently 10). +TEST(CombineTest, CombineWithMaxNumberOfParameters) { + const char* foo = "foo"; + const char* bar = "bar"; + const ParamGenerator > gen = Combine(Values(foo, bar), + Values(1), Values(2), + Values(3), Values(4), + Values(5), Values(6), + Values(7), Values(8), + Values(9)); + + tuple + expected_values[] = {make_tuple(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9), + make_tuple(bar, 1, 2, 3, 4, 5, 6, 7, 8, 9)}; + VerifyGenerator(gen, expected_values); +} + +# endif // GTEST_HAS_COMBINE + +// Tests that an generator produces correct sequence after being +// assigned from another generator. +TEST(ParamGeneratorTest, AssignmentWorks) { + ParamGenerator gen = Values(1, 2); + const ParamGenerator gen2 = Values(3, 4); + gen = gen2; + + const int expected_values[] = {3, 4}; + VerifyGenerator(gen, expected_values); +} + +// This test verifies that the tests are expanded and run as specified: +// one test per element from the sequence produced by the generator +// specified in INSTANTIATE_TEST_CASE_P. It also verifies that the test's +// fixture constructor, SetUp(), and TearDown() have run and have been +// supplied with the correct parameters. + +// The use of environment object allows detection of the case where no test +// case functionality is run at all. In this case TestCaseTearDown will not +// be able to detect missing tests, naturally. +template +class TestGenerationEnvironment : public ::testing::Environment { + public: + static TestGenerationEnvironment* Instance() { + static TestGenerationEnvironment* instance = new TestGenerationEnvironment; + return instance; + } + + void FixtureConstructorExecuted() { fixture_constructor_count_++; } + void SetUpExecuted() { set_up_count_++; } + void TearDownExecuted() { tear_down_count_++; } + void TestBodyExecuted() { test_body_count_++; } + + virtual void TearDown() { + // If all MultipleTestGenerationTest tests have been de-selected + // by the filter flag, the following checks make no sense. + bool perform_check = false; + + for (int i = 0; i < kExpectedCalls; ++i) { + Message msg; + msg << "TestsExpandedAndRun/" << i; + if (UnitTestOptions::FilterMatchesTest( + "TestExpansionModule/MultipleTestGenerationTest", + msg.GetString().c_str())) { + perform_check = true; + } + } + if (perform_check) { + EXPECT_EQ(kExpectedCalls, fixture_constructor_count_) + << "Fixture constructor of ParamTestGenerationTest test case " + << "has not been run as expected."; + EXPECT_EQ(kExpectedCalls, set_up_count_) + << "Fixture SetUp method of ParamTestGenerationTest test case " + << "has not been run as expected."; + EXPECT_EQ(kExpectedCalls, tear_down_count_) + << "Fixture TearDown method of ParamTestGenerationTest test case " + << "has not been run as expected."; + EXPECT_EQ(kExpectedCalls, test_body_count_) + << "Test in ParamTestGenerationTest test case " + << "has not been run as expected."; + } + } + private: + TestGenerationEnvironment() : fixture_constructor_count_(0), set_up_count_(0), + tear_down_count_(0), test_body_count_(0) {} + + int fixture_constructor_count_; + int set_up_count_; + int tear_down_count_; + int test_body_count_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationEnvironment); +}; + +const int test_generation_params[] = {36, 42, 72}; + +class TestGenerationTest : public TestWithParam { + public: + enum { + PARAMETER_COUNT = + sizeof(test_generation_params)/sizeof(test_generation_params[0]) + }; + + typedef TestGenerationEnvironment Environment; + + TestGenerationTest() { + Environment::Instance()->FixtureConstructorExecuted(); + current_parameter_ = GetParam(); + } + virtual void SetUp() { + Environment::Instance()->SetUpExecuted(); + EXPECT_EQ(current_parameter_, GetParam()); + } + virtual void TearDown() { + Environment::Instance()->TearDownExecuted(); + EXPECT_EQ(current_parameter_, GetParam()); + } + + static void SetUpTestCase() { + bool all_tests_in_test_case_selected = true; + + for (int i = 0; i < PARAMETER_COUNT; ++i) { + Message test_name; + test_name << "TestsExpandedAndRun/" << i; + if ( !UnitTestOptions::FilterMatchesTest( + "TestExpansionModule/MultipleTestGenerationTest", + test_name.GetString())) { + all_tests_in_test_case_selected = false; + } + } + EXPECT_TRUE(all_tests_in_test_case_selected) + << "When running the TestGenerationTest test case all of its tests\n" + << "must be selected by the filter flag for the test case to pass.\n" + << "If not all of them are enabled, we can't reliably conclude\n" + << "that the correct number of tests have been generated."; + + collected_parameters_.clear(); + } + + static void TearDownTestCase() { + vector expected_values(test_generation_params, + test_generation_params + PARAMETER_COUNT); + // Test execution order is not guaranteed by Google Test, + // so the order of values in collected_parameters_ can be + // different and we have to sort to compare. + sort(expected_values.begin(), expected_values.end()); + sort(collected_parameters_.begin(), collected_parameters_.end()); + + EXPECT_TRUE(collected_parameters_ == expected_values); + } + protected: + int current_parameter_; + static vector collected_parameters_; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest); +}; +vector TestGenerationTest::collected_parameters_; + +TEST_P(TestGenerationTest, TestsExpandedAndRun) { + Environment::Instance()->TestBodyExecuted(); + EXPECT_EQ(current_parameter_, GetParam()); + collected_parameters_.push_back(GetParam()); +} +INSTANTIATE_TEST_CASE_P(TestExpansionModule, TestGenerationTest, + ValuesIn(test_generation_params)); + +// This test verifies that the element sequence (third parameter of +// INSTANTIATE_TEST_CASE_P) is evaluated in InitGoogleTest() and neither at +// the call site of INSTANTIATE_TEST_CASE_P nor in RUN_ALL_TESTS(). For +// that, we declare param_value_ to be a static member of +// GeneratorEvaluationTest and initialize it to 0. We set it to 1 in +// main(), just before invocation of InitGoogleTest(). After calling +// InitGoogleTest(), we set the value to 2. If the sequence is evaluated +// before or after InitGoogleTest, INSTANTIATE_TEST_CASE_P will create a +// test with parameter other than 1, and the test body will fail the +// assertion. +class GeneratorEvaluationTest : public TestWithParam { + public: + static int param_value() { return param_value_; } + static void set_param_value(int param_value) { param_value_ = param_value; } + + private: + static int param_value_; +}; +int GeneratorEvaluationTest::param_value_ = 0; + +TEST_P(GeneratorEvaluationTest, GeneratorsEvaluatedInMain) { + EXPECT_EQ(1, GetParam()); +} +INSTANTIATE_TEST_CASE_P(GenEvalModule, + GeneratorEvaluationTest, + Values(GeneratorEvaluationTest::param_value())); + +// Tests that generators defined in a different translation unit are +// functional. Generator extern_gen is defined in gtest-param-test_test2.cc. +extern ParamGenerator extern_gen; +class ExternalGeneratorTest : public TestWithParam {}; +TEST_P(ExternalGeneratorTest, ExternalGenerator) { + // Sequence produced by extern_gen contains only a single value + // which we verify here. + EXPECT_EQ(GetParam(), 33); +} +INSTANTIATE_TEST_CASE_P(ExternalGeneratorModule, + ExternalGeneratorTest, + extern_gen); + +// Tests that a parameterized test case can be defined in one translation +// unit and instantiated in another. This test will be instantiated in +// gtest-param-test_test2.cc. ExternalInstantiationTest fixture class is +// defined in gtest-param-test_test.h. +TEST_P(ExternalInstantiationTest, IsMultipleOf33) { + EXPECT_EQ(0, GetParam() % 33); +} + +// Tests that a parameterized test case can be instantiated with multiple +// generators. +class MultipleInstantiationTest : public TestWithParam {}; +TEST_P(MultipleInstantiationTest, AllowsMultipleInstances) { +} +INSTANTIATE_TEST_CASE_P(Sequence1, MultipleInstantiationTest, Values(1, 2)); +INSTANTIATE_TEST_CASE_P(Sequence2, MultipleInstantiationTest, Range(3, 5)); + +// Tests that a parameterized test case can be instantiated +// in multiple translation units. This test will be instantiated +// here and in gtest-param-test_test2.cc. +// InstantiationInMultipleTranslationUnitsTest fixture class +// is defined in gtest-param-test_test.h. +TEST_P(InstantiationInMultipleTranslaionUnitsTest, IsMultipleOf42) { + EXPECT_EQ(0, GetParam() % 42); +} +INSTANTIATE_TEST_CASE_P(Sequence1, + InstantiationInMultipleTranslaionUnitsTest, + Values(42, 42*2)); + +// Tests that each iteration of parameterized test runs in a separate test +// object. +class SeparateInstanceTest : public TestWithParam { + public: + SeparateInstanceTest() : count_(0) {} + + static void TearDownTestCase() { + EXPECT_GE(global_count_, 2) + << "If some (but not all) SeparateInstanceTest tests have been " + << "filtered out this test will fail. Make sure that all " + << "GeneratorEvaluationTest are selected or de-selected together " + << "by the test filter."; + } + + protected: + int count_; + static int global_count_; +}; +int SeparateInstanceTest::global_count_ = 0; + +TEST_P(SeparateInstanceTest, TestsRunInSeparateInstances) { + EXPECT_EQ(0, count_++); + global_count_++; +} +INSTANTIATE_TEST_CASE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4)); + +// Tests that all instantiations of a test have named appropriately. Test +// defined with TEST_P(TestCaseName, TestName) and instantiated with +// INSTANTIATE_TEST_CASE_P(SequenceName, TestCaseName, generator) must be named +// SequenceName/TestCaseName.TestName/i, where i is the 0-based index of the +// sequence element used to instantiate the test. +class NamingTest : public TestWithParam {}; + +TEST_P(NamingTest, TestsReportCorrectNamesAndParameters) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name()); + + Message index_stream; + index_stream << "TestsReportCorrectNamesAndParameters/" << GetParam(); + EXPECT_STREQ(index_stream.GetString().c_str(), test_info->name()); + + EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); +} + +INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5)); + +// Class that cannot be streamed into an ostream. It needs to be copyable +// (and, in case of MSVC, also assignable) in order to be a test parameter +// type. Its default copy constructor and assignment operator do exactly +// what we need. +class Unstreamable { + public: + explicit Unstreamable(int value) : value_(value) {} + + private: + int value_; +}; + +class CommentTest : public TestWithParam {}; + +TEST_P(CommentTest, TestsCorrectlyReportUnstreamableParams) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); +} + +INSTANTIATE_TEST_CASE_P(InstantiationWithComments, + CommentTest, + Values(Unstreamable(1))); + +// Verify that we can create a hierarchy of test fixtures, where the base +// class fixture is not parameterized and the derived class is. In this case +// ParameterizedDerivedTest inherits from NonParameterizedBaseTest. We +// perform simple tests on both. +class NonParameterizedBaseTest : public ::testing::Test { + public: + NonParameterizedBaseTest() : n_(17) { } + protected: + int n_; +}; + +class ParameterizedDerivedTest : public NonParameterizedBaseTest, + public ::testing::WithParamInterface { + protected: + ParameterizedDerivedTest() : count_(0) { } + int count_; + static int global_count_; +}; + +int ParameterizedDerivedTest::global_count_ = 0; + +TEST_F(NonParameterizedBaseTest, FixtureIsInitialized) { + EXPECT_EQ(17, n_); +} + +TEST_P(ParameterizedDerivedTest, SeesSequence) { + EXPECT_EQ(17, n_); + EXPECT_EQ(0, count_++); + EXPECT_EQ(GetParam(), global_count_++); +} + +INSTANTIATE_TEST_CASE_P(RangeZeroToFive, ParameterizedDerivedTest, Range(0, 5)); + +#endif // GTEST_HAS_PARAM_TEST + +TEST(CompileTest, CombineIsDefinedOnlyWhenGtestHasParamTestIsDefined) { +#if GTEST_HAS_COMBINE && !GTEST_HAS_PARAM_TEST + FAIL() << "GTEST_HAS_COMBINE is defined while GTEST_HAS_PARAM_TEST is not\n" +#endif +} + +int main(int argc, char **argv) { +#if GTEST_HAS_PARAM_TEST + // Used in TestGenerationTest test case. + AddGlobalTestEnvironment(TestGenerationTest::Environment::Instance()); + // Used in GeneratorEvaluationTest test case. Tests that the updated value + // will be picked up for instantiating tests in GeneratorEvaluationTest. + GeneratorEvaluationTest::set_param_value(1); +#endif // GTEST_HAS_PARAM_TEST + + ::testing::InitGoogleTest(&argc, argv); + +#if GTEST_HAS_PARAM_TEST + // Used in GeneratorEvaluationTest test case. Tests that value updated + // here will NOT be used for instantiating tests in + // GeneratorEvaluationTest. + GeneratorEvaluationTest::set_param_value(2); +#endif // GTEST_HAS_PARAM_TEST + + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest-param-test_test.h b/third_party/googletest/src/test/gtest-param-test_test.h new file mode 100644 index 0000000..d0f6556 --- /dev/null +++ b/third_party/googletest/src/test/gtest-param-test_test.h @@ -0,0 +1,55 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file provides classes and functions used internally +// for testing Google Test itself. + +#ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ +#define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ + +#include "gtest/gtest.h" + +#if GTEST_HAS_PARAM_TEST + +// Test fixture for testing definition and instantiation of a test +// in separate translation units. +class ExternalInstantiationTest : public ::testing::TestWithParam {}; + +// Test fixture for testing instantiation of a test in multiple +// translation units. +class InstantiationInMultipleTranslaionUnitsTest + : public ::testing::TestWithParam {}; + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ diff --git a/third_party/googletest/src/test/gtest-port_test.cc b/third_party/googletest/src/test/gtest-port_test.cc new file mode 100644 index 0000000..1c6e2b0 --- /dev/null +++ b/third_party/googletest/src/test/gtest-port_test.cc @@ -0,0 +1,1206 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev), wan@google.com (Zhanyong Wan) +// +// This file tests the internal cross-platform support utilities. + +#include "gtest/internal/gtest-port.h" + +#include + +#if GTEST_OS_MAC +# include +#endif // GTEST_OS_MAC + +#include +#include // For std::pair and std::make_pair. +#include + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +using std::make_pair; +using std::pair; + +namespace testing { +namespace internal { + +class Base { + public: + // Copy constructor and assignment operator do exactly what we need, so we + // use them. + Base() : member_(0) {} + explicit Base(int n) : member_(n) {} + virtual ~Base() {} + int member() { return member_; } + + private: + int member_; +}; + +class Derived : public Base { + public: + explicit Derived(int n) : Base(n) {} +}; + +TEST(ImplicitCastTest, ConvertsPointers) { + Derived derived(0); + EXPECT_TRUE(&derived == ::testing::internal::ImplicitCast_(&derived)); +} + +TEST(ImplicitCastTest, CanUseInheritance) { + Derived derived(1); + Base base = ::testing::internal::ImplicitCast_(derived); + EXPECT_EQ(derived.member(), base.member()); +} + +class Castable { + public: + Castable(bool* converted) : converted_(converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + + private: + bool* converted_; +}; + +TEST(ImplicitCastTest, CanUseNonConstCastOperator) { + bool converted = false; + Castable castable(&converted); + Base base = ::testing::internal::ImplicitCast_(castable); + EXPECT_TRUE(converted); +} + +class ConstCastable { + public: + ConstCastable(bool* converted) : converted_(converted) {} + operator Base() const { + *converted_ = true; + return Base(); + } + + private: + bool* converted_; +}; + +TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { + bool converted = false; + const ConstCastable const_castable(&converted); + Base base = ::testing::internal::ImplicitCast_(const_castable); + EXPECT_TRUE(converted); +} + +class ConstAndNonConstCastable { + public: + ConstAndNonConstCastable(bool* converted, bool* const_converted) + : converted_(converted), const_converted_(const_converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + operator Base() const { + *const_converted_ = true; + return Base(); + } + + private: + bool* converted_; + bool* const_converted_; +}; + +TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { + bool converted = false; + bool const_converted = false; + ConstAndNonConstCastable castable(&converted, &const_converted); + Base base = ::testing::internal::ImplicitCast_(castable); + EXPECT_TRUE(converted); + EXPECT_FALSE(const_converted); + + converted = false; + const_converted = false; + const ConstAndNonConstCastable const_castable(&converted, &const_converted); + base = ::testing::internal::ImplicitCast_(const_castable); + EXPECT_FALSE(converted); + EXPECT_TRUE(const_converted); +} + +class To { + public: + To(bool* converted) { *converted = true; } // NOLINT +}; + +TEST(ImplicitCastTest, CanUseImplicitConstructor) { + bool converted = false; + To to = ::testing::internal::ImplicitCast_(&converted); + (void)to; + EXPECT_TRUE(converted); +} + +TEST(IteratorTraitsTest, WorksForSTLContainerIterators) { + StaticAssertTypeEq::const_iterator>::value_type>(); + StaticAssertTypeEq::iterator>::value_type>(); +} + +TEST(IteratorTraitsTest, WorksForPointerToNonConst) { + StaticAssertTypeEq::value_type>(); + StaticAssertTypeEq::value_type>(); +} + +TEST(IteratorTraitsTest, WorksForPointerToConst) { + StaticAssertTypeEq::value_type>(); + StaticAssertTypeEq::value_type>(); +} + +// Tests that the element_type typedef is available in scoped_ptr and refers +// to the parameter type. +TEST(ScopedPtrTest, DefinesElementType) { + StaticAssertTypeEq::element_type>(); +} + +// TODO(vladl@google.com): Implement THE REST of scoped_ptr tests. + +TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { + if (AlwaysFalse()) + GTEST_CHECK_(false) << "This should never be executed; " + "It's a compilation test only."; + + if (AlwaysTrue()) + GTEST_CHECK_(true); + else + ; // NOLINT + + if (AlwaysFalse()) + ; // NOLINT + else + GTEST_CHECK_(true) << ""; +} + +TEST(GtestCheckSyntaxTest, WorksWithSwitch) { + switch (0) { + case 1: + break; + default: + GTEST_CHECK_(true); + } + + switch(0) + case 0: + GTEST_CHECK_(true) << "Check failed in switch case"; +} + +// Verifies behavior of FormatFileLocation. +TEST(FormatFileLocationTest, FormatsFileLocation) { + EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42)); + EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42)); +} + +TEST(FormatFileLocationTest, FormatsUnknownFile) { + EXPECT_PRED_FORMAT2( + IsSubstring, "unknown file", FormatFileLocation(NULL, 42)); + EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation(NULL, 42)); +} + +TEST(FormatFileLocationTest, FormatsUknownLine) { + EXPECT_EQ("foo.cc:", FormatFileLocation("foo.cc", -1)); +} + +TEST(FormatFileLocationTest, FormatsUknownFileAndLine) { + EXPECT_EQ("unknown file:", FormatFileLocation(NULL, -1)); +} + +// Verifies behavior of FormatCompilerIndependentFileLocation. +TEST(FormatCompilerIndependentFileLocationTest, FormatsFileLocation) { + EXPECT_EQ("foo.cc:42", FormatCompilerIndependentFileLocation("foo.cc", 42)); +} + +TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFile) { + EXPECT_EQ("unknown file:42", + FormatCompilerIndependentFileLocation(NULL, 42)); +} + +TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) { + EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1)); +} + +TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { + EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1)); +} + +#if GTEST_OS_MAC +void* ThreadFunc(void* data) { + pthread_mutex_t* mutex = static_cast(data); + pthread_mutex_lock(mutex); + pthread_mutex_unlock(mutex); + return NULL; +} + +TEST(GetThreadCountTest, ReturnsCorrectValue) { + EXPECT_EQ(1U, GetThreadCount()); + pthread_mutex_t mutex; + pthread_attr_t attr; + pthread_t thread_id; + + // TODO(vladl@google.com): turn mutex into internal::Mutex for automatic + // destruction. + pthread_mutex_init(&mutex, NULL); + pthread_mutex_lock(&mutex); + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + + const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); + ASSERT_EQ(0, pthread_attr_destroy(&attr)); + ASSERT_EQ(0, status); + EXPECT_EQ(2U, GetThreadCount()); + pthread_mutex_unlock(&mutex); + + void* dummy; + ASSERT_EQ(0, pthread_join(thread_id, &dummy)); + + // MacOS X may not immediately report the updated thread count after + // joining a thread, causing flakiness in this test. To counter that, we + // wait for up to .5 seconds for the OS to report the correct value. + for (int i = 0; i < 5; ++i) { + if (GetThreadCount() == 1) + break; + + SleepMilliseconds(100); + } + EXPECT_EQ(1U, GetThreadCount()); + pthread_mutex_destroy(&mutex); +} +#else +TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { + EXPECT_EQ(0U, GetThreadCount()); +} +#endif // GTEST_OS_MAC + +TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { + const bool a_false_condition = false; + const char regex[] = +#ifdef _MSC_VER + "gtest-port_test\\.cc\\(\\d+\\):" +#elif GTEST_USES_POSIX_RE + "gtest-port_test\\.cc:[0-9]+" +#else + "gtest-port_test\\.cc:\\d+" +#endif // _MSC_VER + ".*a_false_condition.*Extra info.*"; + + EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", + regex); +} + +#if GTEST_HAS_DEATH_TEST + +TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { + EXPECT_EXIT({ + GTEST_CHECK_(true) << "Extra info"; + ::std::cerr << "Success\n"; + exit(0); }, + ::testing::ExitedWithCode(0), "Success"); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Verifies that Google Test choose regular expression engine appropriate to +// the platform. The test will produce compiler errors in case of failure. +// For simplicity, we only cover the most important platforms here. +TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { +#if GTEST_HAS_POSIX_RE + + EXPECT_TRUE(GTEST_USES_POSIX_RE); + +#else + + EXPECT_TRUE(GTEST_USES_SIMPLE_RE); + +#endif +} + +#if GTEST_USES_POSIX_RE + +# if GTEST_HAS_TYPED_TEST + +template +class RETest : public ::testing::Test {}; + +// Defines StringTypes as the list of all string types that class RE +// supports. +typedef testing::Types< + ::std::string, +# if GTEST_HAS_GLOBAL_STRING + ::string, +# endif // GTEST_HAS_GLOBAL_STRING + const char*> StringTypes; + +TYPED_TEST_CASE(RETest, StringTypes); + +// Tests RE's implicit constructors. +TYPED_TEST(RETest, ImplicitConstructorWorks) { + const RE empty(TypeParam("")); + EXPECT_STREQ("", empty.pattern()); + + const RE simple(TypeParam("hello")); + EXPECT_STREQ("hello", simple.pattern()); + + const RE normal(TypeParam(".*(\\w+)")); + EXPECT_STREQ(".*(\\w+)", normal.pattern()); +} + +// Tests that RE's constructors reject invalid regular expressions. +TYPED_TEST(RETest, RejectsInvalidRegex) { + EXPECT_NONFATAL_FAILURE({ + const RE invalid(TypeParam("?")); + }, "\"?\" is not a valid POSIX Extended regular expression."); +} + +// Tests RE::FullMatch(). +TYPED_TEST(RETest, FullMatchWorks) { + const RE empty(TypeParam("")); + EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty)); + EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty)); + + const RE re(TypeParam("a.*z")); + EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re)); + EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re)); + EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re)); + EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re)); +} + +// Tests RE::PartialMatch(). +TYPED_TEST(RETest, PartialMatchWorks) { + const RE empty(TypeParam("")); + EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty)); + + const RE re(TypeParam("a.*z")); + EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re)); + EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re)); +} + +# endif // GTEST_HAS_TYPED_TEST + +#elif GTEST_USES_SIMPLE_RE + +TEST(IsInSetTest, NulCharIsNotInAnySet) { + EXPECT_FALSE(IsInSet('\0', "")); + EXPECT_FALSE(IsInSet('\0', "\0")); + EXPECT_FALSE(IsInSet('\0', "a")); +} + +TEST(IsInSetTest, WorksForNonNulChars) { + EXPECT_FALSE(IsInSet('a', "Ab")); + EXPECT_FALSE(IsInSet('c', "")); + + EXPECT_TRUE(IsInSet('b', "bcd")); + EXPECT_TRUE(IsInSet('b', "ab")); +} + +TEST(IsAsciiDigitTest, IsFalseForNonDigit) { + EXPECT_FALSE(IsAsciiDigit('\0')); + EXPECT_FALSE(IsAsciiDigit(' ')); + EXPECT_FALSE(IsAsciiDigit('+')); + EXPECT_FALSE(IsAsciiDigit('-')); + EXPECT_FALSE(IsAsciiDigit('.')); + EXPECT_FALSE(IsAsciiDigit('a')); +} + +TEST(IsAsciiDigitTest, IsTrueForDigit) { + EXPECT_TRUE(IsAsciiDigit('0')); + EXPECT_TRUE(IsAsciiDigit('1')); + EXPECT_TRUE(IsAsciiDigit('5')); + EXPECT_TRUE(IsAsciiDigit('9')); +} + +TEST(IsAsciiPunctTest, IsFalseForNonPunct) { + EXPECT_FALSE(IsAsciiPunct('\0')); + EXPECT_FALSE(IsAsciiPunct(' ')); + EXPECT_FALSE(IsAsciiPunct('\n')); + EXPECT_FALSE(IsAsciiPunct('a')); + EXPECT_FALSE(IsAsciiPunct('0')); +} + +TEST(IsAsciiPunctTest, IsTrueForPunct) { + for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { + EXPECT_PRED1(IsAsciiPunct, *p); + } +} + +TEST(IsRepeatTest, IsFalseForNonRepeatChar) { + EXPECT_FALSE(IsRepeat('\0')); + EXPECT_FALSE(IsRepeat(' ')); + EXPECT_FALSE(IsRepeat('a')); + EXPECT_FALSE(IsRepeat('1')); + EXPECT_FALSE(IsRepeat('-')); +} + +TEST(IsRepeatTest, IsTrueForRepeatChar) { + EXPECT_TRUE(IsRepeat('?')); + EXPECT_TRUE(IsRepeat('*')); + EXPECT_TRUE(IsRepeat('+')); +} + +TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) { + EXPECT_FALSE(IsAsciiWhiteSpace('\0')); + EXPECT_FALSE(IsAsciiWhiteSpace('a')); + EXPECT_FALSE(IsAsciiWhiteSpace('1')); + EXPECT_FALSE(IsAsciiWhiteSpace('+')); + EXPECT_FALSE(IsAsciiWhiteSpace('_')); +} + +TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) { + EXPECT_TRUE(IsAsciiWhiteSpace(' ')); + EXPECT_TRUE(IsAsciiWhiteSpace('\n')); + EXPECT_TRUE(IsAsciiWhiteSpace('\r')); + EXPECT_TRUE(IsAsciiWhiteSpace('\t')); + EXPECT_TRUE(IsAsciiWhiteSpace('\v')); + EXPECT_TRUE(IsAsciiWhiteSpace('\f')); +} + +TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) { + EXPECT_FALSE(IsAsciiWordChar('\0')); + EXPECT_FALSE(IsAsciiWordChar('+')); + EXPECT_FALSE(IsAsciiWordChar('.')); + EXPECT_FALSE(IsAsciiWordChar(' ')); + EXPECT_FALSE(IsAsciiWordChar('\n')); +} + +TEST(IsAsciiWordCharTest, IsTrueForLetter) { + EXPECT_TRUE(IsAsciiWordChar('a')); + EXPECT_TRUE(IsAsciiWordChar('b')); + EXPECT_TRUE(IsAsciiWordChar('A')); + EXPECT_TRUE(IsAsciiWordChar('Z')); +} + +TEST(IsAsciiWordCharTest, IsTrueForDigit) { + EXPECT_TRUE(IsAsciiWordChar('0')); + EXPECT_TRUE(IsAsciiWordChar('1')); + EXPECT_TRUE(IsAsciiWordChar('7')); + EXPECT_TRUE(IsAsciiWordChar('9')); +} + +TEST(IsAsciiWordCharTest, IsTrueForUnderscore) { + EXPECT_TRUE(IsAsciiWordChar('_')); +} + +TEST(IsValidEscapeTest, IsFalseForNonPrintable) { + EXPECT_FALSE(IsValidEscape('\0')); + EXPECT_FALSE(IsValidEscape('\007')); +} + +TEST(IsValidEscapeTest, IsFalseForDigit) { + EXPECT_FALSE(IsValidEscape('0')); + EXPECT_FALSE(IsValidEscape('9')); +} + +TEST(IsValidEscapeTest, IsFalseForWhiteSpace) { + EXPECT_FALSE(IsValidEscape(' ')); + EXPECT_FALSE(IsValidEscape('\n')); +} + +TEST(IsValidEscapeTest, IsFalseForSomeLetter) { + EXPECT_FALSE(IsValidEscape('a')); + EXPECT_FALSE(IsValidEscape('Z')); +} + +TEST(IsValidEscapeTest, IsTrueForPunct) { + EXPECT_TRUE(IsValidEscape('.')); + EXPECT_TRUE(IsValidEscape('-')); + EXPECT_TRUE(IsValidEscape('^')); + EXPECT_TRUE(IsValidEscape('$')); + EXPECT_TRUE(IsValidEscape('(')); + EXPECT_TRUE(IsValidEscape(']')); + EXPECT_TRUE(IsValidEscape('{')); + EXPECT_TRUE(IsValidEscape('|')); +} + +TEST(IsValidEscapeTest, IsTrueForSomeLetter) { + EXPECT_TRUE(IsValidEscape('d')); + EXPECT_TRUE(IsValidEscape('D')); + EXPECT_TRUE(IsValidEscape('s')); + EXPECT_TRUE(IsValidEscape('S')); + EXPECT_TRUE(IsValidEscape('w')); + EXPECT_TRUE(IsValidEscape('W')); +} + +TEST(AtomMatchesCharTest, EscapedPunct) { + EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, '\\', ' ')); + EXPECT_FALSE(AtomMatchesChar(true, '_', '.')); + EXPECT_FALSE(AtomMatchesChar(true, '.', 'a')); + + EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\')); + EXPECT_TRUE(AtomMatchesChar(true, '_', '_')); + EXPECT_TRUE(AtomMatchesChar(true, '+', '+')); + EXPECT_TRUE(AtomMatchesChar(true, '.', '.')); +} + +TEST(AtomMatchesCharTest, Escaped_d) { + EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a')); + EXPECT_FALSE(AtomMatchesChar(true, 'd', '.')); + + EXPECT_TRUE(AtomMatchesChar(true, 'd', '0')); + EXPECT_TRUE(AtomMatchesChar(true, 'd', '9')); +} + +TEST(AtomMatchesCharTest, Escaped_D) { + EXPECT_FALSE(AtomMatchesChar(true, 'D', '0')); + EXPECT_FALSE(AtomMatchesChar(true, 'D', '9')); + + EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0')); + EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a')); + EXPECT_TRUE(AtomMatchesChar(true, 'D', '-')); +} + +TEST(AtomMatchesCharTest, Escaped_s) { + EXPECT_FALSE(AtomMatchesChar(true, 's', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 's', 'a')); + EXPECT_FALSE(AtomMatchesChar(true, 's', '.')); + EXPECT_FALSE(AtomMatchesChar(true, 's', '9')); + + EXPECT_TRUE(AtomMatchesChar(true, 's', ' ')); + EXPECT_TRUE(AtomMatchesChar(true, 's', '\n')); + EXPECT_TRUE(AtomMatchesChar(true, 's', '\t')); +} + +TEST(AtomMatchesCharTest, Escaped_S) { + EXPECT_FALSE(AtomMatchesChar(true, 'S', ' ')); + EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r')); + + EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0')); + EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a')); + EXPECT_TRUE(AtomMatchesChar(true, 'S', '9')); +} + +TEST(AtomMatchesCharTest, Escaped_w) { + EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'w', '+')); + EXPECT_FALSE(AtomMatchesChar(true, 'w', ' ')); + EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n')); + + EXPECT_TRUE(AtomMatchesChar(true, 'w', '0')); + EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b')); + EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C')); + EXPECT_TRUE(AtomMatchesChar(true, 'w', '_')); +} + +TEST(AtomMatchesCharTest, Escaped_W) { + EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A')); + EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b')); + EXPECT_FALSE(AtomMatchesChar(true, 'W', '9')); + EXPECT_FALSE(AtomMatchesChar(true, 'W', '_')); + + EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0')); + EXPECT_TRUE(AtomMatchesChar(true, 'W', '*')); + EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n')); +} + +TEST(AtomMatchesCharTest, EscapedWhiteSpace) { + EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n')); + EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r')); + EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a')); + EXPECT_FALSE(AtomMatchesChar(true, 't', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 't', 't')); + EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f')); + + EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f')); + EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n')); + EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r')); + EXPECT_TRUE(AtomMatchesChar(true, 't', '\t')); + EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v')); +} + +TEST(AtomMatchesCharTest, UnescapedDot) { + EXPECT_FALSE(AtomMatchesChar(false, '.', '\n')); + + EXPECT_TRUE(AtomMatchesChar(false, '.', '\0')); + EXPECT_TRUE(AtomMatchesChar(false, '.', '.')); + EXPECT_TRUE(AtomMatchesChar(false, '.', 'a')); + EXPECT_TRUE(AtomMatchesChar(false, '.', ' ')); +} + +TEST(AtomMatchesCharTest, UnescapedChar) { + EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0')); + EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b')); + EXPECT_FALSE(AtomMatchesChar(false, '$', 'a')); + + EXPECT_TRUE(AtomMatchesChar(false, '$', '$')); + EXPECT_TRUE(AtomMatchesChar(false, '5', '5')); + EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z')); +} + +TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid) { + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)), + "NULL is not a valid simple regular expression"); + EXPECT_NONFATAL_FAILURE( + ASSERT_FALSE(ValidateRegex("a\\")), + "Syntax error at index 1 in simple regular expression \"a\\\": "); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")), + "'\\' cannot appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")), + "'\\' cannot appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")), + "invalid escape sequence \"\\h\""); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")), + "'^' can only appear at the beginning"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")), + "'^' can only appear at the beginning"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")), + "'$' can only appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")), + "'$' can only appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")), + "'(' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")), + "')' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")), + "'[' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")), + "'{' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")), + "'?' can only follow a repeatable token"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")), + "'*' can only follow a repeatable token"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")), + "'+' can only follow a repeatable token"); +} + +TEST(ValidateRegexTest, ReturnsTrueForValid) { + EXPECT_TRUE(ValidateRegex("")); + EXPECT_TRUE(ValidateRegex("a")); + EXPECT_TRUE(ValidateRegex(".*")); + EXPECT_TRUE(ValidateRegex("^a_+")); + EXPECT_TRUE(ValidateRegex("^a\\t\\&?")); + EXPECT_TRUE(ValidateRegex("09*$")); + EXPECT_TRUE(ValidateRegex("^Z$")); + EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}")); +} + +TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne) { + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba")); + // Repeating more than once. + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab")); + + // Repeating zero times. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba")); + // Repeating once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab")); + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##")); +} + +TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany) { + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab")); + + // Repeating zero times. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc")); + // Repeating once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc")); + // Repeating more than once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g")); +} + +TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany) { + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab")); + // Repeating zero times. + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc")); + + // Repeating once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc")); + // Repeating more than once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g")); +} + +TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex) { + EXPECT_TRUE(MatchRegexAtHead("", "")); + EXPECT_TRUE(MatchRegexAtHead("", "ab")); +} + +TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex) { + EXPECT_FALSE(MatchRegexAtHead("$", "a")); + + EXPECT_TRUE(MatchRegexAtHead("$", "")); + EXPECT_TRUE(MatchRegexAtHead("a$", "a")); +} + +TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence) { + EXPECT_FALSE(MatchRegexAtHead("\\w", "+")); + EXPECT_FALSE(MatchRegexAtHead("\\W", "ab")); + + EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab")); + EXPECT_TRUE(MatchRegexAtHead("\\d", "1a")); +} + +TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) { + EXPECT_FALSE(MatchRegexAtHead(".+a", "abc")); + EXPECT_FALSE(MatchRegexAtHead("a?b", "aab")); + + EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab")); + EXPECT_TRUE(MatchRegexAtHead("a?b", "b")); + EXPECT_TRUE(MatchRegexAtHead("a?b", "ab")); +} + +TEST(MatchRegexAtHeadTest, + WorksWhenRegexStartsWithRepetionOfEscapeSequence) { + EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc")); + EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b")); + + EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab")); + EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b")); + EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b")); + EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b")); +} + +TEST(MatchRegexAtHeadTest, MatchesSequentially) { + EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc")); + + EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc")); +} + +TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull) { + EXPECT_FALSE(MatchRegexAnywhere("", NULL)); +} + +TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret) { + EXPECT_FALSE(MatchRegexAnywhere("^a", "ba")); + EXPECT_FALSE(MatchRegexAnywhere("^$", "a")); + + EXPECT_TRUE(MatchRegexAnywhere("^a", "ab")); + EXPECT_TRUE(MatchRegexAnywhere("^", "ab")); + EXPECT_TRUE(MatchRegexAnywhere("^$", "")); +} + +TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch) { + EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123")); + EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888")); +} + +TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix) { + EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5")); + EXPECT_TRUE(MatchRegexAnywhere(".*=", "=")); + EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc")); +} + +TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix) { + EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5")); + EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...=")); +} + +// Tests RE's implicit constructors. +TEST(RETest, ImplicitConstructorWorks) { + const RE empty(""); + EXPECT_STREQ("", empty.pattern()); + + const RE simple("hello"); + EXPECT_STREQ("hello", simple.pattern()); +} + +// Tests that RE's constructors reject invalid regular expressions. +TEST(RETest, RejectsInvalidRegex) { + EXPECT_NONFATAL_FAILURE({ + const RE normal(NULL); + }, "NULL is not a valid simple regular expression"); + + EXPECT_NONFATAL_FAILURE({ + const RE normal(".*(\\w+"); + }, "'(' is unsupported"); + + EXPECT_NONFATAL_FAILURE({ + const RE invalid("^?"); + }, "'?' can only follow a repeatable token"); +} + +// Tests RE::FullMatch(). +TEST(RETest, FullMatchWorks) { + const RE empty(""); + EXPECT_TRUE(RE::FullMatch("", empty)); + EXPECT_FALSE(RE::FullMatch("a", empty)); + + const RE re1("a"); + EXPECT_TRUE(RE::FullMatch("a", re1)); + + const RE re("a.*z"); + EXPECT_TRUE(RE::FullMatch("az", re)); + EXPECT_TRUE(RE::FullMatch("axyz", re)); + EXPECT_FALSE(RE::FullMatch("baz", re)); + EXPECT_FALSE(RE::FullMatch("azy", re)); +} + +// Tests RE::PartialMatch(). +TEST(RETest, PartialMatchWorks) { + const RE empty(""); + EXPECT_TRUE(RE::PartialMatch("", empty)); + EXPECT_TRUE(RE::PartialMatch("a", empty)); + + const RE re("a.*z"); + EXPECT_TRUE(RE::PartialMatch("az", re)); + EXPECT_TRUE(RE::PartialMatch("axyz", re)); + EXPECT_TRUE(RE::PartialMatch("baz", re)); + EXPECT_TRUE(RE::PartialMatch("azy", re)); + EXPECT_FALSE(RE::PartialMatch("zza", re)); +} + +#endif // GTEST_USES_POSIX_RE + +#if !GTEST_OS_WINDOWS_MOBILE + +TEST(CaptureTest, CapturesStdout) { + CaptureStdout(); + fprintf(stdout, "abc"); + EXPECT_STREQ("abc", GetCapturedStdout().c_str()); + + CaptureStdout(); + fprintf(stdout, "def%cghi", '\0'); + EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout())); +} + +TEST(CaptureTest, CapturesStderr) { + CaptureStderr(); + fprintf(stderr, "jkl"); + EXPECT_STREQ("jkl", GetCapturedStderr().c_str()); + + CaptureStderr(); + fprintf(stderr, "jkl%cmno", '\0'); + EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr())); +} + +// Tests that stdout and stderr capture don't interfere with each other. +TEST(CaptureTest, CapturesStdoutAndStderr) { + CaptureStdout(); + CaptureStderr(); + fprintf(stdout, "pqr"); + fprintf(stderr, "stu"); + EXPECT_STREQ("pqr", GetCapturedStdout().c_str()); + EXPECT_STREQ("stu", GetCapturedStderr().c_str()); +} + +TEST(CaptureDeathTest, CannotReenterStdoutCapture) { + CaptureStdout(); + EXPECT_DEATH_IF_SUPPORTED(CaptureStdout();, + "Only one stdout capturer can exist at a time"); + GetCapturedStdout(); + + // We cannot test stderr capturing using death tests as they use it + // themselves. +} + +#endif // !GTEST_OS_WINDOWS_MOBILE + +TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) { + ThreadLocal t1; + EXPECT_EQ(0, t1.get()); + + ThreadLocal t2; + EXPECT_TRUE(t2.get() == NULL); +} + +TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) { + ThreadLocal t1(123); + EXPECT_EQ(123, t1.get()); + + int i = 0; + ThreadLocal t2(&i); + EXPECT_EQ(&i, t2.get()); +} + +class NoDefaultContructor { + public: + explicit NoDefaultContructor(const char*) {} + NoDefaultContructor(const NoDefaultContructor&) {} +}; + +TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { + ThreadLocal bar(NoDefaultContructor("foo")); + bar.pointer(); +} + +TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { + ThreadLocal thread_local; + + EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); + + // Verifies the condition still holds after calling set. + thread_local.set("foo"); + EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); +} + +TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { + ThreadLocal thread_local; + const ThreadLocal& const_thread_local = thread_local; + + EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); + + thread_local.set("foo"); + EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); +} + +#if GTEST_IS_THREADSAFE + +void AddTwo(int* param) { *param += 2; } + +TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { + int i = 40; + ThreadWithParam thread(&AddTwo, &i, NULL); + thread.Join(); + EXPECT_EQ(42, i); +} + +TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { + // AssertHeld() is flaky only in the presence of multiple threads accessing + // the lock. In this case, the test is robust. + EXPECT_DEATH_IF_SUPPORTED({ + Mutex m; + { MutexLock lock(&m); } + m.AssertHeld(); + }, + "thread .*hold"); +} + +TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { + Mutex m; + MutexLock lock(&m); + m.AssertHeld(); +} + +class AtomicCounterWithMutex { + public: + explicit AtomicCounterWithMutex(Mutex* mutex) : + value_(0), mutex_(mutex), random_(42) {} + + void Increment() { + MutexLock lock(mutex_); + int temp = value_; + { + // Locking a mutex puts up a memory barrier, preventing reads and + // writes to value_ rearranged when observed from other threads. + // + // We cannot use Mutex and MutexLock here or rely on their memory + // barrier functionality as we are testing them here. + pthread_mutex_t memory_barrier_mutex; + GTEST_CHECK_POSIX_SUCCESS_( + pthread_mutex_init(&memory_barrier_mutex, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); + + SleepMilliseconds(random_.Generate(30)); + + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); + } + value_ = temp + 1; + } + int value() const { return value_; } + + private: + volatile int value_; + Mutex* const mutex_; // Protects value_. + Random random_; +}; + +void CountingThreadFunc(pair param) { + for (int i = 0; i < param.second; ++i) + param.first->Increment(); +} + +// Tests that the mutex only lets one thread at a time to lock it. +TEST(MutexTest, OnlyOneThreadCanLockAtATime) { + Mutex mutex; + AtomicCounterWithMutex locked_counter(&mutex); + + typedef ThreadWithParam > ThreadType; + const int kCycleCount = 20; + const int kThreadCount = 7; + scoped_ptr counting_threads[kThreadCount]; + Notification threads_can_start; + // Creates and runs kThreadCount threads that increment locked_counter + // kCycleCount times each. + for (int i = 0; i < kThreadCount; ++i) { + counting_threads[i].reset(new ThreadType(&CountingThreadFunc, + make_pair(&locked_counter, + kCycleCount), + &threads_can_start)); + } + threads_can_start.Notify(); + for (int i = 0; i < kThreadCount; ++i) + counting_threads[i]->Join(); + + // If the mutex lets more than one thread to increment the counter at a + // time, they are likely to encounter a race condition and have some + // increments overwritten, resulting in the lower then expected counter + // value. + EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); +} + +template +void RunFromThread(void (func)(T), T param) { + ThreadWithParam thread(func, param, NULL); + thread.Join(); +} + +void RetrieveThreadLocalValue(pair*, String*> param) { + *param.second = param.first->get(); +} + +TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { + ThreadLocal thread_local("foo"); + EXPECT_STREQ("foo", thread_local.get().c_str()); + + thread_local.set("bar"); + EXPECT_STREQ("bar", thread_local.get().c_str()); + + String result; + RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); + EXPECT_STREQ("foo", result.c_str()); +} + +// DestructorTracker keeps track of whether its instances have been +// destroyed. +static std::vector g_destroyed; + +class DestructorTracker { + public: + DestructorTracker() : index_(GetNewIndex()) {} + DestructorTracker(const DestructorTracker& /* rhs */) + : index_(GetNewIndex()) {} + ~DestructorTracker() { + // We never access g_destroyed concurrently, so we don't need to + // protect the write operation under a mutex. + g_destroyed[index_] = true; + } + + private: + static int GetNewIndex() { + g_destroyed.push_back(false); + return g_destroyed.size() - 1; + } + const int index_; +}; + +typedef ThreadLocal* ThreadParam; + +void CallThreadLocalGet(ThreadParam thread_local) { + thread_local->get(); +} + +// Tests that when a ThreadLocal object dies in a thread, it destroys +// the managed object for that thread. +TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) { + g_destroyed.clear(); + + { + // The next line default constructs a DestructorTracker object as + // the default value of objects managed by thread_local. + ThreadLocal thread_local; + ASSERT_EQ(1U, g_destroyed.size()); + ASSERT_FALSE(g_destroyed[0]); + + // This creates another DestructorTracker object for the main thread. + thread_local.get(); + ASSERT_EQ(2U, g_destroyed.size()); + ASSERT_FALSE(g_destroyed[0]); + ASSERT_FALSE(g_destroyed[1]); + } + + // Now thread_local has died. It should have destroyed both the + // default value shared by all threads and the value for the main + // thread. + ASSERT_EQ(2U, g_destroyed.size()); + EXPECT_TRUE(g_destroyed[0]); + EXPECT_TRUE(g_destroyed[1]); + + g_destroyed.clear(); +} + +// Tests that when a thread exits, the thread-local object for that +// thread is destroyed. +TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) { + g_destroyed.clear(); + + { + // The next line default constructs a DestructorTracker object as + // the default value of objects managed by thread_local. + ThreadLocal thread_local; + ASSERT_EQ(1U, g_destroyed.size()); + ASSERT_FALSE(g_destroyed[0]); + + // This creates another DestructorTracker object in the new thread. + ThreadWithParam thread( + &CallThreadLocalGet, &thread_local, NULL); + thread.Join(); + + // Now the new thread has exited. The per-thread object for it + // should have been destroyed. + ASSERT_EQ(2U, g_destroyed.size()); + ASSERT_FALSE(g_destroyed[0]); + ASSERT_TRUE(g_destroyed[1]); + } + + // Now thread_local has died. The default value should have been + // destroyed too. + ASSERT_EQ(2U, g_destroyed.size()); + EXPECT_TRUE(g_destroyed[0]); + EXPECT_TRUE(g_destroyed[1]); + + g_destroyed.clear(); +} + +TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { + ThreadLocal thread_local; + thread_local.set("Foo"); + EXPECT_STREQ("Foo", thread_local.get().c_str()); + + String result; + RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); + EXPECT_TRUE(result.c_str() == NULL); +} + +#endif // GTEST_IS_THREADSAFE + +} // namespace internal +} // namespace testing diff --git a/third_party/googletest/src/test/gtest-printers_test.cc b/third_party/googletest/src/test/gtest-printers_test.cc new file mode 100644 index 0000000..6292c7f --- /dev/null +++ b/third_party/googletest/src/test/gtest-printers_test.cc @@ -0,0 +1,1307 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file tests the universal value printer. + +#include "gtest/gtest-printers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +// hash_map and hash_set are available under Visual C++. +#if _MSC_VER +# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. +# include // NOLINT +# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. +# include // NOLINT +#endif // GTEST_OS_WINDOWS + +// Some user-defined types for testing the universal value printer. + +// An anonymous enum type. +enum AnonymousEnum { + kAE1 = -1, + kAE2 = 1 +}; + +// An enum without a user-defined printer. +enum EnumWithoutPrinter { + kEWP1 = -2, + kEWP2 = 42 +}; + +// An enum with a << operator. +enum EnumWithStreaming { + kEWS1 = 10 +}; + +std::ostream& operator<<(std::ostream& os, EnumWithStreaming e) { + return os << (e == kEWS1 ? "kEWS1" : "invalid"); +} + +// An enum with a PrintTo() function. +enum EnumWithPrintTo { + kEWPT1 = 1 +}; + +void PrintTo(EnumWithPrintTo e, std::ostream* os) { + *os << (e == kEWPT1 ? "kEWPT1" : "invalid"); +} + +// A class implicitly convertible to BiggestInt. +class BiggestIntConvertible { + public: + operator ::testing::internal::BiggestInt() const { return 42; } +}; + +// A user-defined unprintable class template in the global namespace. +template +class UnprintableTemplateInGlobal { + public: + UnprintableTemplateInGlobal() : value_() {} + private: + T value_; +}; + +// A user-defined streamable type in the global namespace. +class StreamableInGlobal { + public: + virtual ~StreamableInGlobal() {} +}; + +inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { + os << "StreamableInGlobal"; +} + +void operator<<(::std::ostream& os, const StreamableInGlobal* /* x */) { + os << "StreamableInGlobal*"; +} + +namespace foo { + +// A user-defined unprintable type in a user namespace. +class UnprintableInFoo { + public: + UnprintableInFoo() : z_(0) { memcpy(xy_, "\xEF\x12\x0\x0\x34\xAB\x0\x0", 8); } + private: + char xy_[8]; + double z_; +}; + +// A user-defined printable type in a user-chosen namespace. +struct PrintableViaPrintTo { + PrintableViaPrintTo() : value() {} + int value; +}; + +void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { + *os << "PrintableViaPrintTo: " << x.value; +} + +// A type with a user-defined << for printing its pointer. +struct PointerPrintable { +}; + +::std::ostream& operator<<(::std::ostream& os, + const PointerPrintable* /* x */) { + return os << "PointerPrintable*"; +} + +// A user-defined printable class template in a user-chosen namespace. +template +class PrintableViaPrintToTemplate { + public: + explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template +void PrintTo(const PrintableViaPrintToTemplate& x, ::std::ostream* os) { + *os << "PrintableViaPrintToTemplate: " << x.value(); +} + +// A user-defined streamable class template in a user namespace. +template +class StreamableTemplateInFoo { + public: + StreamableTemplateInFoo() : value_() {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template +inline ::std::ostream& operator<<(::std::ostream& os, + const StreamableTemplateInFoo& x) { + return os << "StreamableTemplateInFoo: " << x.value(); +} + +} // namespace foo + +namespace testing { +namespace gtest_printers_test { + +using ::std::deque; +using ::std::list; +using ::std::make_pair; +using ::std::map; +using ::std::multimap; +using ::std::multiset; +using ::std::pair; +using ::std::set; +using ::std::vector; +using ::testing::PrintToString; +using ::testing::internal::NativeArray; +using ::testing::internal::RE; +using ::testing::internal::Strings; +using ::testing::internal::UniversalTersePrint; +using ::testing::internal::UniversalPrint; +using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; +using ::testing::internal::UniversalPrinter; +using ::testing::internal::kReference; +using ::testing::internal::string; + +#if GTEST_HAS_TR1_TUPLE +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +#endif + +#if _MSC_VER +// MSVC defines the following classes in the ::stdext namespace while +// gcc defines them in the :: namespace. Note that they are not part +// of the C++ standard. +using ::stdext::hash_map; +using ::stdext::hash_set; +using ::stdext::hash_multimap; +using ::stdext::hash_multiset; +#endif + +// Prints a value to a string using the universal value printer. This +// is a helper for testing UniversalPrinter::Print() for various types. +template +string Print(const T& value) { + ::std::stringstream ss; + UniversalPrinter::Print(value, &ss); + return ss.str(); +} + +// Prints a value passed by reference to a string, using the universal +// value printer. This is a helper for testing +// UniversalPrinter::Print() for various types. +template +string PrintByRef(const T& value) { + ::std::stringstream ss; + UniversalPrinter::Print(value, &ss); + return ss.str(); +} + +// Tests printing various enum types. + +TEST(PrintEnumTest, AnonymousEnum) { + EXPECT_EQ("-1", Print(kAE1)); + EXPECT_EQ("1", Print(kAE2)); +} + +TEST(PrintEnumTest, EnumWithoutPrinter) { + EXPECT_EQ("-2", Print(kEWP1)); + EXPECT_EQ("42", Print(kEWP2)); +} + +TEST(PrintEnumTest, EnumWithStreaming) { + EXPECT_EQ("kEWS1", Print(kEWS1)); + EXPECT_EQ("invalid", Print(static_cast(0))); +} + +TEST(PrintEnumTest, EnumWithPrintTo) { + EXPECT_EQ("kEWPT1", Print(kEWPT1)); + EXPECT_EQ("invalid", Print(static_cast(0))); +} + +// Tests printing a class implicitly convertible to BiggestInt. + +TEST(PrintClassTest, BiggestIntConvertible) { + EXPECT_EQ("42", Print(BiggestIntConvertible())); +} + +// Tests printing various char types. + +// char. +TEST(PrintCharTest, PlainChar) { + EXPECT_EQ("'\\0'", Print('\0')); + EXPECT_EQ("'\\'' (39, 0x27)", Print('\'')); + EXPECT_EQ("'\"' (34, 0x22)", Print('"')); + EXPECT_EQ("'?' (63, 0x3F)", Print('?')); + EXPECT_EQ("'\\\\' (92, 0x5C)", Print('\\')); + EXPECT_EQ("'\\a' (7)", Print('\a')); + EXPECT_EQ("'\\b' (8)", Print('\b')); + EXPECT_EQ("'\\f' (12, 0xC)", Print('\f')); + EXPECT_EQ("'\\n' (10, 0xA)", Print('\n')); + EXPECT_EQ("'\\r' (13, 0xD)", Print('\r')); + EXPECT_EQ("'\\t' (9)", Print('\t')); + EXPECT_EQ("'\\v' (11, 0xB)", Print('\v')); + EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); + EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); + EXPECT_EQ("' ' (32, 0x20)", Print(' ')); + EXPECT_EQ("'a' (97, 0x61)", Print('a')); +} + +// signed char. +TEST(PrintCharTest, SignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast('\0'))); + EXPECT_EQ("'\\xCE' (-50)", + Print(static_cast(-50))); +} + +// unsigned char. +TEST(PrintCharTest, UnsignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast('\0'))); + EXPECT_EQ("'b' (98, 0x62)", + Print(static_cast('b'))); +} + +// Tests printing other simple, built-in types. + +// bool. +TEST(PrintBuiltInTypeTest, Bool) { + EXPECT_EQ("false", Print(false)); + EXPECT_EQ("true", Print(true)); +} + +// wchar_t. +TEST(PrintBuiltInTypeTest, Wchar_t) { + EXPECT_EQ("L'\\0'", Print(L'\0')); + EXPECT_EQ("L'\\'' (39, 0x27)", Print(L'\'')); + EXPECT_EQ("L'\"' (34, 0x22)", Print(L'"')); + EXPECT_EQ("L'?' (63, 0x3F)", Print(L'?')); + EXPECT_EQ("L'\\\\' (92, 0x5C)", Print(L'\\')); + EXPECT_EQ("L'\\a' (7)", Print(L'\a')); + EXPECT_EQ("L'\\b' (8)", Print(L'\b')); + EXPECT_EQ("L'\\f' (12, 0xC)", Print(L'\f')); + EXPECT_EQ("L'\\n' (10, 0xA)", Print(L'\n')); + EXPECT_EQ("L'\\r' (13, 0xD)", Print(L'\r')); + EXPECT_EQ("L'\\t' (9)", Print(L'\t')); + EXPECT_EQ("L'\\v' (11, 0xB)", Print(L'\v')); + EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); + EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); + EXPECT_EQ("L' ' (32, 0x20)", Print(L' ')); + EXPECT_EQ("L'a' (97, 0x61)", Print(L'a')); + EXPECT_EQ("L'\\x576' (1398)", Print(static_cast(0x576))); + EXPECT_EQ("L'\\xC74D' (51021)", Print(static_cast(0xC74D))); +} + +// Test that Int64 provides more storage than wchar_t. +TEST(PrintTypeSizeTest, Wchar_t) { + EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); +} + +// Various integer types. +TEST(PrintBuiltInTypeTest, Integer) { + EXPECT_EQ("'\\xFF' (255)", Print(static_cast(255))); // uint8 + EXPECT_EQ("'\\x80' (-128)", Print(static_cast(-128))); // int8 + EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 + EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 + EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 + EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 + EXPECT_EQ("18446744073709551615", + Print(static_cast(-1))); // uint64 + EXPECT_EQ("-9223372036854775808", + Print(static_cast(1) << 63)); // int64 +} + +// Size types. +TEST(PrintBuiltInTypeTest, Size_t) { + EXPECT_EQ("1", Print(sizeof('a'))); // size_t. +#if !GTEST_OS_WINDOWS + // Windows has no ssize_t type. + EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. +#endif // !GTEST_OS_WINDOWS +} + +// Floating-points. +TEST(PrintBuiltInTypeTest, FloatingPoints) { + EXPECT_EQ("1.5", Print(1.5f)); // float + EXPECT_EQ("-2.5", Print(-2.5)); // double +} + +// Since ::std::stringstream::operator<<(const void *) formats the pointer +// output differently with different compilers, we have to create the expected +// output first and use it as our expectation. +static string PrintPointer(const void *p) { + ::std::stringstream expected_result_stream; + expected_result_stream << p; + return expected_result_stream.str(); +} + +// Tests printing C strings. + +// const char*. +TEST(PrintCStringTest, Const) { + const char* p = "World"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); +} + +// char*. +TEST(PrintCStringTest, NonConst) { + char p[] = "Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", + Print(static_cast(p))); +} + +// NULL C string. +TEST(PrintCStringTest, Null) { + const char* p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that C strings are escaped properly. +TEST(PrintCStringTest, EscapesProperly) { + const char* p = "'\"?\\\a\b\f\n\r\t\v\x7F\xFF a"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\x7F\\xFF a\"", + Print(p)); +} + + + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + +// const wchar_t*. +TEST(PrintWideCStringTest, Const) { + const wchar_t* p = L"World"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); +} + +// wchar_t*. +TEST(PrintWideCStringTest, NonConst) { + wchar_t p[] = L"Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", + Print(static_cast(p))); +} + +// NULL wide C string. +TEST(PrintWideCStringTest, Null) { + const wchar_t* p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that wide C strings are escaped properly. +TEST(PrintWideCStringTest, EscapesProperly) { + const wchar_t s[] = {'\'', '"', '?', '\\', '\a', '\b', '\f', '\n', '\r', + '\t', '\v', 0xD3, 0x576, 0x8D3, 0xC74D, ' ', 'a', '\0'}; + EXPECT_EQ(PrintPointer(s) + " pointing to L\"'\\\"?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", + Print(static_cast(s))); +} +#endif // native wchar_t + +// Tests printing pointers to other char types. + +// signed char*. +TEST(PrintCharPointerTest, SignedChar) { + signed char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const signed char*. +TEST(PrintCharPointerTest, ConstSignedChar) { + signed char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// unsigned char*. +TEST(PrintCharPointerTest, UnsignedChar) { + unsigned char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const unsigned char*. +TEST(PrintCharPointerTest, ConstUnsignedChar) { + const unsigned char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to simple, built-in types. + +// bool*. +TEST(PrintPointerToBuiltInTypeTest, Bool) { + bool* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// void*. +TEST(PrintPointerToBuiltInTypeTest, Void) { + void* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const void*. +TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { + const void* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to pointers. +TEST(PrintPointerToPointerTest, IntPointerPointer) { + int** p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing (non-member) function pointers. + +void MyFunction(int /* n */) {} + +TEST(PrintPointerTest, NonMemberFunctionPointer) { + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + EXPECT_EQ( + PrintPointer(reinterpret_cast( + reinterpret_cast(&MyFunction))), + Print(&MyFunction)); + int (*p)(bool) = NULL; // NOLINT + EXPECT_EQ("NULL", Print(p)); +} + +// An assertion predicate determining whether a one string is a prefix for +// another. +template +AssertionResult HasPrefix(const StringType& str, const StringType& prefix) { + if (str.find(prefix, 0) == 0) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(prefix[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << begin_string_quote << prefix << "\" is not a prefix of " + << begin_string_quote << str << "\"\n"; +} + +// Tests printing member variable pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. + +struct Foo { + public: + virtual ~Foo() {} + int MyMethod(char x) { return x + 1; } + virtual char MyVirtualMethod(int /* n */) { return 'a'; } + + int value; +}; + +TEST(PrintPointerTest, MemberVariablePointer) { + EXPECT_TRUE(HasPrefix(Print(&Foo::value), + Print(sizeof(&Foo::value)) + "-byte object ")); + int (Foo::*p) = NULL; // NOLINT + EXPECT_TRUE(HasPrefix(Print(p), + Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing member function pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. +TEST(PrintPointerTest, MemberFunctionPointer) { + EXPECT_TRUE(HasPrefix(Print(&Foo::MyMethod), + Print(sizeof(&Foo::MyMethod)) + "-byte object ")); + EXPECT_TRUE( + HasPrefix(Print(&Foo::MyVirtualMethod), + Print(sizeof((&Foo::MyVirtualMethod))) + "-byte object ")); + int (Foo::*p)(char) = NULL; // NOLINT + EXPECT_TRUE(HasPrefix(Print(p), + Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing C arrays. + +// The difference between this and Print() is that it ensures that the +// argument is a reference to an array. +template +string PrintArrayHelper(T (&a)[N]) { + return Print(a); +} + +// One-dimensional array. +TEST(PrintArrayTest, OneDimensionalArray) { + int a[5] = { 1, 2, 3, 4, 5 }; + EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); +} + +// Two-dimensional array. +TEST(PrintArrayTest, TwoDimensionalArray) { + int a[2][5] = { + { 1, 2, 3, 4, 5 }, + { 6, 7, 8, 9, 0 } + }; + EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); +} + +// Array of const elements. +TEST(PrintArrayTest, ConstArray) { + const bool a[1] = { false }; + EXPECT_EQ("{ false }", PrintArrayHelper(a)); +} + +// Char array. +TEST(PrintArrayTest, CharArray) { + // Array a contains '\0' in the middle and doesn't end with '\0'. + char a[3] = { 'H', '\0', 'i' }; + EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a)); +} + +// Const char array. +TEST(PrintArrayTest, ConstCharArray) { + const char a[4] = "\0Hi"; + EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a)); +} + +// Array of objects. +TEST(PrintArrayTest, ObjectArray) { + string a[3] = { "Hi", "Hello", "Ni hao" }; + EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); +} + +// Array with many elements. +TEST(PrintArrayTest, BigArray) { + int a[100] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", + PrintArrayHelper(a)); +} + +// Tests printing ::string and ::std::string. + +#if GTEST_HAS_GLOBAL_STRING +// ::string. +TEST(PrintStringTest, StringInGlobalNamespace) { + const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_GLOBAL_STRING + +// ::std::string. +TEST(PrintStringTest, StringInStdNamespace) { + const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::std::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} + +TEST(PrintStringTest, StringAmbiguousHex) { + // "\x6BANANA" is ambiguous, it can be interpreted as starting with either of: + // '\x6', '\x6B', or '\x6BA'. + + // a hex escaping sequence following by a decimal digit + EXPECT_EQ("\"0\\x12\" \"3\"", Print(::std::string("0\x12" "3"))); + // a hex escaping sequence following by a hex digit (lower-case) + EXPECT_EQ("\"mm\\x6\" \"bananas\"", Print(::std::string("mm\x6" "bananas"))); + // a hex escaping sequence following by a hex digit (upper-case) + EXPECT_EQ("\"NOM\\x6\" \"BANANA\"", Print(::std::string("NOM\x6" "BANANA"))); + // a hex escaping sequence following by a non-xdigit + EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!"))); +} + +// Tests printing ::wstring and ::std::wstring. + +#if GTEST_HAS_GLOBAL_WSTRING +// ::wstring. +TEST(PrintWideStringTest, StringInGlobalNamespace) { + const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +// ::std::wstring. +TEST(PrintWideStringTest, StringInStdNamespace) { + const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} + +TEST(PrintWideStringTest, StringAmbiguousHex) { + // same for wide strings. + EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" L"3"))); + EXPECT_EQ("L\"mm\\x6\" L\"bananas\"", + Print(::std::wstring(L"mm\x6" L"bananas"))); + EXPECT_EQ("L\"NOM\\x6\" L\"BANANA\"", + Print(::std::wstring(L"NOM\x6" L"BANANA"))); + EXPECT_EQ("L\"!\\x5-!\"", Print(::std::wstring(L"!\x5-!"))); +} +#endif // GTEST_HAS_STD_WSTRING + +// Tests printing types that support generic streaming (i.e. streaming +// to std::basic_ostream for any valid Char and +// CharTraits types). + +// Tests printing a non-template type that supports generic streaming. + +class AllowsGenericStreaming {}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreaming& /* a */) { + return os << "AllowsGenericStreaming"; +} + +TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { + AllowsGenericStreaming a; + EXPECT_EQ("AllowsGenericStreaming", Print(a)); +} + +// Tests printing a template type that supports generic streaming. + +template +class AllowsGenericStreamingTemplate {}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreamingTemplate& /* a */) { + return os << "AllowsGenericStreamingTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TemplateType) { + AllowsGenericStreamingTemplate a; + EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); +} + +// Tests printing a type that supports generic streaming and can be +// implicitly converted to another printable type. + +template +class AllowsGenericStreamingAndImplicitConversionTemplate { + public: + operator bool() const { return false; } +}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreamingAndImplicitConversionTemplate& /* a */) { + return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { + AllowsGenericStreamingAndImplicitConversionTemplate a; + EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); +} + +#if GTEST_HAS_STRING_PIECE_ + +// Tests printing StringPiece. + +TEST(PrintStringPieceTest, SimpleStringPiece) { + const StringPiece sp = "Hello"; + EXPECT_EQ("\"Hello\"", Print(sp)); +} + +TEST(PrintStringPieceTest, UnprintableCharacters) { + const char str[] = "NUL (\0) and \r\t"; + const StringPiece sp(str, sizeof(str) - 1); + EXPECT_EQ("\"NUL (\\0) and \\r\\t\"", Print(sp)); +} + +#endif // GTEST_HAS_STRING_PIECE_ + +// Tests printing STL containers. + +TEST(PrintStlContainerTest, EmptyDeque) { + deque empty; + EXPECT_EQ("{}", Print(empty)); +} + +TEST(PrintStlContainerTest, NonEmptyDeque) { + deque non_empty; + non_empty.push_back(1); + non_empty.push_back(3); + EXPECT_EQ("{ 1, 3 }", Print(non_empty)); +} + +#if GTEST_HAS_HASH_MAP_ + +TEST(PrintStlContainerTest, OneElementHashMap) { + hash_map map1; + map1[1] = 'a'; + EXPECT_EQ("{ (1, 'a' (97, 0x61)) }", Print(map1)); +} + +TEST(PrintStlContainerTest, HashMultiMap) { + hash_multimap map1; + map1.insert(make_pair(5, true)); + map1.insert(make_pair(5, false)); + + // Elements of hash_multimap can be printed in any order. + const string result = Print(map1); + EXPECT_TRUE(result == "{ (5, true), (5, false) }" || + result == "{ (5, false), (5, true) }") + << " where Print(map1) returns \"" << result << "\"."; +} + +#endif // GTEST_HAS_HASH_MAP_ + +#if GTEST_HAS_HASH_SET_ + +TEST(PrintStlContainerTest, HashSet) { + hash_set set1; + set1.insert("hello"); + EXPECT_EQ("{ \"hello\" }", Print(set1)); +} + +TEST(PrintStlContainerTest, HashMultiSet) { + const int kSize = 5; + int a[kSize] = { 1, 1, 2, 5, 1 }; + hash_multiset set1(a, a + kSize); + + // Elements of hash_multiset can be printed in any order. + const string result = Print(set1); + const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. + + // Verifies the result matches the expected pattern; also extracts + // the numbers in the result. + ASSERT_EQ(expected_pattern.length(), result.length()); + std::vector numbers; + for (size_t i = 0; i != result.length(); i++) { + if (expected_pattern[i] == 'd') { + ASSERT_TRUE(isdigit(static_cast(result[i])) != 0); + numbers.push_back(result[i] - '0'); + } else { + EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " + << result; + } + } + + // Makes sure the result contains the right numbers. + std::sort(numbers.begin(), numbers.end()); + std::sort(a, a + kSize); + EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); +} + +#endif // GTEST_HAS_HASH_SET_ + +TEST(PrintStlContainerTest, List) { + const string a[] = { + "hello", + "world" + }; + const list strings(a, a + 2); + EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); +} + +TEST(PrintStlContainerTest, Map) { + map map1; + map1[1] = true; + map1[5] = false; + map1[3] = true; + EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); +} + +TEST(PrintStlContainerTest, MultiMap) { + multimap map1; + // The make_pair template function would deduce the type as + // pair here, and since the key part in a multimap has to + // be constant, without a templated ctor in the pair class (as in + // libCstd on Solaris), make_pair call would fail to compile as no + // implicit conversion is found. Thus explicit typename is used + // here instead. + map1.insert(pair(true, 0)); + map1.insert(pair(true, 1)); + map1.insert(pair(false, 2)); + EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); +} + +TEST(PrintStlContainerTest, Set) { + const unsigned int a[] = { 3, 0, 5 }; + set set1(a, a + 3); + EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, MultiSet) { + const int a[] = { 1, 1, 2, 5, 1 }; + multiset set1(a, a + 5); + EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, Pair) { + pair p(true, 5); + EXPECT_EQ("(true, 5)", Print(p)); +} + +TEST(PrintStlContainerTest, Vector) { + vector v; + v.push_back(1); + v.push_back(2); + EXPECT_EQ("{ 1, 2 }", Print(v)); +} + +TEST(PrintStlContainerTest, LongSequence) { + const int a[100] = { 1, 2, 3 }; + const vector v(a, a + 100); + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " + "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v)); +} + +TEST(PrintStlContainerTest, NestedContainer) { + const int a1[] = { 1, 2 }; + const int a2[] = { 3, 4, 5 }; + const list l1(a1, a1 + 2); + const list l2(a2, a2 + 3); + + vector > v; + v.push_back(l1); + v.push_back(l2); + EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); +} + +TEST(PrintStlContainerTest, OneDimensionalNativeArray) { + const int a[3] = { 1, 2, 3 }; + NativeArray b(a, 3, kReference); + EXPECT_EQ("{ 1, 2, 3 }", Print(b)); +} + +TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { + const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + NativeArray b(a, 2, kReference); + EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); +} + +// Tests that a class named iterator isn't treated as a container. + +struct iterator { + char x; +}; + +TEST(PrintStlContainerTest, Iterator) { + iterator it = {}; + EXPECT_EQ("1-byte object <00>", Print(it)); +} + +// Tests that a class named const_iterator isn't treated as a container. + +struct const_iterator { + char x; +}; + +TEST(PrintStlContainerTest, ConstIterator) { + const_iterator it = {}; + EXPECT_EQ("1-byte object <00>", Print(it)); +} + +#if GTEST_HAS_TR1_TUPLE +// Tests printing tuples. + +// Tuples of various arities. +TEST(PrintTupleTest, VariousSizes) { + tuple<> t0; + EXPECT_EQ("()", Print(t0)); + + tuple t1(5); + EXPECT_EQ("(5)", Print(t1)); + + tuple t2('a', true); + EXPECT_EQ("('a' (97, 0x61), true)", Print(t2)); + + tuple t3(false, 2, 3); + EXPECT_EQ("(false, 2, 3)", Print(t3)); + + tuple t4(false, 2, 3, 4); + EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); + + tuple t5(false, 2, 3, 4, true); + EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); + + tuple t6(false, 2, 3, 4, true, 6); + EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); + + tuple t7(false, 2, 3, 4, true, 6, 7); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); + + tuple t8( + false, 2, 3, 4, true, 6, 7, true); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); + + tuple t9( + false, 2, 3, 4, true, 6, 7, true, 9); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); + + const char* const str = "8"; + tuple + t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, NULL, "10"); + EXPECT_EQ("(false, 'a' (97, 0x61), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + + " pointing to \"8\", NULL, \"10\")", + Print(t10)); +} + +// Nested tuples. +TEST(PrintTupleTest, NestedTuple) { + tuple, char> nested(make_tuple(5, true), 'a'); + EXPECT_EQ("((5, true), 'a' (97, 0x61))", Print(nested)); +} + +#endif // GTEST_HAS_TR1_TUPLE + +// Tests printing user-defined unprintable types. + +// Unprintable types in the global namespace. +TEST(PrintUnprintableTypeTest, InGlobalNamespace) { + EXPECT_EQ("1-byte object <00>", + Print(UnprintableTemplateInGlobal())); +} + +// Unprintable types in a user namespace. +TEST(PrintUnprintableTypeTest, InUserNamespace) { + EXPECT_EQ("16-byte object ", + Print(::foo::UnprintableInFoo())); +} + +// Unprintable types are that too big to be printed completely. + +struct Big { + Big() { memset(array, 0, sizeof(array)); } + char array[257]; +}; + +TEST(PrintUnpritableTypeTest, BigObject) { + EXPECT_EQ("257-byte object <00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 ... 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00>", + Print(Big())); +} + +// Tests printing user-defined streamable types. + +// Streamable types in the global namespace. +TEST(PrintStreamableTypeTest, InGlobalNamespace) { + StreamableInGlobal x; + EXPECT_EQ("StreamableInGlobal", Print(x)); + EXPECT_EQ("StreamableInGlobal*", Print(&x)); +} + +// Printable template types in a user namespace. +TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { + EXPECT_EQ("StreamableTemplateInFoo: 0", + Print(::foo::StreamableTemplateInFoo())); +} + +// Tests printing user-defined types that have a PrintTo() function. +TEST(PrintPrintableTypeTest, InUserNamespace) { + EXPECT_EQ("PrintableViaPrintTo: 0", + Print(::foo::PrintableViaPrintTo())); +} + +// Tests printing a pointer to a user-defined type that has a << +// operator for its pointer. +TEST(PrintPrintableTypeTest, PointerInUserNamespace) { + ::foo::PointerPrintable x; + EXPECT_EQ("PointerPrintable*", Print(&x)); +} + +// Tests printing user-defined class template that have a PrintTo() function. +TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { + EXPECT_EQ("PrintableViaPrintToTemplate: 5", + Print(::foo::PrintableViaPrintToTemplate(5))); +} + +#if GTEST_HAS_PROTOBUF_ + +// Tests printing a protocol message. +TEST(PrintProtocolMessageTest, PrintsShortDebugString) { + testing::internal::TestMessage msg; + msg.set_member("yes"); + EXPECT_EQ("", Print(msg)); +} + +// Tests printing a short proto2 message. +TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) { + testing::internal::FooMessage msg; + msg.set_int_field(2); + msg.set_string_field("hello"); + EXPECT_PRED2(RE::FullMatch, Print(msg), + ""); +} + +// Tests printing a long proto2 message. +TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong) { + testing::internal::FooMessage msg; + msg.set_int_field(2); + msg.set_string_field("hello"); + msg.add_names("peter"); + msg.add_names("paul"); + msg.add_names("mary"); + EXPECT_PRED2(RE::FullMatch, Print(msg), + "<\n" + "int_field:\\s*2\n" + "string_field:\\s*\"hello\"\n" + "names:\\s*\"peter\"\n" + "names:\\s*\"paul\"\n" + "names:\\s*\"mary\"\n" + ">"); +} + +#endif // GTEST_HAS_PROTOBUF_ + +// Tests that the universal printer prints both the address and the +// value of a reference. +TEST(PrintReferenceTest, PrintsAddressAndValue) { + int n = 5; + EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); + + int a[2][3] = { + { 0, 1, 2 }, + { 3, 4, 5 } + }; + EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", + PrintByRef(a)); + + const ::foo::UnprintableInFoo x; + EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " + "", + PrintByRef(x)); +} + +// Tests that the universal printer prints a function pointer passed by +// reference. +TEST(PrintReferenceTest, HandlesFunctionPointer) { + void (*fp)(int n) = &MyFunction; + const string fp_pointer_string = + PrintPointer(reinterpret_cast(&fp)); + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + const string fp_string = PrintPointer(reinterpret_cast( + reinterpret_cast(fp))); + EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, + PrintByRef(fp)); +} + +// Tests that the universal printer prints a member function pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { + int (Foo::*p)(char ch) = &Foo::MyMethod; + EXPECT_TRUE(HasPrefix( + PrintByRef(p), + "@" + PrintPointer(reinterpret_cast(&p)) + " " + + Print(sizeof(p)) + "-byte object ")); + + char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; + EXPECT_TRUE(HasPrefix( + PrintByRef(p2), + "@" + PrintPointer(reinterpret_cast(&p2)) + " " + + Print(sizeof(p2)) + "-byte object ")); +} + +// Tests that the universal printer prints a member variable pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + int (Foo::*p) = &Foo::value; // NOLINT + EXPECT_TRUE(HasPrefix( + PrintByRef(p), + "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object ")); +} + +// Useful for testing PrintToString(). We cannot use EXPECT_EQ() +// there as its implementation uses PrintToString(). The caller must +// ensure that 'value' has no side effect. +#define EXPECT_PRINT_TO_STRING_(value, expected_string) \ + EXPECT_TRUE(PrintToString(value) == (expected_string)) \ + << " where " #value " prints as " << (PrintToString(value)) + +TEST(PrintToStringTest, WorksForScalar) { + EXPECT_PRINT_TO_STRING_(123, "123"); +} + +TEST(PrintToStringTest, WorksForPointerToConstChar) { + const char* p = "hello"; + EXPECT_PRINT_TO_STRING_(p, "\"hello\""); +} + +TEST(PrintToStringTest, WorksForPointerToNonConstChar) { + char s[] = "hello"; + char* p = s; + EXPECT_PRINT_TO_STRING_(p, "\"hello\""); +} + +TEST(PrintToStringTest, WorksForArray) { + int n[3] = { 1, 2, 3 }; + EXPECT_PRINT_TO_STRING_(n, "{ 1, 2, 3 }"); +} + +#undef EXPECT_PRINT_TO_STRING_ + +TEST(UniversalTersePrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalTersePrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalTersePrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalTersePrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalTersePrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalTersePrint(s1, &ss1); + EXPECT_EQ("\"abc\"", ss1.str()); + + char* s2 = const_cast(s1); + ::std::stringstream ss2; + UniversalTersePrint(s2, &ss2); + EXPECT_EQ("\"abc\"", ss2.str()); + + const char* s3 = NULL; + ::std::stringstream ss3; + UniversalTersePrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + +TEST(UniversalPrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalPrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalPrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalPrint(s1, &ss1); + EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str())); + + char* s2 = const_cast(s1); + ::std::stringstream ss2; + UniversalPrint(s2, &ss2); + EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str())); + + const char* s3 = NULL; + ::std::stringstream ss3; + UniversalPrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + + +#if GTEST_HAS_TR1_TUPLE + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple()); + EXPECT_EQ(0u, result.size()); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1)); + ASSERT_EQ(1u, result.size()); + EXPECT_EQ("1", result[0]); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a')); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ("1", result[0]); + EXPECT_EQ("'a' (97, 0x61)", result[1]); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely) { + const int n = 1; + Strings result = UniversalTersePrintTupleFieldsToStrings( + tuple(n, "a")); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ("1", result[0]); + EXPECT_EQ("\"a\"", result[1]); +} + +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace gtest_printers_test +} // namespace testing diff --git a/third_party/googletest/src/test/gtest-test-part_test.cc b/third_party/googletest/src/test/gtest-test-part_test.cc new file mode 100644 index 0000000..ca8ba93 --- /dev/null +++ b/third_party/googletest/src/test/gtest-test-part_test.cc @@ -0,0 +1,208 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#include "gtest/gtest-test-part.h" + +#include "gtest/gtest.h" + +using testing::Message; +using testing::Test; +using testing::TestPartResult; +using testing::TestPartResultArray; + +namespace { + +// Tests the TestPartResult class. + +// The test fixture for testing TestPartResult. +class TestPartResultTest : public Test { + protected: + TestPartResultTest() + : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"), + r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"), + r3_(TestPartResult::kFatalFailure, NULL, -1, "Failure!") {} + + TestPartResult r1_, r2_, r3_; +}; + + +TEST_F(TestPartResultTest, ConstructorWorks) { + Message message; + message << "something is terribly wrong"; + message << static_cast(testing::internal::kStackTraceMarker); + message << "some unimportant stack trace"; + + const TestPartResult result(TestPartResult::kNonFatalFailure, + "some_file.cc", + 42, + message.GetString().c_str()); + + EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type()); + EXPECT_STREQ("some_file.cc", result.file_name()); + EXPECT_EQ(42, result.line_number()); + EXPECT_STREQ(message.GetString().c_str(), result.message()); + EXPECT_STREQ("something is terribly wrong", result.summary()); +} + +TEST_F(TestPartResultTest, ResultAccessorsWork) { + const TestPartResult success(TestPartResult::kSuccess, + "file.cc", + 42, + "message"); + EXPECT_TRUE(success.passed()); + EXPECT_FALSE(success.failed()); + EXPECT_FALSE(success.nonfatally_failed()); + EXPECT_FALSE(success.fatally_failed()); + + const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure, + "file.cc", + 42, + "message"); + EXPECT_FALSE(nonfatal_failure.passed()); + EXPECT_TRUE(nonfatal_failure.failed()); + EXPECT_TRUE(nonfatal_failure.nonfatally_failed()); + EXPECT_FALSE(nonfatal_failure.fatally_failed()); + + const TestPartResult fatal_failure(TestPartResult::kFatalFailure, + "file.cc", + 42, + "message"); + EXPECT_FALSE(fatal_failure.passed()); + EXPECT_TRUE(fatal_failure.failed()); + EXPECT_FALSE(fatal_failure.nonfatally_failed()); + EXPECT_TRUE(fatal_failure.fatally_failed()); +} + +// Tests TestPartResult::type(). +TEST_F(TestPartResultTest, type) { + EXPECT_EQ(TestPartResult::kSuccess, r1_.type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type()); + EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type()); +} + +// Tests TestPartResult::file_name(). +TEST_F(TestPartResultTest, file_name) { + EXPECT_STREQ("foo/bar.cc", r1_.file_name()); + EXPECT_STREQ(NULL, r3_.file_name()); +} + +// Tests TestPartResult::line_number(). +TEST_F(TestPartResultTest, line_number) { + EXPECT_EQ(10, r1_.line_number()); + EXPECT_EQ(-1, r2_.line_number()); +} + +// Tests TestPartResult::message(). +TEST_F(TestPartResultTest, message) { + EXPECT_STREQ("Success!", r1_.message()); +} + +// Tests TestPartResult::passed(). +TEST_F(TestPartResultTest, Passed) { + EXPECT_TRUE(r1_.passed()); + EXPECT_FALSE(r2_.passed()); + EXPECT_FALSE(r3_.passed()); +} + +// Tests TestPartResult::failed(). +TEST_F(TestPartResultTest, Failed) { + EXPECT_FALSE(r1_.failed()); + EXPECT_TRUE(r2_.failed()); + EXPECT_TRUE(r3_.failed()); +} + +// Tests TestPartResult::fatally_failed(). +TEST_F(TestPartResultTest, FatallyFailed) { + EXPECT_FALSE(r1_.fatally_failed()); + EXPECT_FALSE(r2_.fatally_failed()); + EXPECT_TRUE(r3_.fatally_failed()); +} + +// Tests TestPartResult::nonfatally_failed(). +TEST_F(TestPartResultTest, NonfatallyFailed) { + EXPECT_FALSE(r1_.nonfatally_failed()); + EXPECT_TRUE(r2_.nonfatally_failed()); + EXPECT_FALSE(r3_.nonfatally_failed()); +} + +// Tests the TestPartResultArray class. + +class TestPartResultArrayTest : public Test { + protected: + TestPartResultArrayTest() + : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"), + r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {} + + const TestPartResult r1_, r2_; +}; + +// Tests that TestPartResultArray initially has size 0. +TEST_F(TestPartResultArrayTest, InitialSizeIsZero) { + TestPartResultArray results; + EXPECT_EQ(0, results.size()); +} + +// Tests that TestPartResultArray contains the given TestPartResult +// after one Append() operation. +TEST_F(TestPartResultArrayTest, ContainsGivenResultAfterAppend) { + TestPartResultArray results; + results.Append(r1_); + EXPECT_EQ(1, results.size()); + EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); +} + +// Tests that TestPartResultArray contains the given TestPartResults +// after two Append() operations. +TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends) { + TestPartResultArray results; + results.Append(r1_); + results.Append(r2_); + EXPECT_EQ(2, results.size()); + EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); + EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message()); +} + +typedef TestPartResultArrayTest TestPartResultArrayDeathTest; + +// Tests that the program dies when GetTestPartResult() is called with +// an invalid index. +TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound) { + TestPartResultArray results; + results.Append(r1_); + + EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), ""); + EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), ""); +} + +// TODO(mheule@google.com): Add a test for the class HasNewFatalFailureHelper. + +} // namespace diff --git a/third_party/googletest/src/test/gtest-tuple_test.cc b/third_party/googletest/src/test/gtest-tuple_test.cc new file mode 100644 index 0000000..bfaa3e0 --- /dev/null +++ b/third_party/googletest/src/test/gtest-tuple_test.cc @@ -0,0 +1,320 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/internal/gtest-tuple.h" +#include +#include "gtest/gtest.h" + +namespace { + +using ::std::tr1::get; +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +using ::std::tr1::tuple_element; +using ::std::tr1::tuple_size; +using ::testing::StaticAssertTypeEq; + +// Tests that tuple_element >::type returns TK. +TEST(tuple_element_Test, ReturnsElementType) { + StaticAssertTypeEq >::type>(); + StaticAssertTypeEq >::type>(); + StaticAssertTypeEq >::type>(); +} + +// Tests that tuple_size::value gives the number of fields in tuple +// type T. +TEST(tuple_size_Test, ReturnsNumberOfFields) { + EXPECT_EQ(0, +tuple_size >::value); + EXPECT_EQ(1, +tuple_size >::value); + EXPECT_EQ(1, +tuple_size >::value); + EXPECT_EQ(1, +(tuple_size > >::value)); + EXPECT_EQ(2, +(tuple_size >::value)); + EXPECT_EQ(3, +(tuple_size >::value)); +} + +// Tests comparing a tuple with itself. +TEST(ComparisonTest, ComparesWithSelf) { + const tuple a(5, 'a', false); + + EXPECT_TRUE(a == a); + EXPECT_FALSE(a != a); +} + +// Tests comparing two tuples with the same value. +TEST(ComparisonTest, ComparesEqualTuples) { + const tuple a(5, true), b(5, true); + + EXPECT_TRUE(a == b); + EXPECT_FALSE(a != b); +} + +// Tests comparing two different tuples that have no reference fields. +TEST(ComparisonTest, ComparesUnequalTuplesWithoutReferenceFields) { + typedef tuple FooTuple; + + const FooTuple a(0, 'x'); + const FooTuple b(1, 'a'); + + EXPECT_TRUE(a != b); + EXPECT_FALSE(a == b); + + const FooTuple c(1, 'b'); + + EXPECT_TRUE(b != c); + EXPECT_FALSE(b == c); +} + +// Tests comparing two different tuples that have reference fields. +TEST(ComparisonTest, ComparesUnequalTuplesWithReferenceFields) { + typedef tuple FooTuple; + + int i = 5; + const char ch = 'a'; + const FooTuple a(i, ch); + + int j = 6; + const FooTuple b(j, ch); + + EXPECT_TRUE(a != b); + EXPECT_FALSE(a == b); + + j = 5; + const char ch2 = 'b'; + const FooTuple c(j, ch2); + + EXPECT_TRUE(b != c); + EXPECT_FALSE(b == c); +} + +// Tests that a tuple field with a reference type is an alias of the +// variable it's supposed to reference. +TEST(ReferenceFieldTest, IsAliasOfReferencedVariable) { + int n = 0; + tuple t(true, n); + + n = 1; + EXPECT_EQ(n, get<1>(t)) + << "Changing a underlying variable should update the reference field."; + + // Makes sure that the implementation doesn't do anything funny with + // the & operator for the return type of get<>(). + EXPECT_EQ(&n, &(get<1>(t))) + << "The address of a reference field should equal the address of " + << "the underlying variable."; + + get<1>(t) = 2; + EXPECT_EQ(2, n) + << "Changing a reference field should update the underlying variable."; +} + +// Tests that tuple's default constructor default initializes each field. +// This test needs to compile without generating warnings. +TEST(TupleConstructorTest, DefaultConstructorDefaultInitializesEachField) { + // The TR1 report requires that tuple's default constructor default + // initializes each field, even if it's a primitive type. If the + // implementation forgets to do this, this test will catch it by + // generating warnings about using uninitialized variables (assuming + // a decent compiler). + + tuple<> empty; + + tuple a1, b1; + b1 = a1; + EXPECT_EQ(0, get<0>(b1)); + + tuple a2, b2; + b2 = a2; + EXPECT_EQ(0, get<0>(b2)); + EXPECT_EQ(0.0, get<1>(b2)); + + tuple a3, b3; + b3 = a3; + EXPECT_EQ(0.0, get<0>(b3)); + EXPECT_EQ('\0', get<1>(b3)); + EXPECT_TRUE(get<2>(b3) == NULL); + + tuple a10, b10; + b10 = a10; + EXPECT_EQ(0, get<0>(b10)); + EXPECT_EQ(0, get<1>(b10)); + EXPECT_EQ(0, get<2>(b10)); + EXPECT_EQ(0, get<3>(b10)); + EXPECT_EQ(0, get<4>(b10)); + EXPECT_EQ(0, get<5>(b10)); + EXPECT_EQ(0, get<6>(b10)); + EXPECT_EQ(0, get<7>(b10)); + EXPECT_EQ(0, get<8>(b10)); + EXPECT_EQ(0, get<9>(b10)); +} + +// Tests constructing a tuple from its fields. +TEST(TupleConstructorTest, ConstructsFromFields) { + int n = 1; + // Reference field. + tuple a(n); + EXPECT_EQ(&n, &(get<0>(a))); + + // Non-reference fields. + tuple b(5, 'a'); + EXPECT_EQ(5, get<0>(b)); + EXPECT_EQ('a', get<1>(b)); + + // Const reference field. + const int m = 2; + tuple c(true, m); + EXPECT_TRUE(get<0>(c)); + EXPECT_EQ(&m, &(get<1>(c))); +} + +// Tests tuple's copy constructor. +TEST(TupleConstructorTest, CopyConstructor) { + tuple a(0.0, true); + tuple b(a); + + EXPECT_DOUBLE_EQ(0.0, get<0>(b)); + EXPECT_TRUE(get<1>(b)); +} + +// Tests constructing a tuple from another tuple that has a compatible +// but different type. +TEST(TupleConstructorTest, ConstructsFromDifferentTupleType) { + tuple a(0, 1, 'a'); + tuple b(a); + + EXPECT_DOUBLE_EQ(0.0, get<0>(b)); + EXPECT_EQ(1, get<1>(b)); + EXPECT_EQ('a', get<2>(b)); +} + +// Tests constructing a 2-tuple from an std::pair. +TEST(TupleConstructorTest, ConstructsFromPair) { + ::std::pair a(1, 'a'); + tuple b(a); + tuple c(a); +} + +// Tests assigning a tuple to another tuple with the same type. +TEST(TupleAssignmentTest, AssignsToSameTupleType) { + const tuple a(5, 7L); + tuple b; + b = a; + EXPECT_EQ(5, get<0>(b)); + EXPECT_EQ(7L, get<1>(b)); +} + +// Tests assigning a tuple to another tuple with a different but +// compatible type. +TEST(TupleAssignmentTest, AssignsToDifferentTupleType) { + const tuple a(1, 7L, true); + tuple b; + b = a; + EXPECT_EQ(1L, get<0>(b)); + EXPECT_EQ(7, get<1>(b)); + EXPECT_TRUE(get<2>(b)); +} + +// Tests assigning an std::pair to a 2-tuple. +TEST(TupleAssignmentTest, AssignsFromPair) { + const ::std::pair a(5, true); + tuple b; + b = a; + EXPECT_EQ(5, get<0>(b)); + EXPECT_TRUE(get<1>(b)); + + tuple c; + c = a; + EXPECT_EQ(5L, get<0>(c)); + EXPECT_TRUE(get<1>(c)); +} + +// A fixture for testing big tuples. +class BigTupleTest : public testing::Test { + protected: + typedef tuple BigTuple; + + BigTupleTest() : + a_(1, 0, 0, 0, 0, 0, 0, 0, 0, 2), + b_(1, 0, 0, 0, 0, 0, 0, 0, 0, 3) {} + + BigTuple a_, b_; +}; + +// Tests constructing big tuples. +TEST_F(BigTupleTest, Construction) { + BigTuple a; + BigTuple b(b_); +} + +// Tests that get(t) returns the N-th (0-based) field of tuple t. +TEST_F(BigTupleTest, get) { + EXPECT_EQ(1, get<0>(a_)); + EXPECT_EQ(2, get<9>(a_)); + + // Tests that get() works on a const tuple too. + const BigTuple a(a_); + EXPECT_EQ(1, get<0>(a)); + EXPECT_EQ(2, get<9>(a)); +} + +// Tests comparing big tuples. +TEST_F(BigTupleTest, Comparisons) { + EXPECT_TRUE(a_ == a_); + EXPECT_FALSE(a_ != a_); + + EXPECT_TRUE(a_ != b_); + EXPECT_FALSE(a_ == b_); +} + +TEST(MakeTupleTest, WorksForScalarTypes) { + tuple a; + a = make_tuple(true, 5); + EXPECT_TRUE(get<0>(a)); + EXPECT_EQ(5, get<1>(a)); + + tuple b; + b = make_tuple('a', 'b', 5); + EXPECT_EQ('a', get<0>(b)); + EXPECT_EQ('b', get<1>(b)); + EXPECT_EQ(5, get<2>(b)); +} + +TEST(MakeTupleTest, WorksForPointers) { + int a[] = { 1, 2, 3, 4 }; + const char* const str = "hi"; + int* const p = a; + + tuple t; + t = make_tuple(str, p); + EXPECT_EQ(str, get<0>(t)); + EXPECT_EQ(p, get<1>(t)); +} + +} // namespace diff --git a/third_party/googletest/src/test/gtest-typed-test2_test.cc b/third_party/googletest/src/test/gtest-typed-test2_test.cc new file mode 100644 index 0000000..c284700 --- /dev/null +++ b/third_party/googletest/src/test/gtest-typed-test2_test.cc @@ -0,0 +1,45 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include + +#include "test/gtest-typed-test_test.h" +#include "gtest/gtest.h" + +#if GTEST_HAS_TYPED_TEST_P + +// Tests that the same type-parameterized test case can be +// instantiated in different translation units linked together. +// (ContainerTest is also instantiated in gtest-typed-test_test.cc.) +INSTANTIATE_TYPED_TEST_CASE_P(Vector, ContainerTest, + testing::Types >); + +#endif // GTEST_HAS_TYPED_TEST_P diff --git a/third_party/googletest/src/test/gtest-typed-test_test.cc b/third_party/googletest/src/test/gtest-typed-test_test.cc new file mode 100644 index 0000000..dd4ba43 --- /dev/null +++ b/third_party/googletest/src/test/gtest-typed-test_test.cc @@ -0,0 +1,360 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include +#include + +#include "test/gtest-typed-test_test.h" +#include "gtest/gtest.h" + +using testing::Test; + +// Used for testing that SetUpTestCase()/TearDownTestCase(), fixture +// ctor/dtor, and SetUp()/TearDown() work correctly in typed tests and +// type-parameterized test. +template +class CommonTest : public Test { + // For some technical reason, SetUpTestCase() and TearDownTestCase() + // must be public. + public: + static void SetUpTestCase() { + shared_ = new T(5); + } + + static void TearDownTestCase() { + delete shared_; + shared_ = NULL; + } + + // This 'protected:' is optional. There's no harm in making all + // members of this fixture class template public. + protected: + // We used to use std::list here, but switched to std::vector since + // MSVC's doesn't compile cleanly with /W4. + typedef std::vector Vector; + typedef std::set IntSet; + + CommonTest() : value_(1) {} + + virtual ~CommonTest() { EXPECT_EQ(3, value_); } + + virtual void SetUp() { + EXPECT_EQ(1, value_); + value_++; + } + + virtual void TearDown() { + EXPECT_EQ(2, value_); + value_++; + } + + T value_; + static T* shared_; +}; + +template +T* CommonTest::shared_ = NULL; + +// This #ifdef block tests typed tests. +#if GTEST_HAS_TYPED_TEST + +using testing::Types; + +// Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, +// and SetUp()/TearDown() work correctly in typed tests + +typedef Types TwoTypes; +TYPED_TEST_CASE(CommonTest, TwoTypes); + +TYPED_TEST(CommonTest, ValuesAreCorrect) { + // Static members of the fixture class template can be visited via + // the TestFixture:: prefix. + EXPECT_EQ(5, *TestFixture::shared_); + + // Typedefs in the fixture class template can be visited via the + // "typename TestFixture::" prefix. + typename TestFixture::Vector empty; + EXPECT_EQ(0U, empty.size()); + + typename TestFixture::IntSet empty2; + EXPECT_EQ(0U, empty2.size()); + + // Non-static members of the fixture class must be visited via + // 'this', as required by C++ for class templates. + EXPECT_EQ(2, this->value_); +} + +// The second test makes sure shared_ is not deleted after the first +// test. +TYPED_TEST(CommonTest, ValuesAreStillCorrect) { + // Static members of the fixture class template can also be visited + // via 'this'. + ASSERT_TRUE(this->shared_ != NULL); + EXPECT_EQ(5, *this->shared_); + + // TypeParam can be used to refer to the type parameter. + EXPECT_EQ(static_cast(2), this->value_); +} + +// Tests that multiple TYPED_TEST_CASE's can be defined in the same +// translation unit. + +template +class TypedTest1 : public Test { +}; + +// Verifies that the second argument of TYPED_TEST_CASE can be a +// single type. +TYPED_TEST_CASE(TypedTest1, int); +TYPED_TEST(TypedTest1, A) {} + +template +class TypedTest2 : public Test { +}; + +// Verifies that the second argument of TYPED_TEST_CASE can be a +// Types<...> type list. +TYPED_TEST_CASE(TypedTest2, Types); + +// This also verifies that tests from different typed test cases can +// share the same name. +TYPED_TEST(TypedTest2, A) {} + +// Tests that a typed test case can be defined in a namespace. + +namespace library1 { + +template +class NumericTest : public Test { +}; + +typedef Types NumericTypes; +TYPED_TEST_CASE(NumericTest, NumericTypes); + +TYPED_TEST(NumericTest, DefaultIsZero) { + EXPECT_EQ(0, TypeParam()); +} + +} // namespace library1 + +#endif // GTEST_HAS_TYPED_TEST + +// This #ifdef block tests type-parameterized tests. +#if GTEST_HAS_TYPED_TEST_P + +using testing::Types; +using testing::internal::TypedTestCasePState; + +// Tests TypedTestCasePState. + +class TypedTestCasePStateTest : public Test { + protected: + virtual void SetUp() { + state_.AddTestName("foo.cc", 0, "FooTest", "A"); + state_.AddTestName("foo.cc", 0, "FooTest", "B"); + state_.AddTestName("foo.cc", 0, "FooTest", "C"); + } + + TypedTestCasePState state_; +}; + +TEST_F(TypedTestCasePStateTest, SucceedsForMatchingList) { + const char* tests = "A, B, C"; + EXPECT_EQ(tests, + state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); +} + +// Makes sure that the order of the tests and spaces around the names +// don't matter. +TEST_F(TypedTestCasePStateTest, IgnoresOrderAndSpaces) { + const char* tests = "A,C, B"; + EXPECT_EQ(tests, + state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); +} + +typedef TypedTestCasePStateTest TypedTestCasePStateDeathTest; + +TEST_F(TypedTestCasePStateDeathTest, DetectsDuplicates) { + EXPECT_DEATH_IF_SUPPORTED( + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"), + "foo\\.cc.1.?: Test A is listed more than once\\."); +} + +TEST_F(TypedTestCasePStateDeathTest, DetectsExtraTest) { + EXPECT_DEATH_IF_SUPPORTED( + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"), + "foo\\.cc.1.?: No test named D can be found in this test case\\."); +} + +TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest) { + EXPECT_DEATH_IF_SUPPORTED( + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"), + "foo\\.cc.1.?: You forgot to list test B\\."); +} + +// Tests that defining a test for a parameterized test case generates +// a run-time error if the test case has been registered. +TEST_F(TypedTestCasePStateDeathTest, DetectsTestAfterRegistration) { + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C"); + EXPECT_DEATH_IF_SUPPORTED( + state_.AddTestName("foo.cc", 2, "FooTest", "D"), + "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_CASE_P" + "\\(FooTest, \\.\\.\\.\\)\\."); +} + +// Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, +// and SetUp()/TearDown() work correctly in type-parameterized tests. + +template +class DerivedTest : public CommonTest { +}; + +TYPED_TEST_CASE_P(DerivedTest); + +TYPED_TEST_P(DerivedTest, ValuesAreCorrect) { + // Static members of the fixture class template can be visited via + // the TestFixture:: prefix. + EXPECT_EQ(5, *TestFixture::shared_); + + // Non-static members of the fixture class must be visited via + // 'this', as required by C++ for class templates. + EXPECT_EQ(2, this->value_); +} + +// The second test makes sure shared_ is not deleted after the first +// test. +TYPED_TEST_P(DerivedTest, ValuesAreStillCorrect) { + // Static members of the fixture class template can also be visited + // via 'this'. + ASSERT_TRUE(this->shared_ != NULL); + EXPECT_EQ(5, *this->shared_); + EXPECT_EQ(2, this->value_); +} + +REGISTER_TYPED_TEST_CASE_P(DerivedTest, + ValuesAreCorrect, ValuesAreStillCorrect); + +typedef Types MyTwoTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, DerivedTest, MyTwoTypes); + +// Tests that multiple TYPED_TEST_CASE_P's can be defined in the same +// translation unit. + +template +class TypedTestP1 : public Test { +}; + +TYPED_TEST_CASE_P(TypedTestP1); + +// For testing that the code between TYPED_TEST_CASE_P() and +// TYPED_TEST_P() is not enclosed in a namespace. +typedef int IntAfterTypedTestCaseP; + +TYPED_TEST_P(TypedTestP1, A) {} +TYPED_TEST_P(TypedTestP1, B) {} + +// For testing that the code between TYPED_TEST_P() and +// REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace. +typedef int IntBeforeRegisterTypedTestCaseP; + +REGISTER_TYPED_TEST_CASE_P(TypedTestP1, A, B); + +template +class TypedTestP2 : public Test { +}; + +TYPED_TEST_CASE_P(TypedTestP2); + +// This also verifies that tests from different type-parameterized +// test cases can share the same name. +TYPED_TEST_P(TypedTestP2, A) {} + +REGISTER_TYPED_TEST_CASE_P(TypedTestP2, A); + +// Verifies that the code between TYPED_TEST_CASE_P() and +// REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace. +IntAfterTypedTestCaseP after = 0; +IntBeforeRegisterTypedTestCaseP before = 0; + +// Verifies that the last argument of INSTANTIATE_TYPED_TEST_CASE_P() +// can be either a single type or a Types<...> type list. +INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP1, int); +INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP2, Types); + +// Tests that the same type-parameterized test case can be +// instantiated more than once in the same translation unit. +INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types); + +// Tests that the same type-parameterized test case can be +// instantiated in different translation units linked together. +// (ContainerTest is also instantiated in gtest-typed-test_test.cc.) +typedef Types, std::set > MyContainers; +INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers); + +// Tests that a type-parameterized test case can be defined and +// instantiated in a namespace. + +namespace library2 { + +template +class NumericTest : public Test { +}; + +TYPED_TEST_CASE_P(NumericTest); + +TYPED_TEST_P(NumericTest, DefaultIsZero) { + EXPECT_EQ(0, TypeParam()); +} + +TYPED_TEST_P(NumericTest, ZeroIsLessThanOne) { + EXPECT_LT(TypeParam(0), TypeParam(1)); +} + +REGISTER_TYPED_TEST_CASE_P(NumericTest, + DefaultIsZero, ZeroIsLessThanOne); +typedef Types NumericTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes); + +} // namespace library2 + +#endif // GTEST_HAS_TYPED_TEST_P + +#if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) + +// Google Test may not support type-parameterized tests with some +// compilers. If we use conditional compilation to compile out all +// code referring to the gtest_main library, MSVC linker will not link +// that library at all and consequently complain about missing entry +// point defined in that library (fatal error LNK1561: entry point +// must be defined). This dummy test keeps gtest_main linked in. +TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {} + +#endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) diff --git a/third_party/googletest/src/test/gtest-typed-test_test.h b/third_party/googletest/src/test/gtest-typed-test_test.h new file mode 100644 index 0000000..41d7570 --- /dev/null +++ b/third_party/googletest/src/test/gtest-typed-test_test.h @@ -0,0 +1,66 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ +#define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ + +#include "gtest/gtest.h" + +#if GTEST_HAS_TYPED_TEST_P + +using testing::Test; + +// For testing that the same type-parameterized test case can be +// instantiated in different translation units linked together. +// ContainerTest will be instantiated in both gtest-typed-test_test.cc +// and gtest-typed-test2_test.cc. + +template +class ContainerTest : public Test { +}; + +TYPED_TEST_CASE_P(ContainerTest); + +TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed) { + TypeParam container; +} + +TYPED_TEST_P(ContainerTest, InitialSizeIsZero) { + TypeParam container; + EXPECT_EQ(0U, container.size()); +} + +REGISTER_TYPED_TEST_CASE_P(ContainerTest, + CanBeDefaultConstructed, InitialSizeIsZero); + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ diff --git a/third_party/googletest/src/test/gtest-unittest-api_test.cc b/third_party/googletest/src/test/gtest-unittest-api_test.cc new file mode 100644 index 0000000..07083e5 --- /dev/null +++ b/third_party/googletest/src/test/gtest-unittest-api_test.cc @@ -0,0 +1,341 @@ +// Copyright 2009 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) +// +// The Google C++ Testing Framework (Google Test) +// +// This file contains tests verifying correctness of data provided via +// UnitTest's public methods. + +#include "gtest/gtest.h" + +#include // For strcmp. +#include + +using ::testing::InitGoogleTest; + +namespace testing { +namespace internal { + +template +struct LessByName { + bool operator()(const T* a, const T* b) { + return strcmp(a->name(), b->name()) < 0; + } +}; + +class UnitTestHelper { + public: + // Returns the array of pointers to all test cases sorted by the test case + // name. The caller is responsible for deleting the array. + static TestCase const** const GetSortedTestCases() { + UnitTest& unit_test = *UnitTest::GetInstance(); + TestCase const** const test_cases = + new const TestCase*[unit_test.total_test_case_count()]; + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + test_cases[i] = unit_test.GetTestCase(i); + + std::sort(test_cases, + test_cases + unit_test.total_test_case_count(), + LessByName()); + return test_cases; + } + + // Returns the test case by its name. The caller doesn't own the returned + // pointer. + static const TestCase* FindTestCase(const char* name) { + UnitTest& unit_test = *UnitTest::GetInstance(); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase* test_case = unit_test.GetTestCase(i); + if (0 == strcmp(test_case->name(), name)) + return test_case; + } + return NULL; + } + + // Returns the array of pointers to all tests in a particular test case + // sorted by the test name. The caller is responsible for deleting the + // array. + static TestInfo const** const GetSortedTests(const TestCase* test_case) { + TestInfo const** const tests = + new const TestInfo*[test_case->total_test_count()]; + + for (int i = 0; i < test_case->total_test_count(); ++i) + tests[i] = test_case->GetTestInfo(i); + + std::sort(tests, tests + test_case->total_test_count(), + LessByName()); + return tests; + } +}; + +#if GTEST_HAS_TYPED_TEST +template class TestCaseWithCommentTest : public Test {}; +TYPED_TEST_CASE(TestCaseWithCommentTest, Types); +TYPED_TEST(TestCaseWithCommentTest, Dummy) {} + +const int kTypedTestCases = 1; +const int kTypedTests = 1; +#else +const int kTypedTestCases = 0; +const int kTypedTests = 0; +#endif // GTEST_HAS_TYPED_TEST + +// We can only test the accessors that do not change value while tests run. +// Since tests can be run in any order, the values the accessors that track +// test execution (such as failed_test_count) can not be predicted. +TEST(ApiTest, UnitTestImmutableAccessorsWork) { + UnitTest* unit_test = UnitTest::GetInstance(); + + ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); + EXPECT_EQ(1 + kTypedTestCases, unit_test->test_case_to_run_count()); + EXPECT_EQ(2, unit_test->disabled_test_count()); + EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count()); + EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count()); + + const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); + + EXPECT_STREQ("ApiTest", test_cases[0]->name()); + EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); +#if GTEST_HAS_TYPED_TEST + EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name()); +#endif // GTEST_HAS_TYPED_TEST + + delete[] test_cases; + + // The following lines initiate actions to verify certain methods in + // FinalSuccessChecker::TearDown. + + // Records a test property to verify TestResult::GetTestProperty(). + RecordProperty("key", "value"); +} + +AssertionResult IsNull(const char* str) { + if (str != NULL) { + return testing::AssertionFailure() << "argument is " << str; + } + return AssertionSuccess(); +} + +TEST(ApiTest, TestCaseImmutableAccessorsWork) { + const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); + ASSERT_TRUE(test_case != NULL); + + EXPECT_STREQ("ApiTest", test_case->name()); + EXPECT_TRUE(IsNull(test_case->type_param())); + EXPECT_TRUE(test_case->should_run()); + EXPECT_EQ(1, test_case->disabled_test_count()); + EXPECT_EQ(3, test_case->test_to_run_count()); + ASSERT_EQ(4, test_case->total_test_count()); + + const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); + + EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); + EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); + EXPECT_TRUE(IsNull(tests[0]->value_param())); + EXPECT_TRUE(IsNull(tests[0]->type_param())); + EXPECT_FALSE(tests[0]->should_run()); + + EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); + EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); + EXPECT_TRUE(IsNull(tests[1]->value_param())); + EXPECT_TRUE(IsNull(tests[1]->type_param())); + EXPECT_TRUE(tests[1]->should_run()); + + EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); + EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); + EXPECT_TRUE(IsNull(tests[2]->value_param())); + EXPECT_TRUE(IsNull(tests[2]->type_param())); + EXPECT_TRUE(tests[2]->should_run()); + + EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); + EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); + EXPECT_TRUE(IsNull(tests[3]->value_param())); + EXPECT_TRUE(IsNull(tests[3]->type_param())); + EXPECT_TRUE(tests[3]->should_run()); + + delete[] tests; + tests = NULL; + +#if GTEST_HAS_TYPED_TEST + test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); + ASSERT_TRUE(test_case != NULL); + + EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name()); + EXPECT_STREQ(GetTypeName().c_str(), test_case->type_param()); + EXPECT_TRUE(test_case->should_run()); + EXPECT_EQ(0, test_case->disabled_test_count()); + EXPECT_EQ(1, test_case->test_to_run_count()); + ASSERT_EQ(1, test_case->total_test_count()); + + tests = UnitTestHelper::GetSortedTests(test_case); + + EXPECT_STREQ("Dummy", tests[0]->name()); + EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); + EXPECT_TRUE(IsNull(tests[0]->value_param())); + EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); + EXPECT_TRUE(tests[0]->should_run()); + + delete[] tests; +#endif // GTEST_HAS_TYPED_TEST +} + +TEST(ApiTest, TestCaseDisabledAccessorsWork) { + const TestCase* test_case = UnitTestHelper::FindTestCase("DISABLED_Test"); + ASSERT_TRUE(test_case != NULL); + + EXPECT_STREQ("DISABLED_Test", test_case->name()); + EXPECT_TRUE(IsNull(test_case->type_param())); + EXPECT_FALSE(test_case->should_run()); + EXPECT_EQ(1, test_case->disabled_test_count()); + EXPECT_EQ(0, test_case->test_to_run_count()); + ASSERT_EQ(1, test_case->total_test_count()); + + const TestInfo* const test_info = test_case->GetTestInfo(0); + EXPECT_STREQ("Dummy2", test_info->name()); + EXPECT_STREQ("DISABLED_Test", test_info->test_case_name()); + EXPECT_TRUE(IsNull(test_info->value_param())); + EXPECT_TRUE(IsNull(test_info->type_param())); + EXPECT_FALSE(test_info->should_run()); +} + +// These two tests are here to provide support for testing +// test_case_to_run_count, disabled_test_count, and test_to_run_count. +TEST(ApiTest, DISABLED_Dummy1) {} +TEST(DISABLED_Test, Dummy2) {} + +class FinalSuccessChecker : public Environment { + protected: + virtual void TearDown() { + UnitTest* unit_test = UnitTest::GetInstance(); + + EXPECT_EQ(1 + kTypedTestCases, unit_test->successful_test_case_count()); + EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count()); + EXPECT_EQ(0, unit_test->failed_test_case_count()); + EXPECT_EQ(0, unit_test->failed_test_count()); + EXPECT_TRUE(unit_test->Passed()); + EXPECT_FALSE(unit_test->Failed()); + ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); + + const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); + + EXPECT_STREQ("ApiTest", test_cases[0]->name()); + EXPECT_TRUE(IsNull(test_cases[0]->type_param())); + EXPECT_TRUE(test_cases[0]->should_run()); + EXPECT_EQ(1, test_cases[0]->disabled_test_count()); + ASSERT_EQ(4, test_cases[0]->total_test_count()); + EXPECT_EQ(3, test_cases[0]->successful_test_count()); + EXPECT_EQ(0, test_cases[0]->failed_test_count()); + EXPECT_TRUE(test_cases[0]->Passed()); + EXPECT_FALSE(test_cases[0]->Failed()); + + EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); + EXPECT_TRUE(IsNull(test_cases[1]->type_param())); + EXPECT_FALSE(test_cases[1]->should_run()); + EXPECT_EQ(1, test_cases[1]->disabled_test_count()); + ASSERT_EQ(1, test_cases[1]->total_test_count()); + EXPECT_EQ(0, test_cases[1]->successful_test_count()); + EXPECT_EQ(0, test_cases[1]->failed_test_count()); + +#if GTEST_HAS_TYPED_TEST + EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name()); + EXPECT_STREQ(GetTypeName().c_str(), test_cases[2]->type_param()); + EXPECT_TRUE(test_cases[2]->should_run()); + EXPECT_EQ(0, test_cases[2]->disabled_test_count()); + ASSERT_EQ(1, test_cases[2]->total_test_count()); + EXPECT_EQ(1, test_cases[2]->successful_test_count()); + EXPECT_EQ(0, test_cases[2]->failed_test_count()); + EXPECT_TRUE(test_cases[2]->Passed()); + EXPECT_FALSE(test_cases[2]->Failed()); +#endif // GTEST_HAS_TYPED_TEST + + const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); + const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); + EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); + EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); + EXPECT_FALSE(tests[0]->should_run()); + + EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); + EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); + EXPECT_TRUE(IsNull(tests[1]->value_param())); + EXPECT_TRUE(IsNull(tests[1]->type_param())); + EXPECT_TRUE(tests[1]->should_run()); + EXPECT_TRUE(tests[1]->result()->Passed()); + EXPECT_EQ(0, tests[1]->result()->test_property_count()); + + EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); + EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); + EXPECT_TRUE(IsNull(tests[2]->value_param())); + EXPECT_TRUE(IsNull(tests[2]->type_param())); + EXPECT_TRUE(tests[2]->should_run()); + EXPECT_TRUE(tests[2]->result()->Passed()); + EXPECT_EQ(0, tests[2]->result()->test_property_count()); + + EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); + EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); + EXPECT_TRUE(IsNull(tests[3]->value_param())); + EXPECT_TRUE(IsNull(tests[3]->type_param())); + EXPECT_TRUE(tests[3]->should_run()); + EXPECT_TRUE(tests[3]->result()->Passed()); + EXPECT_EQ(1, tests[3]->result()->test_property_count()); + const TestProperty& property = tests[3]->result()->GetTestProperty(0); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("value", property.value()); + + delete[] tests; + +#if GTEST_HAS_TYPED_TEST + test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); + tests = UnitTestHelper::GetSortedTests(test_case); + + EXPECT_STREQ("Dummy", tests[0]->name()); + EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); + EXPECT_TRUE(IsNull(tests[0]->value_param())); + EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); + EXPECT_TRUE(tests[0]->should_run()); + EXPECT_TRUE(tests[0]->result()->Passed()); + EXPECT_EQ(0, tests[0]->result()->test_property_count()); + + delete[] tests; +#endif // GTEST_HAS_TYPED_TEST + delete[] test_cases; + } +}; + +} // namespace internal +} // namespace testing + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker()); + + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_all_test.cc b/third_party/googletest/src/test/gtest_all_test.cc new file mode 100644 index 0000000..955aa62 --- /dev/null +++ b/third_party/googletest/src/test/gtest_all_test.cc @@ -0,0 +1,47 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Tests for Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build most of Google Test's own tests +// by compiling a single file. This file serves this purpose. +#include "test/gtest-filepath_test.cc" +#include "test/gtest-linked_ptr_test.cc" +#include "test/gtest-message_test.cc" +#include "test/gtest-options_test.cc" +#include "test/gtest-port_test.cc" +#include "test/gtest_pred_impl_unittest.cc" +#include "test/gtest_prod_test.cc" +#include "test/gtest-test-part_test.cc" +#include "test/gtest-typed-test_test.cc" +#include "test/gtest-typed-test2_test.cc" +#include "test/gtest_unittest.cc" +#include "test/production.cc" diff --git a/third_party/googletest/src/test/gtest_break_on_failure_unittest.py b/third_party/googletest/src/test/gtest_break_on_failure_unittest.py new file mode 100755 index 0000000..c819183 --- /dev/null +++ b/third_party/googletest/src/test/gtest_break_on_failure_unittest.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for Google Test's break-on-failure mode. + +A user can ask Google Test to seg-fault when an assertion fails, using +either the GTEST_BREAK_ON_FAILURE environment variable or the +--gtest_break_on_failure flag. This script tests such functionality +by invoking gtest_break_on_failure_unittest_ (a program written with +Google Test) with different environments and command line flags. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import gtest_test_utils +import os +import sys + + +# Constants. + +IS_WINDOWS = os.name == 'nt' + +# The environment variable for enabling/disabling the break-on-failure mode. +BREAK_ON_FAILURE_ENV_VAR = 'GTEST_BREAK_ON_FAILURE' + +# The command line flag for enabling/disabling the break-on-failure mode. +BREAK_ON_FAILURE_FLAG = 'gtest_break_on_failure' + +# The environment variable for enabling/disabling the throw-on-failure mode. +THROW_ON_FAILURE_ENV_VAR = 'GTEST_THROW_ON_FAILURE' + +# The environment variable for enabling/disabling the catch-exceptions mode. +CATCH_EXCEPTIONS_ENV_VAR = 'GTEST_CATCH_EXCEPTIONS' + +# Path to the gtest_break_on_failure_unittest_ program. +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'gtest_break_on_failure_unittest_') + + +# Utilities. + + +environ = os.environ.copy() + + +def SetEnvVar(env_var, value): + """Sets an environment variable to a given value; unsets it when the + given value is None. + """ + + if value is not None: + environ[env_var] = value + elif env_var in environ: + del environ[env_var] + + +def Run(command): + """Runs a command; returns 1 if it was killed by a signal, or 0 otherwise.""" + + p = gtest_test_utils.Subprocess(command, env=environ) + if p.terminated_by_signal: + return 1 + else: + return 0 + + +# The tests. + + +class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase): + """Tests using the GTEST_BREAK_ON_FAILURE environment variable or + the --gtest_break_on_failure flag to turn assertion failures into + segmentation faults. + """ + + def RunAndVerify(self, env_var_value, flag_value, expect_seg_fault): + """Runs gtest_break_on_failure_unittest_ and verifies that it does + (or does not) have a seg-fault. + + Args: + env_var_value: value of the GTEST_BREAK_ON_FAILURE environment + variable; None if the variable should be unset. + flag_value: value of the --gtest_break_on_failure flag; + None if the flag should not be present. + expect_seg_fault: 1 if the program is expected to generate a seg-fault; + 0 otherwise. + """ + + SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, env_var_value) + + if env_var_value is None: + env_var_value_msg = ' is not set' + else: + env_var_value_msg = '=' + env_var_value + + if flag_value is None: + flag = '' + elif flag_value == '0': + flag = '--%s=0' % BREAK_ON_FAILURE_FLAG + else: + flag = '--%s' % BREAK_ON_FAILURE_FLAG + + command = [EXE_PATH] + if flag: + command.append(flag) + + if expect_seg_fault: + should_or_not = 'should' + else: + should_or_not = 'should not' + + has_seg_fault = Run(command) + + SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, None) + + msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' % + (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command), + should_or_not)) + self.assert_(has_seg_fault == expect_seg_fault, msg) + + def testDefaultBehavior(self): + """Tests the behavior of the default mode.""" + + self.RunAndVerify(env_var_value=None, + flag_value=None, + expect_seg_fault=0) + + def testEnvVar(self): + """Tests using the GTEST_BREAK_ON_FAILURE environment variable.""" + + self.RunAndVerify(env_var_value='0', + flag_value=None, + expect_seg_fault=0) + self.RunAndVerify(env_var_value='1', + flag_value=None, + expect_seg_fault=1) + + def testFlag(self): + """Tests using the --gtest_break_on_failure flag.""" + + self.RunAndVerify(env_var_value=None, + flag_value='0', + expect_seg_fault=0) + self.RunAndVerify(env_var_value=None, + flag_value='1', + expect_seg_fault=1) + + def testFlagOverridesEnvVar(self): + """Tests that the flag overrides the environment variable.""" + + self.RunAndVerify(env_var_value='0', + flag_value='0', + expect_seg_fault=0) + self.RunAndVerify(env_var_value='0', + flag_value='1', + expect_seg_fault=1) + self.RunAndVerify(env_var_value='1', + flag_value='0', + expect_seg_fault=0) + self.RunAndVerify(env_var_value='1', + flag_value='1', + expect_seg_fault=1) + + def testBreakOnFailureOverridesThrowOnFailure(self): + """Tests that gtest_break_on_failure overrides gtest_throw_on_failure.""" + + SetEnvVar(THROW_ON_FAILURE_ENV_VAR, '1') + try: + self.RunAndVerify(env_var_value=None, + flag_value='1', + expect_seg_fault=1) + finally: + SetEnvVar(THROW_ON_FAILURE_ENV_VAR, None) + + if IS_WINDOWS: + def testCatchExceptionsDoesNotInterfere(self): + """Tests that gtest_catch_exceptions doesn't interfere.""" + + SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, '1') + try: + self.RunAndVerify(env_var_value='1', + flag_value='1', + expect_seg_fault=1) + finally: + SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, None) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_break_on_failure_unittest_.cc b/third_party/googletest/src/test/gtest_break_on_failure_unittest_.cc new file mode 100644 index 0000000..dd07478 --- /dev/null +++ b/third_party/googletest/src/test/gtest_break_on_failure_unittest_.cc @@ -0,0 +1,88 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Unit test for Google Test's break-on-failure mode. +// +// A user can ask Google Test to seg-fault when an assertion fails, using +// either the GTEST_BREAK_ON_FAILURE environment variable or the +// --gtest_break_on_failure flag. This file is used for testing such +// functionality. +// +// This program will be invoked from a Python unit test. It is +// expected to fail. Don't run it directly. + +#include "gtest/gtest.h" + +#if GTEST_OS_WINDOWS +# include +# include +#endif + +namespace { + +// A test that's expected to fail. +TEST(Foo, Bar) { + EXPECT_EQ(2, 3); +} + +#if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE +// On Windows Mobile global exception handlers are not supported. +LONG WINAPI ExitWithExceptionCode( + struct _EXCEPTION_POINTERS* exception_pointers) { + exit(exception_pointers->ExceptionRecord->ExceptionCode); +} +#endif + +} // namespace + +int main(int argc, char **argv) { +#if GTEST_OS_WINDOWS + // Suppresses display of the Windows error dialog upon encountering + // a general protection fault (segment violation). + SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); + +# if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE + + // The default unhandled exception filter does not always exit + // with the exception code as exit code - for example it exits with + // 0 for EXCEPTION_ACCESS_VIOLATION and 1 for EXCEPTION_BREAKPOINT + // if the application is compiled in debug mode. Thus we use our own + // filter which always exits with the exception code for unhandled + // exceptions. + SetUnhandledExceptionFilter(ExitWithExceptionCode); + +# endif +#endif + + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_catch_exceptions_test.py b/third_party/googletest/src/test/gtest_catch_exceptions_test.py new file mode 100755 index 0000000..7fd7dba --- /dev/null +++ b/third_party/googletest/src/test/gtest_catch_exceptions_test.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python +# +# Copyright 2010 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests Google Test's exception catching behavior. + +This script invokes gtest_catch_exceptions_test_ and +gtest_catch_exceptions_ex_test_ (programs written with +Google Test) and verifies their output. +""" + +__author__ = 'vladl@google.com (Vlad Losev)' + +import os + +import gtest_test_utils + +# Constants. +FLAG_PREFIX = '--gtest_' +LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' +NO_CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions=0' +FILTER_FLAG = FLAG_PREFIX + 'filter' + +# Path to the gtest_catch_exceptions_ex_test_ binary, compiled with +# exceptions enabled. +EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'gtest_catch_exceptions_ex_test_') + +# Path to the gtest_catch_exceptions_test_ binary, compiled with +# exceptions disabled. +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'gtest_catch_exceptions_no_ex_test_') + +TEST_LIST = gtest_test_utils.Subprocess([EXE_PATH, LIST_TESTS_FLAG]).output + +SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST + +if SUPPORTS_SEH_EXCEPTIONS: + BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH]).output + +EX_BINARY_OUTPUT = gtest_test_utils.Subprocess([EX_EXE_PATH]).output + +# The tests. +if SUPPORTS_SEH_EXCEPTIONS: + # pylint:disable-msg=C6302 + class CatchSehExceptionsTest(gtest_test_utils.TestCase): + """Tests exception-catching behavior.""" + + + def TestSehExceptions(self, test_output): + self.assert_('SEH exception with code 0x2a thrown ' + 'in the test fixture\'s constructor' + in test_output) + self.assert_('SEH exception with code 0x2a thrown ' + 'in the test fixture\'s destructor' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in SetUpTestCase()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in TearDownTestCase()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in SetUp()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in TearDown()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in the test body' + in test_output) + + def testCatchesSehExceptionsWithCxxExceptionsEnabled(self): + self.TestSehExceptions(EX_BINARY_OUTPUT) + + def testCatchesSehExceptionsWithCxxExceptionsDisabled(self): + self.TestSehExceptions(BINARY_OUTPUT) + + +class CatchCxxExceptionsTest(gtest_test_utils.TestCase): + """Tests C++ exception-catching behavior. + + Tests in this test case verify that: + * C++ exceptions are caught and logged as C++ (not SEH) exceptions + * Exception thrown affect the remainder of the test work flow in the + expected manner. + """ + + def testCatchesCxxExceptionsInFixtureConstructor(self): + self.assert_('C++ exception with description ' + '"Standard C++ exception" thrown ' + 'in the test fixture\'s constructor' + in EX_BINARY_OUTPUT) + self.assert_('unexpected' not in EX_BINARY_OUTPUT, + 'This failure belongs in this test only if ' + '"CxxExceptionInConstructorTest" (no quotes) ' + 'appears on the same line as words "called unexpectedly"') + + def testCatchesCxxExceptionsInFixtureDestructor(self): + self.assert_('C++ exception with description ' + '"Standard C++ exception" thrown ' + 'in the test fixture\'s destructor' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInDestructorTest::TearDownTestCase() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInSetUpTestCase(self): + self.assert_('C++ exception with description "Standard C++ exception"' + ' thrown in SetUpTestCase()' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInConstructorTest::TearDownTestCase() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTestCaseTest constructor ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTestCaseTest destructor ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTestCaseTest::SetUp() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTestCaseTest::TearDown() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTestCaseTest test body ' + 'called as expected.' + in EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInTearDownTestCase(self): + self.assert_('C++ exception with description "Standard C++ exception"' + ' thrown in TearDownTestCase()' + in EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInSetUp(self): + self.assert_('C++ exception with description "Standard C++ exception"' + ' thrown in SetUp()' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTest::TearDownTestCase() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTest destructor ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInSetUpTest::TearDown() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('unexpected' not in EX_BINARY_OUTPUT, + 'This failure belongs in this test only if ' + '"CxxExceptionInSetUpTest" (no quotes) ' + 'appears on the same line as words "called unexpectedly"') + + def testCatchesCxxExceptionsInTearDown(self): + self.assert_('C++ exception with description "Standard C++ exception"' + ' thrown in TearDown()' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInTearDownTest::TearDownTestCase() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInTearDownTest destructor ' + 'called as expected.' + in EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInTestBody(self): + self.assert_('C++ exception with description "Standard C++ exception"' + ' thrown in the test body' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInTestBodyTest::TearDownTestCase() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInTestBodyTest destructor ' + 'called as expected.' + in EX_BINARY_OUTPUT) + self.assert_('CxxExceptionInTestBodyTest::TearDown() ' + 'called as expected.' + in EX_BINARY_OUTPUT) + + def testCatchesNonStdCxxExceptions(self): + self.assert_('Unknown C++ exception thrown in the test body' + in EX_BINARY_OUTPUT) + + def testUnhandledCxxExceptionsAbortTheProgram(self): + # Filters out SEH exception tests on Windows. Unhandled SEH exceptions + # cause tests to show pop-up windows there. + FITLER_OUT_SEH_TESTS_FLAG = FILTER_FLAG + '=-*Seh*' + # By default, Google Test doesn't catch the exceptions. + uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess( + [EX_EXE_PATH, + NO_CATCH_EXCEPTIONS_FLAG, + FITLER_OUT_SEH_TESTS_FLAG]).output + + self.assert_('Unhandled C++ exception terminating the program' + in uncaught_exceptions_ex_binary_output) + self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_catch_exceptions_test_.cc b/third_party/googletest/src/test/gtest_catch_exceptions_test_.cc new file mode 100644 index 0000000..a35103f --- /dev/null +++ b/third_party/googletest/src/test/gtest_catch_exceptions_test_.cc @@ -0,0 +1,308 @@ +// Copyright 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) +// +// Tests for Google Test itself. Tests in this file throw C++ or SEH +// exceptions, and the output is verified by gtest_catch_exceptions_test.py. + +#include "gtest/gtest.h" + +#include // NOLINT +#include // For exit(). + +#if GTEST_HAS_SEH +# include +#endif + +#if GTEST_HAS_EXCEPTIONS +# include // For set_terminate(). +# include +#endif + +using testing::Test; + +#if GTEST_HAS_SEH + +class SehExceptionInConstructorTest : public Test { + public: + SehExceptionInConstructorTest() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInConstructorTest, ThrowsExceptionInConstructor) {} + +class SehExceptionInDestructorTest : public Test { + public: + ~SehExceptionInDestructorTest() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInDestructorTest, ThrowsExceptionInDestructor) {} + +class SehExceptionInSetUpTestCaseTest : public Test { + public: + static void SetUpTestCase() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) {} + +class SehExceptionInTearDownTestCaseTest : public Test { + public: + static void TearDownTestCase() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {} + +class SehExceptionInSetUpTest : public Test { + protected: + virtual void SetUp() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInSetUpTest, ThrowsExceptionInSetUp) {} + +class SehExceptionInTearDownTest : public Test { + protected: + virtual void TearDown() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInTearDownTest, ThrowsExceptionInTearDown) {} + +TEST(SehExceptionTest, ThrowsSehException) { + RaiseException(42, 0, 0, NULL); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +class CxxExceptionInConstructorTest : public Test { + public: + CxxExceptionInConstructorTest() { + // Without this macro VC++ complains about unreachable code at the end of + // the constructor. + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( + throw std::runtime_error("Standard C++ exception")); + } + + static void TearDownTestCase() { + printf("%s", + "CxxExceptionInConstructorTest::TearDownTestCase() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInConstructorTest() { + ADD_FAILURE() << "CxxExceptionInConstructorTest destructor " + << "called unexpectedly."; + } + + virtual void SetUp() { + ADD_FAILURE() << "CxxExceptionInConstructorTest::SetUp() " + << "called unexpectedly."; + } + + virtual void TearDown() { + ADD_FAILURE() << "CxxExceptionInConstructorTest::TearDown() " + << "called unexpectedly."; + } +}; + +TEST_F(CxxExceptionInConstructorTest, ThrowsExceptionInConstructor) { + ADD_FAILURE() << "CxxExceptionInConstructorTest test body " + << "called unexpectedly."; +} + +class CxxExceptionInDestructorTest : public Test { + public: + static void TearDownTestCase() { + printf("%s", + "CxxExceptionInDestructorTest::TearDownTestCase() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInDestructorTest() { + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( + throw std::runtime_error("Standard C++ exception")); + } +}; + +TEST_F(CxxExceptionInDestructorTest, ThrowsExceptionInDestructor) {} + +class CxxExceptionInSetUpTestCaseTest : public Test { + public: + CxxExceptionInSetUpTestCaseTest() { + printf("%s", + "CxxExceptionInSetUpTestCaseTest constructor " + "called as expected.\n"); + } + + static void SetUpTestCase() { + throw std::runtime_error("Standard C++ exception"); + } + + static void TearDownTestCase() { + printf("%s", + "CxxExceptionInSetUpTestCaseTest::TearDownTestCase() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInSetUpTestCaseTest() { + printf("%s", + "CxxExceptionInSetUpTestCaseTest destructor " + "called as expected.\n"); + } + + virtual void SetUp() { + printf("%s", + "CxxExceptionInSetUpTestCaseTest::SetUp() " + "called as expected.\n"); + } + + virtual void TearDown() { + printf("%s", + "CxxExceptionInSetUpTestCaseTest::TearDown() " + "called as expected.\n"); + } +}; + +TEST_F(CxxExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) { + printf("%s", + "CxxExceptionInSetUpTestCaseTest test body " + "called as expected.\n"); +} + +class CxxExceptionInTearDownTestCaseTest : public Test { + public: + static void TearDownTestCase() { + throw std::runtime_error("Standard C++ exception"); + } +}; + +TEST_F(CxxExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {} + +class CxxExceptionInSetUpTest : public Test { + public: + static void TearDownTestCase() { + printf("%s", + "CxxExceptionInSetUpTest::TearDownTestCase() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInSetUpTest() { + printf("%s", + "CxxExceptionInSetUpTest destructor " + "called as expected.\n"); + } + + virtual void SetUp() { throw std::runtime_error("Standard C++ exception"); } + + virtual void TearDown() { + printf("%s", + "CxxExceptionInSetUpTest::TearDown() " + "called as expected.\n"); + } +}; + +TEST_F(CxxExceptionInSetUpTest, ThrowsExceptionInSetUp) { + ADD_FAILURE() << "CxxExceptionInSetUpTest test body " + << "called unexpectedly."; +} + +class CxxExceptionInTearDownTest : public Test { + public: + static void TearDownTestCase() { + printf("%s", + "CxxExceptionInTearDownTest::TearDownTestCase() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInTearDownTest() { + printf("%s", + "CxxExceptionInTearDownTest destructor " + "called as expected.\n"); + } + + virtual void TearDown() { + throw std::runtime_error("Standard C++ exception"); + } +}; + +TEST_F(CxxExceptionInTearDownTest, ThrowsExceptionInTearDown) {} + +class CxxExceptionInTestBodyTest : public Test { + public: + static void TearDownTestCase() { + printf("%s", + "CxxExceptionInTestBodyTest::TearDownTestCase() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInTestBodyTest() { + printf("%s", + "CxxExceptionInTestBodyTest destructor " + "called as expected.\n"); + } + + virtual void TearDown() { + printf("%s", + "CxxExceptionInTestBodyTest::TearDown() " + "called as expected.\n"); + } +}; + +TEST_F(CxxExceptionInTestBodyTest, ThrowsStdCxxException) { + throw std::runtime_error("Standard C++ exception"); +} + +TEST(CxxExceptionTest, ThrowsNonStdCxxException) { + throw "C-string"; +} + +// This terminate handler aborts the program using exit() rather than abort(). +// This avoids showing pop-ups on Windows systems and core dumps on Unix-like +// ones. +void TerminateHandler() { + fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); + fflush(NULL); + exit(3); +} + +#endif // GTEST_HAS_EXCEPTIONS + +int main(int argc, char** argv) { +#if GTEST_HAS_EXCEPTIONS + std::set_terminate(&TerminateHandler); +#endif + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_color_test.py b/third_party/googletest/src/test/gtest_color_test.py new file mode 100755 index 0000000..d02a53e --- /dev/null +++ b/third_party/googletest/src/test/gtest_color_test.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test correctly determines whether to use colors.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import gtest_test_utils + + +IS_WINDOWS = os.name = 'nt' + +COLOR_ENV_VAR = 'GTEST_COLOR' +COLOR_FLAG = 'gtest_color' +COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_color_test_') + + +def SetEnvVar(env_var, value): + """Sets the env variable to 'value'; unsets it when 'value' is None.""" + + if value is not None: + os.environ[env_var] = value + elif env_var in os.environ: + del os.environ[env_var] + + +def UsesColor(term, color_env_var, color_flag): + """Runs gtest_color_test_ and returns its exit code.""" + + SetEnvVar('TERM', term) + SetEnvVar(COLOR_ENV_VAR, color_env_var) + + if color_flag is None: + args = [] + else: + args = ['--%s=%s' % (COLOR_FLAG, color_flag)] + p = gtest_test_utils.Subprocess([COMMAND] + args) + return not p.exited or p.exit_code + + +class GTestColorTest(gtest_test_utils.TestCase): + def testNoEnvVarNoFlag(self): + """Tests the case when there's neither GTEST_COLOR nor --gtest_color.""" + + if not IS_WINDOWS: + self.assert_(not UsesColor('dumb', None, None)) + self.assert_(not UsesColor('emacs', None, None)) + self.assert_(not UsesColor('xterm-mono', None, None)) + self.assert_(not UsesColor('unknown', None, None)) + self.assert_(not UsesColor(None, None, None)) + self.assert_(UsesColor('linux', None, None)) + self.assert_(UsesColor('cygwin', None, None)) + self.assert_(UsesColor('xterm', None, None)) + self.assert_(UsesColor('xterm-color', None, None)) + self.assert_(UsesColor('xterm-256color', None, None)) + + def testFlagOnly(self): + """Tests the case when there's --gtest_color but not GTEST_COLOR.""" + + self.assert_(not UsesColor('dumb', None, 'no')) + self.assert_(not UsesColor('xterm-color', None, 'no')) + if not IS_WINDOWS: + self.assert_(not UsesColor('emacs', None, 'auto')) + self.assert_(UsesColor('xterm', None, 'auto')) + self.assert_(UsesColor('dumb', None, 'yes')) + self.assert_(UsesColor('xterm', None, 'yes')) + + def testEnvVarOnly(self): + """Tests the case when there's GTEST_COLOR but not --gtest_color.""" + + self.assert_(not UsesColor('dumb', 'no', None)) + self.assert_(not UsesColor('xterm-color', 'no', None)) + if not IS_WINDOWS: + self.assert_(not UsesColor('dumb', 'auto', None)) + self.assert_(UsesColor('xterm-color', 'auto', None)) + self.assert_(UsesColor('dumb', 'yes', None)) + self.assert_(UsesColor('xterm-color', 'yes', None)) + + def testEnvVarAndFlag(self): + """Tests the case when there are both GTEST_COLOR and --gtest_color.""" + + self.assert_(not UsesColor('xterm-color', 'no', 'no')) + self.assert_(UsesColor('dumb', 'no', 'yes')) + self.assert_(UsesColor('xterm-color', 'no', 'auto')) + + def testAliasesOfYesAndNo(self): + """Tests using aliases in specifying --gtest_color.""" + + self.assert_(UsesColor('dumb', None, 'true')) + self.assert_(UsesColor('dumb', None, 'YES')) + self.assert_(UsesColor('dumb', None, 'T')) + self.assert_(UsesColor('dumb', None, '1')) + + self.assert_(not UsesColor('xterm', None, 'f')) + self.assert_(not UsesColor('xterm', None, 'false')) + self.assert_(not UsesColor('xterm', None, '0')) + self.assert_(not UsesColor('xterm', None, 'unknown')) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_color_test_.cc b/third_party/googletest/src/test/gtest_color_test_.cc new file mode 100644 index 0000000..f61ebb8 --- /dev/null +++ b/third_party/googletest/src/test/gtest_color_test_.cc @@ -0,0 +1,71 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// A helper program for testing how Google Test determines whether to use +// colors in the output. It prints "YES" and returns 1 if Google Test +// decides to use colors, and prints "NO" and returns 0 otherwise. + +#include + +#include "gtest/gtest.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +using testing::internal::ShouldUseColor; + +// The purpose of this is to ensure that the UnitTest singleton is +// created before main() is entered, and thus that ShouldUseColor() +// works the same way as in a real Google-Test-based test. We don't actual +// run the TEST itself. +TEST(GTestColorTest, Dummy) { +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + if (ShouldUseColor(true)) { + // Google Test decides to use colors in the output (assuming it + // goes to a TTY). + printf("YES\n"); + return 1; + } else { + // Google Test decides not to use colors in the output. + printf("NO\n"); + return 0; + } +} diff --git a/third_party/googletest/src/test/gtest_env_var_test.py b/third_party/googletest/src/test/gtest_env_var_test.py new file mode 100755 index 0000000..ac24337 --- /dev/null +++ b/third_party/googletest/src/test/gtest_env_var_test.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test correctly parses environment variables.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import gtest_test_utils + + +IS_WINDOWS = os.name == 'nt' +IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' + +COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_env_var_test_') + +environ = os.environ.copy() + + +def AssertEq(expected, actual): + if expected != actual: + print 'Expected: %s' % (expected,) + print ' Actual: %s' % (actual,) + raise AssertionError + + +def SetEnvVar(env_var, value): + """Sets the env variable to 'value'; unsets it when 'value' is None.""" + + if value is not None: + environ[env_var] = value + elif env_var in environ: + del environ[env_var] + + +def GetFlag(flag): + """Runs gtest_env_var_test_ and returns its output.""" + + args = [COMMAND] + if flag is not None: + args += [flag] + return gtest_test_utils.Subprocess(args, env=environ).output + + +def TestFlag(flag, test_val, default_val): + """Verifies that the given flag is affected by the corresponding env var.""" + + env_var = 'GTEST_' + flag.upper() + SetEnvVar(env_var, test_val) + AssertEq(test_val, GetFlag(flag)) + SetEnvVar(env_var, None) + AssertEq(default_val, GetFlag(flag)) + + +class GTestEnvVarTest(gtest_test_utils.TestCase): + def testEnvVarAffectsFlag(self): + """Tests that environment variable should affect the corresponding flag.""" + + TestFlag('break_on_failure', '1', '0') + TestFlag('color', 'yes', 'auto') + TestFlag('filter', 'FooTest.Bar', '*') + TestFlag('output', 'xml:tmp/foo.xml', '') + TestFlag('print_time', '0', '1') + TestFlag('repeat', '999', '1') + TestFlag('throw_on_failure', '1', '0') + TestFlag('death_test_style', 'threadsafe', 'fast') + TestFlag('catch_exceptions', '0', '1') + + if IS_LINUX: + TestFlag('death_test_use_fork', '1', '0') + TestFlag('stack_trace_depth', '0', '100') + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_env_var_test_.cc b/third_party/googletest/src/test/gtest_env_var_test_.cc new file mode 100644 index 0000000..539afc9 --- /dev/null +++ b/third_party/googletest/src/test/gtest_env_var_test_.cc @@ -0,0 +1,126 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// A helper program for testing that Google Test parses the environment +// variables correctly. + +#include "gtest/gtest.h" + +#include + +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +using ::std::cout; + +namespace testing { + +// The purpose of this is to make the test more realistic by ensuring +// that the UnitTest singleton is created before main() is entered. +// We don't actual run the TEST itself. +TEST(GTestEnvVarTest, Dummy) { +} + +void PrintFlag(const char* flag) { + if (strcmp(flag, "break_on_failure") == 0) { + cout << GTEST_FLAG(break_on_failure); + return; + } + + if (strcmp(flag, "catch_exceptions") == 0) { + cout << GTEST_FLAG(catch_exceptions); + return; + } + + if (strcmp(flag, "color") == 0) { + cout << GTEST_FLAG(color); + return; + } + + if (strcmp(flag, "death_test_style") == 0) { + cout << GTEST_FLAG(death_test_style); + return; + } + + if (strcmp(flag, "death_test_use_fork") == 0) { + cout << GTEST_FLAG(death_test_use_fork); + return; + } + + if (strcmp(flag, "filter") == 0) { + cout << GTEST_FLAG(filter); + return; + } + + if (strcmp(flag, "output") == 0) { + cout << GTEST_FLAG(output); + return; + } + + if (strcmp(flag, "print_time") == 0) { + cout << GTEST_FLAG(print_time); + return; + } + + if (strcmp(flag, "repeat") == 0) { + cout << GTEST_FLAG(repeat); + return; + } + + if (strcmp(flag, "stack_trace_depth") == 0) { + cout << GTEST_FLAG(stack_trace_depth); + return; + } + + if (strcmp(flag, "throw_on_failure") == 0) { + cout << GTEST_FLAG(throw_on_failure); + return; + } + + cout << "Invalid flag name " << flag + << ". Valid names are break_on_failure, color, filter, etc.\n"; + exit(1); +} + +} // namespace testing + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + if (argc != 2) { + cout << "Usage: gtest_env_var_test_ NAME_OF_FLAG\n"; + return 1; + } + + testing::PrintFlag(argv[1]); + return 0; +} diff --git a/third_party/googletest/src/test/gtest_environment_test.cc b/third_party/googletest/src/test/gtest_environment_test.cc new file mode 100644 index 0000000..ec9aa2c --- /dev/null +++ b/third_party/googletest/src/test/gtest_environment_test.cc @@ -0,0 +1,191 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Tests using global test environments. + +#include +#include +#include "gtest/gtest.h" + +#define GTEST_IMPLEMENTATION_ 1 // Required for the next #include. +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +GTEST_DECLARE_string_(filter); +} + +namespace { + +enum FailureType { + NO_FAILURE, NON_FATAL_FAILURE, FATAL_FAILURE +}; + +// For testing using global test environments. +class MyEnvironment : public testing::Environment { + public: + MyEnvironment() { Reset(); } + + // Depending on the value of failure_in_set_up_, SetUp() will + // generate a non-fatal failure, generate a fatal failure, or + // succeed. + virtual void SetUp() { + set_up_was_run_ = true; + + switch (failure_in_set_up_) { + case NON_FATAL_FAILURE: + ADD_FAILURE() << "Expected non-fatal failure in global set-up."; + break; + case FATAL_FAILURE: + FAIL() << "Expected fatal failure in global set-up."; + break; + default: + break; + } + } + + // Generates a non-fatal failure. + virtual void TearDown() { + tear_down_was_run_ = true; + ADD_FAILURE() << "Expected non-fatal failure in global tear-down."; + } + + // Resets the state of the environment s.t. it can be reused. + void Reset() { + failure_in_set_up_ = NO_FAILURE; + set_up_was_run_ = false; + tear_down_was_run_ = false; + } + + // We call this function to set the type of failure SetUp() should + // generate. + void set_failure_in_set_up(FailureType type) { + failure_in_set_up_ = type; + } + + // Was SetUp() run? + bool set_up_was_run() const { return set_up_was_run_; } + + // Was TearDown() run? + bool tear_down_was_run() const { return tear_down_was_run_; } + private: + FailureType failure_in_set_up_; + bool set_up_was_run_; + bool tear_down_was_run_; +}; + +// Was the TEST run? +bool test_was_run; + +// The sole purpose of this TEST is to enable us to check whether it +// was run. +TEST(FooTest, Bar) { + test_was_run = true; +} + +// Prints the message and aborts the program if condition is false. +void Check(bool condition, const char* msg) { + if (!condition) { + printf("FAILED: %s\n", msg); + testing::internal::posix::Abort(); + } +} + +// Runs the tests. Return true iff successful. +// +// The 'failure' parameter specifies the type of failure that should +// be generated by the global set-up. +int RunAllTests(MyEnvironment* env, FailureType failure) { + env->Reset(); + env->set_failure_in_set_up(failure); + test_was_run = false; + testing::internal::GetUnitTestImpl()->ClearAdHocTestResult(); + return RUN_ALL_TESTS(); +} + +} // namespace + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + // Registers a global test environment, and verifies that the + // registration function returns its argument. + MyEnvironment* const env = new MyEnvironment; + Check(testing::AddGlobalTestEnvironment(env) == env, + "AddGlobalTestEnvironment() should return its argument."); + + // Verifies that RUN_ALL_TESTS() runs the tests when the global + // set-up is successful. + Check(RunAllTests(env, NO_FAILURE) != 0, + "RUN_ALL_TESTS() should return non-zero, as the global tear-down " + "should generate a failure."); + Check(test_was_run, + "The tests should run, as the global set-up should generate no " + "failure"); + Check(env->tear_down_was_run(), + "The global tear-down should run, as the global set-up was run."); + + // Verifies that RUN_ALL_TESTS() runs the tests when the global + // set-up generates no fatal failure. + Check(RunAllTests(env, NON_FATAL_FAILURE) != 0, + "RUN_ALL_TESTS() should return non-zero, as both the global set-up " + "and the global tear-down should generate a non-fatal failure."); + Check(test_was_run, + "The tests should run, as the global set-up should generate no " + "fatal failure."); + Check(env->tear_down_was_run(), + "The global tear-down should run, as the global set-up was run."); + + // Verifies that RUN_ALL_TESTS() runs no test when the global set-up + // generates a fatal failure. + Check(RunAllTests(env, FATAL_FAILURE) != 0, + "RUN_ALL_TESTS() should return non-zero, as the global set-up " + "should generate a fatal failure."); + Check(!test_was_run, + "The tests should not run, as the global set-up should generate " + "a fatal failure."); + Check(env->tear_down_was_run(), + "The global tear-down should run, as the global set-up was run."); + + // Verifies that RUN_ALL_TESTS() doesn't do global set-up or + // tear-down when there is no test to run. + testing::GTEST_FLAG(filter) = "-*"; + Check(RunAllTests(env, NO_FAILURE) == 0, + "RUN_ALL_TESTS() should return zero, as there is no test to run."); + Check(!env->set_up_was_run(), + "The global set-up should not run, as there is no test to run."); + Check(!env->tear_down_was_run(), + "The global tear-down should not run, " + "as the global set-up was not run."); + + printf("PASS\n"); + return 0; +} diff --git a/third_party/googletest/src/test/gtest_filter_unittest.py b/third_party/googletest/src/test/gtest_filter_unittest.py new file mode 100755 index 0000000..0d1a770 --- /dev/null +++ b/third_party/googletest/src/test/gtest_filter_unittest.py @@ -0,0 +1,633 @@ +#!/usr/bin/env python +# +# Copyright 2005 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for Google Test test filters. + +A user can specify which test(s) in a Google Test program to run via either +the GTEST_FILTER environment variable or the --gtest_filter flag. +This script tests such functionality by invoking +gtest_filter_unittest_ (a program written with Google Test) with different +environments and command line flags. + +Note that test sharding may also influence which tests are filtered. Therefore, +we test that here also. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sets +import sys + +import gtest_test_utils + +# Constants. + +# Checks if this platform can pass empty environment variables to child +# processes. We set an env variable to an empty string and invoke a python +# script in a subprocess to print whether the variable is STILL in +# os.environ. We then use 'eval' to parse the child's output so that an +# exception is thrown if the input is anything other than 'True' nor 'False'. +os.environ['EMPTY_VAR'] = '' +child = gtest_test_utils.Subprocess( + [sys.executable, '-c', 'import os; print \'EMPTY_VAR\' in os.environ']) +CAN_PASS_EMPTY_ENV = eval(child.output) + + +# Check if this platform can unset environment variables in child processes. +# We set an env variable to a non-empty string, unset it, and invoke +# a python script in a subprocess to print whether the variable +# is NO LONGER in os.environ. +# We use 'eval' to parse the child's output so that an exception +# is thrown if the input is neither 'True' nor 'False'. +os.environ['UNSET_VAR'] = 'X' +del os.environ['UNSET_VAR'] +child = gtest_test_utils.Subprocess( + [sys.executable, '-c', 'import os; print \'UNSET_VAR\' not in os.environ']) +CAN_UNSET_ENV = eval(child.output) + + +# Checks if we should test with an empty filter. This doesn't +# make sense on platforms that cannot pass empty env variables (Win32) +# and on platforms that cannot unset variables (since we cannot tell +# the difference between "" and NULL -- Borland and Solaris < 5.10) +CAN_TEST_EMPTY_FILTER = (CAN_PASS_EMPTY_ENV and CAN_UNSET_ENV) + + +# The environment variable for specifying the test filters. +FILTER_ENV_VAR = 'GTEST_FILTER' + +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' +SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' + +# The command line flag for specifying the test filters. +FILTER_FLAG = 'gtest_filter' + +# The command line flag for including disabled tests. +ALSO_RUN_DISABED_TESTS_FLAG = 'gtest_also_run_disabled_tests' + +# Command to run the gtest_filter_unittest_ program. +COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_filter_unittest_') + +# Regex for determining whether parameterized tests are enabled in the binary. +PARAM_TEST_REGEX = re.compile(r'/ParamTest') + +# Regex for parsing test case names from Google Test's output. +TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)') + +# Regex for parsing test names from Google Test's output. +TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)') + +# The command line flag to tell Google Test to output the list of tests it +# will run. +LIST_TESTS_FLAG = '--gtest_list_tests' + +# Indicates whether Google Test supports death tests. +SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess( + [COMMAND, LIST_TESTS_FLAG]).output + +# Full names of all tests in gtest_filter_unittests_. +PARAM_TESTS = [ + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + 'SeqQ/ParamTest.TestX/0', + 'SeqQ/ParamTest.TestX/1', + 'SeqQ/ParamTest.TestY/0', + 'SeqQ/ParamTest.TestY/1', + ] + +DISABLED_TESTS = [ + 'BarTest.DISABLED_TestFour', + 'BarTest.DISABLED_TestFive', + 'BazTest.DISABLED_TestC', + 'DISABLED_FoobarTest.Test1', + 'DISABLED_FoobarTest.DISABLED_Test2', + 'DISABLED_FoobarbazTest.TestA', + ] + +if SUPPORTS_DEATH_TESTS: + DEATH_TESTS = [ + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', + ] +else: + DEATH_TESTS = [] + +# All the non-disabled tests. +ACTIVE_TESTS = [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', + ] + DEATH_TESTS + PARAM_TESTS + +param_tests_present = None + +# Utilities. + +environ = os.environ.copy() + + +def SetEnvVar(env_var, value): + """Sets the env variable to 'value'; unsets it when 'value' is None.""" + + if value is not None: + environ[env_var] = value + elif env_var in environ: + del environ[env_var] + + +def RunAndReturnOutput(args = None): + """Runs the test program and returns its output.""" + + return gtest_test_utils.Subprocess([COMMAND] + (args or []), + env=environ).output + + +def RunAndExtractTestList(args = None): + """Runs the test program and returns its exit code and a list of tests run.""" + + p = gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ) + tests_run = [] + test_case = '' + test = '' + for line in p.output.split('\n'): + match = TEST_CASE_REGEX.match(line) + if match is not None: + test_case = match.group(1) + else: + match = TEST_REGEX.match(line) + if match is not None: + test = match.group(1) + tests_run.append(test_case + '.' + test) + return (tests_run, p.exit_code) + + +def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs): + """Runs the given function and arguments in a modified environment.""" + try: + original_env = environ.copy() + environ.update(extra_env) + return function(*args, **kwargs) + finally: + environ.clear() + environ.update(original_env) + + +def RunWithSharding(total_shards, shard_index, command): + """Runs a test program shard and returns exit code and a list of tests run.""" + + extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index), + TOTAL_SHARDS_ENV_VAR: str(total_shards)} + return InvokeWithModifiedEnv(extra_env, RunAndExtractTestList, command) + +# The unit test. + + +class GTestFilterUnitTest(gtest_test_utils.TestCase): + """Tests the env variable or the command line flag to filter tests.""" + + # Utilities. + + def AssertSetEqual(self, lhs, rhs): + """Asserts that two sets are equal.""" + + for elem in lhs: + self.assert_(elem in rhs, '%s in %s' % (elem, rhs)) + + for elem in rhs: + self.assert_(elem in lhs, '%s in %s' % (elem, lhs)) + + def AssertPartitionIsValid(self, set_var, list_of_sets): + """Asserts that list_of_sets is a valid partition of set_var.""" + + full_partition = [] + for slice_var in list_of_sets: + full_partition.extend(slice_var) + self.assertEqual(len(set_var), len(full_partition)) + self.assertEqual(sets.Set(set_var), sets.Set(full_partition)) + + def AdjustForParameterizedTests(self, tests_to_run): + """Adjust tests_to_run in case value parameterized tests are disabled.""" + + global param_tests_present + if not param_tests_present: + return list(sets.Set(tests_to_run) - sets.Set(PARAM_TESTS)) + else: + return tests_to_run + + def RunAndVerify(self, gtest_filter, tests_to_run): + """Checks that the binary runs correct set of tests for a given filter.""" + + tests_to_run = self.AdjustForParameterizedTests(tests_to_run) + + # First, tests using the environment variable. + + # Windows removes empty variables from the environment when passing it + # to a new process. This means it is impossible to pass an empty filter + # into a process using the environment variable. However, we can still + # test the case when the variable is not supplied (i.e., gtest_filter is + # None). + # pylint: disable-msg=C6403 + if CAN_TEST_EMPTY_FILTER or gtest_filter != '': + SetEnvVar(FILTER_ENV_VAR, gtest_filter) + tests_run = RunAndExtractTestList()[0] + SetEnvVar(FILTER_ENV_VAR, None) + self.AssertSetEqual(tests_run, tests_to_run) + # pylint: enable-msg=C6403 + + # Next, tests using the command line flag. + + if gtest_filter is None: + args = [] + else: + args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)] + + tests_run = RunAndExtractTestList(args)[0] + self.AssertSetEqual(tests_run, tests_to_run) + + def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run, + args=None, check_exit_0=False): + """Checks that binary runs correct tests for the given filter and shard. + + Runs all shards of gtest_filter_unittest_ with the given filter, and + verifies that the right set of tests were run. The union of tests run + on each shard should be identical to tests_to_run, without duplicates. + + Args: + gtest_filter: A filter to apply to the tests. + total_shards: A total number of shards to split test run into. + tests_to_run: A set of tests expected to run. + args : Arguments to pass to the to the test binary. + check_exit_0: When set to a true value, make sure that all shards + return 0. + """ + + tests_to_run = self.AdjustForParameterizedTests(tests_to_run) + + # Windows removes empty variables from the environment when passing it + # to a new process. This means it is impossible to pass an empty filter + # into a process using the environment variable. However, we can still + # test the case when the variable is not supplied (i.e., gtest_filter is + # None). + # pylint: disable-msg=C6403 + if CAN_TEST_EMPTY_FILTER or gtest_filter != '': + SetEnvVar(FILTER_ENV_VAR, gtest_filter) + partition = [] + for i in range(0, total_shards): + (tests_run, exit_code) = RunWithSharding(total_shards, i, args) + if check_exit_0: + self.assertEqual(0, exit_code) + partition.append(tests_run) + + self.AssertPartitionIsValid(tests_to_run, partition) + SetEnvVar(FILTER_ENV_VAR, None) + # pylint: enable-msg=C6403 + + def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run): + """Checks that the binary runs correct set of tests for the given filter. + + Runs gtest_filter_unittest_ with the given filter, and enables + disabled tests. Verifies that the right set of tests were run. + + Args: + gtest_filter: A filter to apply to the tests. + tests_to_run: A set of tests expected to run. + """ + + tests_to_run = self.AdjustForParameterizedTests(tests_to_run) + + # Construct the command line. + args = ['--%s' % ALSO_RUN_DISABED_TESTS_FLAG] + if gtest_filter is not None: + args.append('--%s=%s' % (FILTER_FLAG, gtest_filter)) + + tests_run = RunAndExtractTestList(args)[0] + self.AssertSetEqual(tests_run, tests_to_run) + + def setUp(self): + """Sets up test case. + + Determines whether value-parameterized tests are enabled in the binary and + sets the flags accordingly. + """ + + global param_tests_present + if param_tests_present is None: + param_tests_present = PARAM_TEST_REGEX.search( + RunAndReturnOutput()) is not None + + def testDefaultBehavior(self): + """Tests the behavior of not specifying the filter.""" + + self.RunAndVerify(None, ACTIVE_TESTS) + + def testDefaultBehaviorWithShards(self): + """Tests the behavior without the filter, with sharding enabled.""" + + self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS) + + def testEmptyFilter(self): + """Tests an empty filter.""" + + self.RunAndVerify('', []) + self.RunAndVerifyWithSharding('', 1, []) + self.RunAndVerifyWithSharding('', 2, []) + + def testBadFilter(self): + """Tests a filter that matches nothing.""" + + self.RunAndVerify('BadFilter', []) + self.RunAndVerifyAllowingDisabled('BadFilter', []) + + def testFullName(self): + """Tests filtering by full name.""" + + self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz']) + self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz']) + self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz']) + + def testUniversalFilters(self): + """Tests filters that match everything.""" + + self.RunAndVerify('*', ACTIVE_TESTS) + self.RunAndVerify('*.*', ACTIVE_TESTS) + self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS) + self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS) + self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS) + + def testFilterByTestCase(self): + """Tests filtering by test case name.""" + + self.RunAndVerify('FooTest.*', ['FooTest.Abc', 'FooTest.Xyz']) + + BAZ_TESTS = ['BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB'] + self.RunAndVerify('BazTest.*', BAZ_TESTS) + self.RunAndVerifyAllowingDisabled('BazTest.*', + BAZ_TESTS + ['BazTest.DISABLED_TestC']) + + def testFilterByTest(self): + """Tests filtering by test name.""" + + self.RunAndVerify('*.TestOne', ['BarTest.TestOne', 'BazTest.TestOne']) + + def testFilterDisabledTests(self): + """Select only the disabled tests to run.""" + + self.RunAndVerify('DISABLED_FoobarTest.Test1', []) + self.RunAndVerifyAllowingDisabled('DISABLED_FoobarTest.Test1', + ['DISABLED_FoobarTest.Test1']) + + self.RunAndVerify('*DISABLED_*', []) + self.RunAndVerifyAllowingDisabled('*DISABLED_*', DISABLED_TESTS) + + self.RunAndVerify('*.DISABLED_*', []) + self.RunAndVerifyAllowingDisabled('*.DISABLED_*', [ + 'BarTest.DISABLED_TestFour', + 'BarTest.DISABLED_TestFive', + 'BazTest.DISABLED_TestC', + 'DISABLED_FoobarTest.DISABLED_Test2', + ]) + + self.RunAndVerify('DISABLED_*', []) + self.RunAndVerifyAllowingDisabled('DISABLED_*', [ + 'DISABLED_FoobarTest.Test1', + 'DISABLED_FoobarTest.DISABLED_Test2', + 'DISABLED_FoobarbazTest.TestA', + ]) + + def testWildcardInTestCaseName(self): + """Tests using wildcard in the test case name.""" + + self.RunAndVerify('*a*.*', [ + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS) + + def testWildcardInTestName(self): + """Tests using wildcard in the test name.""" + + self.RunAndVerify('*.*A*', ['FooTest.Abc', 'BazTest.TestA']) + + def testFilterWithoutDot(self): + """Tests a filter that has no '.' in it.""" + + self.RunAndVerify('*z*', [ + 'FooTest.Xyz', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', + ]) + + def testTwoPatterns(self): + """Tests filters that consist of two patterns.""" + + self.RunAndVerify('Foo*.*:*A*', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BazTest.TestA', + ]) + + # An empty pattern + a non-empty one + self.RunAndVerify(':*A*', ['FooTest.Abc', 'BazTest.TestA']) + + def testThreePatterns(self): + """Tests filters that consist of three patterns.""" + + self.RunAndVerify('*oo*:*A*:*One', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + + 'BazTest.TestOne', + 'BazTest.TestA', + ]) + + # The 2nd pattern is empty. + self.RunAndVerify('*oo*::*One', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + + 'BazTest.TestOne', + ]) + + # The last 2 patterns are empty. + self.RunAndVerify('*oo*::', [ + 'FooTest.Abc', + 'FooTest.Xyz', + ]) + + def testNegativeFilters(self): + self.RunAndVerify('*-BazTest.TestOne', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + + 'BazTest.TestA', + 'BazTest.TestB', + ] + DEATH_TESTS + PARAM_TESTS) + + self.RunAndVerify('*-FooTest.Abc:BazTest.*', [ + 'FooTest.Xyz', + + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + ] + DEATH_TESTS + PARAM_TESTS) + + self.RunAndVerify('BarTest.*-BarTest.TestOne', [ + 'BarTest.TestTwo', + 'BarTest.TestThree', + ]) + + # Tests without leading '*'. + self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [ + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + ] + DEATH_TESTS + PARAM_TESTS) + + # Value parameterized tests. + self.RunAndVerify('*/*', PARAM_TESTS) + + # Value parameterized tests filtering by the sequence name. + self.RunAndVerify('SeqP/*', [ + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + ]) + + # Value parameterized tests filtering by the test name. + self.RunAndVerify('*/0', [ + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestY/0', + 'SeqQ/ParamTest.TestX/0', + 'SeqQ/ParamTest.TestY/0', + ]) + + def testFlagOverridesEnvVar(self): + """Tests that the filter flag overrides the filtering env. variable.""" + + SetEnvVar(FILTER_ENV_VAR, 'Foo*') + args = ['--%s=%s' % (FILTER_FLAG, '*One')] + tests_run = RunAndExtractTestList(args)[0] + SetEnvVar(FILTER_ENV_VAR, None) + + self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne']) + + def testShardStatusFileIsCreated(self): + """Tests that the shard file is created if specified in the environment.""" + + shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), + 'shard_status_file') + self.assert_(not os.path.exists(shard_status_file)) + + extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} + try: + InvokeWithModifiedEnv(extra_env, RunAndReturnOutput) + finally: + self.assert_(os.path.exists(shard_status_file)) + os.remove(shard_status_file) + + def testShardStatusFileIsCreatedWithListTests(self): + """Tests that the shard file is created with the "list_tests" flag.""" + + shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), + 'shard_status_file2') + self.assert_(not os.path.exists(shard_status_file)) + + extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} + try: + output = InvokeWithModifiedEnv(extra_env, + RunAndReturnOutput, + [LIST_TESTS_FLAG]) + finally: + # This assertion ensures that Google Test enumerated the tests as + # opposed to running them. + self.assert_('[==========]' not in output, + 'Unexpected output during test enumeration.\n' + 'Please ensure that LIST_TESTS_FLAG is assigned the\n' + 'correct flag value for listing Google Test tests.') + + self.assert_(os.path.exists(shard_status_file)) + os.remove(shard_status_file) + + if SUPPORTS_DEATH_TESTS: + def testShardingWorksWithDeathTests(self): + """Tests integration with death tests and sharding.""" + + gtest_filter = 'HasDeathTest.*:SeqP/*' + expected_tests = [ + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', + + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + ] + + for flag in ['--gtest_death_test_style=threadsafe', + '--gtest_death_test_style=fast']: + self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests, + check_exit_0=True, args=[flag]) + self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests, + check_exit_0=True, args=[flag]) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_filter_unittest_.cc b/third_party/googletest/src/test/gtest_filter_unittest_.cc new file mode 100644 index 0000000..77deffc --- /dev/null +++ b/third_party/googletest/src/test/gtest_filter_unittest_.cc @@ -0,0 +1,140 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Unit test for Google Test test filters. +// +// A user can specify which test(s) in a Google Test program to run via +// either the GTEST_FILTER environment variable or the --gtest_filter +// flag. This is used for testing such functionality. +// +// The program will be invoked from a Python unit test. Don't run it +// directly. + +#include "gtest/gtest.h" + +namespace { + +// Test case FooTest. + +class FooTest : public testing::Test { +}; + +TEST_F(FooTest, Abc) { +} + +TEST_F(FooTest, Xyz) { + FAIL() << "Expected failure."; +} + +// Test case BarTest. + +TEST(BarTest, TestOne) { +} + +TEST(BarTest, TestTwo) { +} + +TEST(BarTest, TestThree) { +} + +TEST(BarTest, DISABLED_TestFour) { + FAIL() << "Expected failure."; +} + +TEST(BarTest, DISABLED_TestFive) { + FAIL() << "Expected failure."; +} + +// Test case BazTest. + +TEST(BazTest, TestOne) { + FAIL() << "Expected failure."; +} + +TEST(BazTest, TestA) { +} + +TEST(BazTest, TestB) { +} + +TEST(BazTest, DISABLED_TestC) { + FAIL() << "Expected failure."; +} + +// Test case HasDeathTest + +TEST(HasDeathTest, Test1) { + EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); +} + +// We need at least two death tests to make sure that the all death tests +// aren't on the first shard. +TEST(HasDeathTest, Test2) { + EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); +} + +// Test case FoobarTest + +TEST(DISABLED_FoobarTest, Test1) { + FAIL() << "Expected failure."; +} + +TEST(DISABLED_FoobarTest, DISABLED_Test2) { + FAIL() << "Expected failure."; +} + +// Test case FoobarbazTest + +TEST(DISABLED_FoobarbazTest, TestA) { + FAIL() << "Expected failure."; +} + +#if GTEST_HAS_PARAM_TEST +class ParamTest : public testing::TestWithParam { +}; + +TEST_P(ParamTest, TestX) { +} + +TEST_P(ParamTest, TestY) { +} + +INSTANTIATE_TEST_CASE_P(SeqP, ParamTest, testing::Values(1, 2)); +INSTANTIATE_TEST_CASE_P(SeqQ, ParamTest, testing::Values(5, 6)); +#endif // GTEST_HAS_PARAM_TEST + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_help_test.py b/third_party/googletest/src/test/gtest_help_test.py new file mode 100755 index 0000000..093c838 --- /dev/null +++ b/third_party/googletest/src/test/gtest_help_test.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests the --help flag of Google C++ Testing Framework. + +SYNOPSIS + gtest_help_test.py --build_dir=BUILD/DIR + # where BUILD/DIR contains the built gtest_help_test_ file. + gtest_help_test.py +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import gtest_test_utils + + +IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' +IS_WINDOWS = os.name == 'nt' + +PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_') +FLAG_PREFIX = '--gtest_' +DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style' +STREAM_RESULT_TO_FLAG = FLAG_PREFIX + 'stream_result_to' +UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing' +LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' +INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG), + re.sub('^--', '/', LIST_TESTS_FLAG), + re.sub('_', '-', LIST_TESTS_FLAG)] +INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing' + +SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess( + [PROGRAM_PATH, LIST_TESTS_FLAG]).output + +# The help message must match this regex. +HELP_REGEX = re.compile( + FLAG_PREFIX + r'list_tests.*' + + FLAG_PREFIX + r'filter=.*' + + FLAG_PREFIX + r'also_run_disabled_tests.*' + + FLAG_PREFIX + r'repeat=.*' + + FLAG_PREFIX + r'shuffle.*' + + FLAG_PREFIX + r'random_seed=.*' + + FLAG_PREFIX + r'color=.*' + + FLAG_PREFIX + r'print_time.*' + + FLAG_PREFIX + r'output=.*' + + FLAG_PREFIX + r'break_on_failure.*' + + FLAG_PREFIX + r'throw_on_failure.*' + + FLAG_PREFIX + r'catch_exceptions=0.*', + re.DOTALL) + + +def RunWithFlag(flag): + """Runs gtest_help_test_ with the given flag. + + Returns: + the exit code and the text output as a tuple. + Args: + flag: the command-line flag to pass to gtest_help_test_, or None. + """ + + if flag is None: + command = [PROGRAM_PATH] + else: + command = [PROGRAM_PATH, flag] + child = gtest_test_utils.Subprocess(command) + return child.exit_code, child.output + + +class GTestHelpTest(gtest_test_utils.TestCase): + """Tests the --help flag and its equivalent forms.""" + + def TestHelpFlag(self, flag): + """Verifies correct behavior when help flag is specified. + + The right message must be printed and the tests must + skipped when the given flag is specified. + + Args: + flag: A flag to pass to the binary or None. + """ + + exit_code, output = RunWithFlag(flag) + self.assertEquals(0, exit_code) + self.assert_(HELP_REGEX.search(output), output) + + if IS_LINUX: + self.assert_(STREAM_RESULT_TO_FLAG in output, output) + else: + self.assert_(STREAM_RESULT_TO_FLAG not in output, output) + + if SUPPORTS_DEATH_TESTS and not IS_WINDOWS: + self.assert_(DEATH_TEST_STYLE_FLAG in output, output) + else: + self.assert_(DEATH_TEST_STYLE_FLAG not in output, output) + + def TestNonHelpFlag(self, flag): + """Verifies correct behavior when no help flag is specified. + + Verifies that when no help flag is specified, the tests are run + and the help message is not printed. + + Args: + flag: A flag to pass to the binary or None. + """ + + exit_code, output = RunWithFlag(flag) + self.assert_(exit_code != 0) + self.assert_(not HELP_REGEX.search(output), output) + + def testPrintsHelpWithFullFlag(self): + self.TestHelpFlag('--help') + + def testPrintsHelpWithShortFlag(self): + self.TestHelpFlag('-h') + + def testPrintsHelpWithQuestionFlag(self): + self.TestHelpFlag('-?') + + def testPrintsHelpWithWindowsStyleQuestionFlag(self): + self.TestHelpFlag('/?') + + def testPrintsHelpWithUnrecognizedGoogleTestFlag(self): + self.TestHelpFlag(UNKNOWN_FLAG) + + def testPrintsHelpWithIncorrectFlagStyle(self): + for incorrect_flag in INCORRECT_FLAG_VARIANTS: + self.TestHelpFlag(incorrect_flag) + + def testRunsTestsWithoutHelpFlag(self): + """Verifies that when no help flag is specified, the tests are run + and the help message is not printed.""" + + self.TestNonHelpFlag(None) + + def testRunsTestsWithGtestInternalFlag(self): + """Verifies that the tests are run and no help message is printed when + a flag starting with Google Test prefix and 'internal_' is supplied.""" + + self.TestNonHelpFlag(INTERNAL_FLAG_FOR_TESTING) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_help_test_.cc b/third_party/googletest/src/test/gtest_help_test_.cc new file mode 100644 index 0000000..31f78c2 --- /dev/null +++ b/third_party/googletest/src/test/gtest_help_test_.cc @@ -0,0 +1,46 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// This program is meant to be run by gtest_help_test.py. Do not run +// it directly. + +#include "gtest/gtest.h" + +// When a help flag is specified, this program should skip the tests +// and exit with 0; otherwise the following test will be executed, +// causing this program to exit with a non-zero code. +TEST(HelpFlagTest, ShouldNotBeRun) { + ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified."; +} + +#if GTEST_HAS_DEATH_TEST +TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {} +#endif diff --git a/third_party/googletest/src/test/gtest_list_tests_unittest.py b/third_party/googletest/src/test/gtest_list_tests_unittest.py new file mode 100755 index 0000000..ce8c3ef --- /dev/null +++ b/third_party/googletest/src/test/gtest_list_tests_unittest.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for Google Test's --gtest_list_tests flag. + +A user can ask Google Test to list all tests by specifying the +--gtest_list_tests flag. This script tests such functionality +by invoking gtest_list_tests_unittest_ (a program written with +Google Test) the command line flags. +""" + +__author__ = 'phanna@google.com (Patrick Hanna)' + +import gtest_test_utils + + +# Constants. + +# The command line flag for enabling/disabling listing all tests. +LIST_TESTS_FLAG = 'gtest_list_tests' + +# Path to the gtest_list_tests_unittest_ program. +EXE_PATH = gtest_test_utils.GetTestExecutablePath('gtest_list_tests_unittest_') + +# The expected output when running gtest_list_tests_unittest_ with +# --gtest_list_tests +EXPECTED_OUTPUT_NO_FILTER = """FooDeathTest. + Test1 +Foo. + Bar1 + Bar2 + DISABLED_Bar3 +Abc. + Xyz + Def +FooBar. + Baz +FooTest. + Test1 + DISABLED_Test2 + Test3 +""" + +# The expected output when running gtest_list_tests_unittest_ with +# --gtest_list_tests and --gtest_filter=Foo*. +EXPECTED_OUTPUT_FILTER_FOO = """FooDeathTest. + Test1 +Foo. + Bar1 + Bar2 + DISABLED_Bar3 +FooBar. + Baz +FooTest. + Test1 + DISABLED_Test2 + Test3 +""" + +# Utilities. + + +def Run(args): + """Runs gtest_list_tests_unittest_ and returns the list of tests printed.""" + + return gtest_test_utils.Subprocess([EXE_PATH] + args, + capture_stderr=False).output + + +# The unit test. + +class GTestListTestsUnitTest(gtest_test_utils.TestCase): + """Tests using the --gtest_list_tests flag to list all tests.""" + + def RunAndVerify(self, flag_value, expected_output, other_flag): + """Runs gtest_list_tests_unittest_ and verifies that it prints + the correct tests. + + Args: + flag_value: value of the --gtest_list_tests flag; + None if the flag should not be present. + + expected_output: the expected output after running command; + + other_flag: a different flag to be passed to command + along with gtest_list_tests; + None if the flag should not be present. + """ + + if flag_value is None: + flag = '' + flag_expression = 'not set' + elif flag_value == '0': + flag = '--%s=0' % LIST_TESTS_FLAG + flag_expression = '0' + else: + flag = '--%s' % LIST_TESTS_FLAG + flag_expression = '1' + + args = [flag] + + if other_flag is not None: + args += [other_flag] + + output = Run(args) + + msg = ('when %s is %s, the output of "%s" is "%s".' % + (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output)) + + if expected_output is not None: + self.assert_(output == expected_output, msg) + else: + self.assert_(output != EXPECTED_OUTPUT_NO_FILTER, msg) + + def testDefaultBehavior(self): + """Tests the behavior of the default mode.""" + + self.RunAndVerify(flag_value=None, + expected_output=None, + other_flag=None) + + def testFlag(self): + """Tests using the --gtest_list_tests flag.""" + + self.RunAndVerify(flag_value='0', + expected_output=None, + other_flag=None) + self.RunAndVerify(flag_value='1', + expected_output=EXPECTED_OUTPUT_NO_FILTER, + other_flag=None) + + def testOverrideNonFilterFlags(self): + """Tests that --gtest_list_tests overrides the non-filter flags.""" + + self.RunAndVerify(flag_value='1', + expected_output=EXPECTED_OUTPUT_NO_FILTER, + other_flag='--gtest_break_on_failure') + + def testWithFilterFlags(self): + """Tests that --gtest_list_tests takes into account the + --gtest_filter flag.""" + + self.RunAndVerify(flag_value='1', + expected_output=EXPECTED_OUTPUT_FILTER_FOO, + other_flag='--gtest_filter=Foo*') + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_list_tests_unittest_.cc b/third_party/googletest/src/test/gtest_list_tests_unittest_.cc new file mode 100644 index 0000000..2b1d078 --- /dev/null +++ b/third_party/googletest/src/test/gtest_list_tests_unittest_.cc @@ -0,0 +1,85 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: phanna@google.com (Patrick Hanna) + +// Unit test for Google Test's --gtest_list_tests flag. +// +// A user can ask Google Test to list all tests that will run +// so that when using a filter, a user will know what +// tests to look for. The tests will not be run after listing. +// +// This program will be invoked from a Python unit test. +// Don't run it directly. + +#include "gtest/gtest.h" + +namespace { + +// Several different test cases and tests that will be listed. +TEST(Foo, Bar1) { +} + +TEST(Foo, Bar2) { +} + +TEST(Foo, DISABLED_Bar3) { +} + +TEST(Abc, Xyz) { +} + +TEST(Abc, Def) { +} + +TEST(FooBar, Baz) { +} + +class FooTest : public testing::Test { +}; + +TEST_F(FooTest, Test1) { +} + +TEST_F(FooTest, DISABLED_Test2) { +} + +TEST_F(FooTest, Test3) { +} + +TEST(FooDeathTest, Test1) { +} + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_main_unittest.cc b/third_party/googletest/src/test/gtest_main_unittest.cc new file mode 100644 index 0000000..ecd9bb8 --- /dev/null +++ b/third_party/googletest/src/test/gtest_main_unittest.cc @@ -0,0 +1,45 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest.h" + +// Tests that we don't have to define main() when we link to +// gtest_main instead of gtest. + +namespace { + +TEST(GTestMainTest, ShouldSucceed) { +} + +} // namespace + +// We are using the main() function defined in src/gtest_main.cc, so +// we don't define it here. diff --git a/third_party/googletest/src/test/gtest_no_test_unittest.cc b/third_party/googletest/src/test/gtest_no_test_unittest.cc new file mode 100644 index 0000000..e3a85f1 --- /dev/null +++ b/third_party/googletest/src/test/gtest_no_test_unittest.cc @@ -0,0 +1,57 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Tests that a Google Test program that has no test defined can run +// successfully. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest.h" + + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + // An ad-hoc assertion outside of all tests. + // + // This serves three purposes: + // + // 1. It verifies that an ad-hoc assertion can be executed even if + // no test is defined. + // 2. It verifies that a failed ad-hoc assertion causes the test + // program to fail. + // 3. We had a bug where the XML output won't be generated if an + // assertion is executed before RUN_ALL_TESTS() is called, even + // though --gtest_output=xml is specified. This makes sure the + // bug is fixed and doesn't regress. + EXPECT_EQ(1, 2); + + // The above EXPECT_EQ() should cause RUN_ALL_TESTS() to return non-zero. + return RUN_ALL_TESTS() ? 0 : 1; +} diff --git a/third_party/googletest/src/test/gtest_output_test.py b/third_party/googletest/src/test/gtest_output_test.py new file mode 100755 index 0000000..f409e2a --- /dev/null +++ b/third_party/googletest/src/test/gtest_output_test.py @@ -0,0 +1,335 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests the text output of Google C++ Testing Framework. + +SYNOPSIS + gtest_output_test.py --build_dir=BUILD/DIR --gengolden + # where BUILD/DIR contains the built gtest_output_test_ file. + gtest_output_test.py --gengolden + gtest_output_test.py +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sys +import gtest_test_utils + + +# The flag for generating the golden file +GENGOLDEN_FLAG = '--gengolden' +CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS' + +IS_WINDOWS = os.name == 'nt' + +# TODO(vladl@google.com): remove the _lin suffix. +GOLDEN_NAME = 'gtest_output_test_golden_lin.txt' + +PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_') + +# At least one command we exercise must not have the +# --gtest_internal_skip_environment_and_ad_hoc_tests flag. +COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests']) +COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes']) +COMMAND_WITH_TIME = ({}, [PROGRAM_PATH, + '--gtest_print_time', + '--gtest_internal_skip_environment_and_ad_hoc_tests', + '--gtest_filter=FatalFailureTest.*:LoggingTest.*']) +COMMAND_WITH_DISABLED = ( + {}, [PROGRAM_PATH, + '--gtest_also_run_disabled_tests', + '--gtest_internal_skip_environment_and_ad_hoc_tests', + '--gtest_filter=*DISABLED_*']) +COMMAND_WITH_SHARDING = ( + {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, + [PROGRAM_PATH, + '--gtest_internal_skip_environment_and_ad_hoc_tests', + '--gtest_filter=PassingTest.*']) + +GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME) + + +def ToUnixLineEnding(s): + """Changes all Windows/Mac line endings in s to UNIX line endings.""" + + return s.replace('\r\n', '\n').replace('\r', '\n') + + +def RemoveLocations(test_output): + """Removes all file location info from a Google Test program's output. + + Args: + test_output: the output of a Google Test program. + + Returns: + output with all file location info (in the form of + 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or + 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by + 'FILE_NAME:#: '. + """ + + return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output) + + +def RemoveStackTraceDetails(output): + """Removes all stack traces from a Google Test program's output.""" + + # *? means "find the shortest string that matches". + return re.sub(r'Stack trace:(.|\n)*?\n\n', + 'Stack trace: (omitted)\n\n', output) + + +def RemoveStackTraces(output): + """Removes all traces of stack traces from a Google Test program's output.""" + + # *? means "find the shortest string that matches". + return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output) + + +def RemoveTime(output): + """Removes all time information from a Google Test program's output.""" + + return re.sub(r'\(\d+ ms', '(? ms', output) + + +def RemoveTypeInfoDetails(test_output): + """Removes compiler-specific type info from Google Test program's output. + + Args: + test_output: the output of a Google Test program. + + Returns: + output with type information normalized to canonical form. + """ + + # some compilers output the name of type 'unsigned int' as 'unsigned' + return re.sub(r'unsigned int', 'unsigned', test_output) + + +def NormalizeToCurrentPlatform(test_output): + """Normalizes platform specific output details for easier comparison.""" + + if IS_WINDOWS: + # Removes the color information that is not present on Windows. + test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output) + # Changes failure message headers into the Windows format. + test_output = re.sub(r': Failure\n', r': error: ', test_output) + # Changes file(line_number) to file:line_number. + test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output) + + return test_output + + +def RemoveTestCounts(output): + """Removes test counts from a Google Test program's output.""" + + output = re.sub(r'\d+ tests?, listed below', + '? tests, listed below', output) + output = re.sub(r'\d+ FAILED TESTS', + '? FAILED TESTS', output) + output = re.sub(r'\d+ tests? from \d+ test cases?', + '? tests from ? test cases', output) + output = re.sub(r'\d+ tests? from ([a-zA-Z_])', + r'? tests from \1', output) + return re.sub(r'\d+ tests?\.', '? tests.', output) + + +def RemoveMatchingTests(test_output, pattern): + """Removes output of specified tests from a Google Test program's output. + + This function strips not only the beginning and the end of a test but also + all output in between. + + Args: + test_output: A string containing the test output. + pattern: A regex string that matches names of test cases or + tests to remove. + + Returns: + Contents of test_output with tests whose names match pattern removed. + """ + + test_output = re.sub( + r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % ( + pattern, pattern), + '', + test_output) + return re.sub(r'.*%s.*\n' % pattern, '', test_output) + + +def NormalizeOutput(output): + """Normalizes output (the output of gtest_output_test_.exe).""" + + output = ToUnixLineEnding(output) + output = RemoveLocations(output) + output = RemoveStackTraceDetails(output) + output = RemoveTime(output) + return output + + +def GetShellCommandOutput(env_cmd): + """Runs a command in a sub-process, and returns its output in a string. + + Args: + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra + environment variables to set, and element 1 is a string with + the command and any flags. + + Returns: + A string with the command's combined standard and diagnostic output. + """ + + # Spawns cmd in a sub-process, and gets its standard I/O file objects. + # Set and save the environment properly. + environ = os.environ.copy() + environ.update(env_cmd[0]) + p = gtest_test_utils.Subprocess(env_cmd[1], env=environ) + + return p.output + + +def GetCommandOutput(env_cmd): + """Runs a command and returns its output with all file location + info stripped off. + + Args: + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra + environment variables to set, and element 1 is a string with + the command and any flags. + """ + + # Disables exception pop-ups on Windows. + environ, cmdline = env_cmd + environ = dict(environ) # Ensures we are modifying a copy. + environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1' + return NormalizeOutput(GetShellCommandOutput((environ, cmdline))) + + +def GetOutputOfAllCommands(): + """Returns concatenated output from several representative commands.""" + + return (GetCommandOutput(COMMAND_WITH_COLOR) + + GetCommandOutput(COMMAND_WITH_TIME) + + GetCommandOutput(COMMAND_WITH_DISABLED) + + GetCommandOutput(COMMAND_WITH_SHARDING)) + + +test_list = GetShellCommandOutput(COMMAND_LIST_TESTS) +SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list +SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list +SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list +SUPPORTS_STACK_TRACES = False + +CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and + SUPPORTS_TYPED_TESTS and + SUPPORTS_THREADS) + + +class GTestOutputTest(gtest_test_utils.TestCase): + def RemoveUnsupportedTests(self, test_output): + if not SUPPORTS_DEATH_TESTS: + test_output = RemoveMatchingTests(test_output, 'DeathTest') + if not SUPPORTS_TYPED_TESTS: + test_output = RemoveMatchingTests(test_output, 'TypedTest') + test_output = RemoveMatchingTests(test_output, 'TypedDeathTest') + test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest') + if not SUPPORTS_THREADS: + test_output = RemoveMatchingTests(test_output, + 'ExpectFailureWithThreadsTest') + test_output = RemoveMatchingTests(test_output, + 'ScopedFakeTestPartResultReporterTest') + test_output = RemoveMatchingTests(test_output, + 'WorksConcurrently') + if not SUPPORTS_STACK_TRACES: + test_output = RemoveStackTraces(test_output) + + return test_output + + def testOutput(self): + output = GetOutputOfAllCommands() + + golden_file = open(GOLDEN_PATH, 'rb') + # A mis-configured source control system can cause \r appear in EOL + # sequences when we read the golden file irrespective of an operating + # system used. Therefore, we need to strip those \r's from newlines + # unconditionally. + golden = ToUnixLineEnding(golden_file.read()) + golden_file.close() + + # We want the test to pass regardless of certain features being + # supported or not. + + # We still have to remove type name specifics in all cases. + normalized_actual = RemoveTypeInfoDetails(output) + normalized_golden = RemoveTypeInfoDetails(golden) + + if CAN_GENERATE_GOLDEN_FILE: + self.assertEqual(normalized_golden, normalized_actual) + else: + normalized_actual = NormalizeToCurrentPlatform( + RemoveTestCounts(normalized_actual)) + normalized_golden = NormalizeToCurrentPlatform( + RemoveTestCounts(self.RemoveUnsupportedTests(normalized_golden))) + + # This code is very handy when debugging golden file differences: + if os.getenv('DEBUG_GTEST_OUTPUT_TEST'): + open(os.path.join( + gtest_test_utils.GetSourceDir(), + '_gtest_output_test_normalized_actual.txt'), 'wb').write( + normalized_actual) + open(os.path.join( + gtest_test_utils.GetSourceDir(), + '_gtest_output_test_normalized_golden.txt'), 'wb').write( + normalized_golden) + + self.assertEqual(normalized_golden, normalized_actual) + + +if __name__ == '__main__': + if sys.argv[1:] == [GENGOLDEN_FLAG]: + if CAN_GENERATE_GOLDEN_FILE: + output = GetOutputOfAllCommands() + golden_file = open(GOLDEN_PATH, 'wb') + golden_file.write(output) + golden_file.close() + else: + message = ( + """Unable to write a golden file when compiled in an environment +that does not support all the required features (death tests, typed tests, +and multiple threads). Please generate the golden file using a binary built +with those features enabled.""") + + sys.stderr.write(message) + sys.exit(1) + else: + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_output_test_.cc b/third_party/googletest/src/test/gtest_output_test_.cc new file mode 100644 index 0000000..13dbec4 --- /dev/null +++ b/third_party/googletest/src/test/gtest_output_test_.cc @@ -0,0 +1,1020 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// A unit test for Google Test itself. This verifies that the basic +// constructs of Google Test work. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest-spi.h" +#include "gtest/gtest.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#include + +#if GTEST_IS_THREADSAFE +using testing::ScopedFakeTestPartResultReporter; +using testing::TestPartResultArray; + +using testing::internal::Notification; +using testing::internal::ThreadWithParam; +#endif + +namespace posix = ::testing::internal::posix; +using testing::internal::String; +using testing::internal::scoped_ptr; + +// Tests catching fatal failures. + +// A subroutine used by the following test. +void TestEq1(int x) { + ASSERT_EQ(1, x); +} + +// This function calls a test subroutine, catches the fatal failure it +// generates, and then returns early. +void TryTestSubroutine() { + // Calls a subrountine that yields a fatal failure. + TestEq1(2); + + // Catches the fatal failure and aborts the test. + // + // The testing::Test:: prefix is necessary when calling + // HasFatalFailure() outside of a TEST, TEST_F, or test fixture. + if (testing::Test::HasFatalFailure()) return; + + // If we get here, something is wrong. + FAIL() << "This should never be reached."; +} + +TEST(PassingTest, PassingTest1) { +} + +TEST(PassingTest, PassingTest2) { +} + +// Tests that parameters of failing parameterized tests are printed in the +// failing test summary. +class FailingParamTest : public testing::TestWithParam {}; + +TEST_P(FailingParamTest, Fails) { + EXPECT_EQ(1, GetParam()); +} + +// This generates a test which will fail. Google Test is expected to print +// its parameter when it outputs the list of all failed tests. +INSTANTIATE_TEST_CASE_P(PrintingFailingParams, + FailingParamTest, + testing::Values(2)); + +// Tests catching a fatal failure in a subroutine. +TEST(FatalFailureTest, FatalFailureInSubroutine) { + printf("(expecting a failure that x should be 1)\n"); + + TryTestSubroutine(); +} + +// Tests catching a fatal failure in a nested subroutine. +TEST(FatalFailureTest, FatalFailureInNestedSubroutine) { + printf("(expecting a failure that x should be 1)\n"); + + // Calls a subrountine that yields a fatal failure. + TryTestSubroutine(); + + // Catches the fatal failure and aborts the test. + // + // When calling HasFatalFailure() inside a TEST, TEST_F, or test + // fixture, the testing::Test:: prefix is not needed. + if (HasFatalFailure()) return; + + // If we get here, something is wrong. + FAIL() << "This should never be reached."; +} + +// Tests HasFatalFailure() after a failed EXPECT check. +TEST(FatalFailureTest, NonfatalFailureInSubroutine) { + printf("(expecting a failure on false)\n"); + EXPECT_TRUE(false); // Generates a nonfatal failure + ASSERT_FALSE(HasFatalFailure()); // This should succeed. +} + +// Tests interleaving user logging and Google Test assertions. +TEST(LoggingTest, InterleavingLoggingAndAssertions) { + static const int a[4] = { + 3, 9, 2, 6 + }; + + printf("(expecting 2 failures on (3) >= (a[i]))\n"); + for (int i = 0; i < static_cast(sizeof(a)/sizeof(*a)); i++) { + printf("i == %d\n", i); + EXPECT_GE(3, a[i]); + } +} + +// Tests the SCOPED_TRACE macro. + +// A helper function for testing SCOPED_TRACE. +void SubWithoutTrace(int n) { + EXPECT_EQ(1, n); + ASSERT_EQ(2, n); +} + +// Another helper function for testing SCOPED_TRACE. +void SubWithTrace(int n) { + SCOPED_TRACE(testing::Message() << "n = " << n); + + SubWithoutTrace(n); +} + +// Tests that SCOPED_TRACE() obeys lexical scopes. +TEST(SCOPED_TRACETest, ObeysScopes) { + printf("(expected to fail)\n"); + + // There should be no trace before SCOPED_TRACE() is invoked. + ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; + + { + SCOPED_TRACE("Expected trace"); + // After SCOPED_TRACE(), a failure in the current scope should contain + // the trace. + ADD_FAILURE() << "This failure is expected, and should have a trace."; + } + + // Once the control leaves the scope of the SCOPED_TRACE(), there + // should be no trace again. + ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; +} + +// Tests that SCOPED_TRACE works inside a loop. +TEST(SCOPED_TRACETest, WorksInLoop) { + printf("(expected to fail)\n"); + + for (int i = 1; i <= 2; i++) { + SCOPED_TRACE(testing::Message() << "i = " << i); + + SubWithoutTrace(i); + } +} + +// Tests that SCOPED_TRACE works in a subroutine. +TEST(SCOPED_TRACETest, WorksInSubroutine) { + printf("(expected to fail)\n"); + + SubWithTrace(1); + SubWithTrace(2); +} + +// Tests that SCOPED_TRACE can be nested. +TEST(SCOPED_TRACETest, CanBeNested) { + printf("(expected to fail)\n"); + + SCOPED_TRACE(""); // A trace without a message. + + SubWithTrace(2); +} + +// Tests that multiple SCOPED_TRACEs can be used in the same scope. +TEST(SCOPED_TRACETest, CanBeRepeated) { + printf("(expected to fail)\n"); + + SCOPED_TRACE("A"); + ADD_FAILURE() + << "This failure is expected, and should contain trace point A."; + + SCOPED_TRACE("B"); + ADD_FAILURE() + << "This failure is expected, and should contain trace point A and B."; + + { + SCOPED_TRACE("C"); + ADD_FAILURE() << "This failure is expected, and should contain " + << "trace point A, B, and C."; + } + + SCOPED_TRACE("D"); + ADD_FAILURE() << "This failure is expected, and should contain " + << "trace point A, B, and D."; +} + +#if GTEST_IS_THREADSAFE +// Tests that SCOPED_TRACE()s can be used concurrently from multiple +// threads. Namely, an assertion should be affected by +// SCOPED_TRACE()s in its own thread only. + +// Here's the sequence of actions that happen in the test: +// +// Thread A (main) | Thread B (spawned) +// ===============================|================================ +// spawns thread B | +// -------------------------------+-------------------------------- +// waits for n1 | SCOPED_TRACE("Trace B"); +// | generates failure #1 +// | notifies n1 +// -------------------------------+-------------------------------- +// SCOPED_TRACE("Trace A"); | waits for n2 +// generates failure #2 | +// notifies n2 | +// -------------------------------|-------------------------------- +// waits for n3 | generates failure #3 +// | trace B dies +// | generates failure #4 +// | notifies n3 +// -------------------------------|-------------------------------- +// generates failure #5 | finishes +// trace A dies | +// generates failure #6 | +// -------------------------------|-------------------------------- +// waits for thread B to finish | + +struct CheckPoints { + Notification n1; + Notification n2; + Notification n3; +}; + +static void ThreadWithScopedTrace(CheckPoints* check_points) { + { + SCOPED_TRACE("Trace B"); + ADD_FAILURE() + << "Expected failure #1 (in thread B, only trace B alive)."; + check_points->n1.Notify(); + check_points->n2.WaitForNotification(); + + ADD_FAILURE() + << "Expected failure #3 (in thread B, trace A & B both alive)."; + } // Trace B dies here. + ADD_FAILURE() + << "Expected failure #4 (in thread B, only trace A alive)."; + check_points->n3.Notify(); +} + +TEST(SCOPED_TRACETest, WorksConcurrently) { + printf("(expecting 6 failures)\n"); + + CheckPoints check_points; + ThreadWithParam thread(&ThreadWithScopedTrace, + &check_points, + NULL); + check_points.n1.WaitForNotification(); + + { + SCOPED_TRACE("Trace A"); + ADD_FAILURE() + << "Expected failure #2 (in thread A, trace A & B both alive)."; + check_points.n2.Notify(); + check_points.n3.WaitForNotification(); + + ADD_FAILURE() + << "Expected failure #5 (in thread A, only trace A alive)."; + } // Trace A dies here. + ADD_FAILURE() + << "Expected failure #6 (in thread A, no trace alive)."; + thread.Join(); +} +#endif // GTEST_IS_THREADSAFE + +TEST(DisabledTestsWarningTest, + DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { + // This test body is intentionally empty. Its sole purpose is for + // verifying that the --gtest_also_run_disabled_tests flag + // suppresses the "YOU HAVE 12 DISABLED TESTS" warning at the end of + // the test output. +} + +// Tests using assertions outside of TEST and TEST_F. +// +// This function creates two failures intentionally. +void AdHocTest() { + printf("The non-test part of the code is expected to have 2 failures.\n\n"); + EXPECT_TRUE(false); + EXPECT_EQ(2, 3); +} + +// Runs all TESTs, all TEST_Fs, and the ad hoc test. +int RunAllTests() { + AdHocTest(); + return RUN_ALL_TESTS(); +} + +// Tests non-fatal failures in the fixture constructor. +class NonFatalFailureInFixtureConstructorTest : public testing::Test { + protected: + NonFatalFailureInFixtureConstructorTest() { + printf("(expecting 5 failures)\n"); + ADD_FAILURE() << "Expected failure #1, in the test fixture c'tor."; + } + + ~NonFatalFailureInFixtureConstructorTest() { + ADD_FAILURE() << "Expected failure #5, in the test fixture d'tor."; + } + + virtual void SetUp() { + ADD_FAILURE() << "Expected failure #2, in SetUp()."; + } + + virtual void TearDown() { + ADD_FAILURE() << "Expected failure #4, in TearDown."; + } +}; + +TEST_F(NonFatalFailureInFixtureConstructorTest, FailureInConstructor) { + ADD_FAILURE() << "Expected failure #3, in the test body."; +} + +// Tests fatal failures in the fixture constructor. +class FatalFailureInFixtureConstructorTest : public testing::Test { + protected: + FatalFailureInFixtureConstructorTest() { + printf("(expecting 2 failures)\n"); + Init(); + } + + ~FatalFailureInFixtureConstructorTest() { + ADD_FAILURE() << "Expected failure #2, in the test fixture d'tor."; + } + + virtual void SetUp() { + ADD_FAILURE() << "UNEXPECTED failure in SetUp(). " + << "We should never get here, as the test fixture c'tor " + << "had a fatal failure."; + } + + virtual void TearDown() { + ADD_FAILURE() << "UNEXPECTED failure in TearDown(). " + << "We should never get here, as the test fixture c'tor " + << "had a fatal failure."; + } + private: + void Init() { + FAIL() << "Expected failure #1, in the test fixture c'tor."; + } +}; + +TEST_F(FatalFailureInFixtureConstructorTest, FailureInConstructor) { + ADD_FAILURE() << "UNEXPECTED failure in the test body. " + << "We should never get here, as the test fixture c'tor " + << "had a fatal failure."; +} + +// Tests non-fatal failures in SetUp(). +class NonFatalFailureInSetUpTest : public testing::Test { + protected: + virtual ~NonFatalFailureInSetUpTest() { + Deinit(); + } + + virtual void SetUp() { + printf("(expecting 4 failures)\n"); + ADD_FAILURE() << "Expected failure #1, in SetUp()."; + } + + virtual void TearDown() { + FAIL() << "Expected failure #3, in TearDown()."; + } + private: + void Deinit() { + FAIL() << "Expected failure #4, in the test fixture d'tor."; + } +}; + +TEST_F(NonFatalFailureInSetUpTest, FailureInSetUp) { + FAIL() << "Expected failure #2, in the test function."; +} + +// Tests fatal failures in SetUp(). +class FatalFailureInSetUpTest : public testing::Test { + protected: + virtual ~FatalFailureInSetUpTest() { + Deinit(); + } + + virtual void SetUp() { + printf("(expecting 3 failures)\n"); + FAIL() << "Expected failure #1, in SetUp()."; + } + + virtual void TearDown() { + FAIL() << "Expected failure #2, in TearDown()."; + } + private: + void Deinit() { + FAIL() << "Expected failure #3, in the test fixture d'tor."; + } +}; + +TEST_F(FatalFailureInSetUpTest, FailureInSetUp) { + FAIL() << "UNEXPECTED failure in the test function. " + << "We should never get here, as SetUp() failed."; +} + +TEST(AddFailureAtTest, MessageContainsSpecifiedFileAndLineNumber) { + ADD_FAILURE_AT("foo.cc", 42) << "Expected failure in foo.cc"; +} + +#if GTEST_IS_THREADSAFE + +// A unary function that may die. +void DieIf(bool should_die) { + GTEST_CHECK_(!should_die) << " - death inside DieIf()."; +} + +// Tests running death tests in a multi-threaded context. + +// Used for coordination between the main and the spawn thread. +struct SpawnThreadNotifications { + SpawnThreadNotifications() {} + + Notification spawn_thread_started; + Notification spawn_thread_ok_to_terminate; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications); +}; + +// The function to be executed in the thread spawn by the +// MultipleThreads test (below). +static void ThreadRoutine(SpawnThreadNotifications* notifications) { + // Signals the main thread that this thread has started. + notifications->spawn_thread_started.Notify(); + + // Waits for permission to finish from the main thread. + notifications->spawn_thread_ok_to_terminate.WaitForNotification(); +} + +// This is a death-test test, but it's not named with a DeathTest +// suffix. It starts threads which might interfere with later +// death tests, so it must run after all other death tests. +class DeathTestAndMultiThreadsTest : public testing::Test { + protected: + // Starts a thread and waits for it to begin. + virtual void SetUp() { + thread_.reset(new ThreadWithParam( + &ThreadRoutine, ¬ifications_, NULL)); + notifications_.spawn_thread_started.WaitForNotification(); + } + // Tells the thread to finish, and reaps it. + // Depending on the version of the thread library in use, + // a manager thread might still be left running that will interfere + // with later death tests. This is unfortunate, but this class + // cleans up after itself as best it can. + virtual void TearDown() { + notifications_.spawn_thread_ok_to_terminate.Notify(); + } + + private: + SpawnThreadNotifications notifications_; + scoped_ptr > thread_; +}; + +#endif // GTEST_IS_THREADSAFE + +// The MixedUpTestCaseTest test case verifies that Google Test will fail a +// test if it uses a different fixture class than what other tests in +// the same test case use. It deliberately contains two fixture +// classes with the same name but defined in different namespaces. + +// The MixedUpTestCaseWithSameTestNameTest test case verifies that +// when the user defines two tests with the same test case name AND +// same test name (but in different namespaces), the second test will +// fail. + +namespace foo { + +class MixedUpTestCaseTest : public testing::Test { +}; + +TEST_F(MixedUpTestCaseTest, FirstTestFromNamespaceFoo) {} +TEST_F(MixedUpTestCaseTest, SecondTestFromNamespaceFoo) {} + +class MixedUpTestCaseWithSameTestNameTest : public testing::Test { +}; + +TEST_F(MixedUpTestCaseWithSameTestNameTest, + TheSecondTestWithThisNameShouldFail) {} + +} // namespace foo + +namespace bar { + +class MixedUpTestCaseTest : public testing::Test { +}; + +// The following two tests are expected to fail. We rely on the +// golden file to check that Google Test generates the right error message. +TEST_F(MixedUpTestCaseTest, ThisShouldFail) {} +TEST_F(MixedUpTestCaseTest, ThisShouldFailToo) {} + +class MixedUpTestCaseWithSameTestNameTest : public testing::Test { +}; + +// Expected to fail. We rely on the golden file to check that Google Test +// generates the right error message. +TEST_F(MixedUpTestCaseWithSameTestNameTest, + TheSecondTestWithThisNameShouldFail) {} + +} // namespace bar + +// The following two test cases verify that Google Test catches the user +// error of mixing TEST and TEST_F in the same test case. The first +// test case checks the scenario where TEST_F appears before TEST, and +// the second one checks where TEST appears before TEST_F. + +class TEST_F_before_TEST_in_same_test_case : public testing::Test { +}; + +TEST_F(TEST_F_before_TEST_in_same_test_case, DefinedUsingTEST_F) {} + +// Expected to fail. We rely on the golden file to check that Google Test +// generates the right error message. +TEST(TEST_F_before_TEST_in_same_test_case, DefinedUsingTESTAndShouldFail) {} + +class TEST_before_TEST_F_in_same_test_case : public testing::Test { +}; + +TEST(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST) {} + +// Expected to fail. We rely on the golden file to check that Google Test +// generates the right error message. +TEST_F(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST_FAndShouldFail) { +} + +// Used for testing EXPECT_NONFATAL_FAILURE() and EXPECT_FATAL_FAILURE(). +int global_integer = 0; + +// Tests that EXPECT_NONFATAL_FAILURE() can reference global variables. +TEST(ExpectNonfatalFailureTest, CanReferenceGlobalVariables) { + global_integer = 0; + EXPECT_NONFATAL_FAILURE({ + EXPECT_EQ(1, global_integer) << "Expected non-fatal failure."; + }, "Expected non-fatal failure."); +} + +// Tests that EXPECT_NONFATAL_FAILURE() can reference local variables +// (static or not). +TEST(ExpectNonfatalFailureTest, CanReferenceLocalVariables) { + int m = 0; + static int n; + n = 1; + EXPECT_NONFATAL_FAILURE({ + EXPECT_EQ(m, n) << "Expected non-fatal failure."; + }, "Expected non-fatal failure."); +} + +// Tests that EXPECT_NONFATAL_FAILURE() succeeds when there is exactly +// one non-fatal failure and no fatal failure. +TEST(ExpectNonfatalFailureTest, SucceedsWhenThereIsOneNonfatalFailure) { + EXPECT_NONFATAL_FAILURE({ + ADD_FAILURE() << "Expected non-fatal failure."; + }, "Expected non-fatal failure."); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when there is no +// non-fatal failure. +TEST(ExpectNonfatalFailureTest, FailsWhenThereIsNoNonfatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + }, ""); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when there are two +// non-fatal failures. +TEST(ExpectNonfatalFailureTest, FailsWhenThereAreTwoNonfatalFailures) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + ADD_FAILURE() << "Expected non-fatal failure 1."; + ADD_FAILURE() << "Expected non-fatal failure 2."; + }, ""); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when there is one fatal +// failure. +TEST(ExpectNonfatalFailureTest, FailsWhenThereIsOneFatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + FAIL() << "Expected fatal failure."; + }, ""); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being +// tested returns. +TEST(ExpectNonfatalFailureTest, FailsWhenStatementReturns) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + return; + }, ""); +} + +#if GTEST_HAS_EXCEPTIONS + +// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being +// tested throws. +TEST(ExpectNonfatalFailureTest, FailsWhenStatementThrows) { + printf("(expecting a failure)\n"); + try { + EXPECT_NONFATAL_FAILURE({ + throw 0; + }, ""); + } catch(int) { // NOLINT + } +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests that EXPECT_FATAL_FAILURE() can reference global variables. +TEST(ExpectFatalFailureTest, CanReferenceGlobalVariables) { + global_integer = 0; + EXPECT_FATAL_FAILURE({ + ASSERT_EQ(1, global_integer) << "Expected fatal failure."; + }, "Expected fatal failure."); +} + +// Tests that EXPECT_FATAL_FAILURE() can reference local static +// variables. +TEST(ExpectFatalFailureTest, CanReferenceLocalStaticVariables) { + static int n; + n = 1; + EXPECT_FATAL_FAILURE({ + ASSERT_EQ(0, n) << "Expected fatal failure."; + }, "Expected fatal failure."); +} + +// Tests that EXPECT_FATAL_FAILURE() succeeds when there is exactly +// one fatal failure and no non-fatal failure. +TEST(ExpectFatalFailureTest, SucceedsWhenThereIsOneFatalFailure) { + EXPECT_FATAL_FAILURE({ + FAIL() << "Expected fatal failure."; + }, "Expected fatal failure."); +} + +// Tests that EXPECT_FATAL_FAILURE() fails when there is no fatal +// failure. +TEST(ExpectFatalFailureTest, FailsWhenThereIsNoFatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + }, ""); +} + +// A helper for generating a fatal failure. +void FatalFailure() { + FAIL() << "Expected fatal failure."; +} + +// Tests that EXPECT_FATAL_FAILURE() fails when there are two +// fatal failures. +TEST(ExpectFatalFailureTest, FailsWhenThereAreTwoFatalFailures) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + FatalFailure(); + FatalFailure(); + }, ""); +} + +// Tests that EXPECT_FATAL_FAILURE() fails when there is one non-fatal +// failure. +TEST(ExpectFatalFailureTest, FailsWhenThereIsOneNonfatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + ADD_FAILURE() << "Expected non-fatal failure."; + }, ""); +} + +// Tests that EXPECT_FATAL_FAILURE() fails when the statement being +// tested returns. +TEST(ExpectFatalFailureTest, FailsWhenStatementReturns) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + return; + }, ""); +} + +#if GTEST_HAS_EXCEPTIONS + +// Tests that EXPECT_FATAL_FAILURE() fails when the statement being +// tested throws. +TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) { + printf("(expecting a failure)\n"); + try { + EXPECT_FATAL_FAILURE({ + throw 0; + }, ""); + } catch(int) { // NOLINT + } +} + +#endif // GTEST_HAS_EXCEPTIONS + +// This #ifdef block tests the output of typed tests. +#if GTEST_HAS_TYPED_TEST + +template +class TypedTest : public testing::Test { +}; + +TYPED_TEST_CASE(TypedTest, testing::Types); + +TYPED_TEST(TypedTest, Success) { + EXPECT_EQ(0, TypeParam()); +} + +TYPED_TEST(TypedTest, Failure) { + EXPECT_EQ(1, TypeParam()) << "Expected failure"; +} + +#endif // GTEST_HAS_TYPED_TEST + +// This #ifdef block tests the output of type-parameterized tests. +#if GTEST_HAS_TYPED_TEST_P + +template +class TypedTestP : public testing::Test { +}; + +TYPED_TEST_CASE_P(TypedTestP); + +TYPED_TEST_P(TypedTestP, Success) { + EXPECT_EQ(0U, TypeParam()); +} + +TYPED_TEST_P(TypedTestP, Failure) { + EXPECT_EQ(1U, TypeParam()) << "Expected failure"; +} + +REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure); + +typedef testing::Types UnsignedTypes; +INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes); + +#endif // GTEST_HAS_TYPED_TEST_P + +#if GTEST_HAS_DEATH_TEST + +// We rely on the golden file to verify that tests whose test case +// name ends with DeathTest are run first. + +TEST(ADeathTest, ShouldRunFirst) { +} + +# if GTEST_HAS_TYPED_TEST + +// We rely on the golden file to verify that typed tests whose test +// case name ends with DeathTest are run first. + +template +class ATypedDeathTest : public testing::Test { +}; + +typedef testing::Types NumericTypes; +TYPED_TEST_CASE(ATypedDeathTest, NumericTypes); + +TYPED_TEST(ATypedDeathTest, ShouldRunFirst) { +} + +# endif // GTEST_HAS_TYPED_TEST + +# if GTEST_HAS_TYPED_TEST_P + + +// We rely on the golden file to verify that type-parameterized tests +// whose test case name ends with DeathTest are run first. + +template +class ATypeParamDeathTest : public testing::Test { +}; + +TYPED_TEST_CASE_P(ATypeParamDeathTest); + +TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst) { +} + +REGISTER_TYPED_TEST_CASE_P(ATypeParamDeathTest, ShouldRunFirst); + +INSTANTIATE_TYPED_TEST_CASE_P(My, ATypeParamDeathTest, NumericTypes); + +# endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_HAS_DEATH_TEST + +// Tests various failure conditions of +// EXPECT_{,NON}FATAL_FAILURE{,_ON_ALL_THREADS}. +class ExpectFailureTest : public testing::Test { + public: // Must be public and not protected due to a bug in g++ 3.4.2. + enum FailureMode { + FATAL_FAILURE, + NONFATAL_FAILURE + }; + static void AddFailure(FailureMode failure) { + if (failure == FATAL_FAILURE) { + FAIL() << "Expected fatal failure."; + } else { + ADD_FAILURE() << "Expected non-fatal failure."; + } + } +}; + +TEST_F(ExpectFailureTest, ExpectFatalFailure) { + // Expected fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE(SUCCEED(), "Expected fatal failure."); + // Expected fatal failure, but got a non-fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Expected non-fatal " + "failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE(AddFailure(FATAL_FAILURE), "Some other fatal failure " + "expected."); +} + +TEST_F(ExpectFailureTest, ExpectNonFatalFailure) { + // Expected non-fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE(SUCCEED(), "Expected non-fatal failure."); + // Expected non-fatal failure, but got a fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE(AddFailure(FATAL_FAILURE), "Expected fatal failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Some other non-fatal " + "failure."); +} + +#if GTEST_IS_THREADSAFE + +class ExpectFailureWithThreadsTest : public ExpectFailureTest { + protected: + static void AddFailureInOtherThread(FailureMode failure) { + ThreadWithParam thread(&AddFailure, failure, NULL); + thread.Join(); + } +}; + +TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailure) { + // We only intercept the current thread. + printf("(expecting 2 failures)\n"); + EXPECT_FATAL_FAILURE(AddFailureInOtherThread(FATAL_FAILURE), + "Expected fatal failure."); +} + +TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailure) { + // We only intercept the current thread. + printf("(expecting 2 failures)\n"); + EXPECT_NONFATAL_FAILURE(AddFailureInOtherThread(NONFATAL_FAILURE), + "Expected non-fatal failure."); +} + +typedef ExpectFailureWithThreadsTest ScopedFakeTestPartResultReporterTest; + +// Tests that the ScopedFakeTestPartResultReporter only catches failures from +// the current thread if it is instantiated with INTERCEPT_ONLY_CURRENT_THREAD. +TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) { + printf("(expecting 2 failures)\n"); + TestPartResultArray results; + { + ScopedFakeTestPartResultReporter reporter( + ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, + &results); + AddFailureInOtherThread(FATAL_FAILURE); + AddFailureInOtherThread(NONFATAL_FAILURE); + } + // The two failures should not have been intercepted. + EXPECT_EQ(0, results.size()) << "This shouldn't fail."; +} + +#endif // GTEST_IS_THREADSAFE + +TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) { + // Expected fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected fatal failure."); + // Expected fatal failure, but got a non-fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), + "Expected non-fatal failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), + "Some other fatal failure expected."); +} + +TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads) { + // Expected non-fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected non-fatal " + "failure."); + // Expected non-fatal failure, but got a fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), + "Expected fatal failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), + "Some other non-fatal failure."); +} + + +// Two test environments for testing testing::AddGlobalTestEnvironment(). + +class FooEnvironment : public testing::Environment { + public: + virtual void SetUp() { + printf("%s", "FooEnvironment::SetUp() called.\n"); + } + + virtual void TearDown() { + printf("%s", "FooEnvironment::TearDown() called.\n"); + FAIL() << "Expected fatal failure."; + } +}; + +class BarEnvironment : public testing::Environment { + public: + virtual void SetUp() { + printf("%s", "BarEnvironment::SetUp() called.\n"); + } + + virtual void TearDown() { + printf("%s", "BarEnvironment::TearDown() called.\n"); + ADD_FAILURE() << "Expected non-fatal failure."; + } +}; + +bool GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = false; + +// The main function. +// +// The idea is to use Google Test to run all the tests we have defined (some +// of them are intended to fail), and then compare the test results +// with the "golden" file. +int main(int argc, char **argv) { + testing::GTEST_FLAG(print_time) = false; + + // We just run the tests, knowing some of them are intended to fail. + // We will use a separate Python script to compare the output of + // this program with the golden file. + + // It's hard to test InitGoogleTest() directly, as it has many + // global side effects. The following line serves as a sanity test + // for it. + testing::InitGoogleTest(&argc, argv); + if (argc >= 2 && + String(argv[1]) == "--gtest_internal_skip_environment_and_ad_hoc_tests") + GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = true; + +#if GTEST_HAS_DEATH_TEST + if (testing::internal::GTEST_FLAG(internal_run_death_test) != "") { + // Skip the usual output capturing if we're running as the child + // process of an threadsafe-style death test. +# if GTEST_OS_WINDOWS + posix::FReopen("nul:", "w", stdout); +# else + posix::FReopen("/dev/null", "w", stdout); +# endif // GTEST_OS_WINDOWS + return RUN_ALL_TESTS(); + } +#endif // GTEST_HAS_DEATH_TEST + + if (GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests)) + return RUN_ALL_TESTS(); + + // Registers two global test environments. + // The golden file verifies that they are set up in the order they + // are registered, and torn down in the reverse order. + testing::AddGlobalTestEnvironment(new FooEnvironment); + testing::AddGlobalTestEnvironment(new BarEnvironment); + + return RunAllTests(); +} diff --git a/third_party/googletest/src/test/gtest_output_test_golden_lin.txt b/third_party/googletest/src/test/gtest_output_test_golden_lin.txt new file mode 100644 index 0000000..a1d342d --- /dev/null +++ b/third_party/googletest/src/test/gtest_output_test_golden_lin.txt @@ -0,0 +1,711 @@ +The non-test part of the code is expected to have 2 failures. + +gtest_output_test_.cc:#: Failure +Value of: false + Actual: false +Expected: true +gtest_output_test_.cc:#: Failure +Value of: 3 +Expected: 2 +[==========] Running 62 tests from 27 test cases. +[----------] Global test environment set-up. +FooEnvironment::SetUp() called. +BarEnvironment::SetUp() called. +[----------] 1 test from ADeathTest +[ RUN ] ADeathTest.ShouldRunFirst +[ OK ] ADeathTest.ShouldRunFirst +[----------] 1 test from ATypedDeathTest/0, where TypeParam = int +[ RUN ] ATypedDeathTest/0.ShouldRunFirst +[ OK ] ATypedDeathTest/0.ShouldRunFirst +[----------] 1 test from ATypedDeathTest/1, where TypeParam = double +[ RUN ] ATypedDeathTest/1.ShouldRunFirst +[ OK ] ATypedDeathTest/1.ShouldRunFirst +[----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int +[ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst +[ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst +[----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double +[ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst +[ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst +[----------] 2 tests from PassingTest +[ RUN ] PassingTest.PassingTest1 +[ OK ] PassingTest.PassingTest1 +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 +[----------] 3 tests from FatalFailureTest +[ RUN ] FatalFailureTest.FatalFailureInSubroutine +(expecting a failure that x should be 1) +gtest_output_test_.cc:#: Failure +Value of: x + Actual: 2 +Expected: 1 +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine +[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine +(expecting a failure that x should be 1) +gtest_output_test_.cc:#: Failure +Value of: x + Actual: 2 +Expected: 1 +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine +[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine +(expecting a failure on false) +gtest_output_test_.cc:#: Failure +Value of: false + Actual: false +Expected: true +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine +[----------] 1 test from LoggingTest +[ RUN ] LoggingTest.InterleavingLoggingAndAssertions +(expecting 2 failures on (3) >= (a[i])) +i == 0 +i == 1 +gtest_output_test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 9 +i == 2 +i == 3 +gtest_output_test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 6 +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions +[----------] 6 tests from SCOPED_TRACETest +[ RUN ] SCOPED_TRACETest.ObeysScopes +(expected to fail) +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and shouldn't have a trace. +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and should have a trace. +Google Test trace: +gtest_output_test_.cc:#: Expected trace +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and shouldn't have a trace. +[ FAILED ] SCOPED_TRACETest.ObeysScopes +[ RUN ] SCOPED_TRACETest.WorksInLoop +(expected to fail) +gtest_output_test_.cc:#: Failure +Value of: n + Actual: 1 +Expected: 2 +Google Test trace: +gtest_output_test_.cc:#: i = 1 +gtest_output_test_.cc:#: Failure +Value of: n + Actual: 2 +Expected: 1 +Google Test trace: +gtest_output_test_.cc:#: i = 2 +[ FAILED ] SCOPED_TRACETest.WorksInLoop +[ RUN ] SCOPED_TRACETest.WorksInSubroutine +(expected to fail) +gtest_output_test_.cc:#: Failure +Value of: n + Actual: 1 +Expected: 2 +Google Test trace: +gtest_output_test_.cc:#: n = 1 +gtest_output_test_.cc:#: Failure +Value of: n + Actual: 2 +Expected: 1 +Google Test trace: +gtest_output_test_.cc:#: n = 2 +[ FAILED ] SCOPED_TRACETest.WorksInSubroutine +[ RUN ] SCOPED_TRACETest.CanBeNested +(expected to fail) +gtest_output_test_.cc:#: Failure +Value of: n + Actual: 2 +Expected: 1 +Google Test trace: +gtest_output_test_.cc:#: n = 2 +gtest_output_test_.cc:#: +[ FAILED ] SCOPED_TRACETest.CanBeNested +[ RUN ] SCOPED_TRACETest.CanBeRepeated +(expected to fail) +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A. +Google Test trace: +gtest_output_test_.cc:#: A +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A and B. +Google Test trace: +gtest_output_test_.cc:#: B +gtest_output_test_.cc:#: A +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A, B, and C. +Google Test trace: +gtest_output_test_.cc:#: C +gtest_output_test_.cc:#: B +gtest_output_test_.cc:#: A +gtest_output_test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A, B, and D. +Google Test trace: +gtest_output_test_.cc:#: D +gtest_output_test_.cc:#: B +gtest_output_test_.cc:#: A +[ FAILED ] SCOPED_TRACETest.CanBeRepeated +[ RUN ] SCOPED_TRACETest.WorksConcurrently +(expecting 6 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected failure #1 (in thread B, only trace B alive). +Google Test trace: +gtest_output_test_.cc:#: Trace B +gtest_output_test_.cc:#: Failure +Failed +Expected failure #2 (in thread A, trace A & B both alive). +Google Test trace: +gtest_output_test_.cc:#: Trace A +gtest_output_test_.cc:#: Failure +Failed +Expected failure #3 (in thread B, trace A & B both alive). +Google Test trace: +gtest_output_test_.cc:#: Trace B +gtest_output_test_.cc:#: Failure +Failed +Expected failure #4 (in thread B, only trace A alive). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #5 (in thread A, only trace A alive). +Google Test trace: +gtest_output_test_.cc:#: Trace A +gtest_output_test_.cc:#: Failure +Failed +Expected failure #6 (in thread A, no trace alive). +[ FAILED ] SCOPED_TRACETest.WorksConcurrently +[----------] 1 test from NonFatalFailureInFixtureConstructorTest +[ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor +(expecting 5 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected failure #1, in the test fixture c'tor. +gtest_output_test_.cc:#: Failure +Failed +Expected failure #2, in SetUp(). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #3, in the test body. +gtest_output_test_.cc:#: Failure +Failed +Expected failure #4, in TearDown. +gtest_output_test_.cc:#: Failure +Failed +Expected failure #5, in the test fixture d'tor. +[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor +[----------] 1 test from FatalFailureInFixtureConstructorTest +[ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected failure #1, in the test fixture c'tor. +gtest_output_test_.cc:#: Failure +Failed +Expected failure #2, in the test fixture d'tor. +[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor +[----------] 1 test from NonFatalFailureInSetUpTest +[ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp +(expecting 4 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected failure #1, in SetUp(). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #2, in the test function. +gtest_output_test_.cc:#: Failure +Failed +Expected failure #3, in TearDown(). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #4, in the test fixture d'tor. +[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp +[----------] 1 test from FatalFailureInSetUpTest +[ RUN ] FatalFailureInSetUpTest.FailureInSetUp +(expecting 3 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected failure #1, in SetUp(). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #2, in TearDown(). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #3, in the test fixture d'tor. +[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp +[----------] 1 test from AddFailureAtTest +[ RUN ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber +foo.cc:42: Failure +Failed +Expected failure in foo.cc +[ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber +[----------] 4 tests from MixedUpTestCaseTest +[ RUN ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo +[ OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo +[ RUN ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo +[ OK ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo +[ RUN ] MixedUpTestCaseTest.ThisShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class. However, in test case MixedUpTestCaseTest, +you defined test FirstTestFromNamespaceFoo and test ThisShouldFail +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test cases. +[ FAILED ] MixedUpTestCaseTest.ThisShouldFail +[ RUN ] MixedUpTestCaseTest.ThisShouldFailToo +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class. However, in test case MixedUpTestCaseTest, +you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test cases. +[ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo +[----------] 2 tests from MixedUpTestCaseWithSameTestNameTest +[ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[ OK ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class. However, in test case MixedUpTestCaseWithSameTestNameTest, +you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test cases. +[ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[----------] 2 tests from TEST_F_before_TEST_in_same_test_case +[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F +[ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F +[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class, so mixing TEST_F and TEST in the same test case is +illegal. In test case TEST_F_before_TEST_in_same_test_case, +test DefinedUsingTEST_F is defined using TEST_F but +test DefinedUsingTESTAndShouldFail is defined using TEST. You probably +want to change the TEST to TEST_F or move it to another test +case. +[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail +[----------] 2 tests from TEST_before_TEST_F_in_same_test_case +[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST +[ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST +[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class, so mixing TEST_F and TEST in the same test case is +illegal. In test case TEST_before_TEST_F_in_same_test_case, +test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but +test DefinedUsingTEST is defined using TEST. You probably +want to change the TEST to TEST_F or move it to another test +case. +[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail +[----------] 8 tests from ExpectNonfatalFailureTest +[ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables +[ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables +[ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables +[ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables +[ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure +[ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure +[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure +[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 2 failures +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure 1. + +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure 2. + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures +[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure +[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns +[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows +[----------] 8 tests from ExpectFatalFailureTest +[ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables +[ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables +[ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables +[ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables +[ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure +[ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure +[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure +[ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 2 failures +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures +[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. + +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure +[ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows +[----------] 2 tests from TypedTest/0, where TypeParam = int +[ RUN ] TypedTest/0.Success +[ OK ] TypedTest/0.Success +[ RUN ] TypedTest/0.Failure +gtest_output_test_.cc:#: Failure +Value of: TypeParam() + Actual: 0 +Expected: 1 +Expected failure +[ FAILED ] TypedTest/0.Failure, where TypeParam = int +[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char +[ RUN ] Unsigned/TypedTestP/0.Success +[ OK ] Unsigned/TypedTestP/0.Success +[ RUN ] Unsigned/TypedTestP/0.Failure +gtest_output_test_.cc:#: Failure +Value of: TypeParam() + Actual: '\0' +Expected: 1U +Which is: 1 +Expected failure +[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char +[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int +[ RUN ] Unsigned/TypedTestP/1.Success +[ OK ] Unsigned/TypedTestP/1.Success +[ RUN ] Unsigned/TypedTestP/1.Failure +gtest_output_test_.cc:#: Failure +Value of: TypeParam() + Actual: 0 +Expected: 1U +Which is: 1 +Expected failure +[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int +[----------] 4 tests from ExpectFailureTest +[ RUN ] ExpectFailureTest.ExpectFatalFailure +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +gtest_output_test_.cc:#: Success: +Succeeded + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure containing "Some other fatal failure expected." + Actual: +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +[ FAILED ] ExpectFailureTest.ExpectFatalFailure +[ RUN ] ExpectFailureTest.ExpectNonFatalFailure +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +gtest_output_test_.cc:#: Success: +Succeeded + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure containing "Some other non-fatal failure." + Actual: +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. + +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure +[ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +gtest_output_test_.cc:#: Success: +Succeeded + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure containing "Some other fatal failure expected." + Actual: +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads +[ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +gtest_output_test_.cc:#: Success: +Succeeded + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +gtest_output_test_.cc:#: Fatal failure: +Failed +Expected fatal failure. + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure containing "Some other non-fatal failure." + Actual: +gtest_output_test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. + +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +[----------] 2 tests from ExpectFailureWithThreadsTest +[ RUN ] ExpectFailureWithThreadsTest.ExpectFatalFailure +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected fatal failure. +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure +[ RUN ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected non-fatal failure. +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +[----------] 1 test from ScopedFakeTestPartResultReporterTest +[ RUN ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected fatal failure. +gtest_output_test_.cc:#: Failure +Failed +Expected non-fatal failure. +[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +[----------] 1 test from PrintingFailingParams/FailingParamTest +[ RUN ] PrintingFailingParams/FailingParamTest.Fails/0 +gtest_output_test_.cc:#: Failure +Value of: GetParam() + Actual: 2 +Expected: 1 +[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 +[----------] Global test environment tear-down +BarEnvironment::TearDown() called. +gtest_output_test_.cc:#: Failure +Failed +Expected non-fatal failure. +FooEnvironment::TearDown() called. +gtest_output_test_.cc:#: Failure +Failed +Expected fatal failure. +[==========] 62 tests from 27 test cases ran. +[ PASSED ] 21 tests. +[ FAILED ] 41 tests, listed below: +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions +[ FAILED ] SCOPED_TRACETest.ObeysScopes +[ FAILED ] SCOPED_TRACETest.WorksInLoop +[ FAILED ] SCOPED_TRACETest.WorksInSubroutine +[ FAILED ] SCOPED_TRACETest.CanBeNested +[ FAILED ] SCOPED_TRACETest.CanBeRepeated +[ FAILED ] SCOPED_TRACETest.WorksConcurrently +[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor +[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor +[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp +[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp +[ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber +[ FAILED ] MixedUpTestCaseTest.ThisShouldFail +[ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo +[ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail +[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows +[ FAILED ] TypedTest/0.Failure, where TypeParam = int +[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char +[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int +[ FAILED ] ExpectFailureTest.ExpectFatalFailure +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure +[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure +[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 + +41 FAILED TESTS + YOU HAVE 1 DISABLED TEST + +Note: Google Test filter = FatalFailureTest.*:LoggingTest.* +[==========] Running 4 tests from 2 test cases. +[----------] Global test environment set-up. +[----------] 3 tests from FatalFailureTest +[ RUN ] FatalFailureTest.FatalFailureInSubroutine +(expecting a failure that x should be 1) +gtest_output_test_.cc:#: Failure +Value of: x + Actual: 2 +Expected: 1 +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms) +[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine +(expecting a failure that x should be 1) +gtest_output_test_.cc:#: Failure +Value of: x + Actual: 2 +Expected: 1 +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms) +[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine +(expecting a failure on false) +gtest_output_test_.cc:#: Failure +Value of: false + Actual: false +Expected: true +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms) +[----------] 3 tests from FatalFailureTest (? ms total) + +[----------] 1 test from LoggingTest +[ RUN ] LoggingTest.InterleavingLoggingAndAssertions +(expecting 2 failures on (3) >= (a[i])) +i == 0 +i == 1 +gtest_output_test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 9 +i == 2 +i == 3 +gtest_output_test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 6 +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms) +[----------] 1 test from LoggingTest (? ms total) + +[----------] Global test environment tear-down +[==========] 4 tests from 2 test cases ran. (? ms total) +[ PASSED ] 0 tests. +[ FAILED ] 4 tests, listed below: +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions + + 4 FAILED TESTS + YOU HAVE 1 DISABLED TEST + +Note: Google Test filter = *DISABLED_* +[==========] Running 1 test from 1 test case. +[----------] Global test environment set-up. +[----------] 1 test from DisabledTestsWarningTest +[ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning +[ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning +[----------] Global test environment tear-down +[==========] 1 test from 1 test case ran. +[ PASSED ] 1 test. +Note: Google Test filter = PassingTest.* +Note: This is test shard 2 of 2. +[==========] Running 1 test from 1 test case. +[----------] Global test environment set-up. +[----------] 1 test from PassingTest +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 +[----------] Global test environment tear-down +[==========] 1 test from 1 test case ran. +[ PASSED ] 1 test. + + YOU HAVE 1 DISABLED TEST + diff --git a/third_party/googletest/src/test/gtest_pred_impl_unittest.cc b/third_party/googletest/src/test/gtest_pred_impl_unittest.cc new file mode 100644 index 0000000..35dc9bc --- /dev/null +++ b/third_party/googletest/src/test/gtest_pred_impl_unittest.cc @@ -0,0 +1,2427 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! + +// Regression test for gtest_pred_impl.h +// +// This file is generated by a script and quite long. If you intend to +// learn how Google Test works by reading its unit tests, read +// gtest_unittest.cc instead. +// +// This is intended as a regression test for the Google Test predicate +// assertions. We compile it as part of the gtest_unittest target +// only to keep the implementation tidy and compact, as it is quite +// involved to set up the stage for testing Google Test using Google +// Test itself. +// +// Currently, gtest_unittest takes ~11 seconds to run in the testing +// daemon. In the future, if it grows too large and needs much more +// time to finish, we should consider separating this file into a +// stand-alone regression test. + +#include + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +// A user-defined data type. +struct Bool { + explicit Bool(int val) : value(val != 0) {} + + bool operator>(int n) const { return value > Bool(n).value; } + + Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } + + bool operator==(const Bool& rhs) const { return value == rhs.value; } + + bool value; +}; + +// Enables Bool to be used in assertions. +std::ostream& operator<<(std::ostream& os, const Bool& x) { + return os << (x.value ? "true" : "false"); +} + +// Sample functions/functors for testing unary predicate assertions. + +// A unary predicate function. +template +bool PredFunction1(T1 v1) { + return v1 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction1Int(int v1) { + return v1 > 0; +} +bool PredFunction1Bool(Bool v1) { + return v1 > 0; +} + +// A unary predicate functor. +struct PredFunctor1 { + template + bool operator()(const T1& v1) { + return v1 > 0; + } +}; + +// A unary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction1(const char* e1, + const T1& v1) { + if (PredFunction1(v1)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 + << " is expected to be positive, but evaluates to " + << v1 << "."; +} + +// A unary predicate-formatter functor. +struct PredFormatFunctor1 { + template + testing::AssertionResult operator()(const char* e1, + const T1& v1) const { + return PredFormatFunction1(e1, v1); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT1. + +class Predicate1Test : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false; + n1_ = 0; + } + + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; + + static int n1_; +}; + +bool Predicate1Test::expected_to_finish_; +bool Predicate1Test::finished_; +int Predicate1Test::n1_; + +typedef Predicate1Test EXPECT_PRED_FORMAT1Test; +typedef Predicate1Test ASSERT_PRED_FORMAT1Test; +typedef Predicate1Test EXPECT_PRED1Test; +typedef Predicate1Test ASSERT_PRED1Test; + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED1(PredFunction1Int, + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED1(PredFunction1Bool, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED1(PredFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED1(PredFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunction1Int, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunction1Bool, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED1(PredFunction1Int, + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED1(PredFunction1Bool, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED1(PredFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED1(PredFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunction1Int, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunction1Bool, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunction1, + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunction1, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunction1, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunction1, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunction1, + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunction1, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunction1, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunction1, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing binary predicate assertions. + +// A binary predicate function. +template +bool PredFunction2(T1 v1, T2 v2) { + return v1 + v2 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction2Int(int v1, int v2) { + return v1 + v2 > 0; +} +bool PredFunction2Bool(Bool v1, Bool v2) { + return v1 + v2 > 0; +} + +// A binary predicate functor. +struct PredFunctor2 { + template + bool operator()(const T1& v1, + const T2& v2) { + return v1 + v2 > 0; + } +}; + +// A binary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction2(const char* e1, + const char* e2, + const T1& v1, + const T2& v2) { + if (PredFunction2(v1, v2)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 + << " is expected to be positive, but evaluates to " + << v1 + v2 << "."; +} + +// A binary predicate-formatter functor. +struct PredFormatFunctor2 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const T1& v1, + const T2& v2) const { + return PredFormatFunction2(e1, e2, v1, v2); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT2. + +class Predicate2Test : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = 0; + } + + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; +}; + +bool Predicate2Test::expected_to_finish_; +bool Predicate2Test::finished_; +int Predicate2Test::n1_; +int Predicate2Test::n2_; + +typedef Predicate2Test EXPECT_PRED_FORMAT2Test; +typedef Predicate2Test ASSERT_PRED_FORMAT2Test; +typedef Predicate2Test EXPECT_PRED2Test; +typedef Predicate2Test ASSERT_PRED2Test; + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED2(PredFunction2Int, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED2(PredFunction2Bool, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED2(PredFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED2(PredFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunction2Int, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunction2Bool, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED2(PredFunction2Int, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED2(PredFunction2Bool, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED2(PredFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED2(PredFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunction2Int, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunction2Bool, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunction2, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunction2, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunction2, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunction2, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunction2, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunction2, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunction2, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunction2, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing ternary predicate assertions. + +// A ternary predicate function. +template +bool PredFunction3(T1 v1, T2 v2, T3 v3) { + return v1 + v2 + v3 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction3Int(int v1, int v2, int v3) { + return v1 + v2 + v3 > 0; +} +bool PredFunction3Bool(Bool v1, Bool v2, Bool v3) { + return v1 + v2 + v3 > 0; +} + +// A ternary predicate functor. +struct PredFunctor3 { + template + bool operator()(const T1& v1, + const T2& v2, + const T3& v3) { + return v1 + v2 + v3 > 0; + } +}; + +// A ternary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction3(const char* e1, + const char* e2, + const char* e3, + const T1& v1, + const T2& v2, + const T3& v3) { + if (PredFunction3(v1, v2, v3)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 << " + " << e3 + << " is expected to be positive, but evaluates to " + << v1 + v2 + v3 << "."; +} + +// A ternary predicate-formatter functor. +struct PredFormatFunctor3 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const char* e3, + const T1& v1, + const T2& v2, + const T3& v3) const { + return PredFormatFunction3(e1, e2, e3, v1, v2, v3); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT3. + +class Predicate3Test : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = n3_ = 0; + } + + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + EXPECT_EQ(1, n3_) << + "The predicate assertion didn't evaluate argument 4 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; + static int n3_; +}; + +bool Predicate3Test::expected_to_finish_; +bool Predicate3Test::finished_; +int Predicate3Test::n1_; +int Predicate3Test::n2_; +int Predicate3Test::n3_; + +typedef Predicate3Test EXPECT_PRED_FORMAT3Test; +typedef Predicate3Test ASSERT_PRED_FORMAT3Test; +typedef Predicate3Test EXPECT_PRED3Test; +typedef Predicate3Test ASSERT_PRED3Test; + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED3(PredFunction3Int, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED3(PredFunction3Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED3(PredFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED3(PredFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunction3Int, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunction3Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED3(PredFunction3Int, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED3(PredFunction3Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED3(PredFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED3(PredFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunction3Int, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunction3Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunction3, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunction3, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunction3, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunction3, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunction3, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunction3, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunction3, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunction3, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing 4-ary predicate assertions. + +// A 4-ary predicate function. +template +bool PredFunction4(T1 v1, T2 v2, T3 v3, T4 v4) { + return v1 + v2 + v3 + v4 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction4Int(int v1, int v2, int v3, int v4) { + return v1 + v2 + v3 + v4 > 0; +} +bool PredFunction4Bool(Bool v1, Bool v2, Bool v3, Bool v4) { + return v1 + v2 + v3 + v4 > 0; +} + +// A 4-ary predicate functor. +struct PredFunctor4 { + template + bool operator()(const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + return v1 + v2 + v3 + v4 > 0; + } +}; + +// A 4-ary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction4(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (PredFunction4(v1, v2, v3, v4)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 << " + " << e3 << " + " << e4 + << " is expected to be positive, but evaluates to " + << v1 + v2 + v3 + v4 << "."; +} + +// A 4-ary predicate-formatter functor. +struct PredFormatFunctor4 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) const { + return PredFormatFunction4(e1, e2, e3, e4, v1, v2, v3, v4); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT4. + +class Predicate4Test : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = n3_ = n4_ = 0; + } + + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + EXPECT_EQ(1, n3_) << + "The predicate assertion didn't evaluate argument 4 " + "exactly once."; + EXPECT_EQ(1, n4_) << + "The predicate assertion didn't evaluate argument 5 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; + static int n3_; + static int n4_; +}; + +bool Predicate4Test::expected_to_finish_; +bool Predicate4Test::finished_; +int Predicate4Test::n1_; +int Predicate4Test::n2_; +int Predicate4Test::n3_; +int Predicate4Test::n4_; + +typedef Predicate4Test EXPECT_PRED_FORMAT4Test; +typedef Predicate4Test ASSERT_PRED_FORMAT4Test; +typedef Predicate4Test EXPECT_PRED4Test; +typedef Predicate4Test ASSERT_PRED4Test; + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED4(PredFunction4Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED4(PredFunction4Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED4(PredFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED4(PredFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunction4Int, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunction4Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED4(PredFunction4Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED4(PredFunction4Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED4(PredFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED4(PredFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunction4Int, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunction4Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunction4, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunction4, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunction4, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunction4, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunction4, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunction4, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunction4, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunction4, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing 5-ary predicate assertions. + +// A 5-ary predicate function. +template +bool PredFunction5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { + return v1 + v2 + v3 + v4 + v5 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction5Int(int v1, int v2, int v3, int v4, int v5) { + return v1 + v2 + v3 + v4 + v5 > 0; +} +bool PredFunction5Bool(Bool v1, Bool v2, Bool v3, Bool v4, Bool v5) { + return v1 + v2 + v3 + v4 + v5 > 0; +} + +// A 5-ary predicate functor. +struct PredFunctor5 { + template + bool operator()(const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + return v1 + v2 + v3 + v4 + v5 > 0; + } +}; + +// A 5-ary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction5(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (PredFunction5(v1, v2, v3, v4, v5)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 + << " is expected to be positive, but evaluates to " + << v1 + v2 + v3 + v4 + v5 << "."; +} + +// A 5-ary predicate-formatter functor. +struct PredFormatFunctor5 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) const { + return PredFormatFunction5(e1, e2, e3, e4, e5, v1, v2, v3, v4, v5); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT5. + +class Predicate5Test : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = n3_ = n4_ = n5_ = 0; + } + + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + EXPECT_EQ(1, n3_) << + "The predicate assertion didn't evaluate argument 4 " + "exactly once."; + EXPECT_EQ(1, n4_) << + "The predicate assertion didn't evaluate argument 5 " + "exactly once."; + EXPECT_EQ(1, n5_) << + "The predicate assertion didn't evaluate argument 6 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; + static int n3_; + static int n4_; + static int n5_; +}; + +bool Predicate5Test::expected_to_finish_; +bool Predicate5Test::finished_; +int Predicate5Test::n1_; +int Predicate5Test::n2_; +int Predicate5Test::n3_; +int Predicate5Test::n4_; +int Predicate5Test::n5_; + +typedef Predicate5Test EXPECT_PRED_FORMAT5Test; +typedef Predicate5Test ASSERT_PRED_FORMAT5Test; +typedef Predicate5Test EXPECT_PRED5Test; +typedef Predicate5Test ASSERT_PRED5Test; + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED5(PredFunction5Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED5(PredFunction5Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED5(PredFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED5(PredFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunction5Int, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunction5Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED5(PredFunction5Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED5(PredFunction5Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED5(PredFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED5(PredFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunction5Int, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunction5Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunction5, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunction5, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunction5, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunction5, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunction5, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunction5, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunction5, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunction5, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} diff --git a/third_party/googletest/src/test/gtest_prod_test.cc b/third_party/googletest/src/test/gtest_prod_test.cc new file mode 100644 index 0000000..060abce --- /dev/null +++ b/third_party/googletest/src/test/gtest_prod_test.cc @@ -0,0 +1,57 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Unit test for include/gtest/gtest_prod.h. + +#include "gtest/gtest.h" +#include "test/production.h" + +// Tests that private members can be accessed from a TEST declared as +// a friend of the class. +TEST(PrivateCodeTest, CanAccessPrivateMembers) { + PrivateCode a; + EXPECT_EQ(0, a.x_); + + a.set_x(1); + EXPECT_EQ(1, a.x_); +} + +typedef testing::Test PrivateCodeFixtureTest; + +// Tests that private members can be accessed from a TEST_F declared +// as a friend of the class. +TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers) { + PrivateCode a; + EXPECT_EQ(0, a.x_); + + a.set_x(2); + EXPECT_EQ(2, a.x_); +} diff --git a/third_party/googletest/src/test/gtest_repeat_test.cc b/third_party/googletest/src/test/gtest_repeat_test.cc new file mode 100644 index 0000000..5223dc0 --- /dev/null +++ b/third_party/googletest/src/test/gtest_repeat_test.cc @@ -0,0 +1,253 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Tests the --gtest_repeat=number flag. + +#include +#include +#include "gtest/gtest.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +GTEST_DECLARE_string_(death_test_style); +GTEST_DECLARE_string_(filter); +GTEST_DECLARE_int32_(repeat); + +} // namespace testing + +using testing::GTEST_FLAG(death_test_style); +using testing::GTEST_FLAG(filter); +using testing::GTEST_FLAG(repeat); + +namespace { + +// We need this when we are testing Google Test itself and therefore +// cannot use Google Test assertions. +#define GTEST_CHECK_INT_EQ_(expected, actual) \ + do {\ + const int expected_val = (expected);\ + const int actual_val = (actual);\ + if (::testing::internal::IsTrue(expected_val != actual_val)) {\ + ::std::cout << "Value of: " #actual "\n"\ + << " Actual: " << actual_val << "\n"\ + << "Expected: " #expected "\n"\ + << "Which is: " << expected_val << "\n";\ + ::testing::internal::posix::Abort();\ + }\ + } while(::testing::internal::AlwaysFalse()) + + +// Used for verifying that global environment set-up and tear-down are +// inside the gtest_repeat loop. + +int g_environment_set_up_count = 0; +int g_environment_tear_down_count = 0; + +class MyEnvironment : public testing::Environment { + public: + MyEnvironment() {} + virtual void SetUp() { g_environment_set_up_count++; } + virtual void TearDown() { g_environment_tear_down_count++; } +}; + +// A test that should fail. + +int g_should_fail_count = 0; + +TEST(FooTest, ShouldFail) { + g_should_fail_count++; + EXPECT_EQ(0, 1) << "Expected failure."; +} + +// A test that should pass. + +int g_should_pass_count = 0; + +TEST(FooTest, ShouldPass) { + g_should_pass_count++; +} + +// A test that contains a thread-safe death test and a fast death +// test. It should pass. + +int g_death_test_count = 0; + +TEST(BarDeathTest, ThreadSafeAndFast) { + g_death_test_count++; + + GTEST_FLAG(death_test_style) = "threadsafe"; + EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); + + GTEST_FLAG(death_test_style) = "fast"; + EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); +} + +#if GTEST_HAS_PARAM_TEST +int g_param_test_count = 0; + +const int kNumberOfParamTests = 10; + +class MyParamTest : public testing::TestWithParam {}; + +TEST_P(MyParamTest, ShouldPass) { + // TODO(vladl@google.com): Make parameter value checking robust + // WRT order of tests. + GTEST_CHECK_INT_EQ_(g_param_test_count % kNumberOfParamTests, GetParam()); + g_param_test_count++; +} +INSTANTIATE_TEST_CASE_P(MyParamSequence, + MyParamTest, + testing::Range(0, kNumberOfParamTests)); +#endif // GTEST_HAS_PARAM_TEST + +// Resets the count for each test. +void ResetCounts() { + g_environment_set_up_count = 0; + g_environment_tear_down_count = 0; + g_should_fail_count = 0; + g_should_pass_count = 0; + g_death_test_count = 0; +#if GTEST_HAS_PARAM_TEST + g_param_test_count = 0; +#endif // GTEST_HAS_PARAM_TEST +} + +// Checks that the count for each test is expected. +void CheckCounts(int expected) { + GTEST_CHECK_INT_EQ_(expected, g_environment_set_up_count); + GTEST_CHECK_INT_EQ_(expected, g_environment_tear_down_count); + GTEST_CHECK_INT_EQ_(expected, g_should_fail_count); + GTEST_CHECK_INT_EQ_(expected, g_should_pass_count); + GTEST_CHECK_INT_EQ_(expected, g_death_test_count); +#if GTEST_HAS_PARAM_TEST + GTEST_CHECK_INT_EQ_(expected * kNumberOfParamTests, g_param_test_count); +#endif // GTEST_HAS_PARAM_TEST +} + +// Tests the behavior of Google Test when --gtest_repeat is not specified. +void TestRepeatUnspecified() { + ResetCounts(); + GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); + CheckCounts(1); +} + +// Tests the behavior of Google Test when --gtest_repeat has the given value. +void TestRepeat(int repeat) { + GTEST_FLAG(repeat) = repeat; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(repeat > 0 ? 1 : 0, RUN_ALL_TESTS()); + CheckCounts(repeat); +} + +// Tests using --gtest_repeat when --gtest_filter specifies an empty +// set of tests. +void TestRepeatWithEmptyFilter(int repeat) { + GTEST_FLAG(repeat) = repeat; + GTEST_FLAG(filter) = "None"; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); + CheckCounts(0); +} + +// Tests using --gtest_repeat when --gtest_filter specifies a set of +// successful tests. +void TestRepeatWithFilterForSuccessfulTests(int repeat) { + GTEST_FLAG(repeat) = repeat; + GTEST_FLAG(filter) = "*-*ShouldFail"; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); + GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); + GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); + GTEST_CHECK_INT_EQ_(0, g_should_fail_count); + GTEST_CHECK_INT_EQ_(repeat, g_should_pass_count); + GTEST_CHECK_INT_EQ_(repeat, g_death_test_count); +#if GTEST_HAS_PARAM_TEST + GTEST_CHECK_INT_EQ_(repeat * kNumberOfParamTests, g_param_test_count); +#endif // GTEST_HAS_PARAM_TEST +} + +// Tests using --gtest_repeat when --gtest_filter specifies a set of +// failed tests. +void TestRepeatWithFilterForFailedTests(int repeat) { + GTEST_FLAG(repeat) = repeat; + GTEST_FLAG(filter) = "*ShouldFail"; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); + GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); + GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); + GTEST_CHECK_INT_EQ_(repeat, g_should_fail_count); + GTEST_CHECK_INT_EQ_(0, g_should_pass_count); + GTEST_CHECK_INT_EQ_(0, g_death_test_count); +#if GTEST_HAS_PARAM_TEST + GTEST_CHECK_INT_EQ_(0, g_param_test_count); +#endif // GTEST_HAS_PARAM_TEST +} + +} // namespace + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + testing::AddGlobalTestEnvironment(new MyEnvironment); + + TestRepeatUnspecified(); + TestRepeat(0); + TestRepeat(1); + TestRepeat(5); + + TestRepeatWithEmptyFilter(2); + TestRepeatWithEmptyFilter(3); + + TestRepeatWithFilterForSuccessfulTests(3); + + TestRepeatWithFilterForFailedTests(4); + + // It would be nice to verify that the tests indeed loop forever + // when GTEST_FLAG(repeat) is negative, but this test will be quite + // complicated to write. Since this flag is for interactive + // debugging only and doesn't affect the normal test result, such a + // test would be an overkill. + + printf("PASS\n"); + return 0; +} diff --git a/third_party/googletest/src/test/gtest_shuffle_test.py b/third_party/googletest/src/test/gtest_shuffle_test.py new file mode 100755 index 0000000..30d0303 --- /dev/null +++ b/third_party/googletest/src/test/gtest_shuffle_test.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python +# +# Copyright 2009 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that test shuffling works.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import gtest_test_utils + +# Command to run the gtest_shuffle_test_ program. +COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_') + +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' + +TEST_FILTER = 'A*.A:A*.B:C*' + +ALL_TESTS = [] +ACTIVE_TESTS = [] +FILTERED_TESTS = [] +SHARDED_TESTS = [] + +SHUFFLED_ALL_TESTS = [] +SHUFFLED_ACTIVE_TESTS = [] +SHUFFLED_FILTERED_TESTS = [] +SHUFFLED_SHARDED_TESTS = [] + + +def AlsoRunDisabledTestsFlag(): + return '--gtest_also_run_disabled_tests' + + +def FilterFlag(test_filter): + return '--gtest_filter=%s' % (test_filter,) + + +def RepeatFlag(n): + return '--gtest_repeat=%s' % (n,) + + +def ShuffleFlag(): + return '--gtest_shuffle' + + +def RandomSeedFlag(n): + return '--gtest_random_seed=%s' % (n,) + + +def RunAndReturnOutput(extra_env, args): + """Runs the test program and returns its output.""" + + environ_copy = os.environ.copy() + environ_copy.update(extra_env) + + return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output + + +def GetTestsForAllIterations(extra_env, args): + """Runs the test program and returns a list of test lists. + + Args: + extra_env: a map from environment variables to their values + args: command line flags to pass to gtest_shuffle_test_ + + Returns: + A list where the i-th element is the list of tests run in the i-th + test iteration. + """ + + test_iterations = [] + for line in RunAndReturnOutput(extra_env, args).split('\n'): + if line.startswith('----'): + tests = [] + test_iterations.append(tests) + elif line.strip(): + tests.append(line.strip()) # 'TestCaseName.TestName' + + return test_iterations + + +def GetTestCases(tests): + """Returns a list of test cases in the given full test names. + + Args: + tests: a list of full test names + + Returns: + A list of test cases from 'tests', in their original order. + Consecutive duplicates are removed. + """ + + test_cases = [] + for test in tests: + test_case = test.split('.')[0] + if not test_case in test_cases: + test_cases.append(test_case) + + return test_cases + + +def CalculateTestLists(): + """Calculates the list of tests run under different flags.""" + + if not ALL_TESTS: + ALL_TESTS.extend( + GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0]) + + if not ACTIVE_TESTS: + ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0]) + + if not FILTERED_TESTS: + FILTERED_TESTS.extend( + GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0]) + + if not SHARDED_TESTS: + SHARDED_TESTS.extend( + GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [])[0]) + + if not SHUFFLED_ALL_TESTS: + SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations( + {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0]) + + if not SHUFFLED_ACTIVE_TESTS: + SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) + + if not SHUFFLED_FILTERED_TESTS: + SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0]) + + if not SHUFFLED_SHARDED_TESTS: + SHUFFLED_SHARDED_TESTS.extend( + GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [ShuffleFlag(), RandomSeedFlag(1)])[0]) + + +class GTestShuffleUnitTest(gtest_test_utils.TestCase): + """Tests test shuffling.""" + + def setUp(self): + CalculateTestLists() + + def testShufflePreservesNumberOfTests(self): + self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS)) + self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS)) + self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS)) + self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS)) + + def testShuffleChangesTestOrder(self): + self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS) + self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS) + self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS, + SHUFFLED_FILTERED_TESTS) + self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS, + SHUFFLED_SHARDED_TESTS) + + def testShuffleChangesTestCaseOrder(self): + self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS), + GetTestCases(SHUFFLED_ALL_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS), + GetTestCases(SHUFFLED_ACTIVE_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS), + GetTestCases(SHUFFLED_FILTERED_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS), + GetTestCases(SHUFFLED_SHARDED_TESTS)) + + def testShuffleDoesNotRepeatTest(self): + for test in SHUFFLED_ALL_TESTS: + self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_ACTIVE_TESTS: + self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_FILTERED_TESTS: + self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_SHARDED_TESTS: + self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test), + '%s appears more than once' % (test,)) + + def testShuffleDoesNotCreateNewTest(self): + for test in SHUFFLED_ALL_TESTS: + self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_ACTIVE_TESTS: + self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_FILTERED_TESTS: + self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_SHARDED_TESTS: + self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,)) + + def testShuffleIncludesAllTests(self): + for test in ALL_TESTS: + self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,)) + for test in ACTIVE_TESTS: + self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,)) + for test in FILTERED_TESTS: + self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,)) + for test in SHARDED_TESTS: + self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,)) + + def testShuffleLeavesDeathTestsAtFront(self): + non_death_test_found = False + for test in SHUFFLED_ACTIVE_TESTS: + if 'DeathTest.' in test: + self.assert_(not non_death_test_found, + '%s appears after a non-death test' % (test,)) + else: + non_death_test_found = True + + def _VerifyTestCasesDoNotInterleave(self, tests): + test_cases = [] + for test in tests: + [test_case, _] = test.split('.') + if test_cases and test_cases[-1] != test_case: + test_cases.append(test_case) + self.assertEqual(1, test_cases.count(test_case), + 'Test case %s is not grouped together in %s' % + (test_case, tests)) + + def testShuffleDoesNotInterleaveTestCases(self): + self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS) + + def testShuffleRestoresOrderAfterEachIteration(self): + # Get the test lists in all 3 iterations, using random seed 1, 2, + # and 3 respectively. Google Test picks a different seed in each + # iteration, and this test depends on the current implementation + # picking successive numbers. This dependency is not ideal, but + # makes the test much easier to write. + [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( + GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) + + # Make sure running the tests with random seed 1 gets the same + # order as in iteration 1 above. + [tests_with_seed1] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1)]) + self.assertEqual(tests_in_iteration1, tests_with_seed1) + + # Make sure running the tests with random seed 2 gets the same + # order as in iteration 2 above. Success means that Google Test + # correctly restores the test order before re-shuffling at the + # beginning of iteration 2. + [tests_with_seed2] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(2)]) + self.assertEqual(tests_in_iteration2, tests_with_seed2) + + # Make sure running the tests with random seed 3 gets the same + # order as in iteration 3 above. Success means that Google Test + # correctly restores the test order before re-shuffling at the + # beginning of iteration 3. + [tests_with_seed3] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(3)]) + self.assertEqual(tests_in_iteration3, tests_with_seed3) + + def testShuffleGeneratesNewOrderInEachIteration(self): + [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( + GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) + + self.assert_(tests_in_iteration1 != tests_in_iteration2, + tests_in_iteration1) + self.assert_(tests_in_iteration1 != tests_in_iteration3, + tests_in_iteration1) + self.assert_(tests_in_iteration2 != tests_in_iteration3, + tests_in_iteration2) + + def testShuffleShardedTestsPreservesPartition(self): + # If we run M tests on N shards, the same M tests should be run in + # total, regardless of the random seeds used by the shards. + [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '0'}, + [ShuffleFlag(), RandomSeedFlag(1)]) + [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [ShuffleFlag(), RandomSeedFlag(20)]) + [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '2'}, + [ShuffleFlag(), RandomSeedFlag(25)]) + sorted_sharded_tests = tests1 + tests2 + tests3 + sorted_sharded_tests.sort() + sorted_active_tests = [] + sorted_active_tests.extend(ACTIVE_TESTS) + sorted_active_tests.sort() + self.assertEqual(sorted_active_tests, sorted_sharded_tests) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_shuffle_test_.cc b/third_party/googletest/src/test/gtest_shuffle_test_.cc new file mode 100644 index 0000000..0752789 --- /dev/null +++ b/third_party/googletest/src/test/gtest_shuffle_test_.cc @@ -0,0 +1,104 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Verifies that test shuffling works. + +#include "gtest/gtest.h" + +namespace { + +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Message; +using ::testing::Test; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::UnitTest; +using ::testing::internal::String; +using ::testing::internal::scoped_ptr; + +// The test methods are empty, as the sole purpose of this program is +// to print the test names before/after shuffling. + +class A : public Test {}; +TEST_F(A, A) {} +TEST_F(A, B) {} + +TEST(ADeathTest, A) {} +TEST(ADeathTest, B) {} +TEST(ADeathTest, C) {} + +TEST(B, A) {} +TEST(B, B) {} +TEST(B, C) {} +TEST(B, DISABLED_D) {} +TEST(B, DISABLED_E) {} + +TEST(BDeathTest, A) {} +TEST(BDeathTest, B) {} + +TEST(C, A) {} +TEST(C, B) {} +TEST(C, C) {} +TEST(C, DISABLED_D) {} + +TEST(CDeathTest, A) {} + +TEST(DISABLED_D, A) {} +TEST(DISABLED_D, DISABLED_B) {} + +// This printer prints the full test names only, starting each test +// iteration with a "----" marker. +class TestNamePrinter : public EmptyTestEventListener { + public: + virtual void OnTestIterationStart(const UnitTest& /* unit_test */, + int /* iteration */) { + printf("----\n"); + } + + virtual void OnTestStart(const TestInfo& test_info) { + printf("%s.%s\n", test_info.test_case_name(), test_info.name()); + } +}; + +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + // Replaces the default printer with TestNamePrinter, which prints + // the test name only. + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + delete listeners.Release(listeners.default_result_printer()); + listeners.Append(new TestNamePrinter); + + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_sole_header_test.cc b/third_party/googletest/src/test/gtest_sole_header_test.cc new file mode 100644 index 0000000..ccd091a --- /dev/null +++ b/third_party/googletest/src/test/gtest_sole_header_test.cc @@ -0,0 +1,57 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// This test verifies that it's possible to use Google Test by including +// the gtest.h header file alone. + +#include "gtest/gtest.h" + +namespace { + +void Subroutine() { + EXPECT_EQ(42, 42); +} + +TEST(NoFatalFailureTest, ExpectNoFatalFailure) { + EXPECT_NO_FATAL_FAILURE(;); + EXPECT_NO_FATAL_FAILURE(SUCCEED()); + EXPECT_NO_FATAL_FAILURE(Subroutine()); + EXPECT_NO_FATAL_FAILURE({ SUCCEED(); }); +} + +TEST(NoFatalFailureTest, AssertNoFatalFailure) { + ASSERT_NO_FATAL_FAILURE(;); + ASSERT_NO_FATAL_FAILURE(SUCCEED()); + ASSERT_NO_FATAL_FAILURE(Subroutine()); + ASSERT_NO_FATAL_FAILURE({ SUCCEED(); }); +} + +} // namespace diff --git a/third_party/googletest/src/test/gtest_stress_test.cc b/third_party/googletest/src/test/gtest_stress_test.cc new file mode 100644 index 0000000..4e7d9bf --- /dev/null +++ b/third_party/googletest/src/test/gtest_stress_test.cc @@ -0,0 +1,257 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Tests that SCOPED_TRACE() and various Google Test assertions can be +// used in a large number of threads concurrently. + +#include "gtest/gtest.h" + +#include +#include + +// We must define this macro in order to #include +// gtest-internal-inl.h. This is how Google Test prevents a user from +// accidentally depending on its internal implementation. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_IS_THREADSAFE + +namespace testing { +namespace { + +using internal::Notification; +using internal::String; +using internal::TestPropertyKeyIs; +using internal::ThreadWithParam; +using internal::scoped_ptr; + +// In order to run tests in this file, for platforms where Google Test is +// thread safe, implement ThreadWithParam. See the description of its API +// in gtest-port.h, where it is defined for already supported platforms. + +// How many threads to create? +const int kThreadCount = 50; + +String IdToKey(int id, const char* suffix) { + Message key; + key << "key_" << id << "_" << suffix; + return key.GetString(); +} + +String IdToString(int id) { + Message id_message; + id_message << id; + return id_message.GetString(); +} + +void ExpectKeyAndValueWereRecordedForId( + const std::vector& properties, + int id, const char* suffix) { + TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str()); + const std::vector::const_iterator property = + std::find_if(properties.begin(), properties.end(), matches_key); + ASSERT_TRUE(property != properties.end()) + << "expecting " << suffix << " value for id " << id; + EXPECT_STREQ(IdToString(id).c_str(), property->value()); +} + +// Calls a large number of Google Test assertions, where exactly one of them +// will fail. +void ManyAsserts(int id) { + GTEST_LOG_(INFO) << "Thread #" << id << " running..."; + + SCOPED_TRACE(Message() << "Thread #" << id); + + for (int i = 0; i < kThreadCount; i++) { + SCOPED_TRACE(Message() << "Iteration #" << i); + + // A bunch of assertions that should succeed. + EXPECT_TRUE(true); + ASSERT_FALSE(false) << "This shouldn't fail."; + EXPECT_STREQ("a", "a"); + ASSERT_LE(5, 6); + EXPECT_EQ(i, i) << "This shouldn't fail."; + + // RecordProperty() should interact safely with other threads as well. + // The shared_key forces property updates. + Test::RecordProperty(IdToKey(id, "string").c_str(), IdToString(id).c_str()); + Test::RecordProperty(IdToKey(id, "int").c_str(), id); + Test::RecordProperty("shared_key", IdToString(id).c_str()); + + // This assertion should fail kThreadCount times per thread. It + // is for testing whether Google Test can handle failed assertions in a + // multi-threaded context. + EXPECT_LT(i, 0) << "This should always fail."; + } +} + +void CheckTestFailureCount(int expected_failures) { + const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); + const TestResult* const result = info->result(); + GTEST_CHECK_(expected_failures == result->total_part_count()) + << "Logged " << result->total_part_count() << " failures " + << " vs. " << expected_failures << " expected"; +} + +// Tests using SCOPED_TRACE() and Google Test assertions in many threads +// concurrently. +TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { + { + scoped_ptr > threads[kThreadCount]; + Notification threads_can_start; + for (int i = 0; i != kThreadCount; i++) + threads[i].reset(new ThreadWithParam(&ManyAsserts, + i, + &threads_can_start)); + + threads_can_start.Notify(); + + // Blocks until all the threads are done. + for (int i = 0; i != kThreadCount; i++) + threads[i]->Join(); + } + + // Ensures that kThreadCount*kThreadCount failures have been reported. + const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); + const TestResult* const result = info->result(); + + std::vector properties; + // We have no access to the TestResult's list of properties but we can + // copy them one by one. + for (int i = 0; i < result->test_property_count(); ++i) + properties.push_back(result->GetTestProperty(i)); + + EXPECT_EQ(kThreadCount * 2 + 1, result->test_property_count()) + << "String and int values recorded on each thread, " + << "as well as one shared_key"; + for (int i = 0; i < kThreadCount; ++i) { + ExpectKeyAndValueWereRecordedForId(properties, i, "string"); + ExpectKeyAndValueWereRecordedForId(properties, i, "int"); + } + CheckTestFailureCount(kThreadCount*kThreadCount); +} + +void FailingThread(bool is_fatal) { + if (is_fatal) + FAIL() << "Fatal failure in some other thread. " + << "(This failure is expected.)"; + else + ADD_FAILURE() << "Non-fatal failure in some other thread. " + << "(This failure is expected.)"; +} + +void GenerateFatalFailureInAnotherThread(bool is_fatal) { + ThreadWithParam thread(&FailingThread, is_fatal, NULL); + thread.Join(); +} + +TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads) { + EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); + // We should only have one failure (the one from + // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE + // should succeed. + CheckTestFailureCount(1); +} + +void AssertNoFatalFailureIgnoresFailuresInOtherThreads() { + ASSERT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); +} +TEST(NoFatalFailureTest, AssertNoFatalFailureIgnoresFailuresInOtherThreads) { + // Using a subroutine, to make sure, that the test continues. + AssertNoFatalFailureIgnoresFailuresInOtherThreads(); + // We should only have one failure (the one from + // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE + // should succeed. + CheckTestFailureCount(1); +} + +TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads) { + // This statement should fail, since the current thread doesn't generate a + // fatal failure, only another one does. + EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected"); + CheckTestFailureCount(2); +} + +TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads) { + // This statement should succeed, because failures in all threads are + // considered. + EXPECT_FATAL_FAILURE_ON_ALL_THREADS( + GenerateFatalFailureInAnotherThread(true), "expected"); + CheckTestFailureCount(0); + // We need to add a failure, because main() checks that there are failures. + // But when only this test is run, we shouldn't have any failures. + ADD_FAILURE() << "This is an expected non-fatal failure."; +} + +TEST(NonFatalFailureTest, ExpectNonFatalFailureIgnoresFailuresInOtherThreads) { + // This statement should fail, since the current thread doesn't generate a + // fatal failure, only another one does. + EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false), + "expected"); + CheckTestFailureCount(2); +} + +TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) { + // This statement should succeed, because failures in all threads are + // considered. + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( + GenerateFatalFailureInAnotherThread(false), "expected"); + CheckTestFailureCount(0); + // We need to add a failure, because main() checks that there are failures, + // But when only this test is run, we shouldn't have any failures. + ADD_FAILURE() << "This is an expected non-fatal failure."; +} + +} // namespace +} // namespace testing + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + const int result = RUN_ALL_TESTS(); // Expected to fail. + GTEST_CHECK_(result == 1) << "RUN_ALL_TESTS() did not fail as expected"; + + printf("\nPASS\n"); + return 0; +} + +#else +TEST(StressTest, + DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe) { +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif // GTEST_IS_THREADSAFE diff --git a/third_party/googletest/src/test/gtest_test_utils.py b/third_party/googletest/src/test/gtest_test_utils.py new file mode 100755 index 0000000..4e897bd --- /dev/null +++ b/third_party/googletest/src/test/gtest_test_utils.py @@ -0,0 +1,305 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test utilities for Google C++ Testing Framework.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import atexit +import os +import shutil +import sys +import tempfile +import unittest +_test_module = unittest + +# Suppresses the 'Import not at the top of the file' lint complaint. +# pylint: disable-msg=C6204 +try: + import subprocess + _SUBPROCESS_MODULE_AVAILABLE = True +except: + import popen2 + _SUBPROCESS_MODULE_AVAILABLE = False +# pylint: enable-msg=C6204 + +GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' + +IS_WINDOWS = os.name == 'nt' +IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] + +# Here we expose a class from a particular module, depending on the +# environment. The comment suppresses the 'Invalid variable name' lint +# complaint. +TestCase = _test_module.TestCase # pylint: disable-msg=C6409 + +# Initially maps a flag to its default value. After +# _ParseAndStripGTestFlags() is called, maps a flag to its actual value. +_flag_map = {'source_dir': os.path.dirname(sys.argv[0]), + 'build_dir': os.path.dirname(sys.argv[0])} +_gtest_flags_are_parsed = False + + +def _ParseAndStripGTestFlags(argv): + """Parses and strips Google Test flags from argv. This is idempotent.""" + + # Suppresses the lint complaint about a global variable since we need it + # here to maintain module-wide state. + global _gtest_flags_are_parsed # pylint: disable-msg=W0603 + if _gtest_flags_are_parsed: + return + + _gtest_flags_are_parsed = True + for flag in _flag_map: + # The environment variable overrides the default value. + if flag.upper() in os.environ: + _flag_map[flag] = os.environ[flag.upper()] + + # The command line flag overrides the environment variable. + i = 1 # Skips the program name. + while i < len(argv): + prefix = '--' + flag + '=' + if argv[i].startswith(prefix): + _flag_map[flag] = argv[i][len(prefix):] + del argv[i] + break + else: + # We don't increment i in case we just found a --gtest_* flag + # and removed it from argv. + i += 1 + + +def GetFlag(flag): + """Returns the value of the given flag.""" + + # In case GetFlag() is called before Main(), we always call + # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags + # are parsed. + _ParseAndStripGTestFlags(sys.argv) + + return _flag_map[flag] + + +def GetSourceDir(): + """Returns the absolute path of the directory where the .py files are.""" + + return os.path.abspath(GetFlag('source_dir')) + + +def GetBuildDir(): + """Returns the absolute path of the directory where the test binaries are.""" + + return os.path.abspath(GetFlag('build_dir')) + + +_temp_dir = None + +def _RemoveTempDir(): + if _temp_dir: + shutil.rmtree(_temp_dir, ignore_errors=True) + +atexit.register(_RemoveTempDir) + + +def GetTempDir(): + """Returns a directory for temporary files.""" + + global _temp_dir + if not _temp_dir: + _temp_dir = tempfile.mkdtemp() + return _temp_dir + + +def GetTestExecutablePath(executable_name, build_dir=None): + """Returns the absolute path of the test binary given its name. + + The function will print a message and abort the program if the resulting file + doesn't exist. + + Args: + executable_name: name of the test binary that the test script runs. + build_dir: directory where to look for executables, by default + the result of GetBuildDir(). + + Returns: + The absolute path of the test binary. + """ + + path = os.path.abspath(os.path.join(build_dir or GetBuildDir(), + executable_name)) + if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'): + path += '.exe' + + if not os.path.exists(path): + message = ( + 'Unable to find the test binary. Please make sure to provide path\n' + 'to the binary via the --build_dir flag or the BUILD_DIR\n' + 'environment variable.') + print >> sys.stderr, message + sys.exit(1) + + return path + + +def GetExitStatus(exit_code): + """Returns the argument to exit(), or -1 if exit() wasn't called. + + Args: + exit_code: the result value of os.system(command). + """ + + if os.name == 'nt': + # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns + # the argument to exit() directly. + return exit_code + else: + # On Unix, os.WEXITSTATUS() must be used to extract the exit status + # from the result of os.system(). + if os.WIFEXITED(exit_code): + return os.WEXITSTATUS(exit_code) + else: + return -1 + + +class Subprocess: + def __init__(self, command, working_dir=None, capture_stderr=True, env=None): + """Changes into a specified directory, if provided, and executes a command. + + Restores the old directory afterwards. + + Args: + command: The command to run, in the form of sys.argv. + working_dir: The directory to change into. + capture_stderr: Determines whether to capture stderr in the output member + or to discard it. + env: Dictionary with environment to pass to the subprocess. + + Returns: + An object that represents outcome of the executed process. It has the + following attributes: + terminated_by_signal True iff the child process has been terminated + by a signal. + signal Sygnal that terminated the child process. + exited True iff the child process exited normally. + exit_code The code with which the child process exited. + output Child process's stdout and stderr output + combined in a string. + """ + + # The subprocess module is the preferrable way of running programs + # since it is available and behaves consistently on all platforms, + # including Windows. But it is only available starting in python 2.4. + # In earlier python versions, we revert to the popen2 module, which is + # available in python 2.0 and later but doesn't provide required + # functionality (Popen4) under Windows. This allows us to support Mac + # OS X 10.4 Tiger, which has python 2.3 installed. + if _SUBPROCESS_MODULE_AVAILABLE: + if capture_stderr: + stderr = subprocess.STDOUT + else: + stderr = subprocess.PIPE + + p = subprocess.Popen(command, + stdout=subprocess.PIPE, stderr=stderr, + cwd=working_dir, universal_newlines=True, env=env) + # communicate returns a tuple with the file obect for the child's + # output. + self.output = p.communicate()[0] + self._return_code = p.returncode + else: + old_dir = os.getcwd() + + def _ReplaceEnvDict(dest, src): + # Changes made by os.environ.clear are not inheritable by child + # processes until Python 2.6. To produce inheritable changes we have + # to delete environment items with the del statement. + for key in dest: + del dest[key] + dest.update(src) + + # When 'env' is not None, backup the environment variables and replace + # them with the passed 'env'. When 'env' is None, we simply use the + # current 'os.environ' for compatibility with the subprocess.Popen + # semantics used above. + if env is not None: + old_environ = os.environ.copy() + _ReplaceEnvDict(os.environ, env) + + try: + if working_dir is not None: + os.chdir(working_dir) + if capture_stderr: + p = popen2.Popen4(command) + else: + p = popen2.Popen3(command) + p.tochild.close() + self.output = p.fromchild.read() + ret_code = p.wait() + finally: + os.chdir(old_dir) + + # Restore the old environment variables + # if they were replaced. + if env is not None: + _ReplaceEnvDict(os.environ, old_environ) + + # Converts ret_code to match the semantics of + # subprocess.Popen.returncode. + if os.WIFSIGNALED(ret_code): + self._return_code = -os.WTERMSIG(ret_code) + else: # os.WIFEXITED(ret_code) should return True here. + self._return_code = os.WEXITSTATUS(ret_code) + + if self._return_code < 0: + self.terminated_by_signal = True + self.exited = False + self.signal = -self._return_code + else: + self.terminated_by_signal = False + self.exited = True + self.exit_code = self._return_code + + +def Main(): + """Runs the unit test.""" + + # We must call _ParseAndStripGTestFlags() before calling + # unittest.main(). Otherwise the latter will be confused by the + # --gtest_* flags. + _ParseAndStripGTestFlags(sys.argv) + # The tested binaries should not be writing XML output files unless the + # script explicitly instructs them to. + # TODO(vladl@google.com): Move this into Subprocess when we implement + # passing environment into it as a parameter. + if GTEST_OUTPUT_VAR_NAME in os.environ: + del os.environ[GTEST_OUTPUT_VAR_NAME] + + _test_module.main() diff --git a/third_party/googletest/src/test/gtest_throw_on_failure_ex_test.cc b/third_party/googletest/src/test/gtest_throw_on_failure_ex_test.cc new file mode 100644 index 0000000..8d46c76 --- /dev/null +++ b/third_party/googletest/src/test/gtest_throw_on_failure_ex_test.cc @@ -0,0 +1,92 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Tests Google Test's throw-on-failure mode with exceptions enabled. + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +// Prints the given failure message and exits the program with +// non-zero. We use this instead of a Google Test assertion to +// indicate a failure, as the latter is been tested and cannot be +// relied on. +void Fail(const char* msg) { + printf("FAILURE: %s\n", msg); + fflush(stdout); + exit(1); +} + +// Tests that an assertion failure throws a subclass of +// std::runtime_error. +void TestFailureThrowsRuntimeError() { + testing::GTEST_FLAG(throw_on_failure) = true; + + // A successful assertion shouldn't throw. + try { + EXPECT_EQ(3, 3); + } catch(...) { + Fail("A successful assertion wrongfully threw."); + } + + // A failed assertion should throw a subclass of std::runtime_error. + try { + EXPECT_EQ(2, 3) << "Expected failure"; + } catch(const std::runtime_error& e) { + if (strstr(e.what(), "Expected failure") != NULL) + return; + + printf("%s", + "A failed assertion did throw an exception of the right type, " + "but the message is incorrect. Instead of containing \"Expected " + "failure\", it is:\n"); + Fail(e.what()); + } catch(...) { + Fail("A failed assertion threw the wrong type of exception."); + } + Fail("A failed assertion should've thrown but didn't."); +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + // We want to ensure that people can use Google Test assertions in + // other testing frameworks, as long as they initialize Google Test + // properly and set the thrown-on-failure mode. Therefore, we don't + // use Google Test's constructs for defining and running tests + // (e.g. TEST and RUN_ALL_TESTS) here. + + TestFailureThrowsRuntimeError(); + return 0; +} diff --git a/third_party/googletest/src/test/gtest_throw_on_failure_test.py b/third_party/googletest/src/test/gtest_throw_on_failure_test.py new file mode 100755 index 0000000..5678ffe --- /dev/null +++ b/third_party/googletest/src/test/gtest_throw_on_failure_test.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests Google Test's throw-on-failure mode with exceptions disabled. + +This script invokes gtest_throw_on_failure_test_ (a program written with +Google Test) with different environments and command line flags. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import gtest_test_utils + + +# Constants. + +# The command line flag for enabling/disabling the throw-on-failure mode. +THROW_ON_FAILURE = 'gtest_throw_on_failure' + +# Path to the gtest_throw_on_failure_test_ program, compiled with +# exceptions disabled. +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'gtest_throw_on_failure_test_') + + +# Utilities. + + +def SetEnvVar(env_var, value): + """Sets an environment variable to a given value; unsets it when the + given value is None. + """ + + env_var = env_var.upper() + if value is not None: + os.environ[env_var] = value + elif env_var in os.environ: + del os.environ[env_var] + + +def Run(command): + """Runs a command; returns True/False if its exit code is/isn't 0.""" + + print 'Running "%s". . .' % ' '.join(command) + p = gtest_test_utils.Subprocess(command) + return p.exited and p.exit_code == 0 + + +# The tests. TODO(wan@google.com): refactor the class to share common +# logic with code in gtest_break_on_failure_unittest.py. +class ThrowOnFailureTest(gtest_test_utils.TestCase): + """Tests the throw-on-failure mode.""" + + def RunAndVerify(self, env_var_value, flag_value, should_fail): + """Runs gtest_throw_on_failure_test_ and verifies that it does + (or does not) exit with a non-zero code. + + Args: + env_var_value: value of the GTEST_BREAK_ON_FAILURE environment + variable; None if the variable should be unset. + flag_value: value of the --gtest_break_on_failure flag; + None if the flag should not be present. + should_fail: True iff the program is expected to fail. + """ + + SetEnvVar(THROW_ON_FAILURE, env_var_value) + + if env_var_value is None: + env_var_value_msg = ' is not set' + else: + env_var_value_msg = '=' + env_var_value + + if flag_value is None: + flag = '' + elif flag_value == '0': + flag = '--%s=0' % THROW_ON_FAILURE + else: + flag = '--%s' % THROW_ON_FAILURE + + command = [EXE_PATH] + if flag: + command.append(flag) + + if should_fail: + should_or_not = 'should' + else: + should_or_not = 'should not' + + failed = not Run(command) + + SetEnvVar(THROW_ON_FAILURE, None) + + msg = ('when %s%s, an assertion failure in "%s" %s cause a non-zero ' + 'exit code.' % + (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command), + should_or_not)) + self.assert_(failed == should_fail, msg) + + def testDefaultBehavior(self): + """Tests the behavior of the default mode.""" + + self.RunAndVerify(env_var_value=None, flag_value=None, should_fail=False) + + def testThrowOnFailureEnvVar(self): + """Tests using the GTEST_THROW_ON_FAILURE environment variable.""" + + self.RunAndVerify(env_var_value='0', + flag_value=None, + should_fail=False) + self.RunAndVerify(env_var_value='1', + flag_value=None, + should_fail=True) + + def testThrowOnFailureFlag(self): + """Tests using the --gtest_throw_on_failure flag.""" + + self.RunAndVerify(env_var_value=None, + flag_value='0', + should_fail=False) + self.RunAndVerify(env_var_value=None, + flag_value='1', + should_fail=True) + + def testThrowOnFailureFlagOverridesEnvVar(self): + """Tests that --gtest_throw_on_failure overrides GTEST_THROW_ON_FAILURE.""" + + self.RunAndVerify(env_var_value='0', + flag_value='0', + should_fail=False) + self.RunAndVerify(env_var_value='0', + flag_value='1', + should_fail=True) + self.RunAndVerify(env_var_value='1', + flag_value='0', + should_fail=False) + self.RunAndVerify(env_var_value='1', + flag_value='1', + should_fail=True) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_throw_on_failure_test_.cc b/third_party/googletest/src/test/gtest_throw_on_failure_test_.cc new file mode 100644 index 0000000..03776ec --- /dev/null +++ b/third_party/googletest/src/test/gtest_throw_on_failure_test_.cc @@ -0,0 +1,56 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Tests Google Test's throw-on-failure mode with exceptions disabled. +// +// This program must be compiled with exceptions disabled. It will be +// invoked by gtest_throw_on_failure_test.py, and is expected to exit +// with non-zero in the throw-on-failure mode or 0 otherwise. + +#include "gtest/gtest.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + // We want to ensure that people can use Google Test assertions in + // other testing frameworks, as long as they initialize Google Test + // properly and set the thrown-on-failure mode. Therefore, we don't + // use Google Test's constructs for defining and running tests + // (e.g. TEST and RUN_ALL_TESTS) here. + + // In the throw-on-failure mode with exceptions disabled, this + // assertion will cause the program to exit with a non-zero code. + EXPECT_EQ(2, 3); + + // When not in the throw-on-failure mode, the control will reach + // here. + return 0; +} diff --git a/third_party/googletest/src/test/gtest_uninitialized_test.py b/third_party/googletest/src/test/gtest_uninitialized_test.py new file mode 100755 index 0000000..6ae57ee --- /dev/null +++ b/third_party/googletest/src/test/gtest_uninitialized_test.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test warns the user when not initialized properly.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import gtest_test_utils + + +COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_uninitialized_test_') + + +def Assert(condition): + if not condition: + raise AssertionError + + +def AssertEq(expected, actual): + if expected != actual: + print 'Expected: %s' % (expected,) + print ' Actual: %s' % (actual,) + raise AssertionError + + +def TestExitCodeAndOutput(command): + """Runs the given command and verifies its exit code and output.""" + + # Verifies that 'command' exits with code 1. + p = gtest_test_utils.Subprocess(command) + Assert(p.exited) + AssertEq(1, p.exit_code) + Assert('InitGoogleTest' in p.output) + + +class GTestUninitializedTest(gtest_test_utils.TestCase): + def testExitCodeAndOutput(self): + TestExitCodeAndOutput(COMMAND) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_uninitialized_test_.cc b/third_party/googletest/src/test/gtest_uninitialized_test_.cc new file mode 100644 index 0000000..4431698 --- /dev/null +++ b/third_party/googletest/src/test/gtest_uninitialized_test_.cc @@ -0,0 +1,43 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest.h" + +TEST(DummyTest, Dummy) { + // This test doesn't verify anything. We just need it to create a + // realistic stage for testing the behavior of Google Test when + // RUN_ALL_TESTS() is called without testing::InitGoogleTest() being + // called first. +} + +int main() { + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_unittest.cc b/third_party/googletest/src/test/gtest_unittest.cc new file mode 100644 index 0000000..23d6860 --- /dev/null +++ b/third_party/googletest/src/test/gtest_unittest.cc @@ -0,0 +1,7337 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Tests for Google Test itself. This verifies that the basic constructs of +// Google Test work. + +#include "gtest/gtest.h" +#include +#include + +// Verifies that the command line flag variables can be accessed +// in code once has been #included. +// Do not move it after other #includes. +TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { + bool dummy = testing::GTEST_FLAG(also_run_disabled_tests) + || testing::GTEST_FLAG(break_on_failure) + || testing::GTEST_FLAG(catch_exceptions) + || testing::GTEST_FLAG(color) != "unknown" + || testing::GTEST_FLAG(filter) != "unknown" + || testing::GTEST_FLAG(list_tests) + || testing::GTEST_FLAG(output) != "unknown" + || testing::GTEST_FLAG(print_time) + || testing::GTEST_FLAG(random_seed) + || testing::GTEST_FLAG(repeat) > 0 + || testing::GTEST_FLAG(show_internal_stack_frames) + || testing::GTEST_FLAG(shuffle) + || testing::GTEST_FLAG(stack_trace_depth) > 0 + || testing::GTEST_FLAG(stream_result_to) != "unknown" + || testing::GTEST_FLAG(throw_on_failure); + EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused. +} + +#include "gtest/gtest-spi.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#include // For INT_MAX. +#include +#include + +#include + +namespace testing { +namespace internal { + +// Provides access to otherwise private parts of the TestEventListeners class +// that are needed to test it. +class TestEventListenersAccessor { + public: + static TestEventListener* GetRepeater(TestEventListeners* listeners) { + return listeners->repeater(); + } + + static void SetDefaultResultPrinter(TestEventListeners* listeners, + TestEventListener* listener) { + listeners->SetDefaultResultPrinter(listener); + } + static void SetDefaultXmlGenerator(TestEventListeners* listeners, + TestEventListener* listener) { + listeners->SetDefaultXmlGenerator(listener); + } + + static bool EventForwardingEnabled(const TestEventListeners& listeners) { + return listeners.EventForwardingEnabled(); + } + + static void SuppressEventForwarding(TestEventListeners* listeners) { + listeners->SuppressEventForwarding(); + } +}; + +} // namespace internal +} // namespace testing + +using testing::AssertionFailure; +using testing::AssertionResult; +using testing::AssertionSuccess; +using testing::DoubleLE; +using testing::EmptyTestEventListener; +using testing::FloatLE; +using testing::GTEST_FLAG(also_run_disabled_tests); +using testing::GTEST_FLAG(break_on_failure); +using testing::GTEST_FLAG(catch_exceptions); +using testing::GTEST_FLAG(color); +using testing::GTEST_FLAG(death_test_use_fork); +using testing::GTEST_FLAG(filter); +using testing::GTEST_FLAG(list_tests); +using testing::GTEST_FLAG(output); +using testing::GTEST_FLAG(print_time); +using testing::GTEST_FLAG(random_seed); +using testing::GTEST_FLAG(repeat); +using testing::GTEST_FLAG(show_internal_stack_frames); +using testing::GTEST_FLAG(shuffle); +using testing::GTEST_FLAG(stack_trace_depth); +using testing::GTEST_FLAG(stream_result_to); +using testing::GTEST_FLAG(throw_on_failure); +using testing::IsNotSubstring; +using testing::IsSubstring; +using testing::Message; +using testing::ScopedFakeTestPartResultReporter; +using testing::StaticAssertTypeEq; +using testing::Test; +using testing::TestCase; +using testing::TestEventListeners; +using testing::TestPartResult; +using testing::TestPartResultArray; +using testing::TestProperty; +using testing::TestResult; +using testing::UnitTest; +using testing::kMaxStackTraceDepth; +using testing::internal::AddReference; +using testing::internal::AlwaysFalse; +using testing::internal::AlwaysTrue; +using testing::internal::AppendUserMessage; +using testing::internal::ArrayAwareFind; +using testing::internal::ArrayEq; +using testing::internal::CodePointToUtf8; +using testing::internal::CompileAssertTypesEqual; +using testing::internal::CopyArray; +using testing::internal::CountIf; +using testing::internal::EqFailure; +using testing::internal::FloatingPoint; +using testing::internal::ForEach; +using testing::internal::FormatTimeInMillisAsSeconds; +using testing::internal::GTestFlagSaver; +using testing::internal::GetCurrentOsStackTraceExceptTop; +using testing::internal::GetElementOr; +using testing::internal::GetNextRandomSeed; +using testing::internal::GetRandomSeedFromFlag; +using testing::internal::GetTestTypeId; +using testing::internal::GetTypeId; +using testing::internal::GetUnitTestImpl; +using testing::internal::ImplicitlyConvertible; +using testing::internal::Int32; +using testing::internal::Int32FromEnvOrDie; +using testing::internal::IsAProtocolMessage; +using testing::internal::IsContainer; +using testing::internal::IsContainerTest; +using testing::internal::IsNotContainer; +using testing::internal::NativeArray; +using testing::internal::ParseInt32Flag; +using testing::internal::RemoveConst; +using testing::internal::RemoveReference; +using testing::internal::ShouldRunTestOnShard; +using testing::internal::ShouldShard; +using testing::internal::ShouldUseColor; +using testing::internal::Shuffle; +using testing::internal::ShuffleRange; +using testing::internal::SkipPrefix; +using testing::internal::StreamableToString; +using testing::internal::String; +using testing::internal::TestEventListenersAccessor; +using testing::internal::TestResultAccessor; +using testing::internal::UInt32; +using testing::internal::WideStringToUtf8; +using testing::internal::kCopy; +using testing::internal::kMaxRandomSeed; +using testing::internal::kReference; +using testing::internal::kTestTypeIdInGoogleTest; +using testing::internal::scoped_ptr; + +#if GTEST_HAS_STREAM_REDIRECTION +using testing::internal::CaptureStdout; +using testing::internal::GetCapturedStdout; +#endif + +#if GTEST_IS_THREADSAFE +using testing::internal::ThreadWithParam; +#endif + +class TestingVector : public std::vector { +}; + +::std::ostream& operator<<(::std::ostream& os, + const TestingVector& vector) { + os << "{ "; + for (size_t i = 0; i < vector.size(); i++) { + os << vector[i] << " "; + } + os << "}"; + return os; +} + +// This line tests that we can define tests in an unnamed namespace. +namespace { + +TEST(GetRandomSeedFromFlagTest, HandlesZero) { + const int seed = GetRandomSeedFromFlag(0); + EXPECT_LE(1, seed); + EXPECT_LE(seed, static_cast(kMaxRandomSeed)); +} + +TEST(GetRandomSeedFromFlagTest, PreservesValidSeed) { + EXPECT_EQ(1, GetRandomSeedFromFlag(1)); + EXPECT_EQ(2, GetRandomSeedFromFlag(2)); + EXPECT_EQ(kMaxRandomSeed - 1, GetRandomSeedFromFlag(kMaxRandomSeed - 1)); + EXPECT_EQ(static_cast(kMaxRandomSeed), + GetRandomSeedFromFlag(kMaxRandomSeed)); +} + +TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed) { + const int seed1 = GetRandomSeedFromFlag(-1); + EXPECT_LE(1, seed1); + EXPECT_LE(seed1, static_cast(kMaxRandomSeed)); + + const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1); + EXPECT_LE(1, seed2); + EXPECT_LE(seed2, static_cast(kMaxRandomSeed)); +} + +TEST(GetNextRandomSeedTest, WorksForValidInput) { + EXPECT_EQ(2, GetNextRandomSeed(1)); + EXPECT_EQ(3, GetNextRandomSeed(2)); + EXPECT_EQ(static_cast(kMaxRandomSeed), + GetNextRandomSeed(kMaxRandomSeed - 1)); + EXPECT_EQ(1, GetNextRandomSeed(kMaxRandomSeed)); + + // We deliberately don't test GetNextRandomSeed() with invalid + // inputs, as that requires death tests, which are expensive. This + // is fine as GetNextRandomSeed() is internal and has a + // straightforward definition. +} + +static void ClearCurrentTestPartResults() { + TestResultAccessor::ClearTestPartResults( + GetUnitTestImpl()->current_test_result()); +} + +// Tests GetTypeId. + +TEST(GetTypeIdTest, ReturnsSameValueForSameType) { + EXPECT_EQ(GetTypeId(), GetTypeId()); + EXPECT_EQ(GetTypeId(), GetTypeId()); +} + +class SubClassOfTest : public Test {}; +class AnotherSubClassOfTest : public Test {}; + +TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes) { + EXPECT_NE(GetTypeId(), GetTypeId()); + EXPECT_NE(GetTypeId(), GetTypeId()); + EXPECT_NE(GetTypeId(), GetTestTypeId()); + EXPECT_NE(GetTypeId(), GetTestTypeId()); + EXPECT_NE(GetTypeId(), GetTestTypeId()); + EXPECT_NE(GetTypeId(), GetTypeId()); +} + +// Verifies that GetTestTypeId() returns the same value, no matter it +// is called from inside Google Test or outside of it. +TEST(GetTestTypeIdTest, ReturnsTheSameValueInsideOrOutsideOfGoogleTest) { + EXPECT_EQ(kTestTypeIdInGoogleTest, GetTestTypeId()); +} + +// Tests FormatTimeInMillisAsSeconds(). + +TEST(FormatTimeInMillisAsSecondsTest, FormatsZero) { + EXPECT_EQ("0", FormatTimeInMillisAsSeconds(0)); +} + +TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber) { + EXPECT_EQ("0.003", FormatTimeInMillisAsSeconds(3)); + EXPECT_EQ("0.01", FormatTimeInMillisAsSeconds(10)); + EXPECT_EQ("0.2", FormatTimeInMillisAsSeconds(200)); + EXPECT_EQ("1.2", FormatTimeInMillisAsSeconds(1200)); + EXPECT_EQ("3", FormatTimeInMillisAsSeconds(3000)); +} + +TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) { + EXPECT_EQ("-0.003", FormatTimeInMillisAsSeconds(-3)); + EXPECT_EQ("-0.01", FormatTimeInMillisAsSeconds(-10)); + EXPECT_EQ("-0.2", FormatTimeInMillisAsSeconds(-200)); + EXPECT_EQ("-1.2", FormatTimeInMillisAsSeconds(-1200)); + EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000)); +} + +#if GTEST_CAN_COMPARE_NULL + +# ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +# endif + +// Tests that GTEST_IS_NULL_LITERAL_(x) is true when x is a null +// pointer literal. +TEST(NullLiteralTest, IsTrueForNullLiterals) { + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(NULL)); + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0)); + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0U)); + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0L)); + +# ifndef __BORLANDC__ + + // Some compilers may fail to detect some null pointer literals; + // as long as users of the framework don't use such literals, this + // is harmless. + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(1 - 1)); + +# endif +} + +// Tests that GTEST_IS_NULL_LITERAL_(x) is false when x is not a null +// pointer literal. +TEST(NullLiteralTest, IsFalseForNonNullLiterals) { + EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(1)); + EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(0.0)); + EXPECT_FALSE(GTEST_IS_NULL_LITERAL_('a')); + EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(static_cast(NULL))); +} + +# ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them. +# pragma option pop +# endif + +#endif // GTEST_CAN_COMPARE_NULL +// +// Tests CodePointToUtf8(). + +// Tests that the NUL character L'\0' is encoded correctly. +TEST(CodePointToUtf8Test, CanEncodeNul) { + char buffer[32]; + EXPECT_STREQ("", CodePointToUtf8(L'\0', buffer)); +} + +// Tests that ASCII characters are encoded correctly. +TEST(CodePointToUtf8Test, CanEncodeAscii) { + char buffer[32]; + EXPECT_STREQ("a", CodePointToUtf8(L'a', buffer)); + EXPECT_STREQ("Z", CodePointToUtf8(L'Z', buffer)); + EXPECT_STREQ("&", CodePointToUtf8(L'&', buffer)); + EXPECT_STREQ("\x7F", CodePointToUtf8(L'\x7F', buffer)); +} + +// Tests that Unicode code-points that have 8 to 11 bits are encoded +// as 110xxxxx 10xxxxxx. +TEST(CodePointToUtf8Test, CanEncode8To11Bits) { + char buffer[32]; + // 000 1101 0011 => 110-00011 10-010011 + EXPECT_STREQ("\xC3\x93", CodePointToUtf8(L'\xD3', buffer)); + + // 101 0111 0110 => 110-10101 10-110110 + // Some compilers (e.g., GCC on MinGW) cannot handle non-ASCII codepoints + // in wide strings and wide chars. In order to accomodate them, we have to + // introduce such character constants as integers. + EXPECT_STREQ("\xD5\xB6", + CodePointToUtf8(static_cast(0x576), buffer)); +} + +// Tests that Unicode code-points that have 12 to 16 bits are encoded +// as 1110xxxx 10xxxxxx 10xxxxxx. +TEST(CodePointToUtf8Test, CanEncode12To16Bits) { + char buffer[32]; + // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 + EXPECT_STREQ("\xE0\xA3\x93", + CodePointToUtf8(static_cast(0x8D3), buffer)); + + // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 + EXPECT_STREQ("\xEC\x9D\x8D", + CodePointToUtf8(static_cast(0xC74D), buffer)); +} + +#if !GTEST_WIDE_STRING_USES_UTF16_ +// Tests in this group require a wchar_t to hold > 16 bits, and thus +// are skipped on Windows, Cygwin, and Symbian, where a wchar_t is +// 16-bit wide. This code may not compile on those systems. + +// Tests that Unicode code-points that have 17 to 21 bits are encoded +// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. +TEST(CodePointToUtf8Test, CanEncode17To21Bits) { + char buffer[32]; + // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 + EXPECT_STREQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3', buffer)); + + // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000 + EXPECT_STREQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400', buffer)); + + // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 + EXPECT_STREQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634', buffer)); +} + +// Tests that encoding an invalid code-point generates the expected result. +TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint) { + char buffer[32]; + EXPECT_STREQ("(Invalid Unicode 0x1234ABCD)", + CodePointToUtf8(L'\x1234ABCD', buffer)); +} + +#endif // !GTEST_WIDE_STRING_USES_UTF16_ + +// Tests WideStringToUtf8(). + +// Tests that the NUL character L'\0' is encoded correctly. +TEST(WideStringToUtf8Test, CanEncodeNul) { + EXPECT_STREQ("", WideStringToUtf8(L"", 0).c_str()); + EXPECT_STREQ("", WideStringToUtf8(L"", -1).c_str()); +} + +// Tests that ASCII strings are encoded correctly. +TEST(WideStringToUtf8Test, CanEncodeAscii) { + EXPECT_STREQ("a", WideStringToUtf8(L"a", 1).c_str()); + EXPECT_STREQ("ab", WideStringToUtf8(L"ab", 2).c_str()); + EXPECT_STREQ("a", WideStringToUtf8(L"a", -1).c_str()); + EXPECT_STREQ("ab", WideStringToUtf8(L"ab", -1).c_str()); +} + +// Tests that Unicode code-points that have 8 to 11 bits are encoded +// as 110xxxxx 10xxxxxx. +TEST(WideStringToUtf8Test, CanEncode8To11Bits) { + // 000 1101 0011 => 110-00011 10-010011 + EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", 1).c_str()); + EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", -1).c_str()); + + // 101 0111 0110 => 110-10101 10-110110 + const wchar_t s[] = { 0x576, '\0' }; + EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, 1).c_str()); + EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, -1).c_str()); +} + +// Tests that Unicode code-points that have 12 to 16 bits are encoded +// as 1110xxxx 10xxxxxx 10xxxxxx. +TEST(WideStringToUtf8Test, CanEncode12To16Bits) { + // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 + const wchar_t s1[] = { 0x8D3, '\0' }; + EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, 1).c_str()); + EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, -1).c_str()); + + // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 + const wchar_t s2[] = { 0xC74D, '\0' }; + EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, 1).c_str()); + EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, -1).c_str()); +} + +// Tests that the conversion stops when the function encounters \0 character. +TEST(WideStringToUtf8Test, StopsOnNulCharacter) { + EXPECT_STREQ("ABC", WideStringToUtf8(L"ABC\0XYZ", 100).c_str()); +} + +// Tests that the conversion stops when the function reaches the limit +// specified by the 'length' parameter. +TEST(WideStringToUtf8Test, StopsWhenLengthLimitReached) { + EXPECT_STREQ("ABC", WideStringToUtf8(L"ABCDEF", 3).c_str()); +} + +#if !GTEST_WIDE_STRING_USES_UTF16_ +// Tests that Unicode code-points that have 17 to 21 bits are encoded +// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. This code may not compile +// on the systems using UTF-16 encoding. +TEST(WideStringToUtf8Test, CanEncode17To21Bits) { + // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 + EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", 1).c_str()); + EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", -1).c_str()); + + // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 + EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", 1).c_str()); + EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", -1).c_str()); +} + +// Tests that encoding an invalid code-point generates the expected result. +TEST(WideStringToUtf8Test, CanEncodeInvalidCodePoint) { + EXPECT_STREQ("(Invalid Unicode 0xABCDFF)", + WideStringToUtf8(L"\xABCDFF", -1).c_str()); +} +#else // !GTEST_WIDE_STRING_USES_UTF16_ +// Tests that surrogate pairs are encoded correctly on the systems using +// UTF-16 encoding in the wide strings. +TEST(WideStringToUtf8Test, CanEncodeValidUtf16SUrrogatePairs) { + const wchar_t s[] = { 0xD801, 0xDC00, '\0' }; + EXPECT_STREQ("\xF0\x90\x90\x80", WideStringToUtf8(s, -1).c_str()); +} + +// Tests that encoding an invalid UTF-16 surrogate pair +// generates the expected result. +TEST(WideStringToUtf8Test, CanEncodeInvalidUtf16SurrogatePair) { + // Leading surrogate is at the end of the string. + const wchar_t s1[] = { 0xD800, '\0' }; + EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(s1, -1).c_str()); + // Leading surrogate is not followed by the trailing surrogate. + const wchar_t s2[] = { 0xD800, 'M', '\0' }; + EXPECT_STREQ("\xED\xA0\x80M", WideStringToUtf8(s2, -1).c_str()); + // Trailing surrogate appearas without a leading surrogate. + const wchar_t s3[] = { 0xDC00, 'P', 'Q', 'R', '\0' }; + EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(s3, -1).c_str()); +} +#endif // !GTEST_WIDE_STRING_USES_UTF16_ + +// Tests that codepoint concatenation works correctly. +#if !GTEST_WIDE_STRING_USES_UTF16_ +TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { + const wchar_t s[] = { 0x108634, 0xC74D, '\n', 0x576, 0x8D3, 0x108634, '\0'}; + EXPECT_STREQ( + "\xF4\x88\x98\xB4" + "\xEC\x9D\x8D" + "\n" + "\xD5\xB6" + "\xE0\xA3\x93" + "\xF4\x88\x98\xB4", + WideStringToUtf8(s, -1).c_str()); +} +#else +TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { + const wchar_t s[] = { 0xC74D, '\n', 0x576, 0x8D3, '\0'}; + EXPECT_STREQ( + "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93", + WideStringToUtf8(s, -1).c_str()); +} +#endif // !GTEST_WIDE_STRING_USES_UTF16_ + +// Tests the Random class. + +TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) { + testing::internal::Random random(42); + EXPECT_DEATH_IF_SUPPORTED( + random.Generate(0), + "Cannot generate a number in the range \\[0, 0\\)"); + EXPECT_DEATH_IF_SUPPORTED( + random.Generate(testing::internal::Random::kMaxRange + 1), + "Generation of a number in \\[0, 2147483649\\) was requested, " + "but this can only generate numbers in \\[0, 2147483648\\)"); +} + +TEST(RandomTest, GeneratesNumbersWithinRange) { + const UInt32 kRange = 10000; + testing::internal::Random random(12345); + for (int i = 0; i < 10; i++) { + EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i; + } + + testing::internal::Random random2(testing::internal::Random::kMaxRange); + for (int i = 0; i < 10; i++) { + EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i; + } +} + +TEST(RandomTest, RepeatsWhenReseeded) { + const int kSeed = 123; + const int kArraySize = 10; + const UInt32 kRange = 10000; + UInt32 values[kArraySize]; + + testing::internal::Random random(kSeed); + for (int i = 0; i < kArraySize; i++) { + values[i] = random.Generate(kRange); + } + + random.Reseed(kSeed); + for (int i = 0; i < kArraySize; i++) { + EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i; + } +} + +// Tests STL container utilities. + +// Tests CountIf(). + +static bool IsPositive(int n) { return n > 0; } + +TEST(ContainerUtilityTest, CountIf) { + std::vector v; + EXPECT_EQ(0, CountIf(v, IsPositive)); // Works for an empty container. + + v.push_back(-1); + v.push_back(0); + EXPECT_EQ(0, CountIf(v, IsPositive)); // Works when no value satisfies. + + v.push_back(2); + v.push_back(-10); + v.push_back(10); + EXPECT_EQ(2, CountIf(v, IsPositive)); +} + +// Tests ForEach(). + +static int g_sum = 0; +static void Accumulate(int n) { g_sum += n; } + +TEST(ContainerUtilityTest, ForEach) { + std::vector v; + g_sum = 0; + ForEach(v, Accumulate); + EXPECT_EQ(0, g_sum); // Works for an empty container; + + g_sum = 0; + v.push_back(1); + ForEach(v, Accumulate); + EXPECT_EQ(1, g_sum); // Works for a container with one element. + + g_sum = 0; + v.push_back(20); + v.push_back(300); + ForEach(v, Accumulate); + EXPECT_EQ(321, g_sum); +} + +// Tests GetElementOr(). +TEST(ContainerUtilityTest, GetElementOr) { + std::vector a; + EXPECT_EQ('x', GetElementOr(a, 0, 'x')); + + a.push_back('a'); + a.push_back('b'); + EXPECT_EQ('a', GetElementOr(a, 0, 'x')); + EXPECT_EQ('b', GetElementOr(a, 1, 'x')); + EXPECT_EQ('x', GetElementOr(a, -2, 'x')); + EXPECT_EQ('x', GetElementOr(a, 2, 'x')); +} + +TEST(ContainerUtilityDeathTest, ShuffleRange) { + std::vector a; + a.push_back(0); + a.push_back(1); + a.push_back(2); + testing::internal::Random random(1); + + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, -1, 1, &a), + "Invalid shuffle range start -1: must be in range \\[0, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, 4, 4, &a), + "Invalid shuffle range start 4: must be in range \\[0, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, 3, 2, &a), + "Invalid shuffle range finish 2: must be in range \\[3, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, 3, 4, &a), + "Invalid shuffle range finish 4: must be in range \\[3, 3\\]"); +} + +class VectorShuffleTest : public Test { + protected: + static const int kVectorSize = 20; + + VectorShuffleTest() : random_(1) { + for (int i = 0; i < kVectorSize; i++) { + vector_.push_back(i); + } + } + + static bool VectorIsCorrupt(const TestingVector& vector) { + if (kVectorSize != static_cast(vector.size())) { + return true; + } + + bool found_in_vector[kVectorSize] = { false }; + for (size_t i = 0; i < vector.size(); i++) { + const int e = vector[i]; + if (e < 0 || e >= kVectorSize || found_in_vector[e]) { + return true; + } + found_in_vector[e] = true; + } + + // Vector size is correct, elements' range is correct, no + // duplicate elements. Therefore no corruption has occurred. + return false; + } + + static bool VectorIsNotCorrupt(const TestingVector& vector) { + return !VectorIsCorrupt(vector); + } + + static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) { + for (int i = begin; i < end; i++) { + if (i != vector[i]) { + return true; + } + } + return false; + } + + static bool RangeIsUnshuffled( + const TestingVector& vector, int begin, int end) { + return !RangeIsShuffled(vector, begin, end); + } + + static bool VectorIsShuffled(const TestingVector& vector) { + return RangeIsShuffled(vector, 0, static_cast(vector.size())); + } + + static bool VectorIsUnshuffled(const TestingVector& vector) { + return !VectorIsShuffled(vector); + } + + testing::internal::Random random_; + TestingVector vector_; +}; // class VectorShuffleTest + +const int VectorShuffleTest::kVectorSize; + +TEST_F(VectorShuffleTest, HandlesEmptyRange) { + // Tests an empty range at the beginning... + ShuffleRange(&random_, 0, 0, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...in the middle... + ShuffleRange(&random_, kVectorSize/2, kVectorSize/2, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...at the end... + ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...and past the end. + ShuffleRange(&random_, kVectorSize, kVectorSize, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); +} + +TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne) { + // Tests a size one range at the beginning... + ShuffleRange(&random_, 0, 1, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...in the middle... + ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...and at the end. + ShuffleRange(&random_, kVectorSize - 1, kVectorSize, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); +} + +// Because we use our own random number generator and a fixed seed, +// we can guarantee that the following "random" tests will succeed. + +TEST_F(VectorShuffleTest, ShufflesEntireVector) { + Shuffle(&random_, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_; + + // Tests the first and last elements in particular to ensure that + // there are no off-by-one problems in our shuffle algorithm. + EXPECT_NE(0, vector_[0]); + EXPECT_NE(kVectorSize - 1, vector_[kVectorSize - 1]); +} + +TEST_F(VectorShuffleTest, ShufflesStartOfVector) { + const int kRangeSize = kVectorSize/2; + + ShuffleRange(&random_, 0, kRangeSize, &vector_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, kVectorSize); +} + +TEST_F(VectorShuffleTest, ShufflesEndOfVector) { + const int kRangeSize = kVectorSize / 2; + ShuffleRange(&random_, kRangeSize, kVectorSize, &vector_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, kVectorSize); +} + +TEST_F(VectorShuffleTest, ShufflesMiddleOfVector) { + int kRangeSize = kVectorSize/3; + ShuffleRange(&random_, kRangeSize, 2*kRangeSize, &vector_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 2*kRangeSize, kVectorSize); +} + +TEST_F(VectorShuffleTest, ShufflesRepeatably) { + TestingVector vector2; + for (int i = 0; i < kVectorSize; i++) { + vector2.push_back(i); + } + + random_.Reseed(1234); + Shuffle(&random_, &vector_); + random_.Reseed(1234); + Shuffle(&random_, &vector2); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector2); + + for (int i = 0; i < kVectorSize; i++) { + EXPECT_EQ(vector_[i], vector2[i]) << " where i is " << i; + } +} + +// Tests the size of the AssertHelper class. + +TEST(AssertHelperTest, AssertHelperIsSmall) { + // To avoid breaking clients that use lots of assertions in one + // function, we cannot grow the size of AssertHelper. + EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*)); +} + +// Tests the String class. + +// Tests String's constructors. +TEST(StringTest, Constructors) { + // Default ctor. + String s1; + // We aren't using EXPECT_EQ(NULL, s1.c_str()) because comparing + // pointers with NULL isn't supported on all platforms. + EXPECT_EQ(0U, s1.length()); + EXPECT_TRUE(NULL == s1.c_str()); + + // Implicitly constructs from a C-string. + String s2 = "Hi"; + EXPECT_EQ(2U, s2.length()); + EXPECT_STREQ("Hi", s2.c_str()); + + // Constructs from a C-string and a length. + String s3("hello", 3); + EXPECT_EQ(3U, s3.length()); + EXPECT_STREQ("hel", s3.c_str()); + + // The empty String should be created when String is constructed with + // a NULL pointer and length 0. + EXPECT_EQ(0U, String(NULL, 0).length()); + EXPECT_FALSE(String(NULL, 0).c_str() == NULL); + + // Constructs a String that contains '\0'. + String s4("a\0bcd", 4); + EXPECT_EQ(4U, s4.length()); + EXPECT_EQ('a', s4.c_str()[0]); + EXPECT_EQ('\0', s4.c_str()[1]); + EXPECT_EQ('b', s4.c_str()[2]); + EXPECT_EQ('c', s4.c_str()[3]); + + // Copy ctor where the source is NULL. + const String null_str; + String s5 = null_str; + EXPECT_TRUE(s5.c_str() == NULL); + + // Copy ctor where the source isn't NULL. + String s6 = s3; + EXPECT_EQ(3U, s6.length()); + EXPECT_STREQ("hel", s6.c_str()); + + // Copy ctor where the source contains '\0'. + String s7 = s4; + EXPECT_EQ(4U, s7.length()); + EXPECT_EQ('a', s7.c_str()[0]); + EXPECT_EQ('\0', s7.c_str()[1]); + EXPECT_EQ('b', s7.c_str()[2]); + EXPECT_EQ('c', s7.c_str()[3]); +} + +TEST(StringTest, ConvertsFromStdString) { + // An empty std::string. + const std::string src1(""); + const String dest1 = src1; + EXPECT_EQ(0U, dest1.length()); + EXPECT_STREQ("", dest1.c_str()); + + // A normal std::string. + const std::string src2("Hi"); + const String dest2 = src2; + EXPECT_EQ(2U, dest2.length()); + EXPECT_STREQ("Hi", dest2.c_str()); + + // An std::string with an embedded NUL character. + const char src3[] = "a\0b"; + const String dest3 = std::string(src3, sizeof(src3)); + EXPECT_EQ(sizeof(src3), dest3.length()); + EXPECT_EQ('a', dest3.c_str()[0]); + EXPECT_EQ('\0', dest3.c_str()[1]); + EXPECT_EQ('b', dest3.c_str()[2]); +} + +TEST(StringTest, ConvertsToStdString) { + // An empty String. + const String src1(""); + const std::string dest1 = src1; + EXPECT_EQ("", dest1); + + // A normal String. + const String src2("Hi"); + const std::string dest2 = src2; + EXPECT_EQ("Hi", dest2); + + // A String containing a '\0'. + const String src3("x\0y", 3); + const std::string dest3 = src3; + EXPECT_EQ(std::string("x\0y", 3), dest3); +} + +#if GTEST_HAS_GLOBAL_STRING + +TEST(StringTest, ConvertsFromGlobalString) { + // An empty ::string. + const ::string src1(""); + const String dest1 = src1; + EXPECT_EQ(0U, dest1.length()); + EXPECT_STREQ("", dest1.c_str()); + + // A normal ::string. + const ::string src2("Hi"); + const String dest2 = src2; + EXPECT_EQ(2U, dest2.length()); + EXPECT_STREQ("Hi", dest2.c_str()); + + // An ::string with an embedded NUL character. + const char src3[] = "x\0y"; + const String dest3 = ::string(src3, sizeof(src3)); + EXPECT_EQ(sizeof(src3), dest3.length()); + EXPECT_EQ('x', dest3.c_str()[0]); + EXPECT_EQ('\0', dest3.c_str()[1]); + EXPECT_EQ('y', dest3.c_str()[2]); +} + +TEST(StringTest, ConvertsToGlobalString) { + // An empty String. + const String src1(""); + const ::string dest1 = src1; + EXPECT_EQ("", dest1); + + // A normal String. + const String src2("Hi"); + const ::string dest2 = src2; + EXPECT_EQ("Hi", dest2); + + const String src3("x\0y", 3); + const ::string dest3 = src3; + EXPECT_EQ(::string("x\0y", 3), dest3); +} + +#endif // GTEST_HAS_GLOBAL_STRING + +// Tests String::ShowCStringQuoted(). +TEST(StringTest, ShowCStringQuoted) { + EXPECT_STREQ("(null)", + String::ShowCStringQuoted(NULL).c_str()); + EXPECT_STREQ("\"\"", + String::ShowCStringQuoted("").c_str()); + EXPECT_STREQ("\"foo\"", + String::ShowCStringQuoted("foo").c_str()); +} + +// Tests String::empty(). +TEST(StringTest, Empty) { + EXPECT_TRUE(String("").empty()); + EXPECT_FALSE(String().empty()); + EXPECT_FALSE(String(NULL).empty()); + EXPECT_FALSE(String("a").empty()); + EXPECT_FALSE(String("\0", 1).empty()); +} + +// Tests String::Compare(). +TEST(StringTest, Compare) { + // NULL vs NULL. + EXPECT_EQ(0, String().Compare(String())); + + // NULL vs non-NULL. + EXPECT_EQ(-1, String().Compare(String(""))); + + // Non-NULL vs NULL. + EXPECT_EQ(1, String("").Compare(String())); + + // The following covers non-NULL vs non-NULL. + + // "" vs "". + EXPECT_EQ(0, String("").Compare(String(""))); + + // "" vs non-"". + EXPECT_EQ(-1, String("").Compare(String("\0", 1))); + EXPECT_EQ(-1, String("").Compare(" ")); + + // Non-"" vs "". + EXPECT_EQ(1, String("a").Compare(String(""))); + + // The following covers non-"" vs non-"". + + // Same length and equal. + EXPECT_EQ(0, String("a").Compare(String("a"))); + + // Same length and different. + EXPECT_EQ(-1, String("a\0b", 3).Compare(String("a\0c", 3))); + EXPECT_EQ(1, String("b").Compare(String("a"))); + + // Different lengths. + EXPECT_EQ(-1, String("a").Compare(String("ab"))); + EXPECT_EQ(-1, String("a").Compare(String("a\0", 2))); + EXPECT_EQ(1, String("abc").Compare(String("aacd"))); +} + +// Tests String::operator==(). +TEST(StringTest, Equals) { + const String null(NULL); + EXPECT_TRUE(null == NULL); // NOLINT + EXPECT_FALSE(null == ""); // NOLINT + EXPECT_FALSE(null == "bar"); // NOLINT + + const String empty(""); + EXPECT_FALSE(empty == NULL); // NOLINT + EXPECT_TRUE(empty == ""); // NOLINT + EXPECT_FALSE(empty == "bar"); // NOLINT + + const String foo("foo"); + EXPECT_FALSE(foo == NULL); // NOLINT + EXPECT_FALSE(foo == ""); // NOLINT + EXPECT_FALSE(foo == "bar"); // NOLINT + EXPECT_TRUE(foo == "foo"); // NOLINT + + const String bar("x\0y", 3); + EXPECT_FALSE(bar == "x"); +} + +// Tests String::operator!=(). +TEST(StringTest, NotEquals) { + const String null(NULL); + EXPECT_FALSE(null != NULL); // NOLINT + EXPECT_TRUE(null != ""); // NOLINT + EXPECT_TRUE(null != "bar"); // NOLINT + + const String empty(""); + EXPECT_TRUE(empty != NULL); // NOLINT + EXPECT_FALSE(empty != ""); // NOLINT + EXPECT_TRUE(empty != "bar"); // NOLINT + + const String foo("foo"); + EXPECT_TRUE(foo != NULL); // NOLINT + EXPECT_TRUE(foo != ""); // NOLINT + EXPECT_TRUE(foo != "bar"); // NOLINT + EXPECT_FALSE(foo != "foo"); // NOLINT + + const String bar("x\0y", 3); + EXPECT_TRUE(bar != "x"); +} + +// Tests String::length(). +TEST(StringTest, Length) { + EXPECT_EQ(0U, String().length()); + EXPECT_EQ(0U, String("").length()); + EXPECT_EQ(2U, String("ab").length()); + EXPECT_EQ(3U, String("a\0b", 3).length()); +} + +// Tests String::EndsWith(). +TEST(StringTest, EndsWith) { + EXPECT_TRUE(String("foobar").EndsWith("bar")); + EXPECT_TRUE(String("foobar").EndsWith("")); + EXPECT_TRUE(String("").EndsWith("")); + + EXPECT_FALSE(String("foobar").EndsWith("foo")); + EXPECT_FALSE(String("").EndsWith("foo")); +} + +// Tests String::EndsWithCaseInsensitive(). +TEST(StringTest, EndsWithCaseInsensitive) { + EXPECT_TRUE(String("foobar").EndsWithCaseInsensitive("BAR")); + EXPECT_TRUE(String("foobaR").EndsWithCaseInsensitive("bar")); + EXPECT_TRUE(String("foobar").EndsWithCaseInsensitive("")); + EXPECT_TRUE(String("").EndsWithCaseInsensitive("")); + + EXPECT_FALSE(String("Foobar").EndsWithCaseInsensitive("foo")); + EXPECT_FALSE(String("foobar").EndsWithCaseInsensitive("Foo")); + EXPECT_FALSE(String("").EndsWithCaseInsensitive("foo")); +} + +// C++Builder's preprocessor is buggy; it fails to expand macros that +// appear in macro parameters after wide char literals. Provide an alias +// for NULL as a workaround. +static const wchar_t* const kNull = NULL; + +// Tests String::CaseInsensitiveWideCStringEquals +TEST(StringTest, CaseInsensitiveWideCStringEquals) { + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(NULL, NULL)); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"")); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", kNull)); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"foobar")); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", kNull)); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar")); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR")); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar")); +} + +// Tests that NULL can be assigned to a String. +TEST(StringTest, CanBeAssignedNULL) { + const String src(NULL); + String dest; + + dest = src; + EXPECT_STREQ(NULL, dest.c_str()); +} + +// Tests that the empty string "" can be assigned to a String. +TEST(StringTest, CanBeAssignedEmpty) { + const String src(""); + String dest; + + dest = src; + EXPECT_STREQ("", dest.c_str()); +} + +// Tests that a non-empty string can be assigned to a String. +TEST(StringTest, CanBeAssignedNonEmpty) { + const String src("hello"); + String dest; + dest = src; + EXPECT_EQ(5U, dest.length()); + EXPECT_STREQ("hello", dest.c_str()); + + const String src2("x\0y", 3); + String dest2; + dest2 = src2; + EXPECT_EQ(3U, dest2.length()); + EXPECT_EQ('x', dest2.c_str()[0]); + EXPECT_EQ('\0', dest2.c_str()[1]); + EXPECT_EQ('y', dest2.c_str()[2]); +} + +// Tests that a String can be assigned to itself. +TEST(StringTest, CanBeAssignedSelf) { + String dest("hello"); + + // Use explicit function call notation here to suppress self-assign warning. + dest.operator=(dest); + EXPECT_STREQ("hello", dest.c_str()); +} + +// Sun Studio < 12 incorrectly rejects this code due to an overloading +// ambiguity. +#if !(defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +// Tests streaming a String. +TEST(StringTest, Streams) { + EXPECT_EQ(StreamableToString(String()), "(null)"); + EXPECT_EQ(StreamableToString(String("")), ""); + EXPECT_EQ(StreamableToString(String("a\0b", 3)), "a\\0b"); +} +#endif + +// Tests that String::Format() works. +TEST(StringTest, FormatWorks) { + // Normal case: the format spec is valid, the arguments match the + // spec, and the result is < 4095 characters. + EXPECT_STREQ("Hello, 42", String::Format("%s, %d", "Hello", 42).c_str()); + + // Edge case: the result is 4095 characters. + char buffer[4096]; + const size_t kSize = sizeof(buffer); + memset(buffer, 'a', kSize - 1); + buffer[kSize - 1] = '\0'; + EXPECT_STREQ(buffer, String::Format("%s", buffer).c_str()); + + // The result needs to be 4096 characters, exceeding Format()'s limit. + EXPECT_STREQ("", + String::Format("x%s", buffer).c_str()); + +#if GTEST_OS_LINUX + // On Linux, invalid format spec should lead to an error message. + // In other environment (e.g. MSVC on Windows), String::Format() may + // simply ignore a bad format spec, so this assertion is run on + // Linux only. + EXPECT_STREQ("", + String::Format("%").c_str()); +#endif +} + +#if GTEST_OS_WINDOWS + +// Tests String::ShowWideCString(). +TEST(StringTest, ShowWideCString) { + EXPECT_STREQ("(null)", + String::ShowWideCString(NULL).c_str()); + EXPECT_STREQ("", String::ShowWideCString(L"").c_str()); + EXPECT_STREQ("foo", String::ShowWideCString(L"foo").c_str()); +} + +// Tests String::ShowWideCStringQuoted(). +TEST(StringTest, ShowWideCStringQuoted) { + EXPECT_STREQ("(null)", + String::ShowWideCStringQuoted(NULL).c_str()); + EXPECT_STREQ("L\"\"", + String::ShowWideCStringQuoted(L"").c_str()); + EXPECT_STREQ("L\"foo\"", + String::ShowWideCStringQuoted(L"foo").c_str()); +} + +# if GTEST_OS_WINDOWS_MOBILE +TEST(StringTest, AnsiAndUtf16Null) { + EXPECT_EQ(NULL, String::AnsiToUtf16(NULL)); + EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL)); +} + +TEST(StringTest, AnsiAndUtf16ConvertBasic) { + const char* ansi = String::Utf16ToAnsi(L"str"); + EXPECT_STREQ("str", ansi); + delete [] ansi; + const WCHAR* utf16 = String::AnsiToUtf16("str"); + EXPECT_EQ(0, wcsncmp(L"str", utf16, 3)); + delete [] utf16; +} + +TEST(StringTest, AnsiAndUtf16ConvertPathChars) { + const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?"); + EXPECT_STREQ(".:\\ \"*?", ansi); + delete [] ansi; + const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?"); + EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3)); + delete [] utf16; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#endif // GTEST_OS_WINDOWS + +// Tests TestProperty construction. +TEST(TestPropertyTest, StringValue) { + TestProperty property("key", "1"); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("1", property.value()); +} + +// Tests TestProperty replacing a value. +TEST(TestPropertyTest, ReplaceStringValue) { + TestProperty property("key", "1"); + EXPECT_STREQ("1", property.value()); + property.SetValue("2"); + EXPECT_STREQ("2", property.value()); +} + +// AddFatalFailure() and AddNonfatalFailure() must be stand-alone +// functions (i.e. their definitions cannot be inlined at the call +// sites), or C++Builder won't compile the code. +static void AddFatalFailure() { + FAIL() << "Expected fatal failure."; +} + +static void AddNonfatalFailure() { + ADD_FAILURE() << "Expected non-fatal failure."; +} + +class ScopedFakeTestPartResultReporterTest : public Test { + public: // Must be public and not protected due to a bug in g++ 3.4.2. + enum FailureMode { + FATAL_FAILURE, + NONFATAL_FAILURE + }; + static void AddFailure(FailureMode failure) { + if (failure == FATAL_FAILURE) { + AddFatalFailure(); + } else { + AddNonfatalFailure(); + } + } +}; + +// Tests that ScopedFakeTestPartResultReporter intercepts test +// failures. +TEST_F(ScopedFakeTestPartResultReporterTest, InterceptsTestFailures) { + TestPartResultArray results; + { + ScopedFakeTestPartResultReporter reporter( + ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, + &results); + AddFailure(NONFATAL_FAILURE); + AddFailure(FATAL_FAILURE); + } + + EXPECT_EQ(2, results.size()); + EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); +} + +TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) { + TestPartResultArray results; + { + // Tests, that the deprecated constructor still works. + ScopedFakeTestPartResultReporter reporter(&results); + AddFailure(NONFATAL_FAILURE); + } + EXPECT_EQ(1, results.size()); +} + +#if GTEST_IS_THREADSAFE + +class ScopedFakeTestPartResultReporterWithThreadsTest + : public ScopedFakeTestPartResultReporterTest { + protected: + static void AddFailureInOtherThread(FailureMode failure) { + ThreadWithParam thread(&AddFailure, failure, NULL); + thread.Join(); + } +}; + +TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest, + InterceptsTestFailuresInAllThreads) { + TestPartResultArray results; + { + ScopedFakeTestPartResultReporter reporter( + ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, &results); + AddFailure(NONFATAL_FAILURE); + AddFailure(FATAL_FAILURE); + AddFailureInOtherThread(NONFATAL_FAILURE); + AddFailureInOtherThread(FATAL_FAILURE); + } + + EXPECT_EQ(4, results.size()); + EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(2).nonfatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed()); +} + +#endif // GTEST_IS_THREADSAFE + +// Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they +// work even if the failure is generated in a called function rather than +// the current context. + +typedef ScopedFakeTestPartResultReporterTest ExpectFatalFailureTest; + +TEST_F(ExpectFatalFailureTest, CatchesFatalFaliure) { + EXPECT_FATAL_FAILURE(AddFatalFailure(), "Expected fatal failure."); +} + +#if GTEST_HAS_GLOBAL_STRING +TEST_F(ExpectFatalFailureTest, AcceptsStringObject) { + EXPECT_FATAL_FAILURE(AddFatalFailure(), ::string("Expected fatal failure.")); +} +#endif + +TEST_F(ExpectFatalFailureTest, AcceptsStdStringObject) { + EXPECT_FATAL_FAILURE(AddFatalFailure(), + ::std::string("Expected fatal failure.")); +} + +TEST_F(ExpectFatalFailureTest, CatchesFatalFailureOnAllThreads) { + // We have another test below to verify that the macro catches fatal + // failures generated on another thread. + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFatalFailure(), + "Expected fatal failure."); +} + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true" +# pragma option push -w-ccc +#endif + +// Tests that EXPECT_FATAL_FAILURE() can be used in a non-void +// function even when the statement in it contains ASSERT_*. + +int NonVoidFunction() { + EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); + return 0; +} + +TEST_F(ExpectFatalFailureTest, CanBeUsedInNonVoidFunction) { + NonVoidFunction(); +} + +// Tests that EXPECT_FATAL_FAILURE(statement, ...) doesn't abort the +// current function even though 'statement' generates a fatal failure. + +void DoesNotAbortHelper(bool* aborted) { + EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); + + *aborted = false; +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them. +# pragma option pop +#endif + +TEST_F(ExpectFatalFailureTest, DoesNotAbort) { + bool aborted = true; + DoesNotAbortHelper(&aborted); + EXPECT_FALSE(aborted); +} + +// Tests that the EXPECT_FATAL_FAILURE{,_ON_ALL_THREADS} accepts a +// statement that contains a macro which expands to code containing an +// unprotected comma. + +static int global_var = 0; +#define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++ + +TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE({ + GTEST_USE_UNPROTECTED_COMMA_; + AddFatalFailure(); + }, ""); +#endif + + EXPECT_FATAL_FAILURE_ON_ALL_THREADS({ + GTEST_USE_UNPROTECTED_COMMA_; + AddFatalFailure(); + }, ""); +} + +// Tests EXPECT_NONFATAL_FAILURE{,ON_ALL_THREADS}. + +typedef ScopedFakeTestPartResultReporterTest ExpectNonfatalFailureTest; + +TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), + "Expected non-fatal failure."); +} + +#if GTEST_HAS_GLOBAL_STRING +TEST_F(ExpectNonfatalFailureTest, AcceptsStringObject) { + EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), + ::string("Expected non-fatal failure.")); +} +#endif + +TEST_F(ExpectNonfatalFailureTest, AcceptsStdStringObject) { + EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), + ::std::string("Expected non-fatal failure.")); +} + +TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailureOnAllThreads) { + // We have another test below to verify that the macro catches + // non-fatal failures generated on another thread. + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddNonfatalFailure(), + "Expected non-fatal failure."); +} + +// Tests that the EXPECT_NONFATAL_FAILURE{,_ON_ALL_THREADS} accepts a +// statement that contains a macro which expands to code containing an +// unprotected comma. +TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { + EXPECT_NONFATAL_FAILURE({ + GTEST_USE_UNPROTECTED_COMMA_; + AddNonfatalFailure(); + }, ""); + + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS({ + GTEST_USE_UNPROTECTED_COMMA_; + AddNonfatalFailure(); + }, ""); +} + +#if GTEST_IS_THREADSAFE + +typedef ScopedFakeTestPartResultReporterWithThreadsTest + ExpectFailureWithThreadsTest; + +TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailureOnAllThreads) { + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailureInOtherThread(FATAL_FAILURE), + "Expected fatal failure."); +} + +TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) { + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( + AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); +} + +#endif // GTEST_IS_THREADSAFE + +// Tests the TestProperty class. + +TEST(TestPropertyTest, ConstructorWorks) { + const TestProperty property("key", "value"); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("value", property.value()); +} + +TEST(TestPropertyTest, SetValue) { + TestProperty property("key", "value_1"); + EXPECT_STREQ("key", property.key()); + property.SetValue("value_2"); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("value_2", property.value()); +} + +// Tests the TestResult class + +// The test fixture for testing TestResult. +class TestResultTest : public Test { + protected: + typedef std::vector TPRVector; + + // We make use of 2 TestPartResult objects, + TestPartResult * pr1, * pr2; + + // ... and 3 TestResult objects. + TestResult * r0, * r1, * r2; + + virtual void SetUp() { + // pr1 is for success. + pr1 = new TestPartResult(TestPartResult::kSuccess, + "foo/bar.cc", + 10, + "Success!"); + + // pr2 is for fatal failure. + pr2 = new TestPartResult(TestPartResult::kFatalFailure, + "foo/bar.cc", + -1, // This line number means "unknown" + "Failure!"); + + // Creates the TestResult objects. + r0 = new TestResult(); + r1 = new TestResult(); + r2 = new TestResult(); + + // In order to test TestResult, we need to modify its internal + // state, in particular the TestPartResult vector it holds. + // test_part_results() returns a const reference to this vector. + // We cast it to a non-const object s.t. it can be modified (yes, + // this is a hack). + TPRVector* results1 = const_cast( + &TestResultAccessor::test_part_results(*r1)); + TPRVector* results2 = const_cast( + &TestResultAccessor::test_part_results(*r2)); + + // r0 is an empty TestResult. + + // r1 contains a single SUCCESS TestPartResult. + results1->push_back(*pr1); + + // r2 contains a SUCCESS, and a FAILURE. + results2->push_back(*pr1); + results2->push_back(*pr2); + } + + virtual void TearDown() { + delete pr1; + delete pr2; + + delete r0; + delete r1; + delete r2; + } + + // Helper that compares two two TestPartResults. + static void CompareTestPartResult(const TestPartResult& expected, + const TestPartResult& actual) { + EXPECT_EQ(expected.type(), actual.type()); + EXPECT_STREQ(expected.file_name(), actual.file_name()); + EXPECT_EQ(expected.line_number(), actual.line_number()); + EXPECT_STREQ(expected.summary(), actual.summary()); + EXPECT_STREQ(expected.message(), actual.message()); + EXPECT_EQ(expected.passed(), actual.passed()); + EXPECT_EQ(expected.failed(), actual.failed()); + EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed()); + EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed()); + } +}; + +// Tests TestResult::total_part_count(). +TEST_F(TestResultTest, total_part_count) { + ASSERT_EQ(0, r0->total_part_count()); + ASSERT_EQ(1, r1->total_part_count()); + ASSERT_EQ(2, r2->total_part_count()); +} + +// Tests TestResult::Passed(). +TEST_F(TestResultTest, Passed) { + ASSERT_TRUE(r0->Passed()); + ASSERT_TRUE(r1->Passed()); + ASSERT_FALSE(r2->Passed()); +} + +// Tests TestResult::Failed(). +TEST_F(TestResultTest, Failed) { + ASSERT_FALSE(r0->Failed()); + ASSERT_FALSE(r1->Failed()); + ASSERT_TRUE(r2->Failed()); +} + +// Tests TestResult::GetTestPartResult(). + +typedef TestResultTest TestResultDeathTest; + +TEST_F(TestResultDeathTest, GetTestPartResult) { + CompareTestPartResult(*pr1, r2->GetTestPartResult(0)); + CompareTestPartResult(*pr2, r2->GetTestPartResult(1)); + EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(2), ""); + EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(-1), ""); +} + +// Tests TestResult has no properties when none are added. +TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) { + TestResult test_result; + ASSERT_EQ(0, test_result.test_property_count()); +} + +// Tests TestResult has the expected property when added. +TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded) { + TestResult test_result; + TestProperty property("key_1", "1"); + TestResultAccessor::RecordProperty(&test_result, property); + ASSERT_EQ(1, test_result.test_property_count()); + const TestProperty& actual_property = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property.key()); + EXPECT_STREQ("1", actual_property.value()); +} + +// Tests TestResult has multiple properties when added. +TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) { + TestResult test_result; + TestProperty property_1("key_1", "1"); + TestProperty property_2("key_2", "2"); + TestResultAccessor::RecordProperty(&test_result, property_1); + TestResultAccessor::RecordProperty(&test_result, property_2); + ASSERT_EQ(2, test_result.test_property_count()); + const TestProperty& actual_property_1 = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property_1.key()); + EXPECT_STREQ("1", actual_property_1.value()); + + const TestProperty& actual_property_2 = test_result.GetTestProperty(1); + EXPECT_STREQ("key_2", actual_property_2.key()); + EXPECT_STREQ("2", actual_property_2.value()); +} + +// Tests TestResult::RecordProperty() overrides values for duplicate keys. +TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) { + TestResult test_result; + TestProperty property_1_1("key_1", "1"); + TestProperty property_2_1("key_2", "2"); + TestProperty property_1_2("key_1", "12"); + TestProperty property_2_2("key_2", "22"); + TestResultAccessor::RecordProperty(&test_result, property_1_1); + TestResultAccessor::RecordProperty(&test_result, property_2_1); + TestResultAccessor::RecordProperty(&test_result, property_1_2); + TestResultAccessor::RecordProperty(&test_result, property_2_2); + + ASSERT_EQ(2, test_result.test_property_count()); + const TestProperty& actual_property_1 = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property_1.key()); + EXPECT_STREQ("12", actual_property_1.value()); + + const TestProperty& actual_property_2 = test_result.GetTestProperty(1); + EXPECT_STREQ("key_2", actual_property_2.key()); + EXPECT_STREQ("22", actual_property_2.value()); +} + +// Tests TestResult::GetTestProperty(). +TEST(TestResultPropertyDeathTest, GetTestProperty) { + TestResult test_result; + TestProperty property_1("key_1", "1"); + TestProperty property_2("key_2", "2"); + TestProperty property_3("key_3", "3"); + TestResultAccessor::RecordProperty(&test_result, property_1); + TestResultAccessor::RecordProperty(&test_result, property_2); + TestResultAccessor::RecordProperty(&test_result, property_3); + + const TestProperty& fetched_property_1 = test_result.GetTestProperty(0); + const TestProperty& fetched_property_2 = test_result.GetTestProperty(1); + const TestProperty& fetched_property_3 = test_result.GetTestProperty(2); + + EXPECT_STREQ("key_1", fetched_property_1.key()); + EXPECT_STREQ("1", fetched_property_1.value()); + + EXPECT_STREQ("key_2", fetched_property_2.key()); + EXPECT_STREQ("2", fetched_property_2.value()); + + EXPECT_STREQ("key_3", fetched_property_3.key()); + EXPECT_STREQ("3", fetched_property_3.value()); + + EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(3), ""); + EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(-1), ""); +} + +// When a property using a reserved key is supplied to this function, it tests +// that a non-fatal failure is added, a fatal failure is not added, and that the +// property is not recorded. +void ExpectNonFatalFailureRecordingPropertyWithReservedKey(const char* key) { + TestResult test_result; + TestProperty property(key, "1"); + EXPECT_NONFATAL_FAILURE( + TestResultAccessor::RecordProperty(&test_result, property), + "Reserved key"); + ASSERT_EQ(0, test_result.test_property_count()) << "Not recorded"; +} + +// Attempting to recording a property with the Reserved literal "name" +// should add a non-fatal failure and the property should not be recorded. +TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledName) { + ExpectNonFatalFailureRecordingPropertyWithReservedKey("name"); +} + +// Attempting to recording a property with the Reserved literal "status" +// should add a non-fatal failure and the property should not be recorded. +TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledStatus) { + ExpectNonFatalFailureRecordingPropertyWithReservedKey("status"); +} + +// Attempting to recording a property with the Reserved literal "time" +// should add a non-fatal failure and the property should not be recorded. +TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledTime) { + ExpectNonFatalFailureRecordingPropertyWithReservedKey("time"); +} + +// Attempting to recording a property with the Reserved literal "classname" +// should add a non-fatal failure and the property should not be recorded. +TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledClassname) { + ExpectNonFatalFailureRecordingPropertyWithReservedKey("classname"); +} + +// Tests that GTestFlagSaver works on Windows and Mac. + +class GTestFlagSaverTest : public Test { + protected: + // Saves the Google Test flags such that we can restore them later, and + // then sets them to their default values. This will be called + // before the first test in this test case is run. + static void SetUpTestCase() { + saver_ = new GTestFlagSaver; + + GTEST_FLAG(also_run_disabled_tests) = false; + GTEST_FLAG(break_on_failure) = false; + GTEST_FLAG(catch_exceptions) = false; + GTEST_FLAG(death_test_use_fork) = false; + GTEST_FLAG(color) = "auto"; + GTEST_FLAG(filter) = ""; + GTEST_FLAG(list_tests) = false; + GTEST_FLAG(output) = ""; + GTEST_FLAG(print_time) = true; + GTEST_FLAG(random_seed) = 0; + GTEST_FLAG(repeat) = 1; + GTEST_FLAG(shuffle) = false; + GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; + GTEST_FLAG(stream_result_to) = ""; + GTEST_FLAG(throw_on_failure) = false; + } + + // Restores the Google Test flags that the tests have modified. This will + // be called after the last test in this test case is run. + static void TearDownTestCase() { + delete saver_; + saver_ = NULL; + } + + // Verifies that the Google Test flags have their default values, and then + // modifies each of them. + void VerifyAndModifyFlags() { + EXPECT_FALSE(GTEST_FLAG(also_run_disabled_tests)); + EXPECT_FALSE(GTEST_FLAG(break_on_failure)); + EXPECT_FALSE(GTEST_FLAG(catch_exceptions)); + EXPECT_STREQ("auto", GTEST_FLAG(color).c_str()); + EXPECT_FALSE(GTEST_FLAG(death_test_use_fork)); + EXPECT_STREQ("", GTEST_FLAG(filter).c_str()); + EXPECT_FALSE(GTEST_FLAG(list_tests)); + EXPECT_STREQ("", GTEST_FLAG(output).c_str()); + EXPECT_TRUE(GTEST_FLAG(print_time)); + EXPECT_EQ(0, GTEST_FLAG(random_seed)); + EXPECT_EQ(1, GTEST_FLAG(repeat)); + EXPECT_FALSE(GTEST_FLAG(shuffle)); + EXPECT_EQ(kMaxStackTraceDepth, GTEST_FLAG(stack_trace_depth)); + EXPECT_STREQ("", GTEST_FLAG(stream_result_to).c_str()); + EXPECT_FALSE(GTEST_FLAG(throw_on_failure)); + + GTEST_FLAG(also_run_disabled_tests) = true; + GTEST_FLAG(break_on_failure) = true; + GTEST_FLAG(catch_exceptions) = true; + GTEST_FLAG(color) = "no"; + GTEST_FLAG(death_test_use_fork) = true; + GTEST_FLAG(filter) = "abc"; + GTEST_FLAG(list_tests) = true; + GTEST_FLAG(output) = "xml:foo.xml"; + GTEST_FLAG(print_time) = false; + GTEST_FLAG(random_seed) = 1; + GTEST_FLAG(repeat) = 100; + GTEST_FLAG(shuffle) = true; + GTEST_FLAG(stack_trace_depth) = 1; + GTEST_FLAG(stream_result_to) = "localhost:1234"; + GTEST_FLAG(throw_on_failure) = true; + } + private: + // For saving Google Test flags during this test case. + static GTestFlagSaver* saver_; +}; + +GTestFlagSaver* GTestFlagSaverTest::saver_ = NULL; + +// Google Test doesn't guarantee the order of tests. The following two +// tests are designed to work regardless of their order. + +// Modifies the Google Test flags in the test body. +TEST_F(GTestFlagSaverTest, ModifyGTestFlags) { + VerifyAndModifyFlags(); +} + +// Verifies that the Google Test flags in the body of the previous test were +// restored to their original values. +TEST_F(GTestFlagSaverTest, VerifyGTestFlags) { + VerifyAndModifyFlags(); +} + +// Sets an environment variable with the given name to the given +// value. If the value argument is "", unsets the environment +// variable. The caller must ensure that both arguments are not NULL. +static void SetEnv(const char* name, const char* value) { +#if GTEST_OS_WINDOWS_MOBILE + // Environment variables are not supported on Windows CE. + return; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // C++Builder's putenv only stores a pointer to its parameter; we have to + // ensure that the string remains valid as long as it might be needed. + // We use an std::map to do so. + static std::map added_env; + + // Because putenv stores a pointer to the string buffer, we can't delete the + // previous string (if present) until after it's replaced. + String *prev_env = NULL; + if (added_env.find(name) != added_env.end()) { + prev_env = added_env[name]; + } + added_env[name] = new String((Message() << name << "=" << value).GetString()); + + // The standard signature of putenv accepts a 'char*' argument. Other + // implementations, like C++Builder's, accept a 'const char*'. + // We cast away the 'const' since that would work for both variants. + putenv(const_cast(added_env[name]->c_str())); + delete prev_env; +#elif GTEST_OS_WINDOWS // If we are on Windows proper. + _putenv((Message() << name << "=" << value).GetString().c_str()); +#else + if (*value == '\0') { + unsetenv(name); + } else { + setenv(name, value, 1); + } +#endif // GTEST_OS_WINDOWS_MOBILE +} + +#if !GTEST_OS_WINDOWS_MOBILE +// Environment variables are not supported on Windows CE. + +using testing::internal::Int32FromGTestEnv; + +// Tests Int32FromGTestEnv(). + +// Tests that Int32FromGTestEnv() returns the default value when the +// environment variable is not set. +TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenVariableIsNotSet) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", ""); + EXPECT_EQ(10, Int32FromGTestEnv("temp", 10)); +} + +// Tests that Int32FromGTestEnv() returns the default value when the +// environment variable overflows as an Int32. +TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueOverflows) { + printf("(expecting 2 warnings)\n"); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12345678987654321"); + EXPECT_EQ(20, Int32FromGTestEnv("temp", 20)); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-12345678987654321"); + EXPECT_EQ(30, Int32FromGTestEnv("temp", 30)); +} + +// Tests that Int32FromGTestEnv() returns the default value when the +// environment variable does not represent a valid decimal integer. +TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueIsInvalid) { + printf("(expecting 2 warnings)\n"); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "A1"); + EXPECT_EQ(40, Int32FromGTestEnv("temp", 40)); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12X"); + EXPECT_EQ(50, Int32FromGTestEnv("temp", 50)); +} + +// Tests that Int32FromGTestEnv() parses and returns the value of the +// environment variable when it represents a valid decimal integer in +// the range of an Int32. +TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "123"); + EXPECT_EQ(123, Int32FromGTestEnv("temp", 0)); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321"); + EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0)); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Tests ParseInt32Flag(). + +// Tests that ParseInt32Flag() returns false and doesn't change the +// output value when the flag has wrong format +TEST(ParseInt32FlagTest, ReturnsFalseForInvalidFlag) { + Int32 value = 123; + EXPECT_FALSE(ParseInt32Flag("--a=100", "b", &value)); + EXPECT_EQ(123, value); + + EXPECT_FALSE(ParseInt32Flag("a=100", "a", &value)); + EXPECT_EQ(123, value); +} + +// Tests that ParseInt32Flag() returns false and doesn't change the +// output value when the flag overflows as an Int32. +TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueOverflows) { + printf("(expecting 2 warnings)\n"); + + Int32 value = 123; + EXPECT_FALSE(ParseInt32Flag("--abc=12345678987654321", "abc", &value)); + EXPECT_EQ(123, value); + + EXPECT_FALSE(ParseInt32Flag("--abc=-12345678987654321", "abc", &value)); + EXPECT_EQ(123, value); +} + +// Tests that ParseInt32Flag() returns false and doesn't change the +// output value when the flag does not represent a valid decimal +// integer. +TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueIsInvalid) { + printf("(expecting 2 warnings)\n"); + + Int32 value = 123; + EXPECT_FALSE(ParseInt32Flag("--abc=A1", "abc", &value)); + EXPECT_EQ(123, value); + + EXPECT_FALSE(ParseInt32Flag("--abc=12X", "abc", &value)); + EXPECT_EQ(123, value); +} + +// Tests that ParseInt32Flag() parses the value of the flag and +// returns true when the flag represents a valid decimal integer in +// the range of an Int32. +TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) { + Int32 value = 123; + EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=456", "abc", &value)); + EXPECT_EQ(456, value); + + EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=-789", + "abc", &value)); + EXPECT_EQ(-789, value); +} + +// Tests that Int32FromEnvOrDie() parses the value of the var or +// returns the correct default. +// Environment variables are not supported on Windows CE. +#if !GTEST_OS_WINDOWS_MOBILE +TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { + EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123"); + EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123"); + EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Tests that Int32FromEnvOrDie() aborts with an error message +// if the variable is not an Int32. +TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx"); + EXPECT_DEATH_IF_SUPPORTED( + Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), + ".*"); +} + +// Tests that Int32FromEnvOrDie() aborts with an error message +// if the variable cannot be represnted by an Int32. +TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234"); + EXPECT_DEATH_IF_SUPPORTED( + Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), + ".*"); +} + +// Tests that ShouldRunTestOnShard() selects all tests +// where there is 1 shard. +TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) { + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4)); +} + +class ShouldShardTest : public testing::Test { + protected: + virtual void SetUp() { + index_var_ = GTEST_FLAG_PREFIX_UPPER_ "INDEX"; + total_var_ = GTEST_FLAG_PREFIX_UPPER_ "TOTAL"; + } + + virtual void TearDown() { + SetEnv(index_var_, ""); + SetEnv(total_var_, ""); + } + + const char* index_var_; + const char* total_var_; +}; + +// Tests that sharding is disabled if neither of the environment variables +// are set. +TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet) { + SetEnv(index_var_, ""); + SetEnv(total_var_, ""); + + EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +// Tests that sharding is not enabled if total_shards == 1. +TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) { + SetEnv(index_var_, "0"); + SetEnv(total_var_, "1"); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +// Tests that sharding is enabled if total_shards > 1 and +// we are not in a death test subprocess. +// Environment variables are not supported on Windows CE. +#if !GTEST_OS_WINDOWS_MOBILE +TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { + SetEnv(index_var_, "4"); + SetEnv(total_var_, "22"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); + + SetEnv(index_var_, "8"); + SetEnv(total_var_, "9"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); + + SetEnv(index_var_, "0"); + SetEnv(total_var_, "9"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Tests that we exit in error if the sharding values are not valid. + +typedef ShouldShardTest ShouldShardDeathTest; + +TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid) { + SetEnv(index_var_, "4"); + SetEnv(total_var_, "4"); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); + + SetEnv(index_var_, "4"); + SetEnv(total_var_, "-2"); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); + + SetEnv(index_var_, "5"); + SetEnv(total_var_, ""); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); + + SetEnv(index_var_, ""); + SetEnv(total_var_, "5"); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); +} + +// Tests that ShouldRunTestOnShard is a partition when 5 +// shards are used. +TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) { + // Choose an arbitrary number of tests and shards. + const int num_tests = 17; + const int num_shards = 5; + + // Check partitioning: each test should be on exactly 1 shard. + for (int test_id = 0; test_id < num_tests; test_id++) { + int prev_selected_shard_index = -1; + for (int shard_index = 0; shard_index < num_shards; shard_index++) { + if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) { + if (prev_selected_shard_index < 0) { + prev_selected_shard_index = shard_index; + } else { + ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and " + << shard_index << " are both selected to run test " << test_id; + } + } + } + } + + // Check balance: This is not required by the sharding protocol, but is a + // desirable property for performance. + for (int shard_index = 0; shard_index < num_shards; shard_index++) { + int num_tests_on_shard = 0; + for (int test_id = 0; test_id < num_tests; test_id++) { + num_tests_on_shard += + ShouldRunTestOnShard(num_shards, shard_index, test_id); + } + EXPECT_GE(num_tests_on_shard, num_tests / num_shards); + } +} + +// For the same reason we are not explicitly testing everything in the +// Test class, there are no separate tests for the following classes +// (except for some trivial cases): +// +// TestCase, UnitTest, UnitTestResultPrinter. +// +// Similarly, there are no separate tests for the following macros: +// +// TEST, TEST_F, RUN_ALL_TESTS + +TEST(UnitTestTest, CanGetOriginalWorkingDir) { + ASSERT_TRUE(UnitTest::GetInstance()->original_working_dir() != NULL); + EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), ""); +} + +// This group of tests is for predicate assertions (ASSERT_PRED*, etc) +// of various arities. They do not attempt to be exhaustive. Rather, +// view them as smoke tests that can be easily reviewed and verified. +// A more complete set of tests for predicate assertions can be found +// in gtest_pred_impl_unittest.cc. + +// First, some predicates and predicate-formatters needed by the tests. + +// Returns true iff the argument is an even number. +bool IsEven(int n) { + return (n % 2) == 0; +} + +// A functor that returns true iff the argument is an even number. +struct IsEvenFunctor { + bool operator()(int n) { return IsEven(n); } +}; + +// A predicate-formatter function that asserts the argument is an even +// number. +AssertionResult AssertIsEven(const char* expr, int n) { + if (IsEven(n)) { + return AssertionSuccess(); + } + + Message msg; + msg << expr << " evaluates to " << n << ", which is not even."; + return AssertionFailure(msg); +} + +// A predicate function that returns AssertionResult for use in +// EXPECT/ASSERT_TRUE/FALSE. +AssertionResult ResultIsEven(int n) { + if (IsEven(n)) + return AssertionSuccess() << n << " is even"; + else + return AssertionFailure() << n << " is odd"; +} + +// A predicate function that returns AssertionResult but gives no +// explanation why it succeeds. Needed for testing that +// EXPECT/ASSERT_FALSE handles such functions correctly. +AssertionResult ResultIsEvenNoExplanation(int n) { + if (IsEven(n)) + return AssertionSuccess(); + else + return AssertionFailure() << n << " is odd"; +} + +// A predicate-formatter functor that asserts the argument is an even +// number. +struct AssertIsEvenFunctor { + AssertionResult operator()(const char* expr, int n) { + return AssertIsEven(expr, n); + } +}; + +// Returns true iff the sum of the arguments is an even number. +bool SumIsEven2(int n1, int n2) { + return IsEven(n1 + n2); +} + +// A functor that returns true iff the sum of the arguments is an even +// number. +struct SumIsEven3Functor { + bool operator()(int n1, int n2, int n3) { + return IsEven(n1 + n2 + n3); + } +}; + +// A predicate-formatter function that asserts the sum of the +// arguments is an even number. +AssertionResult AssertSumIsEven4( + const char* e1, const char* e2, const char* e3, const char* e4, + int n1, int n2, int n3, int n4) { + const int sum = n1 + n2 + n3 + n4; + if (IsEven(sum)) { + return AssertionSuccess(); + } + + Message msg; + msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 + << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4 + << ") evaluates to " << sum << ", which is not even."; + return AssertionFailure(msg); +} + +// A predicate-formatter functor that asserts the sum of the arguments +// is an even number. +struct AssertSumIsEven5Functor { + AssertionResult operator()( + const char* e1, const char* e2, const char* e3, const char* e4, + const char* e5, int n1, int n2, int n3, int n4, int n5) { + const int sum = n1 + n2 + n3 + n4 + n5; + if (IsEven(sum)) { + return AssertionSuccess(); + } + + Message msg; + msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 + << " (" + << n1 << " + " << n2 << " + " << n3 << " + " << n4 << " + " << n5 + << ") evaluates to " << sum << ", which is not even."; + return AssertionFailure(msg); + } +}; + + +// Tests unary predicate assertions. + +// Tests unary predicate assertions that don't use a custom formatter. +TEST(Pred1Test, WithoutFormat) { + // Success cases. + EXPECT_PRED1(IsEvenFunctor(), 2) << "This failure is UNEXPECTED!"; + ASSERT_PRED1(IsEven, 4); + + // Failure cases. + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(IsEven, 5) << "This failure is expected."; + }, "This failure is expected."); + EXPECT_FATAL_FAILURE(ASSERT_PRED1(IsEvenFunctor(), 5), + "evaluates to false"); +} + +// Tests unary predicate assertions that use a custom formatter. +TEST(Pred1Test, WithFormat) { + // Success cases. + EXPECT_PRED_FORMAT1(AssertIsEven, 2); + ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), 4) + << "This failure is UNEXPECTED!"; + + // Failure cases. + const int n = 5; + EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT1(AssertIsEvenFunctor(), n), + "n evaluates to 5, which is not even."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(AssertIsEven, 5) << "This failure is expected."; + }, "This failure is expected."); +} + +// Tests that unary predicate assertions evaluates their arguments +// exactly once. +TEST(Pred1Test, SingleEvaluationOnFailure) { + // A success case. + static int n = 0; + EXPECT_PRED1(IsEven, n++); + EXPECT_EQ(1, n) << "The argument is not evaluated exactly once."; + + // A failure case. + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), n++) + << "This failure is expected."; + }, "This failure is expected."); + EXPECT_EQ(2, n) << "The argument is not evaluated exactly once."; +} + + +// Tests predicate assertions whose arity is >= 2. + +// Tests predicate assertions that don't use a custom formatter. +TEST(PredTest, WithoutFormat) { + // Success cases. + ASSERT_PRED2(SumIsEven2, 2, 4) << "This failure is UNEXPECTED!"; + EXPECT_PRED3(SumIsEven3Functor(), 4, 6, 8); + + // Failure cases. + const int n1 = 1; + const int n2 = 2; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(SumIsEven2, n1, n2) << "This failure is expected."; + }, "This failure is expected."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(SumIsEven3Functor(), 1, 2, 4); + }, "evaluates to false"); +} + +// Tests predicate assertions that use a custom formatter. +TEST(PredTest, WithFormat) { + // Success cases. + ASSERT_PRED_FORMAT4(AssertSumIsEven4, 4, 6, 8, 10) << + "This failure is UNEXPECTED!"; + EXPECT_PRED_FORMAT5(AssertSumIsEven5Functor(), 2, 4, 6, 8, 10); + + // Failure cases. + const int n1 = 1; + const int n2 = 2; + const int n3 = 4; + const int n4 = 6; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(AssertSumIsEven4, n1, n2, n3, n4); + }, "evaluates to 13, which is not even."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), 1, 2, 4, 6, 8) + << "This failure is expected."; + }, "This failure is expected."); +} + +// Tests that predicate assertions evaluates their arguments +// exactly once. +TEST(PredTest, SingleEvaluationOnFailure) { + // A success case. + int n1 = 0; + int n2 = 0; + EXPECT_PRED2(SumIsEven2, n1++, n2++); + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + + // Another success case. + n1 = n2 = 0; + int n3 = 0; + int n4 = 0; + int n5 = 0; + ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), + n1++, n2++, n3++, n4++, n5++) + << "This failure is UNEXPECTED!"; + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; + EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; + EXPECT_EQ(1, n5) << "Argument 5 is not evaluated exactly once."; + + // A failure case. + n1 = n2 = n3 = 0; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(SumIsEven3Functor(), ++n1, n2++, n3++) + << "This failure is expected."; + }, "This failure is expected."); + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; + + // Another failure case. + n1 = n2 = n3 = n4 = 0; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(AssertSumIsEven4, ++n1, n2++, n3++, n4++); + }, "evaluates to 1, which is not even."); + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; + EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; +} + + +// Some helper functions for testing using overloaded/template +// functions with ASSERT_PREDn and EXPECT_PREDn. + +bool IsPositive(double x) { + return x > 0; +} + +template +bool IsNegative(T x) { + return x < 0; +} + +template +bool GreaterThan(T1 x1, T2 x2) { + return x1 > x2; +} + +// Tests that overloaded functions can be used in *_PRED* as long as +// their types are explicitly specified. +TEST(PredicateAssertionTest, AcceptsOverloadedFunction) { + // C++Builder requires C-style casts rather than static_cast. + EXPECT_PRED1((bool (*)(int))(IsPositive), 5); // NOLINT + ASSERT_PRED1((bool (*)(double))(IsPositive), 6.0); // NOLINT +} + +// Tests that template functions can be used in *_PRED* as long as +// their types are explicitly specified. +TEST(PredicateAssertionTest, AcceptsTemplateFunction) { + EXPECT_PRED1(IsNegative, -5); + // Makes sure that we can handle templates with more than one + // parameter. + ASSERT_PRED2((GreaterThan), 5, 0); +} + + +// Some helper functions for testing using overloaded/template +// functions with ASSERT_PRED_FORMATn and EXPECT_PRED_FORMATn. + +AssertionResult IsPositiveFormat(const char* /* expr */, int n) { + return n > 0 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +AssertionResult IsPositiveFormat(const char* /* expr */, double x) { + return x > 0 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +template +AssertionResult IsNegativeFormat(const char* /* expr */, T x) { + return x < 0 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +template +AssertionResult EqualsFormat(const char* /* expr1 */, const char* /* expr2 */, + const T1& x1, const T2& x2) { + return x1 == x2 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +// Tests that overloaded functions can be used in *_PRED_FORMAT* +// without explicitly specifying their types. +TEST(PredicateFormatAssertionTest, AcceptsOverloadedFunction) { + EXPECT_PRED_FORMAT1(IsPositiveFormat, 5); + ASSERT_PRED_FORMAT1(IsPositiveFormat, 6.0); +} + +// Tests that template functions can be used in *_PRED_FORMAT* without +// explicitly specifying their types. +TEST(PredicateFormatAssertionTest, AcceptsTemplateFunction) { + EXPECT_PRED_FORMAT1(IsNegativeFormat, -5); + ASSERT_PRED_FORMAT2(EqualsFormat, 3, 3); +} + + +// Tests string assertions. + +// Tests ASSERT_STREQ with non-NULL arguments. +TEST(StringAssertionTest, ASSERT_STREQ) { + const char * const p1 = "good"; + ASSERT_STREQ(p1, p1); + + // Let p2 have the same content as p1, but be at a different address. + const char p2[] = "good"; + ASSERT_STREQ(p1, p2); + + EXPECT_FATAL_FAILURE(ASSERT_STREQ("bad", "good"), + "Expected: \"bad\""); +} + +// Tests ASSERT_STREQ with NULL arguments. +TEST(StringAssertionTest, ASSERT_STREQ_Null) { + ASSERT_STREQ(static_cast(NULL), NULL); + EXPECT_FATAL_FAILURE(ASSERT_STREQ(NULL, "non-null"), + "non-null"); +} + +// Tests ASSERT_STREQ with NULL arguments. +TEST(StringAssertionTest, ASSERT_STREQ_Null2) { + EXPECT_FATAL_FAILURE(ASSERT_STREQ("non-null", NULL), + "non-null"); +} + +// Tests ASSERT_STRNE. +TEST(StringAssertionTest, ASSERT_STRNE) { + ASSERT_STRNE("hi", "Hi"); + ASSERT_STRNE("Hi", NULL); + ASSERT_STRNE(NULL, "Hi"); + ASSERT_STRNE("", NULL); + ASSERT_STRNE(NULL, ""); + ASSERT_STRNE("", "Hi"); + ASSERT_STRNE("Hi", ""); + EXPECT_FATAL_FAILURE(ASSERT_STRNE("Hi", "Hi"), + "\"Hi\" vs \"Hi\""); +} + +// Tests ASSERT_STRCASEEQ. +TEST(StringAssertionTest, ASSERT_STRCASEEQ) { + ASSERT_STRCASEEQ("hi", "Hi"); + ASSERT_STRCASEEQ(static_cast(NULL), NULL); + + ASSERT_STRCASEEQ("", ""); + EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("Hi", "hi2"), + "(ignoring case)"); +} + +// Tests ASSERT_STRCASENE. +TEST(StringAssertionTest, ASSERT_STRCASENE) { + ASSERT_STRCASENE("hi1", "Hi2"); + ASSERT_STRCASENE("Hi", NULL); + ASSERT_STRCASENE(NULL, "Hi"); + ASSERT_STRCASENE("", NULL); + ASSERT_STRCASENE(NULL, ""); + ASSERT_STRCASENE("", "Hi"); + ASSERT_STRCASENE("Hi", ""); + EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("Hi", "hi"), + "(ignoring case)"); +} + +// Tests *_STREQ on wide strings. +TEST(StringAssertionTest, STREQ_Wide) { + // NULL strings. + ASSERT_STREQ(static_cast(NULL), NULL); + + // Empty strings. + ASSERT_STREQ(L"", L""); + + // Non-null vs NULL. + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"non-null", NULL), + "non-null"); + + // Equal strings. + EXPECT_STREQ(L"Hi", L"Hi"); + + // Unequal strings. + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc", L"Abc"), + "Abc"); + + // Strings containing wide characters. + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc\x8119", L"abc\x8120"), + "abc"); +} + +// Tests *_STRNE on wide strings. +TEST(StringAssertionTest, STRNE_Wide) { + // NULL strings. + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_STRNE(static_cast(NULL), NULL); + }, ""); + + // Empty strings. + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"", L""), + "L\"\""); + + // Non-null vs NULL. + ASSERT_STRNE(L"non-null", NULL); + + // Equal strings. + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"Hi", L"Hi"), + "L\"Hi\""); + + // Unequal strings. + EXPECT_STRNE(L"abc", L"Abc"); + + // Strings containing wide characters. + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"abc\x8119", L"abc\x8119"), + "abc"); +} + +// Tests for ::testing::IsSubstring(). + +// Tests that IsSubstring() returns the correct result when the input +// argument type is const char*. +TEST(IsSubstringTest, ReturnsCorrectResultForCString) { + EXPECT_FALSE(IsSubstring("", "", NULL, "a")); + EXPECT_FALSE(IsSubstring("", "", "b", NULL)); + EXPECT_FALSE(IsSubstring("", "", "needle", "haystack")); + + EXPECT_TRUE(IsSubstring("", "", static_cast(NULL), NULL)); + EXPECT_TRUE(IsSubstring("", "", "needle", "two needles")); +} + +// Tests that IsSubstring() returns the correct result when the input +// argument type is const wchar_t*. +TEST(IsSubstringTest, ReturnsCorrectResultForWideCString) { + EXPECT_FALSE(IsSubstring("", "", kNull, L"a")); + EXPECT_FALSE(IsSubstring("", "", L"b", kNull)); + EXPECT_FALSE(IsSubstring("", "", L"needle", L"haystack")); + + EXPECT_TRUE(IsSubstring("", "", static_cast(NULL), NULL)); + EXPECT_TRUE(IsSubstring("", "", L"needle", L"two needles")); +} + +// Tests that IsSubstring() generates the correct message when the input +// argument type is const char*. +TEST(IsSubstringTest, GeneratesCorrectMessageForCString) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: \"needle\"\n" + "Expected: a substring of haystack_expr\n" + "Which is: \"haystack\"", + IsSubstring("needle_expr", "haystack_expr", + "needle", "haystack").failure_message()); +} + +// Tests that IsSubstring returns the correct result when the input +// argument type is ::std::string. +TEST(IsSubstringTest, ReturnsCorrectResultsForStdString) { + EXPECT_TRUE(IsSubstring("", "", std::string("hello"), "ahellob")); + EXPECT_FALSE(IsSubstring("", "", "hello", std::string("world"))); +} + +#if GTEST_HAS_STD_WSTRING +// Tests that IsSubstring returns the correct result when the input +// argument type is ::std::wstring. +TEST(IsSubstringTest, ReturnsCorrectResultForStdWstring) { + EXPECT_TRUE(IsSubstring("", "", ::std::wstring(L"needle"), L"two needles")); + EXPECT_FALSE(IsSubstring("", "", L"needle", ::std::wstring(L"haystack"))); +} + +// Tests that IsSubstring() generates the correct message when the input +// argument type is ::std::wstring. +TEST(IsSubstringTest, GeneratesCorrectMessageForWstring) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: L\"needle\"\n" + "Expected: a substring of haystack_expr\n" + "Which is: L\"haystack\"", + IsSubstring( + "needle_expr", "haystack_expr", + ::std::wstring(L"needle"), L"haystack").failure_message()); +} + +#endif // GTEST_HAS_STD_WSTRING + +// Tests for ::testing::IsNotSubstring(). + +// Tests that IsNotSubstring() returns the correct result when the input +// argument type is const char*. +TEST(IsNotSubstringTest, ReturnsCorrectResultForCString) { + EXPECT_TRUE(IsNotSubstring("", "", "needle", "haystack")); + EXPECT_FALSE(IsNotSubstring("", "", "needle", "two needles")); +} + +// Tests that IsNotSubstring() returns the correct result when the input +// argument type is const wchar_t*. +TEST(IsNotSubstringTest, ReturnsCorrectResultForWideCString) { + EXPECT_TRUE(IsNotSubstring("", "", L"needle", L"haystack")); + EXPECT_FALSE(IsNotSubstring("", "", L"needle", L"two needles")); +} + +// Tests that IsNotSubstring() generates the correct message when the input +// argument type is const wchar_t*. +TEST(IsNotSubstringTest, GeneratesCorrectMessageForWideCString) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: L\"needle\"\n" + "Expected: not a substring of haystack_expr\n" + "Which is: L\"two needles\"", + IsNotSubstring( + "needle_expr", "haystack_expr", + L"needle", L"two needles").failure_message()); +} + +// Tests that IsNotSubstring returns the correct result when the input +// argument type is ::std::string. +TEST(IsNotSubstringTest, ReturnsCorrectResultsForStdString) { + EXPECT_FALSE(IsNotSubstring("", "", std::string("hello"), "ahellob")); + EXPECT_TRUE(IsNotSubstring("", "", "hello", std::string("world"))); +} + +// Tests that IsNotSubstring() generates the correct message when the input +// argument type is ::std::string. +TEST(IsNotSubstringTest, GeneratesCorrectMessageForStdString) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: \"needle\"\n" + "Expected: not a substring of haystack_expr\n" + "Which is: \"two needles\"", + IsNotSubstring( + "needle_expr", "haystack_expr", + ::std::string("needle"), "two needles").failure_message()); +} + +#if GTEST_HAS_STD_WSTRING + +// Tests that IsNotSubstring returns the correct result when the input +// argument type is ::std::wstring. +TEST(IsNotSubstringTest, ReturnsCorrectResultForStdWstring) { + EXPECT_FALSE( + IsNotSubstring("", "", ::std::wstring(L"needle"), L"two needles")); + EXPECT_TRUE(IsNotSubstring("", "", L"needle", ::std::wstring(L"haystack"))); +} + +#endif // GTEST_HAS_STD_WSTRING + +// Tests floating-point assertions. + +template +class FloatingPointTest : public Test { + protected: + + // Pre-calculated numbers to be used by the tests. + struct TestValues { + RawType close_to_positive_zero; + RawType close_to_negative_zero; + RawType further_from_negative_zero; + + RawType close_to_one; + RawType further_from_one; + + RawType infinity; + RawType close_to_infinity; + RawType further_from_infinity; + + RawType nan1; + RawType nan2; + }; + + typedef typename testing::internal::FloatingPoint Floating; + typedef typename Floating::Bits Bits; + + virtual void SetUp() { + const size_t max_ulps = Floating::kMaxUlps; + + // The bits that represent 0.0. + const Bits zero_bits = Floating(0).bits(); + + // Makes some numbers close to 0.0. + values_.close_to_positive_zero = Floating::ReinterpretBits( + zero_bits + max_ulps/2); + values_.close_to_negative_zero = -Floating::ReinterpretBits( + zero_bits + max_ulps - max_ulps/2); + values_.further_from_negative_zero = -Floating::ReinterpretBits( + zero_bits + max_ulps + 1 - max_ulps/2); + + // The bits that represent 1.0. + const Bits one_bits = Floating(1).bits(); + + // Makes some numbers close to 1.0. + values_.close_to_one = Floating::ReinterpretBits(one_bits + max_ulps); + values_.further_from_one = Floating::ReinterpretBits( + one_bits + max_ulps + 1); + + // +infinity. + values_.infinity = Floating::Infinity(); + + // The bits that represent +infinity. + const Bits infinity_bits = Floating(values_.infinity).bits(); + + // Makes some numbers close to infinity. + values_.close_to_infinity = Floating::ReinterpretBits( + infinity_bits - max_ulps); + values_.further_from_infinity = Floating::ReinterpretBits( + infinity_bits - max_ulps - 1); + + // Makes some NAN's. Sets the most significant bit of the fraction so that + // our NaN's are quiet; trying to process a signaling NaN would raise an + // exception if our environment enables floating point exceptions. + values_.nan1 = Floating::ReinterpretBits(Floating::kExponentBitMask + | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 1); + values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask + | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 200); + } + + void TestSize() { + EXPECT_EQ(sizeof(RawType), sizeof(Bits)); + } + + static TestValues values_; +}; + +template +typename FloatingPointTest::TestValues + FloatingPointTest::values_; + +// Instantiates FloatingPointTest for testing *_FLOAT_EQ. +typedef FloatingPointTest FloatTest; + +// Tests that the size of Float::Bits matches the size of float. +TEST_F(FloatTest, Size) { + TestSize(); +} + +// Tests comparing with +0 and -0. +TEST_F(FloatTest, Zeros) { + EXPECT_FLOAT_EQ(0.0, -0.0); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(-0.0, 1.0), + "1.0"); + EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.5), + "1.5"); +} + +// Tests comparing numbers close to 0. +// +// This ensures that *_FLOAT_EQ handles the sign correctly and no +// overflow occurs when comparing numbers whose absolute value is very +// small. +TEST_F(FloatTest, AlmostZeros) { + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const FloatTest::TestValues& v = this->values_; + + EXPECT_FLOAT_EQ(0.0, v.close_to_positive_zero); + EXPECT_FLOAT_EQ(-0.0, v.close_to_negative_zero); + EXPECT_FLOAT_EQ(v.close_to_positive_zero, v.close_to_negative_zero); + + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_FLOAT_EQ(v.close_to_positive_zero, + v.further_from_negative_zero); + }, "v.further_from_negative_zero"); +} + +// Tests comparing numbers close to each other. +TEST_F(FloatTest, SmallDiff) { + EXPECT_FLOAT_EQ(1.0, values_.close_to_one); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, values_.further_from_one), + "values_.further_from_one"); +} + +// Tests comparing numbers far apart. +TEST_F(FloatTest, LargeDiff) { + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(2.5, 3.0), + "3.0"); +} + +// Tests comparing with infinity. +// +// This ensures that no overflow occurs when comparing numbers whose +// absolute value is very large. +TEST_F(FloatTest, Infinity) { + EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity); + EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity); +#if !GTEST_OS_SYMBIAN + // Nokia's STLport crashes if we try to output infinity or NaN. + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity), + "-values_.infinity"); + + // This is interesting as the representations of infinity and nan1 + // are only 1 DLP apart. + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, values_.nan1), + "values_.nan1"); +#endif // !GTEST_OS_SYMBIAN +} + +// Tests that comparing with NAN always returns false. +TEST_F(FloatTest, NaN) { +#if !GTEST_OS_SYMBIAN +// Nokia's STLport crashes if we try to output infinity or NaN. + + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const FloatTest::TestValues& v = this->values_; + + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1), + "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2), + "v.nan2"); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1), + "v.nan1"); + + EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity), + "v.infinity"); +#endif // !GTEST_OS_SYMBIAN +} + +// Tests that *_FLOAT_EQ are reflexive. +TEST_F(FloatTest, Reflexive) { + EXPECT_FLOAT_EQ(0.0, 0.0); + EXPECT_FLOAT_EQ(1.0, 1.0); + ASSERT_FLOAT_EQ(values_.infinity, values_.infinity); +} + +// Tests that *_FLOAT_EQ are commutative. +TEST_F(FloatTest, Commutative) { + // We already tested EXPECT_FLOAT_EQ(1.0, values_.close_to_one). + EXPECT_FLOAT_EQ(values_.close_to_one, 1.0); + + // We already tested EXPECT_FLOAT_EQ(1.0, values_.further_from_one). + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.further_from_one, 1.0), + "1.0"); +} + +// Tests EXPECT_NEAR. +TEST_F(FloatTest, EXPECT_NEAR) { + EXPECT_NEAR(-1.0f, -1.1f, 0.2f); + EXPECT_NEAR(2.0f, 3.0f, 1.0f); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f,1.5f, 0.25f), // NOLINT + "The difference between 1.0f and 1.5f is 0.5, " + "which exceeds 0.25f"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous line. +} + +// Tests ASSERT_NEAR. +TEST_F(FloatTest, ASSERT_NEAR) { + ASSERT_NEAR(-1.0f, -1.1f, 0.2f); + ASSERT_NEAR(2.0f, 3.0f, 1.0f); + EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0f,1.5f, 0.25f), // NOLINT + "The difference between 1.0f and 1.5f is 0.5, " + "which exceeds 0.25f"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous line. +} + +// Tests the cases where FloatLE() should succeed. +TEST_F(FloatTest, FloatLESucceeds) { + EXPECT_PRED_FORMAT2(FloatLE, 1.0f, 2.0f); // When val1 < val2, + ASSERT_PRED_FORMAT2(FloatLE, 1.0f, 1.0f); // val1 == val2, + + // or when val1 is greater than, but almost equals to, val2. + EXPECT_PRED_FORMAT2(FloatLE, values_.close_to_positive_zero, 0.0f); +} + +// Tests the cases where FloatLE() should fail. +TEST_F(FloatTest, FloatLEFails) { + // When val1 is greater than val2 by a large margin, + EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(FloatLE, 2.0f, 1.0f), + "(2.0f) <= (1.0f)"); + + // or by a small yet non-negligible margin, + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(FloatLE, values_.further_from_one, 1.0f); + }, "(values_.further_from_one) <= (1.0f)"); + +#if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) + // Nokia's STLport crashes if we try to output infinity or NaN. + // C++Builder gives bad results for ordered comparisons involving NaNs + // due to compiler bugs. + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(FloatLE, values_.nan1, values_.infinity); + }, "(values_.nan1) <= (values_.infinity)"); + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(FloatLE, -values_.infinity, values_.nan1); + }, "(-values_.infinity) <= (values_.nan1)"); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(FloatLE, values_.nan1, values_.nan1); + }, "(values_.nan1) <= (values_.nan1)"); +#endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) +} + +// Instantiates FloatingPointTest for testing *_DOUBLE_EQ. +typedef FloatingPointTest DoubleTest; + +// Tests that the size of Double::Bits matches the size of double. +TEST_F(DoubleTest, Size) { + TestSize(); +} + +// Tests comparing with +0 and -0. +TEST_F(DoubleTest, Zeros) { + EXPECT_DOUBLE_EQ(0.0, -0.0); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(-0.0, 1.0), + "1.0"); + EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(0.0, 1.0), + "1.0"); +} + +// Tests comparing numbers close to 0. +// +// This ensures that *_DOUBLE_EQ handles the sign correctly and no +// overflow occurs when comparing numbers whose absolute value is very +// small. +TEST_F(DoubleTest, AlmostZeros) { + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const DoubleTest::TestValues& v = this->values_; + + EXPECT_DOUBLE_EQ(0.0, v.close_to_positive_zero); + EXPECT_DOUBLE_EQ(-0.0, v.close_to_negative_zero); + EXPECT_DOUBLE_EQ(v.close_to_positive_zero, v.close_to_negative_zero); + + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_DOUBLE_EQ(v.close_to_positive_zero, + v.further_from_negative_zero); + }, "v.further_from_negative_zero"); +} + +// Tests comparing numbers close to each other. +TEST_F(DoubleTest, SmallDiff) { + EXPECT_DOUBLE_EQ(1.0, values_.close_to_one); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, values_.further_from_one), + "values_.further_from_one"); +} + +// Tests comparing numbers far apart. +TEST_F(DoubleTest, LargeDiff) { + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(2.0, 3.0), + "3.0"); +} + +// Tests comparing with infinity. +// +// This ensures that no overflow occurs when comparing numbers whose +// absolute value is very large. +TEST_F(DoubleTest, Infinity) { + EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity); + EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity); +#if !GTEST_OS_SYMBIAN + // Nokia's STLport crashes if we try to output infinity or NaN. + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity), + "-values_.infinity"); + + // This is interesting as the representations of infinity_ and nan1_ + // are only 1 DLP apart. + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, values_.nan1), + "values_.nan1"); +#endif // !GTEST_OS_SYMBIAN +} + +// Tests that comparing with NAN always returns false. +TEST_F(DoubleTest, NaN) { +#if !GTEST_OS_SYMBIAN + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const DoubleTest::TestValues& v = this->values_; + + // Nokia's STLport crashes if we try to output infinity or NaN. + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1), + "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2"); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1"); + EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity), + "v.infinity"); +#endif // !GTEST_OS_SYMBIAN +} + +// Tests that *_DOUBLE_EQ are reflexive. +TEST_F(DoubleTest, Reflexive) { + EXPECT_DOUBLE_EQ(0.0, 0.0); + EXPECT_DOUBLE_EQ(1.0, 1.0); +#if !GTEST_OS_SYMBIAN + // Nokia's STLport crashes if we try to output infinity or NaN. + ASSERT_DOUBLE_EQ(values_.infinity, values_.infinity); +#endif // !GTEST_OS_SYMBIAN +} + +// Tests that *_DOUBLE_EQ are commutative. +TEST_F(DoubleTest, Commutative) { + // We already tested EXPECT_DOUBLE_EQ(1.0, values_.close_to_one). + EXPECT_DOUBLE_EQ(values_.close_to_one, 1.0); + + // We already tested EXPECT_DOUBLE_EQ(1.0, values_.further_from_one). + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.further_from_one, 1.0), + "1.0"); +} + +// Tests EXPECT_NEAR. +TEST_F(DoubleTest, EXPECT_NEAR) { + EXPECT_NEAR(-1.0, -1.1, 0.2); + EXPECT_NEAR(2.0, 3.0, 1.0); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT + "The difference between 1.0 and 1.5 is 0.5, " + "which exceeds 0.25"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous statement. +} + +// Tests ASSERT_NEAR. +TEST_F(DoubleTest, ASSERT_NEAR) { + ASSERT_NEAR(-1.0, -1.1, 0.2); + ASSERT_NEAR(2.0, 3.0, 1.0); + EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0, 1.5, 0.25), // NOLINT + "The difference between 1.0 and 1.5 is 0.5, " + "which exceeds 0.25"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous statement. +} + +// Tests the cases where DoubleLE() should succeed. +TEST_F(DoubleTest, DoubleLESucceeds) { + EXPECT_PRED_FORMAT2(DoubleLE, 1.0, 2.0); // When val1 < val2, + ASSERT_PRED_FORMAT2(DoubleLE, 1.0, 1.0); // val1 == val2, + + // or when val1 is greater than, but almost equals to, val2. + EXPECT_PRED_FORMAT2(DoubleLE, values_.close_to_positive_zero, 0.0); +} + +// Tests the cases where DoubleLE() should fail. +TEST_F(DoubleTest, DoubleLEFails) { + // When val1 is greater than val2 by a large margin, + EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(DoubleLE, 2.0, 1.0), + "(2.0) <= (1.0)"); + + // or by a small yet non-negligible margin, + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(DoubleLE, values_.further_from_one, 1.0); + }, "(values_.further_from_one) <= (1.0)"); + +#if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) + // Nokia's STLport crashes if we try to output infinity or NaN. + // C++Builder gives bad results for ordered comparisons involving NaNs + // due to compiler bugs. + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.infinity); + }, "(values_.nan1) <= (values_.infinity)"); + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(DoubleLE, -values_.infinity, values_.nan1); + }, " (-values_.infinity) <= (values_.nan1)"); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.nan1); + }, "(values_.nan1) <= (values_.nan1)"); +#endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) +} + + +// Verifies that a test or test case whose name starts with DISABLED_ is +// not run. + +// A test whose name starts with DISABLED_. +// Should not run. +TEST(DisabledTest, DISABLED_TestShouldNotRun) { + FAIL() << "Unexpected failure: Disabled test should not be run."; +} + +// A test whose name does not start with DISABLED_. +// Should run. +TEST(DisabledTest, NotDISABLED_TestShouldRun) { + EXPECT_EQ(1, 1); +} + +// A test case whose name starts with DISABLED_. +// Should not run. +TEST(DISABLED_TestCase, TestShouldNotRun) { + FAIL() << "Unexpected failure: Test in disabled test case should not be run."; +} + +// A test case and test whose names start with DISABLED_. +// Should not run. +TEST(DISABLED_TestCase, DISABLED_TestShouldNotRun) { + FAIL() << "Unexpected failure: Test in disabled test case should not be run."; +} + +// Check that when all tests in a test case are disabled, SetupTestCase() and +// TearDownTestCase() are not called. +class DisabledTestsTest : public Test { + protected: + static void SetUpTestCase() { + FAIL() << "Unexpected failure: All tests disabled in test case. " + "SetupTestCase() should not be called."; + } + + static void TearDownTestCase() { + FAIL() << "Unexpected failure: All tests disabled in test case. " + "TearDownTestCase() should not be called."; + } +}; + +TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_1) { + FAIL() << "Unexpected failure: Disabled test should not be run."; +} + +TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2) { + FAIL() << "Unexpected failure: Disabled test should not be run."; +} + +// Tests that disabled typed tests aren't run. + +#if GTEST_HAS_TYPED_TEST + +template +class TypedTest : public Test { +}; + +typedef testing::Types NumericTypes; +TYPED_TEST_CASE(TypedTest, NumericTypes); + +TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) { + FAIL() << "Unexpected failure: Disabled typed test should not run."; +} + +template +class DISABLED_TypedTest : public Test { +}; + +TYPED_TEST_CASE(DISABLED_TypedTest, NumericTypes); + +TYPED_TEST(DISABLED_TypedTest, ShouldNotRun) { + FAIL() << "Unexpected failure: Disabled typed test should not run."; +} + +#endif // GTEST_HAS_TYPED_TEST + +// Tests that disabled type-parameterized tests aren't run. + +#if GTEST_HAS_TYPED_TEST_P + +template +class TypedTestP : public Test { +}; + +TYPED_TEST_CASE_P(TypedTestP); + +TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun) { + FAIL() << "Unexpected failure: " + << "Disabled type-parameterized test should not run."; +} + +REGISTER_TYPED_TEST_CASE_P(TypedTestP, DISABLED_ShouldNotRun); + +INSTANTIATE_TYPED_TEST_CASE_P(My, TypedTestP, NumericTypes); + +template +class DISABLED_TypedTestP : public Test { +}; + +TYPED_TEST_CASE_P(DISABLED_TypedTestP); + +TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun) { + FAIL() << "Unexpected failure: " + << "Disabled type-parameterized test should not run."; +} + +REGISTER_TYPED_TEST_CASE_P(DISABLED_TypedTestP, ShouldNotRun); + +INSTANTIATE_TYPED_TEST_CASE_P(My, DISABLED_TypedTestP, NumericTypes); + +#endif // GTEST_HAS_TYPED_TEST_P + +// Tests that assertion macros evaluate their arguments exactly once. + +class SingleEvaluationTest : public Test { + public: // Must be public and not protected due to a bug in g++ 3.4.2. + // This helper function is needed by the FailedASSERT_STREQ test + // below. It's public to work around C++Builder's bug with scoping local + // classes. + static void CompareAndIncrementCharPtrs() { + ASSERT_STREQ(p1_++, p2_++); + } + + // This helper function is needed by the FailedASSERT_NE test below. It's + // public to work around C++Builder's bug with scoping local classes. + static void CompareAndIncrementInts() { + ASSERT_NE(a_++, b_++); + } + + protected: + SingleEvaluationTest() { + p1_ = s1_; + p2_ = s2_; + a_ = 0; + b_ = 0; + } + + static const char* const s1_; + static const char* const s2_; + static const char* p1_; + static const char* p2_; + + static int a_; + static int b_; +}; + +const char* const SingleEvaluationTest::s1_ = "01234"; +const char* const SingleEvaluationTest::s2_ = "abcde"; +const char* SingleEvaluationTest::p1_; +const char* SingleEvaluationTest::p2_; +int SingleEvaluationTest::a_; +int SingleEvaluationTest::b_; + +// Tests that when ASSERT_STREQ fails, it evaluates its arguments +// exactly once. +TEST_F(SingleEvaluationTest, FailedASSERT_STREQ) { + EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementCharPtrs(), + "p2_++"); + EXPECT_EQ(s1_ + 1, p1_); + EXPECT_EQ(s2_ + 1, p2_); +} + +// Tests that string assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, ASSERT_STR) { + // successful EXPECT_STRNE + EXPECT_STRNE(p1_++, p2_++); + EXPECT_EQ(s1_ + 1, p1_); + EXPECT_EQ(s2_ + 1, p2_); + + // failed EXPECT_STRCASEEQ + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ(p1_++, p2_++), + "ignoring case"); + EXPECT_EQ(s1_ + 2, p1_); + EXPECT_EQ(s2_ + 2, p2_); +} + +// Tests that when ASSERT_NE fails, it evaluates its arguments exactly +// once. +TEST_F(SingleEvaluationTest, FailedASSERT_NE) { + EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementInts(), + "(a_++) != (b_++)"); + EXPECT_EQ(1, a_); + EXPECT_EQ(1, b_); +} + +// Tests that assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, OtherCases) { + // successful EXPECT_TRUE + EXPECT_TRUE(0 == a_++); // NOLINT + EXPECT_EQ(1, a_); + + // failed EXPECT_TRUE + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(-1 == a_++), "-1 == a_++"); + EXPECT_EQ(2, a_); + + // successful EXPECT_GT + EXPECT_GT(a_++, b_++); + EXPECT_EQ(3, a_); + EXPECT_EQ(1, b_); + + // failed EXPECT_LT + EXPECT_NONFATAL_FAILURE(EXPECT_LT(a_++, b_++), "(a_++) < (b_++)"); + EXPECT_EQ(4, a_); + EXPECT_EQ(2, b_); + + // successful ASSERT_TRUE + ASSERT_TRUE(0 < a_++); // NOLINT + EXPECT_EQ(5, a_); + + // successful ASSERT_GT + ASSERT_GT(a_++, b_++); + EXPECT_EQ(6, a_); + EXPECT_EQ(3, b_); +} + +#if GTEST_HAS_EXCEPTIONS + +void ThrowAnInteger() { + throw 1; +} + +// Tests that assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, ExceptionTests) { + // successful EXPECT_THROW + EXPECT_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }, int); + EXPECT_EQ(1, a_); + + // failed EXPECT_THROW, throws different + EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }, bool), "throws a different type"); + EXPECT_EQ(2, a_); + + // failed EXPECT_THROW, throws nothing + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); + EXPECT_EQ(3, a_); + + // successful EXPECT_NO_THROW + EXPECT_NO_THROW(a_++); + EXPECT_EQ(4, a_); + + // failed EXPECT_NO_THROW + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }), "it throws"); + EXPECT_EQ(5, a_); + + // successful EXPECT_ANY_THROW + EXPECT_ANY_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }); + EXPECT_EQ(6, a_); + + // failed EXPECT_ANY_THROW + EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); + EXPECT_EQ(7, a_); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests {ASSERT|EXPECT}_NO_FATAL_FAILURE. +class NoFatalFailureTest : public Test { + protected: + void Succeeds() {} + void FailsNonFatal() { + ADD_FAILURE() << "some non-fatal failure"; + } + void Fails() { + FAIL() << "some fatal failure"; + } + + void DoAssertNoFatalFailureOnFails() { + ASSERT_NO_FATAL_FAILURE(Fails()); + ADD_FAILURE() << "shold not reach here."; + } + + void DoExpectNoFatalFailureOnFails() { + EXPECT_NO_FATAL_FAILURE(Fails()); + ADD_FAILURE() << "other failure"; + } +}; + +TEST_F(NoFatalFailureTest, NoFailure) { + EXPECT_NO_FATAL_FAILURE(Succeeds()); + ASSERT_NO_FATAL_FAILURE(Succeeds()); +} + +TEST_F(NoFatalFailureTest, NonFatalIsNoFailure) { + EXPECT_NONFATAL_FAILURE( + EXPECT_NO_FATAL_FAILURE(FailsNonFatal()), + "some non-fatal failure"); + EXPECT_NONFATAL_FAILURE( + ASSERT_NO_FATAL_FAILURE(FailsNonFatal()), + "some non-fatal failure"); +} + +TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure) { + TestPartResultArray gtest_failures; + { + ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); + DoAssertNoFatalFailureOnFails(); + } + ASSERT_EQ(2, gtest_failures.size()); + EXPECT_EQ(TestPartResult::kFatalFailure, + gtest_failures.GetTestPartResult(0).type()); + EXPECT_EQ(TestPartResult::kFatalFailure, + gtest_failures.GetTestPartResult(1).type()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", + gtest_failures.GetTestPartResult(0).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", + gtest_failures.GetTestPartResult(1).message()); +} + +TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure) { + TestPartResultArray gtest_failures; + { + ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); + DoExpectNoFatalFailureOnFails(); + } + ASSERT_EQ(3, gtest_failures.size()); + EXPECT_EQ(TestPartResult::kFatalFailure, + gtest_failures.GetTestPartResult(0).type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(1).type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(2).type()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", + gtest_failures.GetTestPartResult(0).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", + gtest_failures.GetTestPartResult(1).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "other failure", + gtest_failures.GetTestPartResult(2).message()); +} + +TEST_F(NoFatalFailureTest, MessageIsStreamable) { + TestPartResultArray gtest_failures; + { + ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); + EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message"; + } + ASSERT_EQ(2, gtest_failures.size()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(0).type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(1).type()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo", + gtest_failures.GetTestPartResult(0).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "my message", + gtest_failures.GetTestPartResult(1).message()); +} + +// Tests non-string assertions. + +// Tests EqFailure(), used for implementing *EQ* assertions. +TEST(AssertionTest, EqFailure) { + const String foo_val("5"), bar_val("6"); + const String msg1( + EqFailure("foo", "bar", foo_val, bar_val, false) + .failure_message()); + EXPECT_STREQ( + "Value of: bar\n" + " Actual: 6\n" + "Expected: foo\n" + "Which is: 5", + msg1.c_str()); + + const String msg2( + EqFailure("foo", "6", foo_val, bar_val, false) + .failure_message()); + EXPECT_STREQ( + "Value of: 6\n" + "Expected: foo\n" + "Which is: 5", + msg2.c_str()); + + const String msg3( + EqFailure("5", "bar", foo_val, bar_val, false) + .failure_message()); + EXPECT_STREQ( + "Value of: bar\n" + " Actual: 6\n" + "Expected: 5", + msg3.c_str()); + + const String msg4( + EqFailure("5", "6", foo_val, bar_val, false).failure_message()); + EXPECT_STREQ( + "Value of: 6\n" + "Expected: 5", + msg4.c_str()); + + const String msg5( + EqFailure("foo", "bar", + String("\"x\""), String("\"y\""), + true).failure_message()); + EXPECT_STREQ( + "Value of: bar\n" + " Actual: \"y\"\n" + "Expected: foo (ignoring case)\n" + "Which is: \"x\"", + msg5.c_str()); +} + +// Tests AppendUserMessage(), used for implementing the *EQ* macros. +TEST(AssertionTest, AppendUserMessage) { + const String foo("foo"); + + Message msg; + EXPECT_STREQ("foo", + AppendUserMessage(foo, msg).c_str()); + + msg << "bar"; + EXPECT_STREQ("foo\nbar", + AppendUserMessage(foo, msg).c_str()); +} + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +#endif + +// Tests ASSERT_TRUE. +TEST(AssertionTest, ASSERT_TRUE) { + ASSERT_TRUE(2 > 1); // NOLINT + EXPECT_FATAL_FAILURE(ASSERT_TRUE(2 < 1), + "2 < 1"); +} + +// Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult. +TEST(AssertionTest, AssertTrueWithAssertionResult) { + ASSERT_TRUE(ResultIsEven(2)); +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)), + "Value of: ResultIsEven(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); +#endif + ASSERT_TRUE(ResultIsEvenNoExplanation(2)); + EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)), + "Value of: ResultIsEvenNoExplanation(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); +} + +// Tests ASSERT_FALSE. +TEST(AssertionTest, ASSERT_FALSE) { + ASSERT_FALSE(2 < 1); // NOLINT + EXPECT_FATAL_FAILURE(ASSERT_FALSE(2 > 1), + "Value of: 2 > 1\n" + " Actual: true\n" + "Expected: false"); +} + +// Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult. +TEST(AssertionTest, AssertFalseWithAssertionResult) { + ASSERT_FALSE(ResultIsEven(3)); +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)), + "Value of: ResultIsEven(2)\n" + " Actual: true (2 is even)\n" + "Expected: false"); +#endif + ASSERT_FALSE(ResultIsEvenNoExplanation(3)); + EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)), + "Value of: ResultIsEvenNoExplanation(2)\n" + " Actual: true\n" + "Expected: false"); +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" supressed them +# pragma option pop +#endif + +// Tests using ASSERT_EQ on double values. The purpose is to make +// sure that the specialization we did for integer and anonymous enums +// isn't used for double arguments. +TEST(ExpectTest, ASSERT_EQ_Double) { + // A success. + ASSERT_EQ(5.6, 5.6); + + // A failure. + EXPECT_FATAL_FAILURE(ASSERT_EQ(5.1, 5.2), + "5.1"); +} + +// Tests ASSERT_EQ. +TEST(AssertionTest, ASSERT_EQ) { + ASSERT_EQ(5, 2 + 3); + EXPECT_FATAL_FAILURE(ASSERT_EQ(5, 2*3), + "Value of: 2*3\n" + " Actual: 6\n" + "Expected: 5"); +} + +// Tests ASSERT_EQ(NULL, pointer). +#if GTEST_CAN_COMPARE_NULL +TEST(AssertionTest, ASSERT_EQ_NULL) { + // A success. + const char* p = NULL; + // Some older GCC versions may issue a spurious waring in this or the next + // assertion statement. This warning should not be suppressed with + // static_cast since the test verifies the ability to use bare NULL as the + // expected parameter to the macro. + ASSERT_EQ(NULL, p); + + // A failure. + static int n = 0; + EXPECT_FATAL_FAILURE(ASSERT_EQ(NULL, &n), + "Value of: &n\n"); +} +#endif // GTEST_CAN_COMPARE_NULL + +// Tests ASSERT_EQ(0, non_pointer). Since the literal 0 can be +// treated as a null pointer by the compiler, we need to make sure +// that ASSERT_EQ(0, non_pointer) isn't interpreted by Google Test as +// ASSERT_EQ(static_cast(NULL), non_pointer). +TEST(ExpectTest, ASSERT_EQ_0) { + int n = 0; + + // A success. + ASSERT_EQ(0, n); + + // A failure. + EXPECT_FATAL_FAILURE(ASSERT_EQ(0, 5.6), + "Expected: 0"); +} + +// Tests ASSERT_NE. +TEST(AssertionTest, ASSERT_NE) { + ASSERT_NE(6, 7); + EXPECT_FATAL_FAILURE(ASSERT_NE('a', 'a'), + "Expected: ('a') != ('a'), " + "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); +} + +// Tests ASSERT_LE. +TEST(AssertionTest, ASSERT_LE) { + ASSERT_LE(2, 3); + ASSERT_LE(2, 2); + EXPECT_FATAL_FAILURE(ASSERT_LE(2, 0), + "Expected: (2) <= (0), actual: 2 vs 0"); +} + +// Tests ASSERT_LT. +TEST(AssertionTest, ASSERT_LT) { + ASSERT_LT(2, 3); + EXPECT_FATAL_FAILURE(ASSERT_LT(2, 2), + "Expected: (2) < (2), actual: 2 vs 2"); +} + +// Tests ASSERT_GE. +TEST(AssertionTest, ASSERT_GE) { + ASSERT_GE(2, 1); + ASSERT_GE(2, 2); + EXPECT_FATAL_FAILURE(ASSERT_GE(2, 3), + "Expected: (2) >= (3), actual: 2 vs 3"); +} + +// Tests ASSERT_GT. +TEST(AssertionTest, ASSERT_GT) { + ASSERT_GT(2, 1); + EXPECT_FATAL_FAILURE(ASSERT_GT(2, 2), + "Expected: (2) > (2), actual: 2 vs 2"); +} + +#if GTEST_HAS_EXCEPTIONS + +void ThrowNothing() {} + +// Tests ASSERT_THROW. +TEST(AssertionTest, ASSERT_THROW) { + ASSERT_THROW(ThrowAnInteger(), int); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder 2007 and 2009. + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowAnInteger(), bool), + "Expected: ThrowAnInteger() throws an exception of type bool.\n" + " Actual: it throws a different type."); +# endif + + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowNothing(), bool), + "Expected: ThrowNothing() throws an exception of type bool.\n" + " Actual: it throws nothing."); +} + +// Tests ASSERT_NO_THROW. +TEST(AssertionTest, ASSERT_NO_THROW) { + ASSERT_NO_THROW(ThrowNothing()); + EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()), + "Expected: ThrowAnInteger() doesn't throw an exception." + "\n Actual: it throws."); +} + +// Tests ASSERT_ANY_THROW. +TEST(AssertionTest, ASSERT_ANY_THROW) { + ASSERT_ANY_THROW(ThrowAnInteger()); + EXPECT_FATAL_FAILURE( + ASSERT_ANY_THROW(ThrowNothing()), + "Expected: ThrowNothing() throws an exception.\n" + " Actual: it doesn't."); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Makes sure we deal with the precedence of <<. This test should +// compile. +TEST(AssertionTest, AssertPrecedence) { + ASSERT_EQ(1 < 2, true); + bool false_value = false; + ASSERT_EQ(true && false_value, false); +} + +// A subroutine used by the following test. +void TestEq1(int x) { + ASSERT_EQ(1, x); +} + +// Tests calling a test subroutine that's not part of a fixture. +TEST(AssertionTest, NonFixtureSubroutine) { + EXPECT_FATAL_FAILURE(TestEq1(2), + "Value of: x"); +} + +// An uncopyable class. +class Uncopyable { + public: + explicit Uncopyable(int a_value) : value_(a_value) {} + + int value() const { return value_; } + bool operator==(const Uncopyable& rhs) const { + return value() == rhs.value(); + } + private: + // This constructor deliberately has no implementation, as we don't + // want this class to be copyable. + Uncopyable(const Uncopyable&); // NOLINT + + int value_; +}; + +::std::ostream& operator<<(::std::ostream& os, const Uncopyable& value) { + return os << value.value(); +} + + +bool IsPositiveUncopyable(const Uncopyable& x) { + return x.value() > 0; +} + +// A subroutine used by the following test. +void TestAssertNonPositive() { + Uncopyable y(-1); + ASSERT_PRED1(IsPositiveUncopyable, y); +} +// A subroutine used by the following test. +void TestAssertEqualsUncopyable() { + Uncopyable x(5); + Uncopyable y(-1); + ASSERT_EQ(x, y); +} + +// Tests that uncopyable objects can be used in assertions. +TEST(AssertionTest, AssertWorksWithUncopyableObject) { + Uncopyable x(5); + ASSERT_PRED1(IsPositiveUncopyable, x); + ASSERT_EQ(x, x); + EXPECT_FATAL_FAILURE(TestAssertNonPositive(), + "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); + EXPECT_FATAL_FAILURE(TestAssertEqualsUncopyable(), + "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5"); +} + +// Tests that uncopyable objects can be used in expects. +TEST(AssertionTest, ExpectWorksWithUncopyableObject) { + Uncopyable x(5); + EXPECT_PRED1(IsPositiveUncopyable, x); + Uncopyable y(-1); + EXPECT_NONFATAL_FAILURE(EXPECT_PRED1(IsPositiveUncopyable, y), + "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); + EXPECT_EQ(x, x); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), + "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5"); +} + +enum NamedEnum { + kE1 = 0, + kE2 = 1 +}; + +TEST(AssertionTest, NamedEnum) { + EXPECT_EQ(kE1, kE1); + EXPECT_LT(kE1, kE2); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 0"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Actual: 1"); +} + +// The version of gcc used in XCode 2.2 has a bug and doesn't allow +// anonymous enums in assertions. Therefore the following test is not +// done on Mac. +// Sun Studio and HP aCC also reject this code. +#if !GTEST_OS_MAC && !defined(__SUNPRO_CC) && !defined(__HP_aCC) + +// Tests using assertions with anonymous enums. +enum { + kCaseA = -1, + +# if GTEST_OS_LINUX + + // We want to test the case where the size of the anonymous enum is + // larger than sizeof(int), to make sure our implementation of the + // assertions doesn't truncate the enums. However, MSVC + // (incorrectly) doesn't allow an enum value to exceed the range of + // an int, so this has to be conditionally compiled. + // + // On Linux, kCaseB and kCaseA have the same value when truncated to + // int size. We want to test whether this will confuse the + // assertions. + kCaseB = testing::internal::kMaxBiggestInt, + +# else + + kCaseB = INT_MAX, + +# endif // GTEST_OS_LINUX + + kCaseC = 42 +}; + +TEST(AssertionTest, AnonymousEnum) { +# if GTEST_OS_LINUX + + EXPECT_EQ(static_cast(kCaseA), static_cast(kCaseB)); + +# endif // GTEST_OS_LINUX + + EXPECT_EQ(kCaseA, kCaseA); + EXPECT_NE(kCaseA, kCaseB); + EXPECT_LT(kCaseA, kCaseB); + EXPECT_LE(kCaseA, kCaseB); + EXPECT_GT(kCaseB, kCaseA); + EXPECT_GE(kCaseA, kCaseA); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseB), + "(kCaseA) >= (kCaseB)"); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseC), + "-1 vs 42"); + + ASSERT_EQ(kCaseA, kCaseA); + ASSERT_NE(kCaseA, kCaseB); + ASSERT_LT(kCaseA, kCaseB); + ASSERT_LE(kCaseA, kCaseB); + ASSERT_GT(kCaseB, kCaseA); + ASSERT_GE(kCaseA, kCaseA); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseB), + "Value of: kCaseB"); + EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), + "Actual: 42"); +# endif + + EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), + "Which is: -1"); +} + +#endif // !GTEST_OS_MAC && !defined(__SUNPRO_CC) + +#if GTEST_OS_WINDOWS + +static HRESULT UnexpectedHRESULTFailure() { + return E_UNEXPECTED; +} + +static HRESULT OkHRESULTSuccess() { + return S_OK; +} + +static HRESULT FalseHRESULTSuccess() { + return S_FALSE; +} + +// HRESULT assertion tests test both zero and non-zero +// success codes as well as failure message for each. +// +// Windows CE doesn't support message texts. +TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED) { + EXPECT_HRESULT_SUCCEEDED(S_OK); + EXPECT_HRESULT_SUCCEEDED(S_FALSE); + + EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), + "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" + " Actual: 0x8000FFFF"); +} + +TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED) { + ASSERT_HRESULT_SUCCEEDED(S_OK); + ASSERT_HRESULT_SUCCEEDED(S_FALSE); + + EXPECT_FATAL_FAILURE(ASSERT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), + "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" + " Actual: 0x8000FFFF"); +} + +TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED) { + EXPECT_HRESULT_FAILED(E_UNEXPECTED); + + EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(OkHRESULTSuccess()), + "Expected: (OkHRESULTSuccess()) fails.\n" + " Actual: 0x00000000"); + EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()), + "Expected: (FalseHRESULTSuccess()) fails.\n" + " Actual: 0x00000001"); +} + +TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED) { + ASSERT_HRESULT_FAILED(E_UNEXPECTED); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder 2007 and 2009. + EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(OkHRESULTSuccess()), + "Expected: (OkHRESULTSuccess()) fails.\n" + " Actual: 0x00000000"); +# endif + + EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()), + "Expected: (FalseHRESULTSuccess()) fails.\n" + " Actual: 0x00000001"); +} + +// Tests that streaming to the HRESULT macros works. +TEST(HRESULTAssertionTest, Streaming) { + EXPECT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; + ASSERT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; + EXPECT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; + ASSERT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; + + EXPECT_NONFATAL_FAILURE( + EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", + "expected failure"); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder 2007 and 2009. + EXPECT_FATAL_FAILURE( + ASSERT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", + "expected failure"); +# endif + + EXPECT_NONFATAL_FAILURE( + EXPECT_HRESULT_FAILED(S_OK) << "expected failure", + "expected failure"); + + EXPECT_FATAL_FAILURE( + ASSERT_HRESULT_FAILED(S_OK) << "expected failure", + "expected failure"); +} + +#endif // GTEST_OS_WINDOWS + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +#endif + +// Tests that the assertion macros behave like single statements. +TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { + if (AlwaysFalse()) + ASSERT_TRUE(false) << "This should never be executed; " + "It's a compilation test only."; + + if (AlwaysTrue()) + EXPECT_FALSE(false); + else + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_LT(1, 3); + + if (AlwaysFalse()) + ; // NOLINT + else + EXPECT_GT(3, 2) << ""; +} + +#if GTEST_HAS_EXCEPTIONS +// Tests that the compiler will not complain about unreachable code in the +// EXPECT_THROW/EXPECT_ANY_THROW/EXPECT_NO_THROW macros. +TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { + int n = 0; + + EXPECT_THROW(throw 1, int); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(n++, int), ""); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw 1, const char*), ""); + EXPECT_NO_THROW(n++); + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(throw 1), ""); + EXPECT_ANY_THROW(throw 1); + EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), ""); +} + +TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { + if (AlwaysFalse()) + EXPECT_THROW(ThrowNothing(), bool); + + if (AlwaysTrue()) + EXPECT_THROW(ThrowAnInteger(), int); + else + ; // NOLINT + + if (AlwaysFalse()) + EXPECT_NO_THROW(ThrowAnInteger()); + + if (AlwaysTrue()) + EXPECT_NO_THROW(ThrowNothing()); + else + ; // NOLINT + + if (AlwaysFalse()) + EXPECT_ANY_THROW(ThrowNothing()); + + if (AlwaysTrue()) + EXPECT_ANY_THROW(ThrowAnInteger()); + else + ; // NOLINT +} +#endif // GTEST_HAS_EXCEPTIONS + +TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { + if (AlwaysFalse()) + EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. " + << "It's a compilation test only."; + else + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_NO_FATAL_FAILURE(FAIL()) << ""; + else + ; // NOLINT + + if (AlwaysTrue()) + EXPECT_NO_FATAL_FAILURE(SUCCEED()); + else + ; // NOLINT + + if (AlwaysFalse()) + ; // NOLINT + else + ASSERT_NO_FATAL_FAILURE(SUCCEED()); +} + +// Tests that the assertion macros work well with switch statements. +TEST(AssertionSyntaxTest, WorksWithSwitch) { + switch (0) { + case 1: + break; + default: + ASSERT_TRUE(true); + } + + switch (0) + case 0: + EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case"; + + // Binary assertions are implemented using a different code path + // than the Boolean assertions. Hence we test them separately. + switch (0) { + case 1: + default: + ASSERT_EQ(1, 1) << "ASSERT_EQ failed in default switch handler"; + } + + switch (0) + case 0: + EXPECT_NE(1, 2); +} + +#if GTEST_HAS_EXCEPTIONS + +void ThrowAString() { + throw "String"; +} + +// Test that the exception assertion macros compile and work with const +// type qualifier. +TEST(AssertionSyntaxTest, WorksWithConst) { + ASSERT_THROW(ThrowAString(), const char*); + + EXPECT_THROW(ThrowAString(), const char*); +} + +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace + +namespace testing { + +// Tests that Google Test tracks SUCCEED*. +TEST(SuccessfulAssertionTest, SUCCEED) { + SUCCEED(); + SUCCEED() << "OK"; + EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful EXPECT_*. +TEST(SuccessfulAssertionTest, EXPECT) { + EXPECT_TRUE(true); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful EXPECT_STR*. +TEST(SuccessfulAssertionTest, EXPECT_STR) { + EXPECT_STREQ("", ""); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful ASSERT_*. +TEST(SuccessfulAssertionTest, ASSERT) { + ASSERT_TRUE(true); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful ASSERT_STR*. +TEST(SuccessfulAssertionTest, ASSERT_STR) { + ASSERT_STREQ("", ""); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +} // namespace testing + +namespace { + +// Tests EXPECT_TRUE. +TEST(ExpectTest, EXPECT_TRUE) { + EXPECT_TRUE(2 > 1); // NOLINT + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 < 1), + "Value of: 2 < 1\n" + " Actual: false\n" + "Expected: true"); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 > 3), + "2 > 3"); +} + +// Tests EXPECT_TRUE(predicate) for predicates returning AssertionResult. +TEST(ExpectTest, ExpectTrueWithAssertionResult) { + EXPECT_TRUE(ResultIsEven(2)); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEven(3)), + "Value of: ResultIsEven(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); + EXPECT_TRUE(ResultIsEvenNoExplanation(2)); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEvenNoExplanation(3)), + "Value of: ResultIsEvenNoExplanation(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); +} + +// Tests EXPECT_FALSE. +TEST(ExpectTest, EXPECT_FALSE) { + EXPECT_FALSE(2 < 1); // NOLINT + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 > 1), + "Value of: 2 > 1\n" + " Actual: true\n" + "Expected: false"); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 < 3), + "2 < 3"); +} + +// Tests EXPECT_FALSE(predicate) for predicates returning AssertionResult. +TEST(ExpectTest, ExpectFalseWithAssertionResult) { + EXPECT_FALSE(ResultIsEven(3)); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEven(2)), + "Value of: ResultIsEven(2)\n" + " Actual: true (2 is even)\n" + "Expected: false"); + EXPECT_FALSE(ResultIsEvenNoExplanation(3)); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEvenNoExplanation(2)), + "Value of: ResultIsEvenNoExplanation(2)\n" + " Actual: true\n" + "Expected: false"); +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" supressed them +# pragma option pop +#endif + +// Tests EXPECT_EQ. +TEST(ExpectTest, EXPECT_EQ) { + EXPECT_EQ(5, 2 + 3); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2*3), + "Value of: 2*3\n" + " Actual: 6\n" + "Expected: 5"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2 - 3), + "2 - 3"); +} + +// Tests using EXPECT_EQ on double values. The purpose is to make +// sure that the specialization we did for integer and anonymous enums +// isn't used for double arguments. +TEST(ExpectTest, EXPECT_EQ_Double) { + // A success. + EXPECT_EQ(5.6, 5.6); + + // A failure. + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5.1, 5.2), + "5.1"); +} + +#if GTEST_CAN_COMPARE_NULL +// Tests EXPECT_EQ(NULL, pointer). +TEST(ExpectTest, EXPECT_EQ_NULL) { + // A success. + const char* p = NULL; + // Some older GCC versions may issue a spurious warning in this or the next + // assertion statement. This warning should not be suppressed with + // static_cast since the test verifies the ability to use bare NULL as the + // expected parameter to the macro. + EXPECT_EQ(NULL, p); + + // A failure. + int n = 0; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(NULL, &n), + "Value of: &n\n"); +} +#endif // GTEST_CAN_COMPARE_NULL + +// Tests EXPECT_EQ(0, non_pointer). Since the literal 0 can be +// treated as a null pointer by the compiler, we need to make sure +// that EXPECT_EQ(0, non_pointer) isn't interpreted by Google Test as +// EXPECT_EQ(static_cast(NULL), non_pointer). +TEST(ExpectTest, EXPECT_EQ_0) { + int n = 0; + + // A success. + EXPECT_EQ(0, n); + + // A failure. + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(0, 5.6), + "Expected: 0"); +} + +// Tests EXPECT_NE. +TEST(ExpectTest, EXPECT_NE) { + EXPECT_NE(6, 7); + + EXPECT_NONFATAL_FAILURE(EXPECT_NE('a', 'a'), + "Expected: ('a') != ('a'), " + "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); + EXPECT_NONFATAL_FAILURE(EXPECT_NE(2, 2), + "2"); + char* const p0 = NULL; + EXPECT_NONFATAL_FAILURE(EXPECT_NE(p0, p0), + "p0"); + // Only way to get the Nokia compiler to compile the cast + // is to have a separate void* variable first. Putting + // the two casts on the same line doesn't work, neither does + // a direct C-style to char*. + void* pv1 = (void*)0x1234; // NOLINT + char* const p1 = reinterpret_cast(pv1); + EXPECT_NONFATAL_FAILURE(EXPECT_NE(p1, p1), + "p1"); +} + +// Tests EXPECT_LE. +TEST(ExpectTest, EXPECT_LE) { + EXPECT_LE(2, 3); + EXPECT_LE(2, 2); + EXPECT_NONFATAL_FAILURE(EXPECT_LE(2, 0), + "Expected: (2) <= (0), actual: 2 vs 0"); + EXPECT_NONFATAL_FAILURE(EXPECT_LE(1.1, 0.9), + "(1.1) <= (0.9)"); +} + +// Tests EXPECT_LT. +TEST(ExpectTest, EXPECT_LT) { + EXPECT_LT(2, 3); + EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 2), + "Expected: (2) < (2), actual: 2 vs 2"); + EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1), + "(2) < (1)"); +} + +// Tests EXPECT_GE. +TEST(ExpectTest, EXPECT_GE) { + EXPECT_GE(2, 1); + EXPECT_GE(2, 2); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(2, 3), + "Expected: (2) >= (3), actual: 2 vs 3"); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(0.9, 1.1), + "(0.9) >= (1.1)"); +} + +// Tests EXPECT_GT. +TEST(ExpectTest, EXPECT_GT) { + EXPECT_GT(2, 1); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 2), + "Expected: (2) > (2), actual: 2 vs 2"); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 3), + "(2) > (3)"); +} + +#if GTEST_HAS_EXCEPTIONS + +// Tests EXPECT_THROW. +TEST(ExpectTest, EXPECT_THROW) { + EXPECT_THROW(ThrowAnInteger(), int); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), + "Expected: ThrowAnInteger() throws an exception of " + "type bool.\n Actual: it throws a different type."); + EXPECT_NONFATAL_FAILURE( + EXPECT_THROW(ThrowNothing(), bool), + "Expected: ThrowNothing() throws an exception of type bool.\n" + " Actual: it throws nothing."); +} + +// Tests EXPECT_NO_THROW. +TEST(ExpectTest, EXPECT_NO_THROW) { + EXPECT_NO_THROW(ThrowNothing()); + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()), + "Expected: ThrowAnInteger() doesn't throw an " + "exception.\n Actual: it throws."); +} + +// Tests EXPECT_ANY_THROW. +TEST(ExpectTest, EXPECT_ANY_THROW) { + EXPECT_ANY_THROW(ThrowAnInteger()); + EXPECT_NONFATAL_FAILURE( + EXPECT_ANY_THROW(ThrowNothing()), + "Expected: ThrowNothing() throws an exception.\n" + " Actual: it doesn't."); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Make sure we deal with the precedence of <<. +TEST(ExpectTest, ExpectPrecedence) { + EXPECT_EQ(1 < 2, true); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(true, true && false), + "Value of: true && false"); +} + + +// Tests the StreamableToString() function. + +// Tests using StreamableToString() on a scalar. +TEST(StreamableToStringTest, Scalar) { + EXPECT_STREQ("5", StreamableToString(5).c_str()); +} + +// Tests using StreamableToString() on a non-char pointer. +TEST(StreamableToStringTest, Pointer) { + int n = 0; + int* p = &n; + EXPECT_STRNE("(null)", StreamableToString(p).c_str()); +} + +// Tests using StreamableToString() on a NULL non-char pointer. +TEST(StreamableToStringTest, NullPointer) { + int* p = NULL; + EXPECT_STREQ("(null)", StreamableToString(p).c_str()); +} + +// Tests using StreamableToString() on a C string. +TEST(StreamableToStringTest, CString) { + EXPECT_STREQ("Foo", StreamableToString("Foo").c_str()); +} + +// Tests using StreamableToString() on a NULL C string. +TEST(StreamableToStringTest, NullCString) { + char* p = NULL; + EXPECT_STREQ("(null)", StreamableToString(p).c_str()); +} + +// Tests using streamable values as assertion messages. + +// Tests using std::string as an assertion message. +TEST(StreamableTest, string) { + static const std::string str( + "This failure message is a std::string, and is expected."); + EXPECT_FATAL_FAILURE(FAIL() << str, + str.c_str()); +} + +// Tests that we can output strings containing embedded NULs. +// Limited to Linux because we can only do this with std::string's. +TEST(StreamableTest, stringWithEmbeddedNUL) { + static const char char_array_with_nul[] = + "Here's a NUL\0 and some more string"; + static const std::string string_with_nul(char_array_with_nul, + sizeof(char_array_with_nul) + - 1); // drops the trailing NUL + EXPECT_FATAL_FAILURE(FAIL() << string_with_nul, + "Here's a NUL\\0 and some more string"); +} + +// Tests that we can output a NUL char. +TEST(StreamableTest, NULChar) { + EXPECT_FATAL_FAILURE({ // NOLINT + FAIL() << "A NUL" << '\0' << " and some more string"; + }, "A NUL\\0 and some more string"); +} + +// Tests using int as an assertion message. +TEST(StreamableTest, int) { + EXPECT_FATAL_FAILURE(FAIL() << 900913, + "900913"); +} + +// Tests using NULL char pointer as an assertion message. +// +// In MSVC, streaming a NULL char * causes access violation. Google Test +// implemented a workaround (substituting "(null)" for NULL). This +// tests whether the workaround works. +TEST(StreamableTest, NullCharPtr) { + EXPECT_FATAL_FAILURE(FAIL() << static_cast(NULL), + "(null)"); +} + +// Tests that basic IO manipulators (endl, ends, and flush) can be +// streamed to testing::Message. +TEST(StreamableTest, BasicIoManip) { + EXPECT_FATAL_FAILURE({ // NOLINT + FAIL() << "Line 1." << std::endl + << "A NUL char " << std::ends << std::flush << " in line 2."; + }, "Line 1.\nA NUL char \\0 in line 2."); +} + +// Tests the macros that haven't been covered so far. + +void AddFailureHelper(bool* aborted) { + *aborted = true; + ADD_FAILURE() << "Failure"; + *aborted = false; +} + +// Tests ADD_FAILURE. +TEST(MacroTest, ADD_FAILURE) { + bool aborted = true; + EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted), + "Failure"); + EXPECT_FALSE(aborted); +} + +// Tests ADD_FAILURE_AT. +TEST(MacroTest, ADD_FAILURE_AT) { + // Verifies that ADD_FAILURE_AT does generate a nonfatal failure and + // the failure message contains the user-streamed part. + EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42) << "Wrong!", "Wrong!"); + + // Verifies that the user-streamed part is optional. + EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42), "Failed"); + + // Unfortunately, we cannot verify that the failure message contains + // the right file path and line number the same way, as + // EXPECT_NONFATAL_FAILURE() doesn't get to see the file path and + // line number. Instead, we do that in gtest_output_test_.cc. +} + +// Tests FAIL. +TEST(MacroTest, FAIL) { + EXPECT_FATAL_FAILURE(FAIL(), + "Failed"); + EXPECT_FATAL_FAILURE(FAIL() << "Intentional failure.", + "Intentional failure."); +} + +// Tests SUCCEED +TEST(MacroTest, SUCCEED) { + SUCCEED(); + SUCCEED() << "Explicit success."; +} + + +// Tests for EXPECT_EQ() and ASSERT_EQ(). +// +// These tests fail *intentionally*, s.t. the failure messages can be +// generated and tested. +// +// We have different tests for different argument types. + +// Tests using bool values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Bool) { + EXPECT_EQ(true, true); + EXPECT_FATAL_FAILURE({ + bool false_value = false; + ASSERT_EQ(false_value, true); + }, "Value of: true"); +} + +// Tests using int values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Int) { + ASSERT_EQ(32, 32); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(32, 33), + "33"); +} + +// Tests using time_t values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Time_T) { + EXPECT_EQ(static_cast(0), + static_cast(0)); + EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0), + static_cast(1234)), + "1234"); +} + +// Tests using char values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Char) { + ASSERT_EQ('z', 'z'); + const char ch = 'b'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ('\0', ch), + "ch"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ('a', ch), + "ch"); +} + +// Tests using wchar_t values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, WideChar) { + EXPECT_EQ(L'b', L'b'); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'\0', L'x'), + "Value of: L'x'\n" + " Actual: L'x' (120, 0x78)\n" + "Expected: L'\0'\n" + "Which is: L'\0' (0, 0x0)"); + + static wchar_t wchar; + wchar = L'b'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar), + "wchar"); + wchar = 0x8119; + EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0x8120), wchar), + "Value of: wchar"); +} + +// Tests using ::std::string values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, StdString) { + // Compares a const char* to an std::string that has identical + // content. + ASSERT_EQ("Test", ::std::string("Test")); + + // Compares two identical std::strings. + static const ::std::string str1("A * in the middle"); + static const ::std::string str2(str1); + EXPECT_EQ(str1, str2); + + // Compares a const char* to an std::string that has different + // content + EXPECT_NONFATAL_FAILURE(EXPECT_EQ("Test", ::std::string("test")), + "::std::string(\"test\")"); + + // Compares an std::string to a char* that has different content. + char* const p1 = const_cast("foo"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::std::string("bar"), p1), + "p1"); + + // Compares two std::strings that have different contents, one of + // which having a NUL character in the middle. This should fail. + static ::std::string str3(str1); + str3.at(2) = '\0'; + EXPECT_FATAL_FAILURE(ASSERT_EQ(str1, str3), + "Value of: str3\n" + " Actual: \"A \\0 in the middle\""); +} + +#if GTEST_HAS_STD_WSTRING + +// Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, StdWideString) { + // Compares two identical std::wstrings. + const ::std::wstring wstr1(L"A * in the middle"); + const ::std::wstring wstr2(wstr1); + ASSERT_EQ(wstr1, wstr2); + + // Compares an std::wstring to a const wchar_t* that has identical + // content. + const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; + EXPECT_EQ(::std::wstring(kTestX8119), kTestX8119); + + // Compares an std::wstring to a const wchar_t* that has different + // content. + const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_EQ(::std::wstring(kTestX8119), kTestX8120); + }, "kTestX8120"); + + // Compares two std::wstrings that have different contents, one of + // which having a NUL character in the middle. + ::std::wstring wstr3(wstr1); + wstr3.at(2) = L'\0'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(wstr1, wstr3), + "wstr3"); + + // Compares a wchar_t* to an std::wstring that has different + // content. + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_EQ(const_cast(L"foo"), ::std::wstring(L"bar")); + }, ""); +} + +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_STRING +// Tests using ::string values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, GlobalString) { + // Compares a const char* to a ::string that has identical content. + EXPECT_EQ("Test", ::string("Test")); + + // Compares two identical ::strings. + const ::string str1("A * in the middle"); + const ::string str2(str1); + ASSERT_EQ(str1, str2); + + // Compares a ::string to a const char* that has different content. + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::string("Test"), "test"), + "test"); + + // Compares two ::strings that have different contents, one of which + // having a NUL character in the middle. + ::string str3(str1); + str3.at(2) = '\0'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(str1, str3), + "str3"); + + // Compares a ::string to a char* that has different content. + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_EQ(::string("bar"), const_cast("foo")); + }, ""); +} + +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING + +// Tests using ::wstring values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, GlobalWideString) { + // Compares two identical ::wstrings. + static const ::wstring wstr1(L"A * in the middle"); + static const ::wstring wstr2(wstr1); + EXPECT_EQ(wstr1, wstr2); + + // Compares a const wchar_t* to a ::wstring that has identical content. + const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; + ASSERT_EQ(kTestX8119, ::wstring(kTestX8119)); + + // Compares a const wchar_t* to a ::wstring that has different + // content. + const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_EQ(kTestX8120, ::wstring(kTestX8119)); + }, "Test\\x8119"); + + // Compares a wchar_t* to a ::wstring that has different content. + wchar_t* const p1 = const_cast(L"foo"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, ::wstring(L"bar")), + "bar"); + + // Compares two ::wstrings that have different contents, one of which + // having a NUL character in the middle. + static ::wstring wstr3; + wstr3 = wstr1; + wstr3.at(2) = L'\0'; + EXPECT_FATAL_FAILURE(ASSERT_EQ(wstr1, wstr3), + "wstr3"); +} + +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Tests using char pointers in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, CharPointer) { + char* const p0 = NULL; + // Only way to get the Nokia compiler to compile the cast + // is to have a separate void* variable first. Putting + // the two casts on the same line doesn't work, neither does + // a direct C-style to char*. + void* pv1 = (void*)0x1234; // NOLINT + void* pv2 = (void*)0xABC0; // NOLINT + char* const p1 = reinterpret_cast(pv1); + char* const p2 = reinterpret_cast(pv2); + ASSERT_EQ(p1, p1); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), + "Value of: p2"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), + "p2"); + EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast(0x1234), + reinterpret_cast(0xABC0)), + "ABC0"); +} + +// Tests using wchar_t pointers in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, WideCharPointer) { + wchar_t* const p0 = NULL; + // Only way to get the Nokia compiler to compile the cast + // is to have a separate void* variable first. Putting + // the two casts on the same line doesn't work, neither does + // a direct C-style to char*. + void* pv1 = (void*)0x1234; // NOLINT + void* pv2 = (void*)0xABC0; // NOLINT + wchar_t* const p1 = reinterpret_cast(pv1); + wchar_t* const p2 = reinterpret_cast(pv2); + EXPECT_EQ(p0, p0); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), + "Value of: p2"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), + "p2"); + void* pv3 = (void*)0x1234; // NOLINT + void* pv4 = (void*)0xABC0; // NOLINT + const wchar_t* p3 = reinterpret_cast(pv3); + const wchar_t* p4 = reinterpret_cast(pv4); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p3, p4), + "p4"); +} + +// Tests using other types of pointers in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, OtherPointer) { + ASSERT_EQ(static_cast(NULL), + static_cast(NULL)); + EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(NULL), + reinterpret_cast(0x1234)), + "0x1234"); +} + +// A class that supports binary comparison operators but not streaming. +class UnprintableChar { + public: + explicit UnprintableChar(char ch) : char_(ch) {} + + bool operator==(const UnprintableChar& rhs) const { + return char_ == rhs.char_; + } + bool operator!=(const UnprintableChar& rhs) const { + return char_ != rhs.char_; + } + bool operator<(const UnprintableChar& rhs) const { + return char_ < rhs.char_; + } + bool operator<=(const UnprintableChar& rhs) const { + return char_ <= rhs.char_; + } + bool operator>(const UnprintableChar& rhs) const { + return char_ > rhs.char_; + } + bool operator>=(const UnprintableChar& rhs) const { + return char_ >= rhs.char_; + } + + private: + char char_; +}; + +// Tests that ASSERT_EQ() and friends don't require the arguments to +// be printable. +TEST(ComparisonAssertionTest, AcceptsUnprintableArgs) { + const UnprintableChar x('x'), y('y'); + ASSERT_EQ(x, x); + EXPECT_NE(x, y); + ASSERT_LT(x, y); + EXPECT_LE(x, y); + ASSERT_GT(y, x); + EXPECT_GE(x, x); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <78>"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <79>"); + EXPECT_NONFATAL_FAILURE(EXPECT_LT(y, y), "1-byte object <79>"); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <78>"); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <79>"); + + // Code tested by EXPECT_FATAL_FAILURE cannot reference local + // variables, so we have to write UnprintableChar('x') instead of x. +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_NE(UnprintableChar('x'), UnprintableChar('x')), + "1-byte object <78>"); + EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), + "1-byte object <78>"); +#endif + EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), + "1-byte object <79>"); + EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), + "1-byte object <78>"); + EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), + "1-byte object <79>"); +} + +// Tests the FRIEND_TEST macro. + +// This class has a private member we want to test. We will test it +// both in a TEST and in a TEST_F. +class Foo { + public: + Foo() {} + + private: + int Bar() const { return 1; } + + // Declares the friend tests that can access the private member + // Bar(). + FRIEND_TEST(FRIEND_TEST_Test, TEST); + FRIEND_TEST(FRIEND_TEST_Test2, TEST_F); +}; + +// Tests that the FRIEND_TEST declaration allows a TEST to access a +// class's private members. This should compile. +TEST(FRIEND_TEST_Test, TEST) { + ASSERT_EQ(1, Foo().Bar()); +} + +// The fixture needed to test using FRIEND_TEST with TEST_F. +class FRIEND_TEST_Test2 : public Test { + protected: + Foo foo; +}; + +// Tests that the FRIEND_TEST declaration allows a TEST_F to access a +// class's private members. This should compile. +TEST_F(FRIEND_TEST_Test2, TEST_F) { + ASSERT_EQ(1, foo.Bar()); +} + +// Tests the life cycle of Test objects. + +// The test fixture for testing the life cycle of Test objects. +// +// This class counts the number of live test objects that uses this +// fixture. +class TestLifeCycleTest : public Test { + protected: + // Constructor. Increments the number of test objects that uses + // this fixture. + TestLifeCycleTest() { count_++; } + + // Destructor. Decrements the number of test objects that uses this + // fixture. + ~TestLifeCycleTest() { count_--; } + + // Returns the number of live test objects that uses this fixture. + int count() const { return count_; } + + private: + static int count_; +}; + +int TestLifeCycleTest::count_ = 0; + +// Tests the life cycle of test objects. +TEST_F(TestLifeCycleTest, Test1) { + // There should be only one test object in this test case that's + // currently alive. + ASSERT_EQ(1, count()); +} + +// Tests the life cycle of test objects. +TEST_F(TestLifeCycleTest, Test2) { + // After Test1 is done and Test2 is started, there should still be + // only one live test object, as the object for Test1 should've been + // deleted. + ASSERT_EQ(1, count()); +} + +} // namespace + +// Tests that the copy constructor works when it is NOT optimized away by +// the compiler. +TEST(AssertionResultTest, CopyConstructorWorksWhenNotOptimied) { + // Checks that the copy constructor doesn't try to dereference NULL pointers + // in the source object. + AssertionResult r1 = AssertionSuccess(); + AssertionResult r2 = r1; + // The following line is added to prevent the compiler from optimizing + // away the constructor call. + r1 << "abc"; + + AssertionResult r3 = r1; + EXPECT_EQ(static_cast(r3), static_cast(r1)); + EXPECT_STREQ("abc", r1.message()); +} + +// Tests that AssertionSuccess and AssertionFailure construct +// AssertionResult objects as expected. +TEST(AssertionResultTest, ConstructionWorks) { + AssertionResult r1 = AssertionSuccess(); + EXPECT_TRUE(r1); + EXPECT_STREQ("", r1.message()); + + AssertionResult r2 = AssertionSuccess() << "abc"; + EXPECT_TRUE(r2); + EXPECT_STREQ("abc", r2.message()); + + AssertionResult r3 = AssertionFailure(); + EXPECT_FALSE(r3); + EXPECT_STREQ("", r3.message()); + + AssertionResult r4 = AssertionFailure() << "def"; + EXPECT_FALSE(r4); + EXPECT_STREQ("def", r4.message()); + + AssertionResult r5 = AssertionFailure(Message() << "ghi"); + EXPECT_FALSE(r5); + EXPECT_STREQ("ghi", r5.message()); +} + +// Tests that the negation flips the predicate result but keeps the message. +TEST(AssertionResultTest, NegationWorks) { + AssertionResult r1 = AssertionSuccess() << "abc"; + EXPECT_FALSE(!r1); + EXPECT_STREQ("abc", (!r1).message()); + + AssertionResult r2 = AssertionFailure() << "def"; + EXPECT_TRUE(!r2); + EXPECT_STREQ("def", (!r2).message()); +} + +TEST(AssertionResultTest, StreamingWorks) { + AssertionResult r = AssertionSuccess(); + r << "abc" << 'd' << 0 << true; + EXPECT_STREQ("abcd0true", r.message()); +} + +TEST(AssertionResultTest, CanStreamOstreamManipulators) { + AssertionResult r = AssertionSuccess(); + r << "Data" << std::endl << std::flush << std::ends << "Will be visible"; + EXPECT_STREQ("Data\n\\0Will be visible", r.message()); +} + +// Tests streaming a user type whose definition and operator << are +// both in the global namespace. +class Base { + public: + explicit Base(int an_x) : x_(an_x) {} + int x() const { return x_; } + private: + int x_; +}; +std::ostream& operator<<(std::ostream& os, + const Base& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const Base* pointer) { + return os << "(" << pointer->x() << ")"; +} + +TEST(MessageTest, CanStreamUserTypeInGlobalNameSpace) { + Message msg; + Base a(1); + + msg << a << &a; // Uses ::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming a user type whose definition and operator<< are +// both in an unnamed namespace. +namespace { +class MyTypeInUnnamedNameSpace : public Base { + public: + explicit MyTypeInUnnamedNameSpace(int an_x): Base(an_x) {} +}; +std::ostream& operator<<(std::ostream& os, + const MyTypeInUnnamedNameSpace& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const MyTypeInUnnamedNameSpace* pointer) { + return os << "(" << pointer->x() << ")"; +} +} // namespace + +TEST(MessageTest, CanStreamUserTypeInUnnamedNameSpace) { + Message msg; + MyTypeInUnnamedNameSpace a(1); + + msg << a << &a; // Uses ::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming a user type whose definition and operator<< are +// both in a user namespace. +namespace namespace1 { +class MyTypeInNameSpace1 : public Base { + public: + explicit MyTypeInNameSpace1(int an_x): Base(an_x) {} +}; +std::ostream& operator<<(std::ostream& os, + const MyTypeInNameSpace1& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const MyTypeInNameSpace1* pointer) { + return os << "(" << pointer->x() << ")"; +} +} // namespace namespace1 + +TEST(MessageTest, CanStreamUserTypeInUserNameSpace) { + Message msg; + namespace1::MyTypeInNameSpace1 a(1); + + msg << a << &a; // Uses namespace1::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming a user type whose definition is in a user namespace +// but whose operator<< is in the global namespace. +namespace namespace2 { +class MyTypeInNameSpace2 : public ::Base { + public: + explicit MyTypeInNameSpace2(int an_x): Base(an_x) {} +}; +} // namespace namespace2 +std::ostream& operator<<(std::ostream& os, + const namespace2::MyTypeInNameSpace2& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const namespace2::MyTypeInNameSpace2* pointer) { + return os << "(" << pointer->x() << ")"; +} + +TEST(MessageTest, CanStreamUserTypeInUserNameSpaceWithStreamOperatorInGlobal) { + Message msg; + namespace2::MyTypeInNameSpace2 a(1); + + msg << a << &a; // Uses ::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming NULL pointers to testing::Message. +TEST(MessageTest, NullPointers) { + Message msg; + char* const p1 = NULL; + unsigned char* const p2 = NULL; + int* p3 = NULL; + double* p4 = NULL; + bool* p5 = NULL; + Message* p6 = NULL; + + msg << p1 << p2 << p3 << p4 << p5 << p6; + ASSERT_STREQ("(null)(null)(null)(null)(null)(null)", + msg.GetString().c_str()); +} + +// Tests streaming wide strings to testing::Message. +TEST(MessageTest, WideStrings) { + // Streams a NULL of type const wchar_t*. + const wchar_t* const_wstr = NULL; + EXPECT_STREQ("(null)", + (Message() << const_wstr).GetString().c_str()); + + // Streams a NULL of type wchar_t*. + wchar_t* wstr = NULL; + EXPECT_STREQ("(null)", + (Message() << wstr).GetString().c_str()); + + // Streams a non-NULL of type const wchar_t*. + const_wstr = L"abc\x8119"; + EXPECT_STREQ("abc\xe8\x84\x99", + (Message() << const_wstr).GetString().c_str()); + + // Streams a non-NULL of type wchar_t*. + wstr = const_cast(const_wstr); + EXPECT_STREQ("abc\xe8\x84\x99", + (Message() << wstr).GetString().c_str()); +} + + +// This line tests that we can define tests in the testing namespace. +namespace testing { + +// Tests the TestInfo class. + +class TestInfoTest : public Test { + protected: + static const TestInfo* GetTestInfo(const char* test_name) { + const TestCase* const test_case = GetUnitTestImpl()-> + GetTestCase("TestInfoTest", "", NULL, NULL); + + for (int i = 0; i < test_case->total_test_count(); ++i) { + const TestInfo* const test_info = test_case->GetTestInfo(i); + if (strcmp(test_name, test_info->name()) == 0) + return test_info; + } + return NULL; + } + + static const TestResult* GetTestResult( + const TestInfo* test_info) { + return test_info->result(); + } +}; + +// Tests TestInfo::test_case_name() and TestInfo::name(). +TEST_F(TestInfoTest, Names) { + const TestInfo* const test_info = GetTestInfo("Names"); + + ASSERT_STREQ("TestInfoTest", test_info->test_case_name()); + ASSERT_STREQ("Names", test_info->name()); +} + +// Tests TestInfo::result(). +TEST_F(TestInfoTest, result) { + const TestInfo* const test_info = GetTestInfo("result"); + + // Initially, there is no TestPartResult for this test. + ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); + + // After the previous assertion, there is still none. + ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); +} + +// Tests setting up and tearing down a test case. + +class SetUpTestCaseTest : public Test { + protected: + // This will be called once before the first test in this test case + // is run. + static void SetUpTestCase() { + printf("Setting up the test case . . .\n"); + + // Initializes some shared resource. In this simple example, we + // just create a C string. More complex stuff can be done if + // desired. + shared_resource_ = "123"; + + // Increments the number of test cases that have been set up. + counter_++; + + // SetUpTestCase() should be called only once. + EXPECT_EQ(1, counter_); + } + + // This will be called once after the last test in this test case is + // run. + static void TearDownTestCase() { + printf("Tearing down the test case . . .\n"); + + // Decrements the number of test cases that have been set up. + counter_--; + + // TearDownTestCase() should be called only once. + EXPECT_EQ(0, counter_); + + // Cleans up the shared resource. + shared_resource_ = NULL; + } + + // This will be called before each test in this test case. + virtual void SetUp() { + // SetUpTestCase() should be called only once, so counter_ should + // always be 1. + EXPECT_EQ(1, counter_); + } + + // Number of test cases that have been set up. + static int counter_; + + // Some resource to be shared by all tests in this test case. + static const char* shared_resource_; +}; + +int SetUpTestCaseTest::counter_ = 0; +const char* SetUpTestCaseTest::shared_resource_ = NULL; + +// A test that uses the shared resource. +TEST_F(SetUpTestCaseTest, Test1) { + EXPECT_STRNE(NULL, shared_resource_); +} + +// Another test that uses the shared resource. +TEST_F(SetUpTestCaseTest, Test2) { + EXPECT_STREQ("123", shared_resource_); +} + +// The InitGoogleTestTest test case tests testing::InitGoogleTest(). + +// The Flags struct stores a copy of all Google Test flags. +struct Flags { + // Constructs a Flags struct where each flag has its default value. + Flags() : also_run_disabled_tests(false), + break_on_failure(false), + catch_exceptions(false), + death_test_use_fork(false), + filter(""), + list_tests(false), + output(""), + print_time(true), + random_seed(0), + repeat(1), + shuffle(false), + stack_trace_depth(kMaxStackTraceDepth), + stream_result_to(""), + throw_on_failure(false) {} + + // Factory methods. + + // Creates a Flags struct where the gtest_also_run_disabled_tests flag has + // the given value. + static Flags AlsoRunDisabledTests(bool also_run_disabled_tests) { + Flags flags; + flags.also_run_disabled_tests = also_run_disabled_tests; + return flags; + } + + // Creates a Flags struct where the gtest_break_on_failure flag has + // the given value. + static Flags BreakOnFailure(bool break_on_failure) { + Flags flags; + flags.break_on_failure = break_on_failure; + return flags; + } + + // Creates a Flags struct where the gtest_catch_exceptions flag has + // the given value. + static Flags CatchExceptions(bool catch_exceptions) { + Flags flags; + flags.catch_exceptions = catch_exceptions; + return flags; + } + + // Creates a Flags struct where the gtest_death_test_use_fork flag has + // the given value. + static Flags DeathTestUseFork(bool death_test_use_fork) { + Flags flags; + flags.death_test_use_fork = death_test_use_fork; + return flags; + } + + // Creates a Flags struct where the gtest_filter flag has the given + // value. + static Flags Filter(const char* filter) { + Flags flags; + flags.filter = filter; + return flags; + } + + // Creates a Flags struct where the gtest_list_tests flag has the + // given value. + static Flags ListTests(bool list_tests) { + Flags flags; + flags.list_tests = list_tests; + return flags; + } + + // Creates a Flags struct where the gtest_output flag has the given + // value. + static Flags Output(const char* output) { + Flags flags; + flags.output = output; + return flags; + } + + // Creates a Flags struct where the gtest_print_time flag has the given + // value. + static Flags PrintTime(bool print_time) { + Flags flags; + flags.print_time = print_time; + return flags; + } + + // Creates a Flags struct where the gtest_random_seed flag has + // the given value. + static Flags RandomSeed(Int32 random_seed) { + Flags flags; + flags.random_seed = random_seed; + return flags; + } + + // Creates a Flags struct where the gtest_repeat flag has the given + // value. + static Flags Repeat(Int32 repeat) { + Flags flags; + flags.repeat = repeat; + return flags; + } + + // Creates a Flags struct where the gtest_shuffle flag has + // the given value. + static Flags Shuffle(bool shuffle) { + Flags flags; + flags.shuffle = shuffle; + return flags; + } + + // Creates a Flags struct where the GTEST_FLAG(stack_trace_depth) flag has + // the given value. + static Flags StackTraceDepth(Int32 stack_trace_depth) { + Flags flags; + flags.stack_trace_depth = stack_trace_depth; + return flags; + } + + // Creates a Flags struct where the GTEST_FLAG(stream_result_to) flag has + // the given value. + static Flags StreamResultTo(const char* stream_result_to) { + Flags flags; + flags.stream_result_to = stream_result_to; + return flags; + } + + // Creates a Flags struct where the gtest_throw_on_failure flag has + // the given value. + static Flags ThrowOnFailure(bool throw_on_failure) { + Flags flags; + flags.throw_on_failure = throw_on_failure; + return flags; + } + + // These fields store the flag values. + bool also_run_disabled_tests; + bool break_on_failure; + bool catch_exceptions; + bool death_test_use_fork; + const char* filter; + bool list_tests; + const char* output; + bool print_time; + Int32 random_seed; + Int32 repeat; + bool shuffle; + Int32 stack_trace_depth; + const char* stream_result_to; + bool throw_on_failure; +}; + +// Fixture for testing InitGoogleTest(). +class InitGoogleTestTest : public Test { + protected: + // Clears the flags before each test. + virtual void SetUp() { + GTEST_FLAG(also_run_disabled_tests) = false; + GTEST_FLAG(break_on_failure) = false; + GTEST_FLAG(catch_exceptions) = false; + GTEST_FLAG(death_test_use_fork) = false; + GTEST_FLAG(filter) = ""; + GTEST_FLAG(list_tests) = false; + GTEST_FLAG(output) = ""; + GTEST_FLAG(print_time) = true; + GTEST_FLAG(random_seed) = 0; + GTEST_FLAG(repeat) = 1; + GTEST_FLAG(shuffle) = false; + GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; + GTEST_FLAG(stream_result_to) = ""; + GTEST_FLAG(throw_on_failure) = false; + } + + // Asserts that two narrow or wide string arrays are equal. + template + static void AssertStringArrayEq(size_t size1, CharType** array1, + size_t size2, CharType** array2) { + ASSERT_EQ(size1, size2) << " Array sizes different."; + + for (size_t i = 0; i != size1; i++) { + ASSERT_STREQ(array1[i], array2[i]) << " where i == " << i; + } + } + + // Verifies that the flag values match the expected values. + static void CheckFlags(const Flags& expected) { + EXPECT_EQ(expected.also_run_disabled_tests, + GTEST_FLAG(also_run_disabled_tests)); + EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure)); + EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions)); + EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork)); + EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str()); + EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests)); + EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str()); + EXPECT_EQ(expected.print_time, GTEST_FLAG(print_time)); + EXPECT_EQ(expected.random_seed, GTEST_FLAG(random_seed)); + EXPECT_EQ(expected.repeat, GTEST_FLAG(repeat)); + EXPECT_EQ(expected.shuffle, GTEST_FLAG(shuffle)); + EXPECT_EQ(expected.stack_trace_depth, GTEST_FLAG(stack_trace_depth)); + EXPECT_STREQ(expected.stream_result_to, + GTEST_FLAG(stream_result_to).c_str()); + EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure)); + } + + // Parses a command line (specified by argc1 and argv1), then + // verifies that the flag values are expected and that the + // recognized flags are removed from the command line. + template + static void TestParsingFlags(int argc1, const CharType** argv1, + int argc2, const CharType** argv2, + const Flags& expected, bool should_print_help) { + const bool saved_help_flag = ::testing::internal::g_help_flag; + ::testing::internal::g_help_flag = false; + +#if GTEST_HAS_STREAM_REDIRECTION + CaptureStdout(); +#endif + + // Parses the command line. + internal::ParseGoogleTestFlagsOnly(&argc1, const_cast(argv1)); + +#if GTEST_HAS_STREAM_REDIRECTION + const String captured_stdout = GetCapturedStdout(); +#endif + + // Verifies the flag values. + CheckFlags(expected); + + // Verifies that the recognized flags are removed from the command + // line. + AssertStringArrayEq(argc1 + 1, argv1, argc2 + 1, argv2); + + // ParseGoogleTestFlagsOnly should neither set g_help_flag nor print the + // help message for the flags it recognizes. + EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag); + +#if GTEST_HAS_STREAM_REDIRECTION + const char* const expected_help_fragment = + "This program contains tests written using"; + if (should_print_help) { + EXPECT_PRED_FORMAT2(IsSubstring, expected_help_fragment, captured_stdout); + } else { + EXPECT_PRED_FORMAT2(IsNotSubstring, + expected_help_fragment, captured_stdout); + } +#endif // GTEST_HAS_STREAM_REDIRECTION + + ::testing::internal::g_help_flag = saved_help_flag; + } + + // This macro wraps TestParsingFlags s.t. the user doesn't need + // to specify the array sizes. + +#define GTEST_TEST_PARSING_FLAGS_(argv1, argv2, expected, should_print_help) \ + TestParsingFlags(sizeof(argv1)/sizeof(*argv1) - 1, argv1, \ + sizeof(argv2)/sizeof(*argv2) - 1, argv2, \ + expected, should_print_help) +}; + +// Tests parsing an empty command line. +TEST_F(InitGoogleTestTest, Empty) { + const char* argv[] = { + NULL + }; + + const char* argv2[] = { + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); +} + +// Tests parsing a command line that has no flag. +TEST_F(InitGoogleTestTest, NoFlag) { + const char* argv[] = { + "foo.exe", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); +} + +// Tests parsing a bad --gtest_filter flag. +TEST_F(InitGoogleTestTest, FilterBad) { + const char* argv[] = { + "foo.exe", + "--gtest_filter", + NULL + }; + + const char* argv2[] = { + "foo.exe", + "--gtest_filter", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true); +} + +// Tests parsing an empty --gtest_filter flag. +TEST_F(InitGoogleTestTest, FilterEmpty) { + const char* argv[] = { + "foo.exe", + "--gtest_filter=", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), false); +} + +// Tests parsing a non-empty --gtest_filter flag. +TEST_F(InitGoogleTestTest, FilterNonEmpty) { + const char* argv[] = { + "foo.exe", + "--gtest_filter=abc", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false); +} + +// Tests parsing --gtest_break_on_failure. +TEST_F(InitGoogleTestTest, BreakOnFailureWithoutValue) { + const char* argv[] = { + "foo.exe", + "--gtest_break_on_failure", + NULL +}; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); +} + +// Tests parsing --gtest_break_on_failure=0. +TEST_F(InitGoogleTestTest, BreakOnFailureFalse_0) { + const char* argv[] = { + "foo.exe", + "--gtest_break_on_failure=0", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); +} + +// Tests parsing --gtest_break_on_failure=f. +TEST_F(InitGoogleTestTest, BreakOnFailureFalse_f) { + const char* argv[] = { + "foo.exe", + "--gtest_break_on_failure=f", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); +} + +// Tests parsing --gtest_break_on_failure=F. +TEST_F(InitGoogleTestTest, BreakOnFailureFalse_F) { + const char* argv[] = { + "foo.exe", + "--gtest_break_on_failure=F", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); +} + +// Tests parsing a --gtest_break_on_failure flag that has a "true" +// definition. +TEST_F(InitGoogleTestTest, BreakOnFailureTrue) { + const char* argv[] = { + "foo.exe", + "--gtest_break_on_failure=1", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); +} + +// Tests parsing --gtest_catch_exceptions. +TEST_F(InitGoogleTestTest, CatchExceptions) { + const char* argv[] = { + "foo.exe", + "--gtest_catch_exceptions", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::CatchExceptions(true), false); +} + +// Tests parsing --gtest_death_test_use_fork. +TEST_F(InitGoogleTestTest, DeathTestUseFork) { + const char* argv[] = { + "foo.exe", + "--gtest_death_test_use_fork", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::DeathTestUseFork(true), false); +} + +// Tests having the same flag twice with different values. The +// expected behavior is that the one coming last takes precedence. +TEST_F(InitGoogleTestTest, DuplicatedFlags) { + const char* argv[] = { + "foo.exe", + "--gtest_filter=a", + "--gtest_filter=b", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("b"), false); +} + +// Tests having an unrecognized flag on the command line. +TEST_F(InitGoogleTestTest, UnrecognizedFlag) { + const char* argv[] = { + "foo.exe", + "--gtest_break_on_failure", + "bar", // Unrecognized by Google Test. + "--gtest_filter=b", + NULL + }; + + const char* argv2[] = { + "foo.exe", + "bar", + NULL + }; + + Flags flags; + flags.break_on_failure = true; + flags.filter = "b"; + GTEST_TEST_PARSING_FLAGS_(argv, argv2, flags, false); +} + +// Tests having a --gtest_list_tests flag +TEST_F(InitGoogleTestTest, ListTestsFlag) { + const char* argv[] = { + "foo.exe", + "--gtest_list_tests", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); +} + +// Tests having a --gtest_list_tests flag with a "true" value +TEST_F(InitGoogleTestTest, ListTestsTrue) { + const char* argv[] = { + "foo.exe", + "--gtest_list_tests=1", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); +} + +// Tests having a --gtest_list_tests flag with a "false" value +TEST_F(InitGoogleTestTest, ListTestsFalse) { + const char* argv[] = { + "foo.exe", + "--gtest_list_tests=0", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); +} + +// Tests parsing --gtest_list_tests=f. +TEST_F(InitGoogleTestTest, ListTestsFalse_f) { + const char* argv[] = { + "foo.exe", + "--gtest_list_tests=f", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); +} + +// Tests parsing --gtest_list_tests=F. +TEST_F(InitGoogleTestTest, ListTestsFalse_F) { + const char* argv[] = { + "foo.exe", + "--gtest_list_tests=F", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); +} + +// Tests parsing --gtest_output (invalid). +TEST_F(InitGoogleTestTest, OutputEmpty) { + const char* argv[] = { + "foo.exe", + "--gtest_output", + NULL + }; + + const char* argv2[] = { + "foo.exe", + "--gtest_output", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true); +} + +// Tests parsing --gtest_output=xml +TEST_F(InitGoogleTestTest, OutputXml) { + const char* argv[] = { + "foo.exe", + "--gtest_output=xml", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml"), false); +} + +// Tests parsing --gtest_output=xml:file +TEST_F(InitGoogleTestTest, OutputXmlFile) { + const char* argv[] = { + "foo.exe", + "--gtest_output=xml:file", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:file"), false); +} + +// Tests parsing --gtest_output=xml:directory/path/ +TEST_F(InitGoogleTestTest, OutputXmlDirectory) { + const char* argv[] = { + "foo.exe", + "--gtest_output=xml:directory/path/", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, + Flags::Output("xml:directory/path/"), false); +} + +// Tests having a --gtest_print_time flag +TEST_F(InitGoogleTestTest, PrintTimeFlag) { + const char* argv[] = { + "foo.exe", + "--gtest_print_time", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); +} + +// Tests having a --gtest_print_time flag with a "true" value +TEST_F(InitGoogleTestTest, PrintTimeTrue) { + const char* argv[] = { + "foo.exe", + "--gtest_print_time=1", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); +} + +// Tests having a --gtest_print_time flag with a "false" value +TEST_F(InitGoogleTestTest, PrintTimeFalse) { + const char* argv[] = { + "foo.exe", + "--gtest_print_time=0", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); +} + +// Tests parsing --gtest_print_time=f. +TEST_F(InitGoogleTestTest, PrintTimeFalse_f) { + const char* argv[] = { + "foo.exe", + "--gtest_print_time=f", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); +} + +// Tests parsing --gtest_print_time=F. +TEST_F(InitGoogleTestTest, PrintTimeFalse_F) { + const char* argv[] = { + "foo.exe", + "--gtest_print_time=F", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); +} + +// Tests parsing --gtest_random_seed=number +TEST_F(InitGoogleTestTest, RandomSeed) { + const char* argv[] = { + "foo.exe", + "--gtest_random_seed=1000", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::RandomSeed(1000), false); +} + +// Tests parsing --gtest_repeat=number +TEST_F(InitGoogleTestTest, Repeat) { + const char* argv[] = { + "foo.exe", + "--gtest_repeat=1000", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Repeat(1000), false); +} + +// Tests having a --gtest_also_run_disabled_tests flag +TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFlag) { + const char* argv[] = { + "foo.exe", + "--gtest_also_run_disabled_tests", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, + Flags::AlsoRunDisabledTests(true), false); +} + +// Tests having a --gtest_also_run_disabled_tests flag with a "true" value +TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsTrue) { + const char* argv[] = { + "foo.exe", + "--gtest_also_run_disabled_tests=1", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, + Flags::AlsoRunDisabledTests(true), false); +} + +// Tests having a --gtest_also_run_disabled_tests flag with a "false" value +TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFalse) { + const char* argv[] = { + "foo.exe", + "--gtest_also_run_disabled_tests=0", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, + Flags::AlsoRunDisabledTests(false), false); +} + +// Tests parsing --gtest_shuffle. +TEST_F(InitGoogleTestTest, ShuffleWithoutValue) { + const char* argv[] = { + "foo.exe", + "--gtest_shuffle", + NULL +}; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); +} + +// Tests parsing --gtest_shuffle=0. +TEST_F(InitGoogleTestTest, ShuffleFalse_0) { + const char* argv[] = { + "foo.exe", + "--gtest_shuffle=0", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(false), false); +} + +// Tests parsing a --gtest_shuffle flag that has a "true" +// definition. +TEST_F(InitGoogleTestTest, ShuffleTrue) { + const char* argv[] = { + "foo.exe", + "--gtest_shuffle=1", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); +} + +// Tests parsing --gtest_stack_trace_depth=number. +TEST_F(InitGoogleTestTest, StackTraceDepth) { + const char* argv[] = { + "foo.exe", + "--gtest_stack_trace_depth=5", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::StackTraceDepth(5), false); +} + +TEST_F(InitGoogleTestTest, StreamResultTo) { + const char* argv[] = { + "foo.exe", + "--gtest_stream_result_to=localhost:1234", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_( + argv, argv2, Flags::StreamResultTo("localhost:1234"), false); +} + +// Tests parsing --gtest_throw_on_failure. +TEST_F(InitGoogleTestTest, ThrowOnFailureWithoutValue) { + const char* argv[] = { + "foo.exe", + "--gtest_throw_on_failure", + NULL +}; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); +} + +// Tests parsing --gtest_throw_on_failure=0. +TEST_F(InitGoogleTestTest, ThrowOnFailureFalse_0) { + const char* argv[] = { + "foo.exe", + "--gtest_throw_on_failure=0", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(false), false); +} + +// Tests parsing a --gtest_throw_on_failure flag that has a "true" +// definition. +TEST_F(InitGoogleTestTest, ThrowOnFailureTrue) { + const char* argv[] = { + "foo.exe", + "--gtest_throw_on_failure=1", + NULL + }; + + const char* argv2[] = { + "foo.exe", + NULL + }; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); +} + +#if GTEST_OS_WINDOWS +// Tests parsing wide strings. +TEST_F(InitGoogleTestTest, WideStrings) { + const wchar_t* argv[] = { + L"foo.exe", + L"--gtest_filter=Foo*", + L"--gtest_list_tests=1", + L"--gtest_break_on_failure", + L"--non_gtest_flag", + NULL + }; + + const wchar_t* argv2[] = { + L"foo.exe", + L"--non_gtest_flag", + NULL + }; + + Flags expected_flags; + expected_flags.break_on_failure = true; + expected_flags.filter = "Foo*"; + expected_flags.list_tests = true; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false); +} +#endif // GTEST_OS_WINDOWS + +// Tests current_test_info() in UnitTest. +class CurrentTestInfoTest : public Test { + protected: + // Tests that current_test_info() returns NULL before the first test in + // the test case is run. + static void SetUpTestCase() { + // There should be no tests running at this point. + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + EXPECT_TRUE(test_info == NULL) + << "There should be no tests running at this point."; + } + + // Tests that current_test_info() returns NULL after the last test in + // the test case has run. + static void TearDownTestCase() { + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + EXPECT_TRUE(test_info == NULL) + << "There should be no tests running at this point."; + } +}; + +// Tests that current_test_info() returns TestInfo for currently running +// test by checking the expected test name against the actual one. +TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestCase) { + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + ASSERT_TRUE(NULL != test_info) + << "There is a test running so we should have a valid TestInfo."; + EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) + << "Expected the name of the currently running test case."; + EXPECT_STREQ("WorksForFirstTestInATestCase", test_info->name()) + << "Expected the name of the currently running test."; +} + +// Tests that current_test_info() returns TestInfo for currently running +// test by checking the expected test name against the actual one. We +// use this test to see that the TestInfo object actually changed from +// the previous invocation. +TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestCase) { + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + ASSERT_TRUE(NULL != test_info) + << "There is a test running so we should have a valid TestInfo."; + EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) + << "Expected the name of the currently running test case."; + EXPECT_STREQ("WorksForSecondTestInATestCase", test_info->name()) + << "Expected the name of the currently running test."; +} + +} // namespace testing + +// These two lines test that we can define tests in a namespace that +// has the name "testing" and is nested in another namespace. +namespace my_namespace { +namespace testing { + +// Makes sure that TEST knows to use ::testing::Test instead of +// ::my_namespace::testing::Test. +class Test {}; + +// Makes sure that an assertion knows to use ::testing::Message instead of +// ::my_namespace::testing::Message. +class Message {}; + +// Makes sure that an assertion knows to use +// ::testing::AssertionResult instead of +// ::my_namespace::testing::AssertionResult. +class AssertionResult {}; + +// Tests that an assertion that should succeed works as expected. +TEST(NestedTestingNamespaceTest, Success) { + EXPECT_EQ(1, 1) << "This shouldn't fail."; +} + +// Tests that an assertion that should fail works as expected. +TEST(NestedTestingNamespaceTest, Failure) { + EXPECT_FATAL_FAILURE(FAIL() << "This failure is expected.", + "This failure is expected."); +} + +} // namespace testing +} // namespace my_namespace + +// Tests that one can call superclass SetUp and TearDown methods-- +// that is, that they are not private. +// No tests are based on this fixture; the test "passes" if it compiles +// successfully. +class ProtectedFixtureMethodsTest : public Test { + protected: + virtual void SetUp() { + Test::SetUp(); + } + virtual void TearDown() { + Test::TearDown(); + } +}; + +// StreamingAssertionsTest tests the streaming versions of a representative +// sample of assertions. +TEST(StreamingAssertionsTest, Unconditional) { + SUCCEED() << "expected success"; + EXPECT_NONFATAL_FAILURE(ADD_FAILURE() << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(FAIL() << "expected failure", + "expected failure"); +} + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +#endif + +TEST(StreamingAssertionsTest, Truth) { + EXPECT_TRUE(true) << "unexpected failure"; + ASSERT_TRUE(true) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_TRUE(false) << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, Truth2) { + EXPECT_FALSE(false) << "unexpected failure"; + ASSERT_FALSE(false) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_FALSE(true) << "expected failure", + "expected failure"); +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" supressed them +# pragma option pop +#endif + +TEST(StreamingAssertionsTest, IntegerEquals) { + EXPECT_EQ(1, 1) << "unexpected failure"; + ASSERT_EQ(1, 1) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(1, 2) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_EQ(1, 2) << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, IntegerLessThan) { + EXPECT_LT(1, 2) << "unexpected failure"; + ASSERT_LT(1, 2) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_LT(2, 1) << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringsEqual) { + EXPECT_STREQ("foo", "foo") << "unexpected failure"; + ASSERT_STREQ("foo", "foo") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ("foo", "bar") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STREQ("foo", "bar") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringsNotEqual) { + EXPECT_STRNE("foo", "bar") << "unexpected failure"; + ASSERT_STRNE("foo", "bar") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("foo", "foo") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STRNE("foo", "foo") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringsEqualIgnoringCase) { + EXPECT_STRCASEEQ("foo", "FOO") << "unexpected failure"; + ASSERT_STRCASEEQ("foo", "FOO") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ("foo", "bar") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("foo", "bar") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringNotEqualIgnoringCase) { + EXPECT_STRCASENE("foo", "bar") << "unexpected failure"; + ASSERT_STRCASENE("foo", "bar") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("foo", "FOO") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("bar", "BAR") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, FloatingPointEquals) { + EXPECT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; + ASSERT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(0.0, 1.0) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.0) << "expected failure", + "expected failure"); +} + +#if GTEST_HAS_EXCEPTIONS + +TEST(StreamingAssertionsTest, Throw) { + EXPECT_THROW(ThrowAnInteger(), int) << "unexpected failure"; + ASSERT_THROW(ThrowAnInteger(), int) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool) << + "expected failure", "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_THROW(ThrowAnInteger(), bool) << + "expected failure", "expected failure"); +} + +TEST(StreamingAssertionsTest, NoThrow) { + EXPECT_NO_THROW(ThrowNothing()) << "unexpected failure"; + ASSERT_NO_THROW(ThrowNothing()) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()) << + "expected failure", "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()) << + "expected failure", "expected failure"); +} + +TEST(StreamingAssertionsTest, AnyThrow) { + EXPECT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; + ASSERT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(ThrowNothing()) << + "expected failure", "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_ANY_THROW(ThrowNothing()) << + "expected failure", "expected failure"); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests that Google Test correctly decides whether to use colors in the output. + +TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsYes) { + GTEST_FLAG(color) = "yes"; + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. + + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. +} + +TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsAliasOfYes) { + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + + GTEST_FLAG(color) = "True"; + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. + + GTEST_FLAG(color) = "t"; + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. + + GTEST_FLAG(color) = "1"; + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. +} + +TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsNo) { + GTEST_FLAG(color) = "no"; + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. + + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. +} + +TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsInvalid) { + SetEnv("TERM", "xterm"); // TERM supports colors. + + GTEST_FLAG(color) = "F"; + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + GTEST_FLAG(color) = "0"; + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + GTEST_FLAG(color) = "unknown"; + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. +} + +TEST(ColoredOutputTest, UsesColorsWhenStdoutIsTty) { + GTEST_FLAG(color) = "auto"; + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. +} + +TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) { + GTEST_FLAG(color) = "auto"; + +#if GTEST_OS_WINDOWS + // On Windows, we ignore the TERM variable as it's usually not set. + + SetEnv("TERM", "dumb"); + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", ""); + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm"); + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. +#else + // On non-Windows platforms, we rely on TERM to determine if the + // terminal supports colors. + + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "emacs"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "vt100"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm-mono"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm-color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm-256color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "screen"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "linux"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "cygwin"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. +#endif // GTEST_OS_WINDOWS +} + +// Verifies that StaticAssertTypeEq works in a namespace scope. + +static bool dummy1 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq(); +static bool dummy2 GTEST_ATTRIBUTE_UNUSED_ = + StaticAssertTypeEq(); + +// Verifies that StaticAssertTypeEq works in a class. + +template +class StaticAssertTypeEqTestHelper { + public: + StaticAssertTypeEqTestHelper() { StaticAssertTypeEq(); } +}; + +TEST(StaticAssertTypeEqTest, WorksInClass) { + StaticAssertTypeEqTestHelper(); +} + +// Verifies that StaticAssertTypeEq works inside a function. + +typedef int IntAlias; + +TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { + StaticAssertTypeEq(); + StaticAssertTypeEq(); +} + +TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) { + testing::UnitTest* const unit_test = testing::UnitTest::GetInstance(); + + // We don't have a stack walker in Google Test yet. + EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 0).c_str()); + EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 1).c_str()); +} + +TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure) { + EXPECT_FALSE(HasNonfatalFailure()); +} + +static void FailFatally() { FAIL(); } + +TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure) { + FailFatally(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_FALSE(has_nonfatal_failure); +} + +TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { + FailFatally(); + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +// A wrapper for calling HasNonfatalFailure outside of a test body. +static bool HasNonfatalFailureHelper() { + return testing::Test::HasNonfatalFailure(); +} + +TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody) { + EXPECT_FALSE(HasNonfatalFailureHelper()); +} + +TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2) { + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailureHelper(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure) { + EXPECT_FALSE(HasFailure()); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure) { + FailFatally(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { + ADD_FAILURE(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { + FailFatally(); + ADD_FAILURE(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +// A wrapper for calling HasFailure outside of a test body. +static bool HasFailureHelper() { return testing::Test::HasFailure(); } + +TEST(HasFailureTest, WorksOutsideOfTestBody) { + EXPECT_FALSE(HasFailureHelper()); +} + +TEST(HasFailureTest, WorksOutsideOfTestBody2) { + ADD_FAILURE(); + const bool has_failure = HasFailureHelper(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +class TestListener : public EmptyTestEventListener { + public: + TestListener() : on_start_counter_(NULL), is_destroyed_(NULL) {} + TestListener(int* on_start_counter, bool* is_destroyed) + : on_start_counter_(on_start_counter), + is_destroyed_(is_destroyed) {} + + virtual ~TestListener() { + if (is_destroyed_) + *is_destroyed_ = true; + } + + protected: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { + if (on_start_counter_ != NULL) + (*on_start_counter_)++; + } + + private: + int* on_start_counter_; + bool* is_destroyed_; +}; + +// Tests the constructor. +TEST(TestEventListenersTest, ConstructionWorks) { + TestEventListeners listeners; + + EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != NULL); + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_TRUE(listeners.default_xml_generator() == NULL); +} + +// Tests that the TestEventListeners destructor deletes all the listeners it +// owns. +TEST(TestEventListenersTest, DestructionWorks) { + bool default_result_printer_is_destroyed = false; + bool default_xml_printer_is_destroyed = false; + bool extra_listener_is_destroyed = false; + TestListener* default_result_printer = new TestListener( + NULL, &default_result_printer_is_destroyed); + TestListener* default_xml_printer = new TestListener( + NULL, &default_xml_printer_is_destroyed); + TestListener* extra_listener = new TestListener( + NULL, &extra_listener_is_destroyed); + + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, + default_result_printer); + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, + default_xml_printer); + listeners.Append(extra_listener); + } + EXPECT_TRUE(default_result_printer_is_destroyed); + EXPECT_TRUE(default_xml_printer_is_destroyed); + EXPECT_TRUE(extra_listener_is_destroyed); +} + +// Tests that a listener Append'ed to a TestEventListeners list starts +// receiving events. +TEST(TestEventListenersTest, Append) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + listeners.Append(listener); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); + } + EXPECT_TRUE(is_destroyed); +} + +// Tests that listeners receive events in the order they were appended to +// the list, except for *End requests, which must be received in the reverse +// order. +class SequenceTestingListener : public EmptyTestEventListener { + public: + SequenceTestingListener(std::vector* vector, const char* id) + : vector_(vector), id_(id) {} + + protected: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { + vector_->push_back(GetEventDescription("OnTestProgramStart")); + } + + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { + vector_->push_back(GetEventDescription("OnTestProgramEnd")); + } + + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) { + vector_->push_back(GetEventDescription("OnTestIterationStart")); + } + + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) { + vector_->push_back(GetEventDescription("OnTestIterationEnd")); + } + + private: + String GetEventDescription(const char* method) { + Message message; + message << id_ << "." << method; + return message.GetString(); + } + + std::vector* vector_; + const char* const id_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener); +}; + +TEST(EventListenerTest, AppendKeepsOrder) { + std::vector vec; + TestEventListeners listeners; + listeners.Append(new SequenceTestingListener(&vec, "1st")); + listeners.Append(new SequenceTestingListener(&vec, "2nd")); + listeners.Append(new SequenceTestingListener(&vec, "3rd")); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("1st.OnTestProgramStart", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestProgramStart", vec[1].c_str()); + EXPECT_STREQ("3rd.OnTestProgramStart", vec[2].c_str()); + + vec.clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd( + *UnitTest::GetInstance()); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("3rd.OnTestProgramEnd", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestProgramEnd", vec[1].c_str()); + EXPECT_STREQ("1st.OnTestProgramEnd", vec[2].c_str()); + + vec.clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart( + *UnitTest::GetInstance(), 0); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("1st.OnTestIterationStart", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestIterationStart", vec[1].c_str()); + EXPECT_STREQ("3rd.OnTestIterationStart", vec[2].c_str()); + + vec.clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd( + *UnitTest::GetInstance(), 0); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("3rd.OnTestIterationEnd", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestIterationEnd", vec[1].c_str()); + EXPECT_STREQ("1st.OnTestIterationEnd", vec[2].c_str()); +} + +// Tests that a listener removed from a TestEventListeners list stops receiving +// events and is not deleted when the list is destroyed. +TEST(TestEventListenersTest, Release) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + listeners.Append(listener); + EXPECT_EQ(listener, listeners.Release(listener)); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_TRUE(listeners.Release(listener) == NULL); + } + EXPECT_EQ(0, on_start_counter); + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Tests that no events are forwarded when event forwarding is disabled. +TEST(EventListenerTest, SuppressEventForwarding) { + int on_start_counter = 0; + TestListener* listener = new TestListener(&on_start_counter, NULL); + + TestEventListeners listeners; + listeners.Append(listener); + ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); + TestEventListenersAccessor::SuppressEventForwarding(&listeners); + ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); +} + +// Tests that events generated by Google Test are not forwarded in +// death test subprocesses. +TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) { + EXPECT_DEATH_IF_SUPPORTED({ + GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled( + *GetUnitTestImpl()->listeners())) << "expected failure";}, + "expected failure"); +} + +// Tests that a listener installed via SetDefaultResultPrinter() starts +// receiving events and is returned via default_result_printer() and that +// the previous default_result_printer is removed from the list and deleted. +TEST(EventListenerTest, default_result_printer) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_result_printer()); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_result_printer with something else should remove it + // from the list and destroy it. + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, NULL); + + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_TRUE(is_destroyed); + + // After broadcasting an event the counter is still the same, indicating + // the listener is not in the list anymore. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); +} + +// Tests that the default_result_printer listener stops receiving events +// when removed via Release and that is not owned by the list anymore. +TEST(EventListenerTest, RemovingDefaultResultPrinterWorks) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.Release(listener)); + EXPECT_TRUE(listeners.default_result_printer() == NULL); + EXPECT_FALSE(is_destroyed); + + // Broadcasting events now should not affect default_result_printer. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); + } + // Destroying the list should not affect the listener now, too. + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Tests that a listener installed via SetDefaultXmlGenerator() starts +// receiving events and is returned via default_xml_generator() and that +// the previous default_xml_generator is removed from the list and deleted. +TEST(EventListenerTest, default_xml_generator) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_xml_generator()); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_xml_generator with something else should remove it + // from the list and destroy it. + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, NULL); + + EXPECT_TRUE(listeners.default_xml_generator() == NULL); + EXPECT_TRUE(is_destroyed); + + // After broadcasting an event the counter is still the same, indicating + // the listener is not in the list anymore. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); +} + +// Tests that the default_xml_generator listener stops receiving events +// when removed via Release and that is not owned by the list anymore. +TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.Release(listener)); + EXPECT_TRUE(listeners.default_xml_generator() == NULL); + EXPECT_FALSE(is_destroyed); + + // Broadcasting events now should not affect default_xml_generator. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); + } + // Destroying the list should not affect the listener now, too. + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Sanity tests to ensure that the alternative, verbose spellings of +// some of the macros work. We don't test them thoroughly as that +// would be quite involved. Since their implementations are +// straightforward, and they are rarely used, we'll just rely on the +// users to tell us when they are broken. +GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST. + GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED. + + // GTEST_FAIL is the same as FAIL. + EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure", + "An expected failure"); + + // GTEST_ASSERT_XY is the same as ASSERT_XY. + + GTEST_ASSERT_EQ(0, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(0, 1) << "An expected failure", + "An expected failure"); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(1, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_NE(0, 1); + GTEST_ASSERT_NE(1, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_NE(0, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_LE(0, 0); + GTEST_ASSERT_LE(0, 1); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_LE(1, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_LT(0, 1); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(0, 0) << "An expected failure", + "An expected failure"); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(1, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_GE(0, 0); + GTEST_ASSERT_GE(1, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_GE(0, 1) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_GT(1, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(0, 1) << "An expected failure", + "An expected failure"); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(1, 1) << "An expected failure", + "An expected failure"); +} + +// Tests for internal utilities necessary for implementation of the universal +// printing. +// TODO(vladl@google.com): Find a better home for them. + +class ConversionHelperBase {}; +class ConversionHelperDerived : public ConversionHelperBase {}; + +// Tests that IsAProtocolMessage::value is a compile-time constant. +TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { + GTEST_COMPILE_ASSERT_(IsAProtocolMessage::value, + const_true); + GTEST_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); +} + +// Tests that IsAProtocolMessage::value is true when T is +// proto2::Message or a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { + EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); + EXPECT_TRUE(IsAProtocolMessage::value); +} + +// Tests that IsAProtocolMessage::value is false when T is neither +// ProtocolMessage nor a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { + EXPECT_FALSE(IsAProtocolMessage::value); + EXPECT_FALSE(IsAProtocolMessage::value); +} + +// Tests that CompileAssertTypesEqual compiles when the type arguments are +// equal. +TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { + CompileAssertTypesEqual(); + CompileAssertTypesEqual(); +} + +// Tests that RemoveReference does not affect non-reference types. +TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests that RemoveReference removes reference from reference types. +TEST(RemoveReferenceTest, RemovesReference) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests GTEST_REMOVE_REFERENCE_. + +template +void TestGTestRemoveReference() { + CompileAssertTypesEqual(); +} + +TEST(RemoveReferenceTest, MacroVersion) { + TestGTestRemoveReference(); + TestGTestRemoveReference(); +} + + +// Tests that RemoveConst does not affect non-const types. +TEST(RemoveConstTest, DoesNotAffectNonConstType) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests that RemoveConst removes const from const types. +TEST(RemoveConstTest, RemovesConst) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests GTEST_REMOVE_CONST_. + +template +void TestGTestRemoveConst() { + CompileAssertTypesEqual(); +} + +TEST(RemoveConstTest, MacroVersion) { + TestGTestRemoveConst(); + TestGTestRemoveConst(); + TestGTestRemoveConst(); +} + +// Tests GTEST_REMOVE_REFERENCE_AND_CONST_. + +template +void TestGTestRemoveReferenceAndConst() { + CompileAssertTypesEqual(); +} + +TEST(RemoveReferenceToConstTest, Works) { + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); +} + +// Tests that AddReference does not affect reference types. +TEST(AddReferenceTest, DoesNotAffectReferenceType) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests that AddReference adds reference to non-reference types. +TEST(AddReferenceTest, AddsReference) { + CompileAssertTypesEqual::type>(); + CompileAssertTypesEqual::type>(); +} + +// Tests GTEST_ADD_REFERENCE_. + +template +void TestGTestAddReference() { + CompileAssertTypesEqual(); +} + +TEST(AddReferenceTest, MacroVersion) { + TestGTestAddReference(); + TestGTestAddReference(); +} + +// Tests GTEST_REFERENCE_TO_CONST_. + +template +void TestGTestReferenceToConst() { + CompileAssertTypesEqual(); +} + +TEST(GTestReferenceToConstTest, Works) { + TestGTestReferenceToConst(); + TestGTestReferenceToConst(); + TestGTestReferenceToConst(); + TestGTestReferenceToConst(); +} + +// Tests that ImplicitlyConvertible::value is a compile-time constant. +TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { + GTEST_COMPILE_ASSERT_((ImplicitlyConvertible::value), const_true); + GTEST_COMPILE_ASSERT_((!ImplicitlyConvertible::value), + const_false); +} + +// Tests that ImplicitlyConvertible::value is true when T1 can +// be implicitly converted to T2. +TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) { + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); + EXPECT_TRUE((ImplicitlyConvertible::value)); +} + +// Tests that ImplicitlyConvertible::value is false when T1 +// cannot be implicitly converted to T2. +TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { + EXPECT_FALSE((ImplicitlyConvertible::value)); + EXPECT_FALSE((ImplicitlyConvertible::value)); + EXPECT_FALSE((ImplicitlyConvertible::value)); + EXPECT_FALSE((ImplicitlyConvertible::value)); +} + +// Tests IsContainerTest. + +class NonContainer {}; + +TEST(IsContainerTestTest, WorksForNonContainer) { + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); +} + +TEST(IsContainerTestTest, WorksForContainer) { + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest >(0))); + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest >(0))); +} + +// Tests ArrayEq(). + +TEST(ArrayEqTest, WorksForDegeneratedArrays) { + EXPECT_TRUE(ArrayEq(5, 5L)); + EXPECT_FALSE(ArrayEq('a', 0)); +} + +TEST(ArrayEqTest, WorksForOneDimensionalArrays) { + const int a[] = { 0, 1 }; + long b[] = { 0, 1 }; + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + b[0] = 2; + EXPECT_FALSE(ArrayEq(a, b)); + EXPECT_FALSE(ArrayEq(a, 1, b)); +} + +TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { + const char a[][3] = { "hi", "lo" }; + const char b[][3] = { "hi", "lo" }; + const char c[][3] = { "hi", "li" }; + + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + EXPECT_FALSE(ArrayEq(a, c)); + EXPECT_FALSE(ArrayEq(a, 2, c)); +} + +// Tests ArrayAwareFind(). + +TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { + const char a[] = "hello"; + EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); + EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); +} + +TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { + int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; + const int b[2] = { 2, 3 }; + EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); + + const int c[2] = { 6, 7 }; + EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); +} + +// Tests CopyArray(). + +TEST(CopyArrayTest, WorksForDegeneratedArrays) { + int n = 0; + CopyArray('a', &n); + EXPECT_EQ('a', n); +} + +TEST(CopyArrayTest, WorksForOneDimensionalArrays) { + const char a[3] = "hi"; + int b[3]; +#ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); +#endif + + int c[3]; + CopyArray(a, 3, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { + const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; + int b[2][3]; +#ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); +#endif + + int c[2][3]; + CopyArray(a, 2, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +// Tests NativeArray. + +TEST(NativeArrayTest, ConstructorFromArrayWorks) { + const int a[3] = { 0, 1, 2 }; + NativeArray na(a, 3, kReference); + EXPECT_EQ(3U, na.size()); + EXPECT_EQ(a, na.begin()); +} + +TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { + typedef int Array[2]; + Array* a = new Array[1]; + (*a)[0] = 0; + (*a)[1] = 1; + NativeArray na(*a, 2, kCopy); + EXPECT_NE(*a, na.begin()); + delete[] a; + EXPECT_EQ(0, na.begin()[0]); + EXPECT_EQ(1, na.begin()[1]); + + // We rely on the heap checker to verify that na deletes the copy of + // array. +} + +TEST(NativeArrayTest, TypeMembersAreCorrect) { + StaticAssertTypeEq::value_type>(); + StaticAssertTypeEq::value_type>(); + + StaticAssertTypeEq::const_iterator>(); + StaticAssertTypeEq::const_iterator>(); +} + +TEST(NativeArrayTest, MethodsWork) { + const int a[3] = { 0, 1, 2 }; + NativeArray na(a, 3, kCopy); + ASSERT_EQ(3U, na.size()); + EXPECT_EQ(3, na.end() - na.begin()); + + NativeArray::const_iterator it = na.begin(); + EXPECT_EQ(0, *it); + ++it; + EXPECT_EQ(1, *it); + it++; + EXPECT_EQ(2, *it); + ++it; + EXPECT_EQ(na.end(), it); + + EXPECT_TRUE(na == na); + + NativeArray na2(a, 3, kReference); + EXPECT_TRUE(na == na2); + + const int b1[3] = { 0, 1, 1 }; + const int b2[4] = { 0, 1, 2, 3 }; + EXPECT_FALSE(na == NativeArray(b1, 3, kReference)); + EXPECT_FALSE(na == NativeArray(b2, 4, kCopy)); +} + +TEST(NativeArrayTest, WorksForTwoDimensionalArray) { + const char a[2][3] = { "hi", "lo" }; + NativeArray na(a, 2, kReference); + ASSERT_EQ(2U, na.size()); + EXPECT_EQ(a, na.begin()); +} + +// Tests SkipPrefix(). + +TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { + const char* const str = "hello"; + + const char* p = str; + EXPECT_TRUE(SkipPrefix("", &p)); + EXPECT_EQ(str, p); + + p = str; + EXPECT_TRUE(SkipPrefix("hell", &p)); + EXPECT_EQ(str + 4, p); +} + +TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { + const char* const str = "world"; + + const char* p = str; + EXPECT_FALSE(SkipPrefix("W", &p)); + EXPECT_EQ(str, p); + + p = str; + EXPECT_FALSE(SkipPrefix("world!", &p)); + EXPECT_EQ(str, p); +} diff --git a/third_party/googletest/src/test/gtest_xml_outfile1_test_.cc b/third_party/googletest/src/test/gtest_xml_outfile1_test_.cc new file mode 100644 index 0000000..531ced4 --- /dev/null +++ b/third_party/googletest/src/test/gtest_xml_outfile1_test_.cc @@ -0,0 +1,49 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// gtest_xml_outfile1_test_ writes some xml via TestProperty used by +// gtest_xml_outfiles_test.py + +#include "gtest/gtest.h" + +class PropertyOne : public testing::Test { + protected: + virtual void SetUp() { + RecordProperty("SetUpProp", 1); + } + virtual void TearDown() { + RecordProperty("TearDownProp", 1); + } +}; + +TEST_F(PropertyOne, TestSomeProperties) { + RecordProperty("TestSomeProperty", 1); +} diff --git a/third_party/googletest/src/test/gtest_xml_outfile2_test_.cc b/third_party/googletest/src/test/gtest_xml_outfile2_test_.cc new file mode 100644 index 0000000..7b400b2 --- /dev/null +++ b/third_party/googletest/src/test/gtest_xml_outfile2_test_.cc @@ -0,0 +1,49 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// gtest_xml_outfile2_test_ writes some xml via TestProperty used by +// gtest_xml_outfiles_test.py + +#include "gtest/gtest.h" + +class PropertyTwo : public testing::Test { + protected: + virtual void SetUp() { + RecordProperty("SetUpProp", 2); + } + virtual void TearDown() { + RecordProperty("TearDownProp", 2); + } +}; + +TEST_F(PropertyTwo, TestSomeProperties) { + RecordProperty("TestSomeProperty", 2); +} diff --git a/third_party/googletest/src/test/gtest_xml_outfiles_test.py b/third_party/googletest/src/test/gtest_xml_outfiles_test.py new file mode 100755 index 0000000..0fe947f --- /dev/null +++ b/third_party/googletest/src/test/gtest_xml_outfiles_test.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for the gtest_xml_output module.""" + +__author__ = "keith.ray@gmail.com (Keith Ray)" + +import os +from xml.dom import minidom, Node + +import gtest_test_utils +import gtest_xml_test_utils + + +GTEST_OUTPUT_SUBDIR = "xml_outfiles" +GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_" +GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_" + +EXPECTED_XML_1 = """ + + + + + +""" + +EXPECTED_XML_2 = """ + + + + + +""" + + +class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase): + """Unit test for Google Test's XML output functionality.""" + + def setUp(self): + # We want the trailing '/' that the last "" provides in os.path.join, for + # telling Google Test to create an output directory instead of a single file + # for xml output. + self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_OUTPUT_SUBDIR, "") + self.DeleteFilesAndDir() + + def tearDown(self): + self.DeleteFilesAndDir() + + def DeleteFilesAndDir(self): + try: + os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml")) + except os.error: + pass + try: + os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml")) + except os.error: + pass + try: + os.rmdir(self.output_dir_) + except os.error: + pass + + def testOutfile1(self): + self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_XML_1) + + def testOutfile2(self): + self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_XML_2) + + def _TestOutFile(self, test_name, expected_xml): + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name) + command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_] + p = gtest_test_utils.Subprocess(command, + working_dir=gtest_test_utils.GetTempDir()) + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + + # TODO(wan@google.com): libtool causes the built test binary to be + # named lt-gtest_xml_outfiles_test_ instead of + # gtest_xml_outfiles_test_. To account for this possibillity, we + # allow both names in the following code. We should remove this + # hack when Chandler Carruth's libtool replacement tool is ready. + output_file_name1 = test_name + ".xml" + output_file1 = os.path.join(self.output_dir_, output_file_name1) + output_file_name2 = 'lt-' + output_file_name1 + output_file2 = os.path.join(self.output_dir_, output_file_name2) + self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2), + output_file1) + + expected = minidom.parseString(expected_xml) + if os.path.isfile(output_file1): + actual = minidom.parse(output_file1) + else: + actual = minidom.parse(output_file2) + self.NormalizeXml(actual.documentElement) + self.AssertEquivalentNodes(expected.documentElement, + actual.documentElement) + expected.unlink() + actual.unlink() + + +if __name__ == "__main__": + os.environ["GTEST_STACK_TRACE_DEPTH"] = "0" + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_xml_output_unittest.py b/third_party/googletest/src/test/gtest_xml_output_unittest.py new file mode 100755 index 0000000..bdd5035 --- /dev/null +++ b/third_party/googletest/src/test/gtest_xml_output_unittest.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for the gtest_xml_output module""" + +__author__ = 'eefacm@gmail.com (Sean Mcafee)' + +import errno +import os +import sys +from xml.dom import minidom, Node + +import gtest_test_utils +import gtest_xml_test_utils + + +GTEST_OUTPUT_FLAG = "--gtest_output" +GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" +GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_" + +SUPPORTS_STACK_TRACES = False + +if SUPPORTS_STACK_TRACES: + STACK_TRACE_TEMPLATE = "\nStack trace:\n*" +else: + STACK_TRACE_TEMPLATE = "" + +EXPECTED_NON_EMPTY_XML = """ + + + + + + + + + + + + + + + + + + + + ]]>%(stack)s]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +""" % {'stack': STACK_TRACE_TEMPLATE} + + +EXPECTED_EMPTY_XML = """ + +""" + + +class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): + """ + Unit test for Google Test's XML output functionality. + """ + + def testNonEmptyXmlOutput(self): + """ + Runs a test program that generates a non-empty XML output, and + tests that the XML output is expected. + """ + self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1) + + def testEmptyXmlOutput(self): + """ + Runs a test program that generates an empty XML output, and + tests that the XML output is expected. + """ + + self._TestXmlOutput("gtest_no_test_unittest", + EXPECTED_EMPTY_XML, 0) + + def testDefaultOutputFile(self): + """ + Confirms that Google Test produces an XML output file with the expected + default name if no name is explicitly specified. + """ + output_file = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_DEFAULT_OUTPUT_FILE) + gtest_prog_path = gtest_test_utils.GetTestExecutablePath( + "gtest_no_test_unittest") + try: + os.remove(output_file) + except OSError, e: + if e.errno != errno.ENOENT: + raise + + p = gtest_test_utils.Subprocess( + [gtest_prog_path, "%s=xml" % GTEST_OUTPUT_FLAG], + working_dir=gtest_test_utils.GetTempDir()) + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + self.assert_(os.path.isfile(output_file)) + + def testSuppressedXmlOutput(self): + """ + Tests that no XML file is generated if the default XML listener is + shut down before RUN_ALL_TESTS is invoked. + """ + + xml_path = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_PROGRAM_NAME + "out.xml") + if os.path.isfile(xml_path): + os.remove(xml_path) + + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) + + command = [gtest_prog_path, + "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path), + "--shut_down_xml"] + p = gtest_test_utils.Subprocess(command) + if p.terminated_by_signal: + self.assert_(False, + "%s was killed by signal %d" % (gtest_prog_name, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(1, p.exit_code, + "'%s' exited with code %s, which doesn't match " + "the expected exit code %s." + % (command, p.exit_code, 1)) + + self.assert_(not os.path.isfile(xml_path)) + + + def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code): + """ + Asserts that the XML document generated by running the program + gtest_prog_name matches expected_xml, a string containing another + XML document. Furthermore, the program's exit code must be + expected_exit_code. + """ + xml_path = os.path.join(gtest_test_utils.GetTempDir(), + gtest_prog_name + "out.xml") + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name) + + command = [gtest_prog_path, "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path)] + p = gtest_test_utils.Subprocess(command) + if p.terminated_by_signal: + self.assert_(False, + "%s was killed by signal %d" % (gtest_prog_name, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(expected_exit_code, p.exit_code, + "'%s' exited with code %s, which doesn't match " + "the expected exit code %s." + % (command, p.exit_code, expected_exit_code)) + + expected = minidom.parseString(expected_xml) + actual = minidom.parse(xml_path) + self.NormalizeXml(actual.documentElement) + self.AssertEquivalentNodes(expected.documentElement, + actual.documentElement) + expected.unlink() + actual .unlink() + + + +if __name__ == '__main__': + os.environ['GTEST_STACK_TRACE_DEPTH'] = '1' + gtest_test_utils.Main() diff --git a/third_party/googletest/src/test/gtest_xml_output_unittest_.cc b/third_party/googletest/src/test/gtest_xml_output_unittest_.cc new file mode 100644 index 0000000..741a887 --- /dev/null +++ b/third_party/googletest/src/test/gtest_xml_output_unittest_.cc @@ -0,0 +1,174 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: eefacm@gmail.com (Sean Mcafee) + +// Unit test for Google Test XML output. +// +// A user can specify XML output in a Google Test program to run via +// either the GTEST_OUTPUT environment variable or the --gtest_output +// flag. This is used for testing such functionality. +// +// This program will be invoked from a Python unit test. Don't run it +// directly. + +#include "gtest/gtest.h" + +using ::testing::InitGoogleTest; +using ::testing::TestEventListeners; +using ::testing::TestWithParam; +using ::testing::UnitTest; +using ::testing::Test; +using ::testing::Types; +using ::testing::Values; + +class SuccessfulTest : public Test { +}; + +TEST_F(SuccessfulTest, Succeeds) { + SUCCEED() << "This is a success."; + ASSERT_EQ(1, 1); +} + +class FailedTest : public Test { +}; + +TEST_F(FailedTest, Fails) { + ASSERT_EQ(1, 2); +} + +class DisabledTest : public Test { +}; + +TEST_F(DisabledTest, DISABLED_test_not_run) { + FAIL() << "Unexpected failure: Disabled test should not be run"; +} + +TEST(MixedResultTest, Succeeds) { + EXPECT_EQ(1, 1); + ASSERT_EQ(1, 1); +} + +TEST(MixedResultTest, Fails) { + EXPECT_EQ(1, 2); + ASSERT_EQ(2, 3); +} + +TEST(MixedResultTest, DISABLED_test) { + FAIL() << "Unexpected failure: Disabled test should not be run"; +} + +TEST(XmlQuotingTest, OutputsCData) { + FAIL() << "XML output: " + ""; +} + +// Helps to test that invalid characters produced by test code do not make +// it into the XML file. +TEST(InvalidCharactersTest, InvalidCharactersInMessage) { + FAIL() << "Invalid characters in brackets [\x1\x2]"; +} + +class PropertyRecordingTest : public Test { +}; + +TEST_F(PropertyRecordingTest, OneProperty) { + RecordProperty("key_1", "1"); +} + +TEST_F(PropertyRecordingTest, IntValuedProperty) { + RecordProperty("key_int", 1); +} + +TEST_F(PropertyRecordingTest, ThreeProperties) { + RecordProperty("key_1", "1"); + RecordProperty("key_2", "2"); + RecordProperty("key_3", "3"); +} + +TEST_F(PropertyRecordingTest, TwoValuesForOneKeyUsesLastValue) { + RecordProperty("key_1", "1"); + RecordProperty("key_1", "2"); +} + +TEST(NoFixtureTest, RecordProperty) { + RecordProperty("key", "1"); +} + +void ExternalUtilityThatCallsRecordProperty(const char* key, int value) { + testing::Test::RecordProperty(key, value); +} + +void ExternalUtilityThatCallsRecordProperty(const char* key, + const char* value) { + testing::Test::RecordProperty(key, value); +} + +TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { + ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1); +} + +TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { + ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); +} + +// Verifies that the test parameter value is output in the 'value_param' +// XML attribute for value-parameterized tests. +class ValueParamTest : public TestWithParam {}; +TEST_P(ValueParamTest, HasValueParamAttribute) {} +TEST_P(ValueParamTest, AnotherTestThatHasValueParamAttribute) {} +INSTANTIATE_TEST_CASE_P(Single, ValueParamTest, Values(33, 42)); + +// Verifies that the type parameter name is output in the 'type_param' +// XML attribute for typed tests. +template class TypedTest : public Test {}; +typedef Types TypedTestTypes; +TYPED_TEST_CASE(TypedTest, TypedTestTypes); +TYPED_TEST(TypedTest, HasTypeParamAttribute) {} + +// Verifies that the type parameter name is output in the 'type_param' +// XML attribute for type-parameterized tests. +template class TypeParameterizedTestCase : public Test {}; +TYPED_TEST_CASE_P(TypeParameterizedTestCase); +TYPED_TEST_P(TypeParameterizedTestCase, HasTypeParamAttribute) {} +REGISTER_TYPED_TEST_CASE_P(TypeParameterizedTestCase, HasTypeParamAttribute); +typedef Types TypeParameterizedTestCaseTypes; +INSTANTIATE_TYPED_TEST_CASE_P(Single, + TypeParameterizedTestCase, + TypeParameterizedTestCaseTypes); + +int main(int argc, char** argv) { + InitGoogleTest(&argc, argv); + + if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) { + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + delete listeners.Release(listeners.default_xml_generator()); + } + return RUN_ALL_TESTS(); +} diff --git a/third_party/googletest/src/test/gtest_xml_test_utils.py b/third_party/googletest/src/test/gtest_xml_test_utils.py new file mode 100755 index 0000000..0f55c16 --- /dev/null +++ b/third_party/googletest/src/test/gtest_xml_test_utils.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test utilities for gtest_xml_output""" + +__author__ = 'eefacm@gmail.com (Sean Mcafee)' + +import re +from xml.dom import minidom, Node + +import gtest_test_utils + + +GTEST_OUTPUT_FLAG = "--gtest_output" +GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" + +class GTestXMLTestCase(gtest_test_utils.TestCase): + """ + Base class for tests of Google Test's XML output functionality. + """ + + + def AssertEquivalentNodes(self, expected_node, actual_node): + """ + Asserts that actual_node (a DOM node object) is equivalent to + expected_node (another DOM node object), in that either both of + them are CDATA nodes and have the same value, or both are DOM + elements and actual_node meets all of the following conditions: + + * It has the same tag name as expected_node. + * It has the same set of attributes as expected_node, each with + the same value as the corresponding attribute of expected_node. + Exceptions are any attribute named "time", which needs only be + convertible to a floating-point number and any attribute named + "type_param" which only has to be non-empty. + * It has an equivalent set of child nodes (including elements and + CDATA sections) as expected_node. Note that we ignore the + order of the children as they are not guaranteed to be in any + particular order. + """ + + if expected_node.nodeType == Node.CDATA_SECTION_NODE: + self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType) + self.assertEquals(expected_node.nodeValue, actual_node.nodeValue) + return + + self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType) + self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType) + self.assertEquals(expected_node.tagName, actual_node.tagName) + + expected_attributes = expected_node.attributes + actual_attributes = actual_node .attributes + self.assertEquals( + expected_attributes.length, actual_attributes.length, + "attribute numbers differ in element " + actual_node.tagName) + for i in range(expected_attributes.length): + expected_attr = expected_attributes.item(i) + actual_attr = actual_attributes.get(expected_attr.name) + self.assert_( + actual_attr is not None, + "expected attribute %s not found in element %s" % + (expected_attr.name, actual_node.tagName)) + self.assertEquals(expected_attr.value, actual_attr.value, + " values of attribute %s in element %s differ" % + (expected_attr.name, actual_node.tagName)) + + expected_children = self._GetChildren(expected_node) + actual_children = self._GetChildren(actual_node) + self.assertEquals( + len(expected_children), len(actual_children), + "number of child elements differ in element " + actual_node.tagName) + for child_id, child in expected_children.iteritems(): + self.assert_(child_id in actual_children, + '<%s> is not in <%s> (in element %s)' % + (child_id, actual_children, actual_node.tagName)) + self.AssertEquivalentNodes(child, actual_children[child_id]) + + identifying_attribute = { + "testsuites": "name", + "testsuite": "name", + "testcase": "name", + "failure": "message", + } + + def _GetChildren(self, element): + """ + Fetches all of the child nodes of element, a DOM Element object. + Returns them as the values of a dictionary keyed by the IDs of the + children. For , and elements, the ID + is the value of their "name" attribute; for elements, it is + the value of the "message" attribute; CDATA sections and non-whitespace + text nodes are concatenated into a single CDATA section with ID + "detail". An exception is raised if any element other than the above + four is encountered, if two child elements with the same identifying + attributes are encountered, or if any other type of node is encountered. + """ + + children = {} + for child in element.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + self.assert_(child.tagName in self.identifying_attribute, + "Encountered unknown element <%s>" % child.tagName) + childID = child.getAttribute(self.identifying_attribute[child.tagName]) + self.assert_(childID not in children) + children[childID] = child + elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: + if "detail" not in children: + if (child.nodeType == Node.CDATA_SECTION_NODE or + not child.nodeValue.isspace()): + children["detail"] = child.ownerDocument.createCDATASection( + child.nodeValue) + else: + children["detail"].nodeValue += child.nodeValue + else: + self.fail("Encountered unexpected node type %d" % child.nodeType) + return children + + def NormalizeXml(self, element): + """ + Normalizes Google Test's XML output to eliminate references to transient + information that may change from run to run. + + * The "time" attribute of , and + elements is replaced with a single asterisk, if it contains + only digit characters. + * The "type_param" attribute of elements is replaced with a + single asterisk (if it sn non-empty) as it is the type name returned + by the compiler and is platform dependent. + * The line number reported in the first line of the "message" + attribute of elements is replaced with a single asterisk. + * The directory names in file paths are removed. + * The stack traces are removed. + """ + + if element.tagName in ("testsuites", "testsuite", "testcase"): + time = element.getAttributeNode("time") + time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value) + type_param = element.getAttributeNode("type_param") + if type_param and type_param.value: + type_param.value = "*" + elif element.tagName == "failure": + for child in element.childNodes: + if child.nodeType == Node.CDATA_SECTION_NODE: + # Removes the source line number. + cdata = re.sub(r"^.*[/\\](.*:)\d+\n", "\\1*\n", child.nodeValue) + # Removes the actual stack trace. + child.nodeValue = re.sub(r"\nStack trace:\n(.|\n)*", + "", cdata) + for child in element.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + self.NormalizeXml(child) diff --git a/third_party/googletest/src/test/production.cc b/third_party/googletest/src/test/production.cc new file mode 100644 index 0000000..8b8a40b --- /dev/null +++ b/third_party/googletest/src/test/production.cc @@ -0,0 +1,36 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This is part of the unit test for include/gtest/gtest_prod.h. + +#include "production.h" + +PrivateCode::PrivateCode() : x_(0) {} diff --git a/third_party/googletest/src/test/production.h b/third_party/googletest/src/test/production.h new file mode 100644 index 0000000..98fd5e4 --- /dev/null +++ b/third_party/googletest/src/test/production.h @@ -0,0 +1,55 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This is part of the unit test for include/gtest/gtest_prod.h. + +#ifndef GTEST_TEST_PRODUCTION_H_ +#define GTEST_TEST_PRODUCTION_H_ + +#include "gtest/gtest_prod.h" + +class PrivateCode { + public: + // Declares a friend test that does not use a fixture. + FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers); + + // Declares a friend test that uses a fixture. + FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers); + + PrivateCode(); + + int x() const { return x_; } + private: + void set_x(int an_x) { x_ = an_x; } + int x_; +}; + +#endif // GTEST_TEST_PRODUCTION_H_ diff --git a/third_party/googletest/src/xcode/Config/DebugProject.xcconfig b/third_party/googletest/src/xcode/Config/DebugProject.xcconfig new file mode 100644 index 0000000..3d68157 --- /dev/null +++ b/third_party/googletest/src/xcode/Config/DebugProject.xcconfig @@ -0,0 +1,30 @@ +// +// DebugProject.xcconfig +// +// These are Debug Configuration project settings for the gtest framework and +// examples. It is set in the "Based On:" dropdown in the "Project" info +// dialog. +// This file is based on the Xcode Configuration files in: +// http://code.google.com/p/google-toolbox-for-mac/ +// + +#include "General.xcconfig" + +// No optimization +GCC_OPTIMIZATION_LEVEL = 0 + +// Deployment postprocessing is what triggers Xcode to strip, turn it off +DEPLOYMENT_POSTPROCESSING = NO + +// Dead code stripping off +DEAD_CODE_STRIPPING = NO + +// Debug symbols should be on obviously +GCC_GENERATE_DEBUGGING_SYMBOLS = YES + +// Define the DEBUG macro in all debug builds +OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1 + +// These are turned off to avoid STL incompatibilities with client code +// // Turns on special C++ STL checks to "encourage" good STL use +// GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS diff --git a/third_party/googletest/src/xcode/Config/FrameworkTarget.xcconfig b/third_party/googletest/src/xcode/Config/FrameworkTarget.xcconfig new file mode 100644 index 0000000..357b1c8 --- /dev/null +++ b/third_party/googletest/src/xcode/Config/FrameworkTarget.xcconfig @@ -0,0 +1,17 @@ +// +// FrameworkTarget.xcconfig +// +// These are Framework target settings for the gtest framework and examples. It +// is set in the "Based On:" dropdown in the "Target" info dialog. +// This file is based on the Xcode Configuration files in: +// http://code.google.com/p/google-toolbox-for-mac/ +// + +// Dynamic libs need to be position independent +GCC_DYNAMIC_NO_PIC = NO + +// Dynamic libs should not have their external symbols stripped. +STRIP_STYLE = non-global + +// Let the user install by specifying the $DSTROOT with xcodebuild +SKIP_INSTALL = NO diff --git a/third_party/googletest/src/xcode/Config/General.xcconfig b/third_party/googletest/src/xcode/Config/General.xcconfig new file mode 100644 index 0000000..f23e322 --- /dev/null +++ b/third_party/googletest/src/xcode/Config/General.xcconfig @@ -0,0 +1,41 @@ +// +// General.xcconfig +// +// These are General configuration settings for the gtest framework and +// examples. +// This file is based on the Xcode Configuration files in: +// http://code.google.com/p/google-toolbox-for-mac/ +// + +// Build for PPC and Intel, 32- and 64-bit +ARCHS = i386 x86_64 ppc ppc64 + +// Zerolink prevents link warnings so turn it off +ZERO_LINK = NO + +// Prebinding considered unhelpful in 10.3 and later +PREBINDING = NO + +// Strictest warning policy +WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof -Wno-sign-compare -Wshadow + +// Work around Xcode bugs by using external strip. See: +// http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html +SEPARATE_STRIP = YES + +// Force C99 dialect +GCC_C_LANGUAGE_STANDARD = c99 + +// not sure why apple defaults this on, but it's pretty risky +ALWAYS_SEARCH_USER_PATHS = NO + +// Turn on position dependent code for most cases (overridden where appropriate) +GCC_DYNAMIC_NO_PIC = YES + +// Default SDK and minimum OS version is 10.4 +SDKROOT = $(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk +MACOSX_DEPLOYMENT_TARGET = 10.4 +GCC_VERSION = 4.0 + +// VERSIONING BUILD SETTINGS (used in Info.plist) +GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc. diff --git a/third_party/googletest/src/xcode/Config/ReleaseProject.xcconfig b/third_party/googletest/src/xcode/Config/ReleaseProject.xcconfig new file mode 100644 index 0000000..5349f0a --- /dev/null +++ b/third_party/googletest/src/xcode/Config/ReleaseProject.xcconfig @@ -0,0 +1,32 @@ +// +// ReleaseProject.xcconfig +// +// These are Release Configuration project settings for the gtest framework +// and examples. It is set in the "Based On:" dropdown in the "Project" info +// dialog. +// This file is based on the Xcode Configuration files in: +// http://code.google.com/p/google-toolbox-for-mac/ +// + +#include "General.xcconfig" + +// subconfig/Release.xcconfig + +// Optimize for space and size (Apple recommendation) +GCC_OPTIMIZATION_LEVEL = s + +// Deploment postprocessing is what triggers Xcode to strip +DEPLOYMENT_POSTPROCESSING = YES + +// No symbols +GCC_GENERATE_DEBUGGING_SYMBOLS = NO + +// Dead code strip does not affect ObjC code but can help for C +DEAD_CODE_STRIPPING = YES + +// NDEBUG is used by things like assert.h, so define it for general compat. +// ASSERT going away in release tends to create unused vars. +OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable + +// When we strip we want to strip all symbols in release, but save externals. +STRIP_STYLE = all diff --git a/third_party/googletest/src/xcode/Config/StaticLibraryTarget.xcconfig b/third_party/googletest/src/xcode/Config/StaticLibraryTarget.xcconfig new file mode 100644 index 0000000..3922fa5 --- /dev/null +++ b/third_party/googletest/src/xcode/Config/StaticLibraryTarget.xcconfig @@ -0,0 +1,18 @@ +// +// StaticLibraryTarget.xcconfig +// +// These are static library target settings for libgtest.a. It +// is set in the "Based On:" dropdown in the "Target" info dialog. +// This file is based on the Xcode Configuration files in: +// http://code.google.com/p/google-toolbox-for-mac/ +// + +// Static libs can be included in bundles so make them position independent +GCC_DYNAMIC_NO_PIC = NO + +// Static libs should not have their internal globals or external symbols +// stripped. +STRIP_STYLE = debugging + +// Let the user install by specifying the $DSTROOT with xcodebuild +SKIP_INSTALL = NO diff --git a/third_party/googletest/src/xcode/Config/TestTarget.xcconfig b/third_party/googletest/src/xcode/Config/TestTarget.xcconfig new file mode 100644 index 0000000..e6652ba --- /dev/null +++ b/third_party/googletest/src/xcode/Config/TestTarget.xcconfig @@ -0,0 +1,8 @@ +// +// TestTarget.xcconfig +// +// These are Test target settings for the gtest framework and examples. It +// is set in the "Based On:" dropdown in the "Target" info dialog. + +PRODUCT_NAME = $(TARGET_NAME) +HEADER_SEARCH_PATHS = ../include diff --git a/third_party/googletest/src/xcode/Resources/Info.plist b/third_party/googletest/src/xcode/Resources/Info.plist new file mode 100644 index 0000000..9dd28ea --- /dev/null +++ b/third_party/googletest/src/xcode/Resources/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.google.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + GTEST_VERSIONINFO_LONG + CFBundleShortVersionString + GTEST_VERSIONINFO_SHORT + CFBundleGetInfoString + ${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT} + NSHumanReadableCopyright + ${GTEST_VERSIONINFO_ABOUT} + CSResourcesFileMapped + + + diff --git a/third_party/googletest/src/xcode/Samples/FrameworkSample/Info.plist b/third_party/googletest/src/xcode/Samples/FrameworkSample/Info.plist new file mode 100644 index 0000000..f3852ed --- /dev/null +++ b/third_party/googletest/src/xcode/Samples/FrameworkSample/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.google.gtest.${PRODUCT_NAME:identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + CSResourcesFileMapped + + + diff --git a/third_party/googletest/src/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj b/third_party/googletest/src/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj new file mode 100644 index 0000000..497617e --- /dev/null +++ b/third_party/googletest/src/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj @@ -0,0 +1,457 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + 4024D162113D7D2400C7059E /* Test */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */; + buildPhases = ( + 4024D161113D7D2400C7059E /* ShellScript */, + ); + dependencies = ( + 4024D166113D7D3100C7059E /* PBXTargetDependency */, + ); + name = Test; + productName = TestAndBuild; + }; + 4024D1E9113D83FF00C7059E /* TestAndBuild */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */; + buildPhases = ( + ); + dependencies = ( + 4024D1ED113D840900C7059E /* PBXTargetDependency */, + 4024D1EF113D840D00C7059E /* PBXTargetDependency */, + ); + name = TestAndBuild; + productName = TestAndBuild; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1230E5AEE3500C7F239 /* widget.cc */; }; + 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7EB1240E5AEE3500C7F239 /* widget.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */; }; + 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; }; + 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D185113D7D5500C7059E /* libgtest.a */; }; + 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D183113D7D5500C7059E /* libgtest_main.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; + remoteInfo = gTestExample; + }; + 4024D165113D7D3100C7059E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3B07BDE90E3F3F9E00647869; + remoteInfo = WidgetFrameworkTest; + }; + 4024D1EC113D840900C7059E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; + remoteInfo = WidgetFramework; + }; + 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4024D162113D7D2400C7059E; + remoteInfo = Test; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WidgetFrameworkTest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B7EB1230E5AEE3500C7F239 /* widget.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget.cc; sourceTree = ""; }; + 3B7EB1240E5AEE3500C7F239 /* widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = widget.h; sourceTree = ""; }; + 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget_test.cc; sourceTree = ""; }; + 4024D183113D7D5500C7059E /* libgtest_main.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest_main.a; path = /usr/local/lib/libgtest_main.a; sourceTree = ""; }; + 4024D185113D7D5500C7059E /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest.a; path = /usr/local/lib/libgtest.a; sourceTree = ""; }; + 4024D1E2113D838200C7059E /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; + 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D07F2C80486CC7A007CD1D0 /* Widget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Widget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3B07BDE80E3F3F9E00647869 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */, + 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */, + 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DDFF38A45A11DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 8D07F2C80486CC7A007CD1D0 /* Widget.framework */, + 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* gTestExample */ = { + isa = PBXGroup; + children = ( + 4024D1E1113D836C00C7059E /* Scripts */, + 08FB77ACFE841707C02AAC07 /* Source */, + 089C1665FE841158C02AAC07 /* Resources */, + 3B07BE350E4094E400647869 /* Test */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 034768DDFF38A45A11DB9C8B /* Products */, + ); + name = gTestExample; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 4024D183113D7D5500C7059E /* libgtest_main.a */, + 4024D185113D7D5500C7059E /* libgtest.a */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8D07F2C70486CC7A007CD1D0 /* Info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77ACFE841707C02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 3B7EB1230E5AEE3500C7F239 /* widget.cc */, + 3B7EB1240E5AEE3500C7F239 /* widget.h */, + ); + name = Source; + sourceTree = ""; + }; + 3B07BE350E4094E400647869 /* Test */ = { + isa = PBXGroup; + children = ( + 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */, + ); + name = Test; + sourceTree = ""; + }; + 4024D1E1113D836C00C7059E /* Scripts */ = { + isa = PBXGroup; + children = ( + 4024D1E2113D838200C7059E /* runtests.sh */, + ); + name = Scripts; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */; + buildPhases = ( + 3B07BDE70E3F3F9E00647869 /* Sources */, + 3B07BDE80E3F3F9E00647869 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */, + ); + name = WidgetFrameworkTest; + productName = gTestExampleTest; + productReference = 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */; + productType = "com.apple.product-type.tool"; + }; + 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */; + buildPhases = ( + 8D07F2C10486CC7A007CD1D0 /* Sources */, + 8D07F2C30486CC7A007CD1D0 /* Frameworks */, + 8D07F2BD0486CC7A007CD1D0 /* Headers */, + 8D07F2BF0486CC7A007CD1D0 /* Resources */, + 8D07F2C50486CC7A007CD1D0 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WidgetFramework; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = gTestExample; + productReference = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* gTestExample */; + productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */, + 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */, + 4024D162113D7D2400C7059E /* Test */, + 4024D1E9113D83FF00C7059E /* TestAndBuild */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D07F2C50486CC7A007CD1D0 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 4024D161113D7D2400C7059E /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/bash $SRCROOT/runtests.sh $BUILT_PRODUCTS_DIR/WidgetFrameworkTest\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 3B07BDE70E3F3F9E00647869 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C10486CC7A007CD1D0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */; + targetProxy = 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */; + }; + 4024D166113D7D3100C7059E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */; + targetProxy = 4024D165113D7D3100C7059E /* PBXContainerItemProxy */; + }; + 4024D1ED113D840900C7059E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */; + targetProxy = 4024D1EC113D840900C7059E /* PBXContainerItemProxy */; + }; + 4024D1EF113D840D00C7059E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4024D162113D7D2400C7059E /* Test */; + targetProxy = 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 3B07BDEC0E3F3F9F00647869 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = WidgetFrameworkTest; + }; + name = Debug; + }; + 3B07BDED0E3F3F9F00647869 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = WidgetFrameworkTest; + }; + name = Release; + }; + 4024D163113D7D2400C7059E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = TestAndBuild; + }; + name = Debug; + }; + 4024D164113D7D2400C7059E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = TestAndBuild; + }; + name = Release; + }; + 4024D1EA113D83FF00C7059E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = TestAndBuild; + }; + name = Debug; + }; + 4024D1EB113D83FF00C7059E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = TestAndBuild; + }; + name = Release; + }; + 4FADC24308B4156D00ABE55E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "@loader_path/../Frameworks"; + PRODUCT_NAME = Widget; + }; + name = Debug; + }; + 4FADC24408B4156D00ABE55E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "@loader_path/../Frameworks"; + PRODUCT_NAME = Widget; + }; + name = Release; + }; + 4FADC24708B4156D00ABE55E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_VERSION = 4.0; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + 4FADC24808B4156D00ABE55E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_VERSION = 4.0; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3B07BDEC0E3F3F9F00647869 /* Debug */, + 3B07BDED0E3F3F9F00647869 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4024D163113D7D2400C7059E /* Debug */, + 4024D164113D7D2400C7059E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4024D1EA113D83FF00C7059E /* Debug */, + 4024D1EB113D83FF00C7059E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4FADC24308B4156D00ABE55E /* Debug */, + 4FADC24408B4156D00ABE55E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4FADC24708B4156D00ABE55E /* Debug */, + 4FADC24808B4156D00ABE55E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/third_party/googletest/src/xcode/Samples/FrameworkSample/runtests.sh b/third_party/googletest/src/xcode/Samples/FrameworkSample/runtests.sh new file mode 100755 index 0000000..4a0d413 --- /dev/null +++ b/third_party/googletest/src/xcode/Samples/FrameworkSample/runtests.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Executes the samples and tests for the Google Test Framework. + +# Help the dynamic linker find the path to the libraries. +export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR +export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR + +# Create some executables. +test_executables=$@ + +# Now execute each one in turn keeping track of how many succeeded and failed. +succeeded=0 +failed=0 +failed_list=() +for test in ${test_executables[*]}; do + "$test" + result=$? + if [ $result -eq 0 ]; then + succeeded=$(( $succeeded + 1 )) + else + failed=$(( failed + 1 )) + failed_list="$failed_list $test" + fi +done + +# Report the successes and failures to the console. +echo "Tests complete with $succeeded successes and $failed failures." +if [ $failed -ne 0 ]; then + echo "The following tests failed:" + echo $failed_list +fi +exit $failed diff --git a/third_party/googletest/src/xcode/Samples/FrameworkSample/widget.cc b/third_party/googletest/src/xcode/Samples/FrameworkSample/widget.cc new file mode 100644 index 0000000..bfc4e7f --- /dev/null +++ b/third_party/googletest/src/xcode/Samples/FrameworkSample/widget.cc @@ -0,0 +1,63 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: preston.a.jackson@gmail.com (Preston Jackson) +// +// Google Test - FrameworkSample +// widget.cc +// + +// Widget is a very simple class used for demonstrating the use of gtest + +#include "widget.h" + +Widget::Widget(int number, const std::string& name) + : number_(number), + name_(name) {} + +Widget::~Widget() {} + +float Widget::GetFloatValue() const { + return number_; +} + +int Widget::GetIntValue() const { + return static_cast(number_); +} + +std::string Widget::GetStringValue() const { + return name_; +} + +void Widget::GetCharPtrValue(char* buffer, size_t max_size) const { + // Copy the char* representation of name_ into buffer, up to max_size. + strncpy(buffer, name_.c_str(), max_size-1); + buffer[max_size-1] = '\0'; + return; +} diff --git a/third_party/googletest/src/xcode/Samples/FrameworkSample/widget.h b/third_party/googletest/src/xcode/Samples/FrameworkSample/widget.h new file mode 100644 index 0000000..0c55cdc --- /dev/null +++ b/third_party/googletest/src/xcode/Samples/FrameworkSample/widget.h @@ -0,0 +1,59 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: preston.a.jackson@gmail.com (Preston Jackson) +// +// Google Test - FrameworkSample +// widget.h +// + +// Widget is a very simple class used for demonstrating the use of gtest. It +// simply stores two values a string and an integer, which are returned via +// public accessors in multiple forms. + +#import + +class Widget { + public: + Widget(int number, const std::string& name); + ~Widget(); + + // Public accessors to number data + float GetFloatValue() const; + int GetIntValue() const; + + // Public accessors to the string data + std::string GetStringValue() const; + void GetCharPtrValue(char* buffer, size_t max_size) const; + + private: + // Data members + float number_; + std::string name_; +}; diff --git a/third_party/googletest/src/xcode/Samples/FrameworkSample/widget_test.cc b/third_party/googletest/src/xcode/Samples/FrameworkSample/widget_test.cc new file mode 100644 index 0000000..8725994 --- /dev/null +++ b/third_party/googletest/src/xcode/Samples/FrameworkSample/widget_test.cc @@ -0,0 +1,68 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: preston.a.jackson@gmail.com (Preston Jackson) +// +// Google Test - FrameworkSample +// widget_test.cc +// + +// This is a simple test file for the Widget class in the Widget.framework + +#include +#include "gtest/gtest.h" + +#include + +// This test verifies that the constructor sets the internal state of the +// Widget class correctly. +TEST(WidgetInitializerTest, TestConstructor) { + Widget widget(1.0f, "name"); + EXPECT_FLOAT_EQ(1.0f, widget.GetFloatValue()); + EXPECT_EQ(std::string("name"), widget.GetStringValue()); +} + +// This test verifies the conversion of the float and string values to int and +// char*, respectively. +TEST(WidgetInitializerTest, TestConversion) { + Widget widget(1.0f, "name"); + EXPECT_EQ(1, widget.GetIntValue()); + + size_t max_size = 128; + char buffer[max_size]; + widget.GetCharPtrValue(buffer, max_size); + EXPECT_STREQ("name", buffer); +} + +// Use the Google Test main that is linked into the framework. It does something +// like this: +// int main(int argc, char** argv) { +// testing::InitGoogleTest(&argc, argv); +// return RUN_ALL_TESTS(); +// } diff --git a/third_party/googletest/src/xcode/Scripts/runtests.sh b/third_party/googletest/src/xcode/Scripts/runtests.sh new file mode 100755 index 0000000..3fc229f --- /dev/null +++ b/third_party/googletest/src/xcode/Scripts/runtests.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Executes the samples and tests for the Google Test Framework. + +# Help the dynamic linker find the path to the libraries. +export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR +export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR + +# Create some executables. +test_executables=("$BUILT_PRODUCTS_DIR/gtest_unittest-framework" + "$BUILT_PRODUCTS_DIR/gtest_unittest" + "$BUILT_PRODUCTS_DIR/sample1_unittest-framework" + "$BUILT_PRODUCTS_DIR/sample1_unittest-static") + +# Now execute each one in turn keeping track of how many succeeded and failed. +succeeded=0 +failed=0 +failed_list=() +for test in ${test_executables[*]}; do + "$test" + result=$? + if [ $result -eq 0 ]; then + succeeded=$(( $succeeded + 1 )) + else + failed=$(( failed + 1 )) + failed_list="$failed_list $test" + fi +done + +# Report the successes and failures to the console. +echo "Tests complete with $succeeded successes and $failed failures." +if [ $failed -ne 0 ]; then + echo "The following tests failed:" + echo $failed_list +fi +exit $failed diff --git a/third_party/googletest/src/xcode/Scripts/versiongenerate.py b/third_party/googletest/src/xcode/Scripts/versiongenerate.py new file mode 100755 index 0000000..81de8c9 --- /dev/null +++ b/third_party/googletest/src/xcode/Scripts/versiongenerate.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""A script to prepare version informtion for use the gtest Info.plist file. + + This script extracts the version information from the configure.ac file and + uses it to generate a header file containing the same information. The + #defines in this header file will be included in during the generation of + the Info.plist of the framework, giving the correct value to the version + shown in the Finder. + + This script makes the following assumptions (these are faults of the script, + not problems with the Autoconf): + 1. The AC_INIT macro will be contained within the first 1024 characters + of configure.ac + 2. The version string will be 3 integers separated by periods and will be + surrounded by squre brackets, "[" and "]" (e.g. [1.0.1]). The first + segment represents the major version, the second represents the minor + version and the third represents the fix version. + 3. No ")" character exists between the opening "(" and closing ")" of + AC_INIT, including in comments and character strings. +""" + +import sys +import re + +# Read the command line argument (the output directory for Version.h) +if (len(sys.argv) < 3): + print "Usage: versiongenerate.py input_dir output_dir" + sys.exit(1) +else: + input_dir = sys.argv[1] + output_dir = sys.argv[2] + +# Read the first 1024 characters of the configure.ac file +config_file = open("%s/configure.ac" % input_dir, 'r') +buffer_size = 1024 +opening_string = config_file.read(buffer_size) +config_file.close() + +# Extract the version string from the AC_INIT macro +# The following init_expression means: +# Extract three integers separated by periods and surrounded by squre +# brackets(e.g. "[1.0.1]") between "AC_INIT(" and ")". Do not be greedy +# (*? is the non-greedy flag) since that would pull in everything between +# the first "(" and the last ")" in the file. +version_expression = re.compile(r"AC_INIT\(.*?\[(\d+)\.(\d+)\.(\d+)\].*?\)", + re.DOTALL) +version_values = version_expression.search(opening_string) +major_version = version_values.group(1) +minor_version = version_values.group(2) +fix_version = version_values.group(3) + +# Write the version information to a header file to be included in the +# Info.plist file. +file_data = """// +// DO NOT MODIFY THIS FILE (but you can delete it) +// +// This file is autogenerated by the versiongenerate.py script. This script +// is executed in a "Run Script" build phase when creating gtest.framework. This +// header file is not used during compilation of C-source. Rather, it simply +// defines some version strings for substitution in the Info.plist. Because of +// this, we are not not restricted to C-syntax nor are we using include guards. +// + +#define GTEST_VERSIONINFO_SHORT %s.%s +#define GTEST_VERSIONINFO_LONG %s.%s.%s + +""" % (major_version, minor_version, major_version, minor_version, fix_version) +version_file = open("%s/Version.h" % output_dir, 'w') +version_file.write(file_data) +version_file.close() diff --git a/third_party/googletest/src/xcode/gtest.xcodeproj/project.pbxproj b/third_party/googletest/src/xcode/gtest.xcodeproj/project.pbxproj new file mode 100644 index 0000000..74a7815 --- /dev/null +++ b/third_party/googletest/src/xcode/gtest.xcodeproj/project.pbxproj @@ -0,0 +1,1084 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + 3B238F5F0E828B5400846E11 /* Check */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */; + buildPhases = ( + 3B238F5E0E828B5400846E11 /* ShellScript */, + ); + dependencies = ( + 40899F9D0FFA740F000B29AE /* PBXTargetDependency */, + 40C849F7101A43440083642A /* PBXTargetDependency */, + 4089A0980FFAD34A000B29AE /* PBXTargetDependency */, + 40C849F9101A43490083642A /* PBXTargetDependency */, + ); + name = Check; + productName = Check; + }; + 40C44ADC0E3798F4008FCC51 /* Version Info */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */; + buildPhases = ( + 40C44ADB0E3798F4008FCC51 /* Generate Version.h */, + ); + comments = "The generation of Version.h must be performed in its own target. Since the Info.plist is preprocessed before any of the other build phases in gtest, the Version.h file would not be ready if included as a build phase of that target."; + dependencies = ( + ); + name = "Version Info"; + productName = Version.h; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */ = {isa = PBXBuildFile; fileRef = 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */; }; + 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DB0E2F799B00CF7658 /* gtest-death-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 404884390E2F799B00CF7658 /* gtest-message.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DC0E2F799B00CF7658 /* gtest-message.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DD0E2F799B00CF7658 /* gtest-spi.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4048843B0E2F799B00CF7658 /* gtest.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DE0E2F799B00CF7658 /* gtest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883E00E2F799B00CF7658 /* gtest_prod.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 404884500E2F799B00CF7658 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 404883F60E2F799B00CF7658 /* README */; }; + 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */; }; + 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E30E2F799B00CF7658 /* gtest-filepath.h */; }; + 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E40E2F799B00CF7658 /* gtest-internal.h */; }; + 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E50E2F799B00CF7658 /* gtest-port.h */; }; + 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E60E2F799B00CF7658 /* gtest-string.h */; }; + 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */ = {isa = PBXBuildFile; fileRef = 404884A90E2F7CD900CF7658 /* CHANGES */; }; + 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */ = {isa = PBXBuildFile; fileRef = 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */; }; + 404884AE0E2F7CD900CF7658 /* COPYING in Resources */ = {isa = PBXBuildFile; fileRef = 404884AB0E2F7CD900CF7658 /* COPYING */; }; + 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; }; + 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 40899F4D0FFA7271000B29AE /* gtest-tuple.h */; }; + 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; }; + 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; }; + 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; }; + 40C848FF101A21150083642A /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; }; + 40C84915101A21DF0083642A /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4048840D0E2F799B00CF7658 /* gtest_main.cc */; }; + 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; + 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; + 40C84978101A36540083642A /* libgtest_main.a in Resources */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; + 40C84980101A36850083642A /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; }; + 40C84982101A36850083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; }; + 40C84983101A36850083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; + 40C8498F101A36A60083642A /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; }; + 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; }; + 40C84992101A36A60083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; }; + 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; + 40C849A2101A37050083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; }; + 40C849A4101A37150083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; }; + 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 4539C9330EC280AE00A70F4C /* gtest-param-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */; }; + 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */; }; + 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9370EC280E200A70F4C /* gtest-param-util.h */; }; + 4567C8181264FF71007740BE /* gtest-printers.h in Headers */ = {isa = PBXBuildFile; fileRef = 4567C8171264FF71007740BE /* gtest-printers.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40899F420FFA7184000B29AE; + remoteInfo = gtest_unittest; + }; + 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4089A0120FFACEFC000B29AE; + remoteInfo = sample1_unittest; + }; + 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C848F9101A209C0083642A; + remoteInfo = "gtest-static"; + }; + 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C44ADC0E3798F4008FCC51; + remoteInfo = Version.h; + }; + 40C8497C101A36850083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C848F9101A209C0083642A; + remoteInfo = "gtest-static"; + }; + 40C8497E101A36850083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C8490A101A217E0083642A; + remoteInfo = "gtest_main-static"; + }; + 40C8498B101A36A60083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C848F9101A209C0083642A; + remoteInfo = "gtest-static"; + }; + 40C8498D101A36A60083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C8490A101A217E0083642A; + remoteInfo = "gtest_main-static"; + }; + 40C8499B101A36DC0083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C8490A101A217E0083642A; + remoteInfo = "gtest_main-static"; + }; + 40C8499D101A36E50083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; + remoteInfo = "gtest-framework"; + }; + 40C8499F101A36F10083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; + remoteInfo = "gtest-framework"; + }; + 40C849F6101A43440083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C8497A101A36850083642A; + remoteInfo = "gtest_unittest-static"; + }; + 40C849F8101A43490083642A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40C84989101A36A60083642A; + remoteInfo = "sample1_unittest-static"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 404884A50E2F7C0400CF7658 /* Copy Headers Internal */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = Headers/internal; + dstSubfolderSpec = 6; + files = ( + 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */, + 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */, + 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */, + 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */, + 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */, + 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */, + 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */, + 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */, + 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */, + 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */, + ); + name = "Copy Headers Internal"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 224A12A10E9EADA700BD17FD /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-all.cc"; sourceTree = ""; }; + 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "gtest-test-part.h"; sourceTree = ""; }; + 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_unittest.cc; sourceTree = ""; }; + 3B87D2100E96B92E000D1852 /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; + 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-type-util.h"; sourceTree = ""; }; + 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-typed-test.h"; sourceTree = ""; }; + 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = ""; }; + 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = ""; }; + 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = ""; }; + 404883DD0E2F799B00CF7658 /* gtest-spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-spi.h"; sourceTree = ""; }; + 404883DE0E2F799B00CF7658 /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest.h; sourceTree = ""; }; + 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_pred_impl.h; sourceTree = ""; }; + 404883E00E2F799B00CF7658 /* gtest_prod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_prod.h; sourceTree = ""; }; + 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test-internal.h"; sourceTree = ""; }; + 404883E30E2F799B00CF7658 /* gtest-filepath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-filepath.h"; sourceTree = ""; }; + 404883E40E2F799B00CF7658 /* gtest-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-internal.h"; sourceTree = ""; }; + 404883E50E2F799B00CF7658 /* gtest-port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-port.h"; sourceTree = ""; }; + 404883E60E2F799B00CF7658 /* gtest-string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-string.h"; sourceTree = ""; }; + 404883F60E2F799B00CF7658 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README; path = ../README; sourceTree = SOURCE_ROOT; }; + 4048840D0E2F799B00CF7658 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_main.cc; sourceTree = ""; }; + 404884A90E2F7CD900CF7658 /* CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CHANGES; path = ../CHANGES; sourceTree = SOURCE_ROOT; }; + 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CONTRIBUTORS; path = ../CONTRIBUTORS; sourceTree = SOURCE_ROOT; }; + 404884AB0E2F7CD900CF7658 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING; path = ../COPYING; sourceTree = SOURCE_ROOT; }; + 40899F430FFA7184000B29AE /* gtest_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gtest_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 40899F4D0FFA7271000B29AE /* gtest-tuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-tuple.h"; sourceTree = ""; }; + 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryTarget.xcconfig; sourceTree = ""; }; + 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 4089A02C0FFACF7F000B29AE /* sample1.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1.cc; sourceTree = ""; }; + 4089A02D0FFACF7F000B29AE /* sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample1.h; sourceTree = ""; }; + 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1_unittest.cc; sourceTree = ""; }; + 40C848FA101A209C0083642A /* libgtest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 40C8490B101A217E0083642A /* libgtest_main.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest_main.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 40C84987101A36850083642A /* gtest_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gtest_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + 40C84997101A36A60083642A /* sample1_unittest-static */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-static"; sourceTree = BUILT_PRODUCTS_DIR; }; + 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugProject.xcconfig; sourceTree = ""; }; + 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = ""; }; + 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = ""; }; + 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = ""; }; + 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4539C8FF0EC27F6400A70F4C /* gtest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = gtest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4539C9330EC280AE00A70F4C /* gtest-param-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-test.h"; sourceTree = ""; }; + 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-linked_ptr.h"; sourceTree = ""; }; + 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util-generated.h"; sourceTree = ""; }; + 4539C9370EC280E200A70F4C /* gtest-param-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util.h"; sourceTree = ""; }; + 4567C8171264FF71007740BE /* gtest-printers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-printers.h"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 40899F410FFA7184000B29AE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C849A4101A37150083642A /* gtest.framework in Frameworks */, + 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4089A0110FFACEFC000B29AE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C849A2101A37050083642A /* gtest.framework in Frameworks */, + 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 40C84981101A36850083642A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C84982101A36850083642A /* libgtest.a in Frameworks */, + 40C84983101A36850083642A /* libgtest_main.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 40C84991101A36A60083642A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C84992101A36A60083642A /* libgtest.a in Frameworks */, + 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DDFF38A45A11DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 4539C8FF0EC27F6400A70F4C /* gtest.framework */, + 40C848FA101A209C0083642A /* libgtest.a */, + 40C8490B101A217E0083642A /* libgtest_main.a */, + 40899F430FFA7184000B29AE /* gtest_unittest-framework */, + 40C84987101A36850083642A /* gtest_unittest */, + 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */, + 40C84997101A36A60083642A /* sample1_unittest-static */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* gtest */ = { + isa = PBXGroup; + children = ( + 40D4CDF00E30E07400294801 /* Config */, + 08FB77ACFE841707C02AAC07 /* Source */, + 40D4CF4E0E30F5E200294801 /* Resources */, + 403EE37B0E377822004BD1E2 /* Scripts */, + 034768DDFF38A45A11DB9C8B /* Products */, + ); + name = gtest; + sourceTree = ""; + }; + 08FB77ACFE841707C02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 404884A90E2F7CD900CF7658 /* CHANGES */, + 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */, + 404884AB0E2F7CD900CF7658 /* COPYING */, + 404883F60E2F799B00CF7658 /* README */, + 404883D90E2F799B00CF7658 /* include */, + 4089A02F0FFACF84000B29AE /* samples */, + 404884070E2F799B00CF7658 /* src */, + 3B238BF00E7FE13B00846E11 /* test */, + ); + name = Source; + sourceTree = ""; + }; + 3B238BF00E7FE13B00846E11 /* test */ = { + isa = PBXGroup; + children = ( + 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */, + ); + name = test; + path = ../test; + sourceTree = SOURCE_ROOT; + }; + 403EE37B0E377822004BD1E2 /* Scripts */ = { + isa = PBXGroup; + children = ( + 403EE37C0E377822004BD1E2 /* versiongenerate.py */, + 3B87D2100E96B92E000D1852 /* runtests.sh */, + ); + path = Scripts; + sourceTree = ""; + }; + 404883D90E2F799B00CF7658 /* include */ = { + isa = PBXGroup; + children = ( + 404883DA0E2F799B00CF7658 /* gtest */, + ); + name = include; + path = ../include; + sourceTree = SOURCE_ROOT; + }; + 404883DA0E2F799B00CF7658 /* gtest */ = { + isa = PBXGroup; + children = ( + 404883E10E2F799B00CF7658 /* internal */, + 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */, + 404883DB0E2F799B00CF7658 /* gtest-death-test.h */, + 404883DC0E2F799B00CF7658 /* gtest-message.h */, + 4539C9330EC280AE00A70F4C /* gtest-param-test.h */, + 4567C8171264FF71007740BE /* gtest-printers.h */, + 404883DD0E2F799B00CF7658 /* gtest-spi.h */, + 404883DE0E2F799B00CF7658 /* gtest.h */, + 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */, + 404883E00E2F799B00CF7658 /* gtest_prod.h */, + 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */, + ); + path = gtest; + sourceTree = ""; + }; + 404883E10E2F799B00CF7658 /* internal */ = { + isa = PBXGroup; + children = ( + 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */, + 404883E30E2F799B00CF7658 /* gtest-filepath.h */, + 404883E40E2F799B00CF7658 /* gtest-internal.h */, + 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */, + 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */, + 4539C9370EC280E200A70F4C /* gtest-param-util.h */, + 404883E50E2F799B00CF7658 /* gtest-port.h */, + 404883E60E2F799B00CF7658 /* gtest-string.h */, + 40899F4D0FFA7271000B29AE /* gtest-tuple.h */, + 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */, + ); + path = internal; + sourceTree = ""; + }; + 404884070E2F799B00CF7658 /* src */ = { + isa = PBXGroup; + children = ( + 224A12A10E9EADA700BD17FD /* gtest-all.cc */, + 4048840D0E2F799B00CF7658 /* gtest_main.cc */, + ); + name = src; + path = ../src; + sourceTree = SOURCE_ROOT; + }; + 4089A02F0FFACF84000B29AE /* samples */ = { + isa = PBXGroup; + children = ( + 4089A02C0FFACF7F000B29AE /* sample1.cc */, + 4089A02D0FFACF7F000B29AE /* sample1.h */, + 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */, + ); + name = samples; + path = ../samples; + sourceTree = SOURCE_ROOT; + }; + 40D4CDF00E30E07400294801 /* Config */ = { + isa = PBXGroup; + children = ( + 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */, + 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */, + 40D4CDF30E30E07400294801 /* General.xcconfig */, + 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */, + 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */, + ); + path = Config; + sourceTree = ""; + }; + 40D4CF4E0E30F5E200294801 /* Resources */ = { + isa = PBXGroup; + children = ( + 40D4CF510E30F5E200294801 /* Info.plist */, + ); + path = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */, + 404884390E2F799B00CF7658 /* gtest-message.h in Headers */, + 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */, + 4567C8181264FF71007740BE /* gtest-printers.h in Headers */, + 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */, + 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */, + 4048843B0E2F799B00CF7658 /* gtest.h in Headers */, + 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */, + 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */, + 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 40899F420FFA7184000B29AE /* gtest_unittest-framework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */; + buildPhases = ( + 40899F400FFA7184000B29AE /* Sources */, + 40899F410FFA7184000B29AE /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 40C849A0101A36F10083642A /* PBXTargetDependency */, + ); + name = "gtest_unittest-framework"; + productName = gtest_unittest; + productReference = 40899F430FFA7184000B29AE /* gtest_unittest-framework */; + productType = "com.apple.product-type.tool"; + }; + 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */; + buildPhases = ( + 4089A0100FFACEFC000B29AE /* Sources */, + 4089A0110FFACEFC000B29AE /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 40C8499E101A36E50083642A /* PBXTargetDependency */, + ); + name = "sample1_unittest-framework"; + productName = sample1_unittest; + productReference = 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */; + productType = "com.apple.product-type.tool"; + }; + 40C848F9101A209C0083642A /* gtest-static */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */; + buildPhases = ( + 40C848F7101A209C0083642A /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "gtest-static"; + productName = "gtest-static"; + productReference = 40C848FA101A209C0083642A /* libgtest.a */; + productType = "com.apple.product-type.library.static"; + }; + 40C8490A101A217E0083642A /* gtest_main-static */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */; + buildPhases = ( + 40C84908101A217E0083642A /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "gtest_main-static"; + productName = "gtest_main-static"; + productReference = 40C8490B101A217E0083642A /* libgtest_main.a */; + productType = "com.apple.product-type.library.static"; + }; + 40C8497A101A36850083642A /* gtest_unittest-static */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */; + buildPhases = ( + 40C8497F101A36850083642A /* Sources */, + 40C84981101A36850083642A /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 40C8497B101A36850083642A /* PBXTargetDependency */, + 40C8497D101A36850083642A /* PBXTargetDependency */, + ); + name = "gtest_unittest-static"; + productName = gtest_unittest; + productReference = 40C84987101A36850083642A /* gtest_unittest */; + productType = "com.apple.product-type.tool"; + }; + 40C84989101A36A60083642A /* sample1_unittest-static */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */; + buildPhases = ( + 40C8498E101A36A60083642A /* Sources */, + 40C84991101A36A60083642A /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 40C8498A101A36A60083642A /* PBXTargetDependency */, + 40C8498C101A36A60083642A /* PBXTargetDependency */, + ); + name = "sample1_unittest-static"; + productName = sample1_unittest; + productReference = 40C84997101A36A60083642A /* sample1_unittest-static */; + productType = "com.apple.product-type.tool"; + }; + 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */; + buildPhases = ( + 8D07F2C10486CC7A007CD1D0 /* Sources */, + 8D07F2BD0486CC7A007CD1D0 /* Headers */, + 404884A50E2F7C0400CF7658 /* Copy Headers Internal */, + 8D07F2BF0486CC7A007CD1D0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 40C44AE60E379922008FCC51 /* PBXTargetDependency */, + 408BEC101046CFE900DEF522 /* PBXTargetDependency */, + 40C8499C101A36DC0083642A /* PBXTargetDependency */, + ); + name = "gtest-framework"; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = gtest; + productReference = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + en, + ); + mainGroup = 0867D691FE84028FC02AAC07 /* gtest */; + productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */, + 40C848F9101A209C0083642A /* gtest-static */, + 40C8490A101A217E0083642A /* gtest_main-static */, + 40899F420FFA7184000B29AE /* gtest_unittest-framework */, + 40C8497A101A36850083642A /* gtest_unittest-static */, + 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */, + 40C84989101A36A60083642A /* sample1_unittest-static */, + 3B238F5F0E828B5400846E11 /* Check */, + 40C44ADC0E3798F4008FCC51 /* Version Info */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 404884500E2F799B00CF7658 /* README in Resources */, + 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */, + 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */, + 404884AE0E2F7CD900CF7658 /* COPYING in Resources */, + 40C84978101A36540083642A /* libgtest_main.a in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B238F5E0E828B5400846E11 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/bin/bash Scripts/runtests.sh"; + }; + 40C44ADB0E3798F4008FCC51 /* Generate Version.h */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Scripts/versiongenerate.py", + "$(SRCROOT)/../configure.ac", + ); + name = "Generate Version.h"; + outputPaths = ( + "$(PROJECT_TEMP_DIR)/Version.h", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/usr/bin/python Scripts/versiongenerate.py ../ $PROJECT_TEMP_DIR"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 40899F400FFA7184000B29AE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4089A0100FFACEFC000B29AE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */, + 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 40C848F7101A209C0083642A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C848FF101A21150083642A /* gtest-all.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 40C84908101A217E0083642A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C84915101A21DF0083642A /* gtest_main.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 40C8497F101A36850083642A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C84980101A36850083642A /* gtest_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 40C8498E101A36A60083642A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40C8498F101A36A60083642A /* sample1.cc in Sources */, + 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C10486CC7A007CD1D0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 40899F9D0FFA740F000B29AE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40899F420FFA7184000B29AE /* gtest_unittest-framework */; + targetProxy = 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */; + }; + 4089A0980FFAD34A000B29AE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */; + targetProxy = 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */; + }; + 408BEC101046CFE900DEF522 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C848F9101A209C0083642A /* gtest-static */; + targetProxy = 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */; + }; + 40C44AE60E379922008FCC51 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C44ADC0E3798F4008FCC51 /* Version Info */; + targetProxy = 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */; + }; + 40C8497B101A36850083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C848F9101A209C0083642A /* gtest-static */; + targetProxy = 40C8497C101A36850083642A /* PBXContainerItemProxy */; + }; + 40C8497D101A36850083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C8490A101A217E0083642A /* gtest_main-static */; + targetProxy = 40C8497E101A36850083642A /* PBXContainerItemProxy */; + }; + 40C8498A101A36A60083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C848F9101A209C0083642A /* gtest-static */; + targetProxy = 40C8498B101A36A60083642A /* PBXContainerItemProxy */; + }; + 40C8498C101A36A60083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C8490A101A217E0083642A /* gtest_main-static */; + targetProxy = 40C8498D101A36A60083642A /* PBXContainerItemProxy */; + }; + 40C8499C101A36DC0083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C8490A101A217E0083642A /* gtest_main-static */; + targetProxy = 40C8499B101A36DC0083642A /* PBXContainerItemProxy */; + }; + 40C8499E101A36E50083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */; + targetProxy = 40C8499D101A36E50083642A /* PBXContainerItemProxy */; + }; + 40C849A0101A36F10083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */; + targetProxy = 40C8499F101A36F10083642A /* PBXContainerItemProxy */; + }; + 40C849F7101A43440083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C8497A101A36850083642A /* gtest_unittest-static */; + targetProxy = 40C849F6101A43440083642A /* PBXContainerItemProxy */; + }; + 40C849F9101A43490083642A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40C84989101A36A60083642A /* sample1_unittest-static */; + targetProxy = 40C849F8101A43490083642A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 3B238F600E828B5400846E11 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = Check; + }; + name = Debug; + }; + 3B238F610E828B5400846E11 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + PRODUCT_NAME = Check; + ZERO_LINK = NO; + }; + name = Release; + }; + 40899F450FFA7185000B29AE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../; + PRODUCT_NAME = "gtest_unittest-framework"; + }; + name = Debug; + }; + 40899F460FFA7185000B29AE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../; + PRODUCT_NAME = "gtest_unittest-framework"; + }; + name = Release; + }; + 4089A0150FFACEFD000B29AE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "sample1_unittest-framework"; + }; + name = Debug; + }; + 4089A0160FFACEFD000B29AE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "sample1_unittest-framework"; + }; + name = Release; + }; + 40C44ADF0E3798F4008FCC51 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = gtest; + TARGET_NAME = gtest; + }; + name = Debug; + }; + 40C44AE00E3798F4008FCC51 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = gtest; + TARGET_NAME = gtest; + }; + name = Release; + }; + 40C848FB101A209D0083642A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; + buildSettings = { + GCC_INLINES_ARE_PRIVATE_EXTERN = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + HEADER_SEARCH_PATHS = ( + ../, + ../include/, + ); + PRODUCT_NAME = gtest; + }; + name = Debug; + }; + 40C848FC101A209D0083642A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; + buildSettings = { + GCC_INLINES_ARE_PRIVATE_EXTERN = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + HEADER_SEARCH_PATHS = ( + ../, + ../include/, + ); + PRODUCT_NAME = gtest; + }; + name = Release; + }; + 40C8490E101A217F0083642A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; + buildSettings = { + HEADER_SEARCH_PATHS = ( + ../, + ../include/, + ); + PRODUCT_NAME = gtest_main; + }; + name = Debug; + }; + 40C8490F101A217F0083642A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; + buildSettings = { + HEADER_SEARCH_PATHS = ( + ../, + ../include/, + ); + PRODUCT_NAME = gtest_main; + }; + name = Release; + }; + 40C84985101A36850083642A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../; + PRODUCT_NAME = gtest_unittest; + }; + name = Debug; + }; + 40C84986101A36850083642A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../; + PRODUCT_NAME = gtest_unittest; + }; + name = Release; + }; + 40C84995101A36A60083642A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "sample1_unittest-static"; + }; + name = Debug; + }; + 40C84996101A36A60083642A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "sample1_unittest-static"; + }; + name = Release; + }; + 4FADC24308B4156D00ABE55E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + HEADER_SEARCH_PATHS = ( + ../, + ../include/, + ); + INFOPLIST_FILE = Resources/Info.plist; + INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; + INFOPLIST_PREPROCESS = YES; + PRODUCT_NAME = gtest; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 4FADC24408B4156D00ABE55E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + HEADER_SEARCH_PATHS = ( + ../, + ../include/, + ); + INFOPLIST_FILE = Resources/Info.plist; + INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; + INFOPLIST_PREPROCESS = YES; + PRODUCT_NAME = gtest; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 4FADC24708B4156D00ABE55E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 4FADC24808B4156D00ABE55E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */; + buildSettings = { + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3B238F600E828B5400846E11 /* Debug */, + 3B238F610E828B5400846E11 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40899F450FFA7185000B29AE /* Debug */, + 40899F460FFA7185000B29AE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4089A0150FFACEFD000B29AE /* Debug */, + 4089A0160FFACEFD000B29AE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40C44ADF0E3798F4008FCC51 /* Debug */, + 40C44AE00E3798F4008FCC51 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40C848FB101A209D0083642A /* Debug */, + 40C848FC101A209D0083642A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40C8490E101A217F0083642A /* Debug */, + 40C8490F101A217F0083642A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40C84985101A36850083642A /* Debug */, + 40C84986101A36850083642A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40C84995101A36A60083642A /* Debug */, + 40C84996101A36A60083642A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4FADC24308B4156D00ABE55E /* Debug */, + 4FADC24408B4156D00ABE55E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4FADC24708B4156D00ABE55E /* Debug */, + 4FADC24808B4156D00ABE55E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/third_party/libyuv/README.webm b/third_party/libyuv/README.webm new file mode 100644 index 0000000..d3495ca --- /dev/null +++ b/third_party/libyuv/README.webm @@ -0,0 +1,17 @@ +Name: libyuv +URL: http://code.google.com/p/libyuv/ +Version: 102 +License: BSD +License File: LICENSE + +Description: +libyuv is an open source project that includes YUV conversion and scaling +functionality. + +The optimized scaler in libyuv is used in multiple resolution encoder example, +which down-samples the original input video (f.g. 1280x720) a number of times +in order to encode multiple resolution bit streams. + +Local Modifications: +Modified the original scaler code from C++ to C to fit in our current build +system. This is a temporal solution, and will be improved later. \ No newline at end of file diff --git a/third_party/libyuv/include/libyuv/basic_types.h b/third_party/libyuv/include/libyuv/basic_types.h new file mode 100644 index 0000000..30504ce --- /dev/null +++ b/third_party/libyuv/include/libyuv/basic_types.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_BASIC_TYPES_H_ +#define INCLUDE_LIBYUV_BASIC_TYPES_H_ + +#include // for NULL, size_t + +#if !(defined(_MSC_VER) && (_MSC_VER < 1600)) +#include // for uintptr_t +#endif + +#ifndef INT_TYPES_DEFINED +#define INT_TYPES_DEFINED +#ifdef COMPILER_MSVC +typedef unsigned __int64 uint64; +typedef __int64 int64; +#ifndef INT64_C +#define INT64_C(x) x ## I64 +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## UI64 +#endif +#define INT64_F "I64" +#else // COMPILER_MSVC +#ifdef __LP64__ +typedef unsigned long uint64; +typedef long int64; +#ifndef INT64_C +#define INT64_C(x) x ## L +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## UL +#endif +#define INT64_F "l" +#else // __LP64__ +typedef unsigned long long uint64; +typedef long long int64; +#ifndef INT64_C +#define INT64_C(x) x ## LL +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## ULL +#endif +#define INT64_F "ll" +#endif // __LP64__ +#endif // COMPILER_MSVC +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; +#endif // INT_TYPES_DEFINED + +// Detect compiler is for x86 or x64. +#if defined(__x86_64__) || defined(_M_X64) || \ + defined(__i386__) || defined(_M_IX86) +#define CPU_X86 1 +#endif + +#define ALIGNP(p, t) \ + ((uint8*)((((uintptr_t)(p) + \ + ((t)-1)) & ~((t)-1)))) + +#endif // INCLUDE_LIBYUV_BASIC_TYPES_H_ diff --git a/third_party/libyuv/include/libyuv/cpu_id.h b/third_party/libyuv/include/libyuv/cpu_id.h new file mode 100644 index 0000000..4a53b5b --- /dev/null +++ b/third_party/libyuv/include/libyuv/cpu_id.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_CPU_ID_H_ +#define INCLUDE_LIBYUV_CPU_ID_H_ + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// These flags are only valid on x86 processors +static const int kCpuHasSSE2 = 1; +static const int kCpuHasSSSE3 = 2; + +// These flags are only valid on ARM processors +static const int kCpuHasNEON = 4; + +// Internal flag to indicate cpuid is initialized. +static const int kCpuInitialized = 8; + +// Detect CPU has SSE2 etc. +// test_flag parameter should be one of kCpuHas constants above +// returns non-zero if instruction set is detected +static __inline int TestCpuFlag(int test_flag) { + extern int cpu_info_; + extern int InitCpuFlags(); + return (cpu_info_ ? cpu_info_ : InitCpuFlags()) & test_flag; +} + +// For testing, allow CPU flags to be disabled. +// ie MaskCpuFlags(~kCpuHasSSSE3) to disable SSSE3. +// -1 to enable all cpu specific optimizations. +// 0 to disable all cpu specific optimizations. +void MaskCpuFlags(int enable_flags); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_CPU_ID_H_ diff --git a/third_party/libyuv/include/libyuv/scale.h b/third_party/libyuv/include/libyuv/scale.h new file mode 100644 index 0000000..21fe360 --- /dev/null +++ b/third_party/libyuv/include/libyuv/scale.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_SCALE_H_ +#define INCLUDE_LIBYUV_SCALE_H_ + +#include "third_party/libyuv/include/libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Supported filtering +typedef enum { + kFilterNone = 0, // Point sample; Fastest + kFilterBilinear = 1, // Faster than box, but lower quality scaling down. + kFilterBox = 2 // Highest quality +}FilterMode; + +// Scales a YUV 4:2:0 image from the src width and height to the +// dst width and height. +// If filtering is kFilterNone, a simple nearest-neighbor algorithm is +// used. This produces basic (blocky) quality at the fastest speed. +// If filtering is kFilterBilinear, interpolation is used to produce a better +// quality image, at the expense of speed. +// If filtering is kFilterBox, averaging is used to produce ever better +// quality image, at further expense of speed. +// Returns 0 if successful. + +int I420Scale(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + int src_width, int src_height, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int dst_width, int dst_height, + FilterMode filtering); + +// Legacy API. Deprecated +int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v, + int src_stride_y, int src_stride_u, int src_stride_v, + int src_width, int src_height, + uint8* dst_y, uint8* dst_u, uint8* dst_v, + int dst_stride_y, int dst_stride_u, int dst_stride_v, + int dst_width, int dst_height, + int interpolate); + +// Legacy API. Deprecated +int ScaleOffset(const uint8* src, int src_width, int src_height, + uint8* dst, int dst_width, int dst_height, int dst_yoffset, + int interpolate); + +// For testing, allow disabling of optimizations. +void SetUseReferenceImpl(int use); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_SCALE_H_ diff --git a/third_party/libyuv/source/cpu_id.c b/third_party/libyuv/source/cpu_id.c new file mode 100644 index 0000000..fccf3dd --- /dev/null +++ b/third_party/libyuv/source/cpu_id.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "third_party/libyuv/include/libyuv/cpu_id.h" + +#ifdef _MSC_VER +#include +#endif +#ifdef __ANDROID__ +#include +#endif + +#include "third_party/libyuv/include/libyuv/basic_types.h" // for CPU_X86 + +// TODO(fbarchard): Use cpuid.h when gcc 4.4 is used on OSX and Linux. +#if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__) +static inline void __cpuid(int cpu_info[4], int info_type) { + asm volatile ( + "mov %%ebx, %%edi \n" + "cpuid \n" + "xchg %%edi, %%ebx \n" + : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type) + ); +} +#elif defined(__i386__) || defined(__x86_64__) +static inline void __cpuid(int cpu_info[4], int info_type) { + asm volatile ( + "cpuid \n" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type) + ); +} +#endif + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// CPU detect function for SIMD instruction sets. +int cpu_info_ = 0; + +int InitCpuFlags() { +#ifdef CPU_X86 + int cpu_info[4]; + __cpuid(cpu_info, 1); + cpu_info_ = (cpu_info[3] & 0x04000000 ? kCpuHasSSE2 : 0) | + (cpu_info[2] & 0x00000200 ? kCpuHasSSSE3 : 0) | + kCpuInitialized; +#elif defined(__ANDROID__) && defined(__ARM_NEON__) + uint64_t features = android_getCpuFeatures(); + cpu_info_ = ((features & ANDROID_CPU_ARM_FEATURE_NEON) ? kCpuHasNEON : 0) | + kCpuInitialized; +#elif defined(__ARM_NEON__) + // gcc -mfpu=neon defines __ARM_NEON__ + // Enable Neon if you want support for Neon and Arm, and use MaskCpuFlags + // to disable Neon on devices that do not have it. + cpu_info_ = kCpuHasNEON | kCpuInitialized; +#else + cpu_info_ = kCpuInitialized; +#endif + return cpu_info_; +} + +void MaskCpuFlags(int enable_flags) { + InitCpuFlags(); + cpu_info_ = (cpu_info_ & enable_flags) | kCpuInitialized; +} + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/third_party/libyuv/source/row.h b/third_party/libyuv/source/row.h new file mode 100644 index 0000000..eabe180 --- /dev/null +++ b/third_party/libyuv/source/row.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef LIBYUV_SOURCE_ROW_H_ +#define LIBYUV_SOURCE_ROW_H_ + +#include "third_party/libyuv/include/libyuv/basic_types.h" + +#define kMaxStride (2048 * 4) +#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1))) + +#if defined(COVERAGE_ENABLED) || defined(TARGET_IPHONE_SIMULATOR) +#define YUV_DISABLE_ASM +#endif + +#if defined(__ARM_NEON__) && !defined(YUV_DISABLE_ASM) +#define HAS_FASTCONVERTYUVTOARGBROW_NEON +void FastConvertYUVToARGBRow_NEON(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); +#define HAS_FASTCONVERTYUVTOBGRAROW_NEON +void FastConvertYUVToBGRARow_NEON(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); +#define HAS_FASTCONVERTYUVTOABGRROW_NEON +void FastConvertYUVToABGRRow_NEON(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); +#endif + +// The following are available on all x86 platforms +#if (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) && \ + !defined(YUV_DISABLE_ASM) +#define HAS_ABGRTOARGBROW_SSSE3 +#define HAS_BGRATOARGBROW_SSSE3 +#define HAS_BG24TOARGBROW_SSSE3 +#define HAS_RAWTOARGBROW_SSSE3 +#define HAS_RGB24TOYROW_SSSE3 +#define HAS_RAWTOYROW_SSSE3 +#define HAS_RGB24TOUVROW_SSSE3 +#define HAS_RAWTOUVROW_SSSE3 +#define HAS_ARGBTOYROW_SSSE3 +#define HAS_BGRATOYROW_SSSE3 +#define HAS_ABGRTOYROW_SSSE3 +#define HAS_ARGBTOUVROW_SSSE3 +#define HAS_BGRATOUVROW_SSSE3 +#define HAS_ABGRTOUVROW_SSSE3 +#define HAS_I400TOARGBROW_SSE2 +#define HAS_FASTCONVERTYTOARGBROW_SSE2 +#define HAS_FASTCONVERTYUVTOARGBROW_SSSE3 +#define HAS_FASTCONVERTYUVTOBGRAROW_SSSE3 +#define HAS_FASTCONVERTYUVTOABGRROW_SSSE3 +#define HAS_FASTCONVERTYUV444TOARGBROW_SSSE3 +#define HAS_REVERSE_ROW_SSSE3 +#endif + +// The following are available on Neon platforms +#if defined(__ARM_NEON__) && !defined(YUV_DISABLE_ASM) +#define HAS_REVERSE_ROW_NEON +#endif + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#ifdef HAS_ARGBTOYROW_SSSE3 +void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void ABGRToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void BGRAToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ABGRToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +#endif +#if defined(HAS_BG24TOARGBROW_SSSE3) && defined(HAS_ARGBTOYROW_SSSE3) +#define HASRGB24TOYROW_SSSE3 +#endif +#ifdef HASRGB24TOYROW_SSSE3 +void RGB24ToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void RAWToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void RGB24ToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void RAWToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +#endif +#ifdef HAS_REVERSE_ROW_SSSE3 +void ReverseRow_SSSE3(const uint8* src, uint8* dst, int width); +#endif +#ifdef HAS_REVERSE_ROW_NEON +void ReverseRow_NEON(const uint8* src, uint8* dst, int width); +#endif +void ReverseRow_C(const uint8* src, uint8* dst, int width); + +void ARGBToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void ABGRToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void RGB24ToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void RAWToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToUVRow_C(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void BGRAToUVRow_C(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ABGRToUVRow_C(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void RGB24ToUVRow_C(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void RAWToUVRow_C(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); + +#ifdef HAS_BG24TOARGBROW_SSSE3 +void ABGRToARGBRow_SSSE3(const uint8* src_abgr, uint8* dst_argb, int pix); +void BGRAToARGBRow_SSSE3(const uint8* src_bgra, uint8* dst_argb, int pix); +void BG24ToARGBRow_SSSE3(const uint8* src_bg24, uint8* dst_argb, int pix); +void RAWToARGBRow_SSSE3(const uint8* src_bg24, uint8* dst_argb, int pix); +#endif +void ABGRToARGBRow_C(const uint8* src_abgr, uint8* dst_argb, int pix); +void BGRAToARGBRow_C(const uint8* src_bgra, uint8* dst_argb, int pix); +void BG24ToARGBRow_C(const uint8* src_bg24, uint8* dst_argb, int pix); +void RAWToARGBRow_C(const uint8* src_bg24, uint8* dst_argb, int pix); + +#ifdef HAS_I400TOARGBROW_SSE2 +void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix); +#endif +void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int pix); + +#if defined(_MSC_VER) +#define SIMD_ALIGNED(var) __declspec(align(16)) var +typedef __declspec(align(16)) signed char vec8[16]; +typedef __declspec(align(16)) unsigned char uvec8[16]; +typedef __declspec(align(16)) signed short vec16[8]; +#else // __GNUC__ +#define SIMD_ALIGNED(var) var __attribute__((aligned(16))) +typedef signed char __attribute__((vector_size(16))) vec8; +typedef unsigned char __attribute__((vector_size(16))) uvec8; +typedef signed short __attribute__((vector_size(16))) vec16; +#endif + +//extern "C" +SIMD_ALIGNED(const int16 kCoefficientsRgbY[768][4]); +//extern "C" +SIMD_ALIGNED(const int16 kCoefficientsBgraY[768][4]); +//extern "C" +SIMD_ALIGNED(const int16 kCoefficientsAbgrY[768][4]); + +void FastConvertYUVToARGBRow_C(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToBGRARow_C(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToABGRRow_C(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUV444ToARGBRow_C(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYToARGBRow_C(const uint8* y_buf, + uint8* rgb_buf, + int width); + +#ifdef HAS_FASTCONVERTYUVTOARGBROW_SSE2 +void FastConvertYUVToARGBRow_SSE2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToARGBRow4_SSE2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToBGRARow_SSE2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToABGRRow_SSE2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUV444ToARGBRow_SSE2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYToARGBRow_SSE2(const uint8* y_buf, + uint8* rgb_buf, + int width); +#endif + +#ifdef HAS_FASTCONVERTYUVTOARGBROW_SSSE3 +void FastConvertYUVToARGBRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToBGRARow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUVToABGRRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +void FastConvertYUV444ToARGBRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* rgb_buf, + int width); + +#endif + +#ifdef HAS_FASTCONVERTYTOARGBROW_SSE2 +void FastConvertYToARGBRow_SSE2(const uint8* y_buf, + uint8* rgb_buf, + int width); + +#endif + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // LIBYUV_SOURCE_ROW_H_ diff --git a/third_party/libyuv/source/scale.c b/third_party/libyuv/source/scale.c new file mode 100644 index 0000000..930a7ae --- /dev/null +++ b/third_party/libyuv/source/scale.c @@ -0,0 +1,3884 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "third_party/libyuv/include/libyuv/scale.h" + +#include +#include + +#include "third_party/libyuv/include/libyuv/cpu_id.h" +#include "third_party/libyuv/source/row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +/* + * Note: Defining YUV_DISABLE_ASM allows to use c version. + */ +//#define YUV_DISABLE_ASM + +#if defined(_MSC_VER) +#define ALIGN16(var) __declspec(align(16)) var +#else +#define ALIGN16(var) var __attribute__((aligned(16))) +#endif + +// Note: A Neon reference manual +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204j/CJAJIIGG.html +// Note: Some SSE2 reference manuals +// cpuvol1.pdf agner_instruction_tables.pdf 253666.pdf 253667.pdf + +// Set the following flag to true to revert to only +// using the reference implementation ScalePlaneBox(), and +// NOT the optimized versions. Useful for debugging and +// when comparing the quality of the resulting YUV planes +// as produced by the optimized and non-optimized versions. + +static int use_reference_impl_ = 0; + +void SetUseReferenceImpl(int use) { + use_reference_impl_ = use; +} + +// ScaleRowDown2Int also used by planar functions + +/** + * NEON downscalers with interpolation. + * + * Provided by Fritz Koenig + * + */ + +#if defined(__ARM_NEON__) && !defined(YUV_DISABLE_ASM) +#define HAS_SCALEROWDOWN2_NEON +void ScaleRowDown2_NEON(const uint8* src_ptr, int /* src_stride */, + uint8* dst, int dst_width) { + asm volatile ( + "1: \n" + "vld2.u8 {q0,q1}, [%0]! \n" // load even pixels into q0, odd into q1 + "vst1.u8 {q0}, [%1]! \n" // store even pixels + "subs %2, %2, #16 \n" // 16 processed per loop + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst), // %1 + "+r"(dst_width) // %2 + : + : "q0", "q1" // Clobber List + ); +} + +void ScaleRowDown2Int_NEON(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + asm volatile ( + "add %1, %0 \n" // change the stride to row 2 pointer + "1: \n" + "vld1.u8 {q0,q1}, [%0]! \n" // load row 1 and post increment + "vld1.u8 {q2,q3}, [%1]! \n" // load row 2 and post increment + "vpaddl.u8 q0, q0 \n" // row 1 add adjacent + "vpaddl.u8 q1, q1 \n" + "vpadal.u8 q0, q2 \n" // row 2 add adjacent, add row 1 to row 2 + "vpadal.u8 q1, q3 \n" + "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack + "vrshrn.u16 d1, q1, #2 \n" + "vst1.u8 {q0}, [%2]! \n" + "subs %3, %3, #16 \n" // 16 processed per loop + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(src_stride), // %1 + "+r"(dst), // %2 + "+r"(dst_width) // %3 + : + : "q0", "q1", "q2", "q3" // Clobber List + ); +} + +#define HAS_SCALEROWDOWN4_NEON +static void ScaleRowDown4_NEON(const uint8* src_ptr, int /* src_stride */, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "1: \n" + "vld2.u8 {d0, d1}, [%0]! \n" + "vtrn.u8 d1, d0 \n" + "vshrn.u16 d0, q0, #8 \n" + "vst1.u32 {d0[1]}, [%1]! \n" + + "subs %2, #4 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "q0", "q1", "memory", "cc" + ); +} + +static void ScaleRowDown4Int_NEON(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "add r4, %0, %3 \n" + "add r5, r4, %3 \n" + "add %3, r5, %3 \n" + "1: \n" + "vld1.u8 {q0}, [%0]! \n" // load up 16x4 block of input data + "vld1.u8 {q1}, [r4]! \n" + "vld1.u8 {q2}, [r5]! \n" + "vld1.u8 {q3}, [%3]! \n" + + "vpaddl.u8 q0, q0 \n" + "vpadal.u8 q0, q1 \n" + "vpadal.u8 q0, q2 \n" + "vpadal.u8 q0, q3 \n" + + "vpaddl.u16 q0, q0 \n" + + "vrshrn.u32 d0, q0, #4 \n" // divide by 16 w/rounding + + "vmovn.u16 d0, q0 \n" + "vst1.u32 {d0[0]}, [%1]! \n" + + "subs %2, #4 \n" + "bhi 1b \n" + + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"(src_stride) // %3 + : "r4", "r5", "q0", "q1", "q2", "q3", "memory", "cc" + ); +} + +#define HAS_SCALEROWDOWN34_NEON +// Down scale from 4 to 3 pixels. Use the neon multilane read/write +// to load up the every 4th pixel into a 4 different registers. +// Point samples 32 pixels to 24 pixels. +static void ScaleRowDown34_NEON(const uint8* src_ptr, int /* src_stride */, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "1: \n" + "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 + "vmov d2, d3 \n" // order needs to be d0, d1, d2 + "vst3.u8 {d0, d1, d2}, [%1]! \n" + "subs %2, #24 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "d0", "d1", "d2", "d3", "memory", "cc" + ); +} + +static void ScaleRowDown34_0_Int_NEON(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vmov.u8 d24, #3 \n" + "add %3, %0 \n" + "1: \n" + "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 + "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 + + // filter src line 0 with src line 1 + // expand chars to shorts to allow for room + // when adding lines together + "vmovl.u8 q8, d4 \n" + "vmovl.u8 q9, d5 \n" + "vmovl.u8 q10, d6 \n" + "vmovl.u8 q11, d7 \n" + + // 3 * line_0 + line_1 + "vmlal.u8 q8, d0, d24 \n" + "vmlal.u8 q9, d1, d24 \n" + "vmlal.u8 q10, d2, d24 \n" + "vmlal.u8 q11, d3, d24 \n" + + // (3 * line_0 + line_1) >> 2 + "vqrshrn.u16 d0, q8, #2 \n" + "vqrshrn.u16 d1, q9, #2 \n" + "vqrshrn.u16 d2, q10, #2 \n" + "vqrshrn.u16 d3, q11, #2 \n" + + // a0 = (src[0] * 3 + s[1] * 1) >> 2 + "vmovl.u8 q8, d1 \n" + "vmlal.u8 q8, d0, d24 \n" + "vqrshrn.u16 d0, q8, #2 \n" + + // a1 = (src[1] * 1 + s[2] * 1) >> 1 + "vrhadd.u8 d1, d1, d2 \n" + + // a2 = (src[2] * 1 + s[3] * 3) >> 2 + "vmovl.u8 q8, d2 \n" + "vmlal.u8 q8, d3, d24 \n" + "vqrshrn.u16 d2, q8, #2 \n" + + "vst3.u8 {d0, d1, d2}, [%1]! \n" + + "subs %2, #24 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : + : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "d24", "memory", "cc" + ); +} + +static void ScaleRowDown34_1_Int_NEON(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vmov.u8 d24, #3 \n" + "add %3, %0 \n" + "1: \n" + "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 + "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 + + // average src line 0 with src line 1 + "vrhadd.u8 q0, q0, q2 \n" + "vrhadd.u8 q1, q1, q3 \n" + + // a0 = (src[0] * 3 + s[1] * 1) >> 2 + "vmovl.u8 q3, d1 \n" + "vmlal.u8 q3, d0, d24 \n" + "vqrshrn.u16 d0, q3, #2 \n" + + // a1 = (src[1] * 1 + s[2] * 1) >> 1 + "vrhadd.u8 d1, d1, d2 \n" + + // a2 = (src[2] * 1 + s[3] * 3) >> 2 + "vmovl.u8 q3, d2 \n" + "vmlal.u8 q3, d3, d24 \n" + "vqrshrn.u16 d2, q3, #2 \n" + + "vst3.u8 {d0, d1, d2}, [%1]! \n" + + "subs %2, #24 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : + : "r4", "q0", "q1", "q2", "q3", "d24", "memory", "cc" + ); +} + +#define HAS_SCALEROWDOWN38_NEON +const uint8 shuf38[16] __attribute__ ((aligned(16))) = + { 0, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 30, 0, 0, 0, 0 }; +const uint8 shuf38_2[16] __attribute__ ((aligned(16))) = + { 0, 8, 16, 2, 10, 17, 4, 12, 18, 6, 14, 19, 0, 0, 0, 0 }; +const unsigned short mult38_div6[8] __attribute__ ((aligned(16))) = + { 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12, + 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12 }; +const unsigned short mult38_div9[8] __attribute__ ((aligned(16))) = + { 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18, + 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18 }; + +// 32 -> 12 +static void ScaleRowDown38_NEON(const uint8* src_ptr, int, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vld1.u8 {q3}, [%3] \n" + "1: \n" + "vld1.u8 {d0, d1, d2, d3}, [%0]! \n" + "vtbl.u8 d4, {d0, d1, d2, d3}, d6 \n" + "vtbl.u8 d5, {d0, d1, d2, d3}, d7 \n" + "vst1.u8 {d4}, [%1]! \n" + "vst1.u32 {d5[0]}, [%1]! \n" + "subs %2, #12 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"(shuf38) // %3 + : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc" + ); +} + +// 32x3 -> 12x1 +static void ScaleRowDown38_3_Int_NEON(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vld1.u16 {q13}, [%4] \n" + "vld1.u8 {q14}, [%5] \n" + "vld1.u8 {q15}, [%6] \n" + "add r4, %0, %3, lsl #1 \n" + "add %3, %0 \n" + "1: \n" + + // d0 = 00 40 01 41 02 42 03 43 + // d1 = 10 50 11 51 12 52 13 53 + // d2 = 20 60 21 61 22 62 23 63 + // d3 = 30 70 31 71 32 72 33 73 + "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" + "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" + "vld4.u8 {d16, d17, d18, d19}, [r4]! \n" + + // Shuffle the input data around to get align the data + // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 + // d0 = 00 10 01 11 02 12 03 13 + // d1 = 40 50 41 51 42 52 43 53 + "vtrn.u8 d0, d1 \n" + "vtrn.u8 d4, d5 \n" + "vtrn.u8 d16, d17 \n" + + // d2 = 20 30 21 31 22 32 23 33 + // d3 = 60 70 61 71 62 72 63 73 + "vtrn.u8 d2, d3 \n" + "vtrn.u8 d6, d7 \n" + "vtrn.u8 d18, d19 \n" + + // d0 = 00+10 01+11 02+12 03+13 + // d2 = 40+50 41+51 42+52 43+53 + "vpaddl.u8 q0, q0 \n" + "vpaddl.u8 q2, q2 \n" + "vpaddl.u8 q8, q8 \n" + + // d3 = 60+70 61+71 62+72 63+73 + "vpaddl.u8 d3, d3 \n" + "vpaddl.u8 d7, d7 \n" + "vpaddl.u8 d19, d19 \n" + + // combine source lines + "vadd.u16 q0, q2 \n" + "vadd.u16 q0, q8 \n" + "vadd.u16 d4, d3, d7 \n" + "vadd.u16 d4, d19 \n" + + // dst_ptr[3] = (s[6 + st * 0] + s[7 + st * 0] + // + s[6 + st * 1] + s[7 + st * 1] + // + s[6 + st * 2] + s[7 + st * 2]) / 6 + "vqrdmulh.s16 q2, q13 \n" + "vmovn.u16 d4, q2 \n" + + // Shuffle 2,3 reg around so that 2 can be added to the + // 0,1 reg and 3 can be added to the 4,5 reg. This + // requires expanding from u8 to u16 as the 0,1 and 4,5 + // registers are already expanded. Then do transposes + // to get aligned. + // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33 + "vmovl.u8 q1, d2 \n" + "vmovl.u8 q3, d6 \n" + "vmovl.u8 q9, d18 \n" + + // combine source lines + "vadd.u16 q1, q3 \n" + "vadd.u16 q1, q9 \n" + + // d4 = xx 20 xx 30 xx 22 xx 32 + // d5 = xx 21 xx 31 xx 23 xx 33 + "vtrn.u32 d2, d3 \n" + + // d4 = xx 20 xx 21 xx 22 xx 23 + // d5 = xx 30 xx 31 xx 32 xx 33 + "vtrn.u16 d2, d3 \n" + + // 0+1+2, 3+4+5 + "vadd.u16 q0, q1 \n" + + // Need to divide, but can't downshift as the the value + // isn't a power of 2. So multiply by 65536 / n + // and take the upper 16 bits. + "vqrdmulh.s16 q0, q15 \n" + + // Align for table lookup, vtbl requires registers to + // be adjacent + "vmov.u8 d2, d4 \n" + + "vtbl.u8 d3, {d0, d1, d2}, d28 \n" + "vtbl.u8 d4, {d0, d1, d2}, d29 \n" + + "vst1.u8 {d3}, [%1]! \n" + "vst1.u32 {d4[0]}, [%1]! \n" + "subs %2, #12 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : "r"(mult38_div6), // %4 + "r"(shuf38_2), // %5 + "r"(mult38_div9) // %6 + : "r4", "q0", "q1", "q2", "q3", "q8", "q9", + "q13", "q14", "q15", "memory", "cc" + ); +} + +// 32x2 -> 12x1 +static void ScaleRowDown38_2_Int_NEON(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vld1.u16 {q13}, [%4] \n" + "vld1.u8 {q14}, [%5] \n" + "add %3, %0 \n" + "1: \n" + + // d0 = 00 40 01 41 02 42 03 43 + // d1 = 10 50 11 51 12 52 13 53 + // d2 = 20 60 21 61 22 62 23 63 + // d3 = 30 70 31 71 32 72 33 73 + "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" + "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" + + // Shuffle the input data around to get align the data + // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 + // d0 = 00 10 01 11 02 12 03 13 + // d1 = 40 50 41 51 42 52 43 53 + "vtrn.u8 d0, d1 \n" + "vtrn.u8 d4, d5 \n" + + // d2 = 20 30 21 31 22 32 23 33 + // d3 = 60 70 61 71 62 72 63 73 + "vtrn.u8 d2, d3 \n" + "vtrn.u8 d6, d7 \n" + + // d0 = 00+10 01+11 02+12 03+13 + // d2 = 40+50 41+51 42+52 43+53 + "vpaddl.u8 q0, q0 \n" + "vpaddl.u8 q2, q2 \n" + + // d3 = 60+70 61+71 62+72 63+73 + "vpaddl.u8 d3, d3 \n" + "vpaddl.u8 d7, d7 \n" + + // combine source lines + "vadd.u16 q0, q2 \n" + "vadd.u16 d4, d3, d7 \n" + + // dst_ptr[3] = (s[6] + s[7] + s[6+st] + s[7+st]) / 4 + "vqrshrn.u16 d4, q2, #2 \n" + + // Shuffle 2,3 reg around so that 2 can be added to the + // 0,1 reg and 3 can be added to the 4,5 reg. This + // requires expanding from u8 to u16 as the 0,1 and 4,5 + // registers are already expanded. Then do transposes + // to get aligned. + // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33 + "vmovl.u8 q1, d2 \n" + "vmovl.u8 q3, d6 \n" + + // combine source lines + "vadd.u16 q1, q3 \n" + + // d4 = xx 20 xx 30 xx 22 xx 32 + // d5 = xx 21 xx 31 xx 23 xx 33 + "vtrn.u32 d2, d3 \n" + + // d4 = xx 20 xx 21 xx 22 xx 23 + // d5 = xx 30 xx 31 xx 32 xx 33 + "vtrn.u16 d2, d3 \n" + + // 0+1+2, 3+4+5 + "vadd.u16 q0, q1 \n" + + // Need to divide, but can't downshift as the the value + // isn't a power of 2. So multiply by 65536 / n + // and take the upper 16 bits. + "vqrdmulh.s16 q0, q13 \n" + + // Align for table lookup, vtbl requires registers to + // be adjacent + "vmov.u8 d2, d4 \n" + + "vtbl.u8 d3, {d0, d1, d2}, d28 \n" + "vtbl.u8 d4, {d0, d1, d2}, d29 \n" + + "vst1.u8 {d3}, [%1]! \n" + "vst1.u32 {d4[0]}, [%1]! \n" + "subs %2, #12 \n" + "bhi 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : "r"(mult38_div6), // %4 + "r"(shuf38_2) // %5 + : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc" + ); +} + +/** + * SSE2 downscalers with interpolation. + * + * Provided by Frank Barchard (fbarchard@google.com) + * + */ + +// Constants for SSE2 code +#elif (defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && \ + !defined(YUV_DISABLE_ASM) +#if defined(_MSC_VER) +#define TALIGN16(t, var) __declspec(align(16)) t _ ## var +#elif (defined(__APPLE__) || defined(__MINGW32__) || defined(__CYGWIN__)) && defined(__i386__) +#define TALIGN16(t, var) t var __attribute__((aligned(16))) +#else +#define TALIGN16(t, var) t _ ## var __attribute__((aligned(16))) +#endif + +#if (defined(__APPLE__) || defined(__MINGW32__) || defined(__CYGWIN__)) && \ + defined(__i386__) +#define DECLARE_FUNCTION(name) \ + ".text \n" \ + ".globl _" #name " \n" \ +"_" #name ": \n" +#else +#define DECLARE_FUNCTION(name) \ + ".text \n" \ + ".global " #name " \n" \ +#name ": \n" +#endif + + +// Offsets for source bytes 0 to 9 +//extern "C" +TALIGN16(const uint8, shuf0[16]) = + { 0, 1, 3, 4, 5, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Offsets for source bytes 11 to 20 with 8 subtracted = 3 to 12. +//extern "C" +TALIGN16(const uint8, shuf1[16]) = + { 3, 4, 5, 7, 8, 9, 11, 12, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. +//extern "C" +TALIGN16(const uint8, shuf2[16]) = + { 5, 7, 8, 9, 11, 12, 13, 15, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Offsets for source bytes 0 to 10 +//extern "C" +TALIGN16(const uint8, shuf01[16]) = + { 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10 }; + +// Offsets for source bytes 10 to 21 with 8 subtracted = 3 to 13. +//extern "C" +TALIGN16(const uint8, shuf11[16]) = + { 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13 }; + +// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. +//extern "C" +TALIGN16(const uint8, shuf21[16]) = + { 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15 }; + +// Coefficients for source bytes 0 to 10 +//extern "C" +TALIGN16(const uint8, madd01[16]) = + { 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2 }; + +// Coefficients for source bytes 10 to 21 +//extern "C" +TALIGN16(const uint8, madd11[16]) = + { 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1 }; + +// Coefficients for source bytes 21 to 31 +//extern "C" +TALIGN16(const uint8, madd21[16]) = + { 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3 }; + +// Coefficients for source bytes 21 to 31 +//extern "C" +TALIGN16(const int16, round34[8]) = + { 2, 2, 2, 2, 2, 2, 2, 2 }; + +//extern "C" +TALIGN16(const uint8, shuf38a[16]) = + { 0, 3, 6, 8, 11, 14, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }; + +//extern "C" +TALIGN16(const uint8, shuf38b[16]) = + { 128, 128, 128, 128, 128, 128, 0, 3, 6, 8, 11, 14, 128, 128, 128, 128 }; + +// Arrange words 0,3,6 into 0,1,2 +//extern "C" +TALIGN16(const uint8, shufac0[16]) = + { 0, 1, 6, 7, 12, 13, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Arrange words 0,3,6 into 3,4,5 +//extern "C" +TALIGN16(const uint8, shufac3[16]) = + { 128, 128, 128, 128, 128, 128, 0, 1, 6, 7, 12, 13, 128, 128, 128, 128 }; + +// Scaling values for boxes of 3x3 and 2x3 +//extern "C" +TALIGN16(const uint16, scaleac3[8]) = + { 65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, 65536 / 9, 65536 / 6, 0, 0 }; + +// Arrange first value for pixels 0,1,2,3,4,5 +//extern "C" +TALIGN16(const uint8, shufab0[16]) = + { 0, 128, 3, 128, 6, 128, 8, 128, 11, 128, 14, 128, 128, 128, 128, 128 }; + +// Arrange second value for pixels 0,1,2,3,4,5 +//extern "C" +TALIGN16(const uint8, shufab1[16]) = + { 1, 128, 4, 128, 7, 128, 9, 128, 12, 128, 15, 128, 128, 128, 128, 128 }; + +// Arrange third value for pixels 0,1,2,3,4,5 +//extern "C" +TALIGN16(const uint8, shufab2[16]) = + { 2, 128, 5, 128, 128, 128, 10, 128, 13, 128, 128, 128, 128, 128, 128, 128 }; + +// Scaling values for boxes of 3x2 and 2x2 +//extern "C" +TALIGN16(const uint16, scaleab2[8]) = + { 65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, 65536 / 3, 65536 / 2, 0, 0 }; +#endif + +#if defined(_M_IX86) && !defined(YUV_DISABLE_ASM) + +#define HAS_SCALEROWDOWN2_SSE2 +// Reads 32 pixels, throws half away and writes 16 pixels. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned. +__declspec(naked) +static void ScaleRowDown2_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + mov eax, [esp + 4] // src_ptr + // src_stride ignored + mov edx, [esp + 12] // dst_ptr + mov ecx, [esp + 16] // dst_width + pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff + psrlw xmm5, 8 + + wloop: + movdqa xmm0, [eax] + movdqa xmm1, [eax + 16] + lea eax, [eax + 32] + pand xmm0, xmm5 + pand xmm1, xmm5 + packuswb xmm0, xmm1 + movdqa [edx], xmm0 + lea edx, [edx + 16] + sub ecx, 16 + ja wloop + + ret + } +} +// Blends 32x2 rectangle to 16x1. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned. +__declspec(naked) +void ScaleRowDown2Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + push esi + mov eax, [esp + 4 + 4] // src_ptr + mov esi, [esp + 4 + 8] // src_stride + mov edx, [esp + 4 + 12] // dst_ptr + mov ecx, [esp + 4 + 16] // dst_width + pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff + psrlw xmm5, 8 + + wloop: + movdqa xmm0, [eax] + movdqa xmm1, [eax + 16] + movdqa xmm2, [eax + esi] + movdqa xmm3, [eax + esi + 16] + lea eax, [eax + 32] + pavgb xmm0, xmm2 // average rows + pavgb xmm1, xmm3 + + movdqa xmm2, xmm0 // average columns (32 to 16 pixels) + psrlw xmm0, 8 + movdqa xmm3, xmm1 + psrlw xmm1, 8 + pand xmm2, xmm5 + pand xmm3, xmm5 + pavgw xmm0, xmm2 + pavgw xmm1, xmm3 + packuswb xmm0, xmm1 + + movdqa [edx], xmm0 + lea edx, [edx + 16] + sub ecx, 16 + ja wloop + + pop esi + ret + } +} + +#define HAS_SCALEROWDOWN4_SSE2 +// Point samples 32 pixels to 8 pixels. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned. +__declspec(naked) +static void ScaleRowDown4_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + // src_stride ignored + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + pcmpeqb xmm5, xmm5 // generate mask 0x000000ff + psrld xmm5, 24 + + wloop: + movdqa xmm0, [esi] + movdqa xmm1, [esi + 16] + lea esi, [esi + 32] + pand xmm0, xmm5 + pand xmm1, xmm5 + packuswb xmm0, xmm1 + packuswb xmm0, xmm0 + movq qword ptr [edi], xmm0 + lea edi, [edi + 8] + sub ecx, 8 + ja wloop + + popad + ret + } +} + +// Blends 32x4 rectangle to 8x1. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned. +__declspec(naked) +static void ScaleRowDown4Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov ebx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + pcmpeqb xmm7, xmm7 // generate mask 0x00ff00ff + psrlw xmm7, 8 + lea edx, [ebx + ebx * 2] // src_stride * 3 + + wloop: + movdqa xmm0, [esi] + movdqa xmm1, [esi + 16] + movdqa xmm2, [esi + ebx] + movdqa xmm3, [esi + ebx + 16] + pavgb xmm0, xmm2 // average rows + pavgb xmm1, xmm3 + movdqa xmm2, [esi + ebx * 2] + movdqa xmm3, [esi + ebx * 2 + 16] + movdqa xmm4, [esi + edx] + movdqa xmm5, [esi + edx + 16] + lea esi, [esi + 32] + pavgb xmm2, xmm4 + pavgb xmm3, xmm5 + pavgb xmm0, xmm2 + pavgb xmm1, xmm3 + + movdqa xmm2, xmm0 // average columns (32 to 16 pixels) + psrlw xmm0, 8 + movdqa xmm3, xmm1 + psrlw xmm1, 8 + pand xmm2, xmm7 + pand xmm3, xmm7 + pavgw xmm0, xmm2 + pavgw xmm1, xmm3 + packuswb xmm0, xmm1 + + movdqa xmm2, xmm0 // average columns (16 to 8 pixels) + psrlw xmm0, 8 + pand xmm2, xmm7 + pavgw xmm0, xmm2 + packuswb xmm0, xmm0 + + movq qword ptr [edi], xmm0 + lea edi, [edi + 8] + sub ecx, 8 + ja wloop + + popad + ret + } +} + +#define HAS_SCALEROWDOWN8_SSE2 +// Point samples 32 pixels to 4 pixels. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 4 byte aligned. +__declspec(naked) +static void ScaleRowDown8_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + // src_stride ignored + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + pcmpeqb xmm5, xmm5 // generate mask isolating 1 src 8 bytes + psrlq xmm5, 56 + + wloop: + movdqa xmm0, [esi] + movdqa xmm1, [esi + 16] + lea esi, [esi + 32] + pand xmm0, xmm5 + pand xmm1, xmm5 + packuswb xmm0, xmm1 // 32->16 + packuswb xmm0, xmm0 // 16->8 + packuswb xmm0, xmm0 // 8->4 + movd dword ptr [edi], xmm0 + lea edi, [edi + 4] + sub ecx, 4 + ja wloop + + popad + ret + } +} + +// Blends 32x8 rectangle to 4x1. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 4 byte aligned. +__declspec(naked) +static void ScaleRowDown8Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov ebx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + lea edx, [ebx + ebx * 2] // src_stride * 3 + pxor xmm7, xmm7 + + wloop: + movdqa xmm0, [esi] // average 8 rows to 1 + movdqa xmm1, [esi + 16] + movdqa xmm2, [esi + ebx] + movdqa xmm3, [esi + ebx + 16] + pavgb xmm0, xmm2 + pavgb xmm1, xmm3 + movdqa xmm2, [esi + ebx * 2] + movdqa xmm3, [esi + ebx * 2 + 16] + movdqa xmm4, [esi + edx] + movdqa xmm5, [esi + edx + 16] + lea ebp, [esi + ebx * 4] + lea esi, [esi + 32] + pavgb xmm2, xmm4 + pavgb xmm3, xmm5 + pavgb xmm0, xmm2 + pavgb xmm1, xmm3 + + movdqa xmm2, [ebp] + movdqa xmm3, [ebp + 16] + movdqa xmm4, [ebp + ebx] + movdqa xmm5, [ebp + ebx + 16] + pavgb xmm2, xmm4 + pavgb xmm3, xmm5 + movdqa xmm4, [ebp + ebx * 2] + movdqa xmm5, [ebp + ebx * 2 + 16] + movdqa xmm6, [ebp + edx] + pavgb xmm4, xmm6 + movdqa xmm6, [ebp + edx + 16] + pavgb xmm5, xmm6 + pavgb xmm2, xmm4 + pavgb xmm3, xmm5 + pavgb xmm0, xmm2 + pavgb xmm1, xmm3 + + psadbw xmm0, xmm7 // average 32 pixels to 4 + psadbw xmm1, xmm7 + pshufd xmm0, xmm0, 0xd8 // x1x0 -> xx01 + pshufd xmm1, xmm1, 0x8d // x3x2 -> 32xx + por xmm0, xmm1 // -> 3201 + psrlw xmm0, 3 + packuswb xmm0, xmm0 + packuswb xmm0, xmm0 + movd dword ptr [edi], xmm0 + + lea edi, [edi + 4] + sub ecx, 4 + ja wloop + + popad + ret + } +} + +#define HAS_SCALEROWDOWN34_SSSE3 +// Point samples 32 pixels to 24 pixels. +// Produces three 8 byte values. For each 8 bytes, 16 bytes are read. +// Then shuffled to do the scaling. + +// Note that movdqa+palign may be better than movdqu. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned. +__declspec(naked) +static void ScaleRowDown34_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + // src_stride ignored + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + movdqa xmm3, _shuf0 + movdqa xmm4, _shuf1 + movdqa xmm5, _shuf2 + + wloop: + movdqa xmm0, [esi] + movdqa xmm1, [esi + 16] + lea esi, [esi + 32] + movdqa xmm2, xmm1 + palignr xmm1, xmm0, 8 + pshufb xmm0, xmm3 + pshufb xmm1, xmm4 + pshufb xmm2, xmm5 + movq qword ptr [edi], xmm0 + movq qword ptr [edi + 8], xmm1 + movq qword ptr [edi + 16], xmm2 + lea edi, [edi + 24] + sub ecx, 24 + ja wloop + + popad + ret + } +} + +// Blends 32x2 rectangle to 24x1 +// Produces three 8 byte values. For each 8 bytes, 16 bytes are read. +// Then shuffled to do the scaling. + +// Register usage: +// xmm0 src_row 0 +// xmm1 src_row 1 +// xmm2 shuf 0 +// xmm3 shuf 1 +// xmm4 shuf 2 +// xmm5 madd 0 +// xmm6 madd 1 +// xmm7 round34 + +// Note that movdqa+palign may be better than movdqu. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned. +__declspec(naked) +static void ScaleRowDown34_1_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov ebx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + movdqa xmm2, _shuf01 + movdqa xmm3, _shuf11 + movdqa xmm4, _shuf21 + movdqa xmm5, _madd01 + movdqa xmm6, _madd11 + movdqa xmm7, _round34 + + wloop: + movdqa xmm0, [esi] // pixels 0..7 + movdqa xmm1, [esi+ebx] + pavgb xmm0, xmm1 + pshufb xmm0, xmm2 + pmaddubsw xmm0, xmm5 + paddsw xmm0, xmm7 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edi], xmm0 + movdqu xmm0, [esi+8] // pixels 8..15 + movdqu xmm1, [esi+ebx+8] + pavgb xmm0, xmm1 + pshufb xmm0, xmm3 + pmaddubsw xmm0, xmm6 + paddsw xmm0, xmm7 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edi+8], xmm0 + movdqa xmm0, [esi+16] // pixels 16..23 + movdqa xmm1, [esi+ebx+16] + lea esi, [esi+32] + pavgb xmm0, xmm1 + pshufb xmm0, xmm4 + movdqa xmm1, _madd21 + pmaddubsw xmm0, xmm1 + paddsw xmm0, xmm7 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edi+16], xmm0 + lea edi, [edi+24] + sub ecx, 24 + ja wloop + + popad + ret + } +} + +// Note that movdqa+palign may be better than movdqu. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned. +__declspec(naked) +static void ScaleRowDown34_0_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov ebx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + movdqa xmm2, _shuf01 + movdqa xmm3, _shuf11 + movdqa xmm4, _shuf21 + movdqa xmm5, _madd01 + movdqa xmm6, _madd11 + movdqa xmm7, _round34 + + wloop: + movdqa xmm0, [esi] // pixels 0..7 + movdqa xmm1, [esi+ebx] + pavgb xmm1, xmm0 + pavgb xmm0, xmm1 + pshufb xmm0, xmm2 + pmaddubsw xmm0, xmm5 + paddsw xmm0, xmm7 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edi], xmm0 + movdqu xmm0, [esi+8] // pixels 8..15 + movdqu xmm1, [esi+ebx+8] + pavgb xmm1, xmm0 + pavgb xmm0, xmm1 + pshufb xmm0, xmm3 + pmaddubsw xmm0, xmm6 + paddsw xmm0, xmm7 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edi+8], xmm0 + movdqa xmm0, [esi+16] // pixels 16..23 + movdqa xmm1, [esi+ebx+16] + lea esi, [esi+32] + pavgb xmm1, xmm0 + pavgb xmm0, xmm1 + pshufb xmm0, xmm4 + movdqa xmm1, _madd21 + pmaddubsw xmm0, xmm1 + paddsw xmm0, xmm7 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edi+16], xmm0 + lea edi, [edi+24] + sub ecx, 24 + ja wloop + + popad + ret + } +} + +#define HAS_SCALEROWDOWN38_SSSE3 +// 3/8 point sampler + +// Scale 32 pixels to 12 +__declspec(naked) +static void ScaleRowDown38_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov edx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + movdqa xmm4, _shuf38a + movdqa xmm5, _shuf38b + + xloop: + movdqa xmm0, [esi] // 16 pixels -> 0,1,2,3,4,5 + movdqa xmm1, [esi + 16] // 16 pixels -> 6,7,8,9,10,11 + lea esi, [esi + 32] + pshufb xmm0, xmm4 + pshufb xmm1, xmm5 + paddusb xmm0, xmm1 + + movq qword ptr [edi], xmm0 // write 12 pixels + movhlps xmm1, xmm0 + movd [edi + 8], xmm1 + lea edi, [edi + 12] + sub ecx, 12 + ja xloop + + popad + ret + } +} + +// Scale 16x3 pixels to 6x1 with interpolation +__declspec(naked) +static void ScaleRowDown38_3_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov edx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + movdqa xmm4, _shufac0 + movdqa xmm5, _shufac3 + movdqa xmm6, _scaleac3 + pxor xmm7, xmm7 + + xloop: + movdqa xmm0, [esi] // sum up 3 rows into xmm0/1 + movdqa xmm2, [esi + edx] + movhlps xmm1, xmm0 + movhlps xmm3, xmm2 + punpcklbw xmm0, xmm7 + punpcklbw xmm1, xmm7 + punpcklbw xmm2, xmm7 + punpcklbw xmm3, xmm7 + paddusw xmm0, xmm2 + paddusw xmm1, xmm3 + movdqa xmm2, [esi + edx * 2] + lea esi, [esi + 16] + movhlps xmm3, xmm2 + punpcklbw xmm2, xmm7 + punpcklbw xmm3, xmm7 + paddusw xmm0, xmm2 + paddusw xmm1, xmm3 + + movdqa xmm2, xmm0 // 8 pixels -> 0,1,2 of xmm2 + psrldq xmm0, 2 + paddusw xmm2, xmm0 + psrldq xmm0, 2 + paddusw xmm2, xmm0 + pshufb xmm2, xmm4 + + movdqa xmm3, xmm1 // 8 pixels -> 3,4,5 of xmm2 + psrldq xmm1, 2 + paddusw xmm3, xmm1 + psrldq xmm1, 2 + paddusw xmm3, xmm1 + pshufb xmm3, xmm5 + paddusw xmm2, xmm3 + + pmulhuw xmm2, xmm6 // divide by 9,9,6, 9,9,6 + packuswb xmm2, xmm2 + + movd [edi], xmm2 // write 6 pixels + pextrw eax, xmm2, 2 + mov [edi + 4], ax + lea edi, [edi + 6] + sub ecx, 6 + ja xloop + + popad + ret + } +} + +// Scale 16x2 pixels to 6x1 with interpolation +__declspec(naked) +static void ScaleRowDown38_2_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov edx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + movdqa xmm4, _shufab0 + movdqa xmm5, _shufab1 + movdqa xmm6, _shufab2 + movdqa xmm7, _scaleab2 + + xloop: + movdqa xmm2, [esi] // average 2 rows into xmm2 + pavgb xmm2, [esi + edx] + lea esi, [esi + 16] + + movdqa xmm0, xmm2 // 16 pixels -> 0,1,2,3,4,5 of xmm0 + pshufb xmm0, xmm4 + movdqa xmm1, xmm2 + pshufb xmm1, xmm5 + paddusw xmm0, xmm1 + pshufb xmm2, xmm6 + paddusw xmm0, xmm2 + + pmulhuw xmm0, xmm7 // divide by 3,3,2, 3,3,2 + packuswb xmm0, xmm0 + + movd [edi], xmm0 // write 6 pixels + pextrw eax, xmm0, 2 + mov [edi + 4], ax + lea edi, [edi + 6] + sub ecx, 6 + ja xloop + + popad + ret + } +} + +#define HAS_SCALEADDROWS_SSE2 + +// Reads 8xN bytes and produces 16 shorts at a time. +__declspec(naked) +static void ScaleAddRows_SSE2(const uint8* src_ptr, int src_stride, + uint16* dst_ptr, int src_width, + int src_height) { + __asm { + pushad + mov esi, [esp + 32 + 4] // src_ptr + mov edx, [esp + 32 + 8] // src_stride + mov edi, [esp + 32 + 12] // dst_ptr + mov ecx, [esp + 32 + 16] // dst_width + mov ebx, [esp + 32 + 20] // height + pxor xmm5, xmm5 + dec ebx + + xloop: + // first row + movdqa xmm2, [esi] + lea eax, [esi + edx] + movhlps xmm3, xmm2 + mov ebp, ebx + punpcklbw xmm2, xmm5 + punpcklbw xmm3, xmm5 + + // sum remaining rows + yloop: + movdqa xmm0, [eax] // read 16 pixels + lea eax, [eax + edx] // advance to next row + movhlps xmm1, xmm0 + punpcklbw xmm0, xmm5 + punpcklbw xmm1, xmm5 + paddusw xmm2, xmm0 // sum 16 words + paddusw xmm3, xmm1 + sub ebp, 1 + ja yloop + + movdqa [edi], xmm2 + movdqa [edi + 16], xmm3 + lea edi, [edi + 32] + lea esi, [esi + 16] + + sub ecx, 16 + ja xloop + + popad + ret + } +} + +// Bilinear row filtering combines 16x2 -> 16x1. SSE2 version. +#define HAS_SCALEFILTERROWS_SSE2 +__declspec(naked) +static void ScaleFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr, + int src_stride, int dst_width, + int source_y_fraction) { + __asm { + push esi + push edi + mov edi, [esp + 8 + 4] // dst_ptr + mov esi, [esp + 8 + 8] // src_ptr + mov edx, [esp + 8 + 12] // src_stride + mov ecx, [esp + 8 + 16] // dst_width + mov eax, [esp + 8 + 20] // source_y_fraction (0..255) + cmp eax, 0 + je xloop1 + cmp eax, 128 + je xloop2 + + movd xmm6, eax // xmm6 = y fraction + punpcklwd xmm6, xmm6 + pshufd xmm6, xmm6, 0 + neg eax // xmm5 = 256 - y fraction + add eax, 256 + movd xmm5, eax + punpcklwd xmm5, xmm5 + pshufd xmm5, xmm5, 0 + pxor xmm7, xmm7 + + xloop: + movdqa xmm0, [esi] + movdqa xmm2, [esi + edx] + lea esi, [esi + 16] + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + punpcklbw xmm0, xmm7 + punpcklbw xmm2, xmm7 + punpckhbw xmm1, xmm7 + punpckhbw xmm3, xmm7 + pmullw xmm0, xmm5 // scale row 0 + pmullw xmm1, xmm5 + pmullw xmm2, xmm6 // scale row 1 + pmullw xmm3, xmm6 + paddusw xmm0, xmm2 // sum rows + paddusw xmm1, xmm3 + psrlw xmm0, 8 + psrlw xmm1, 8 + packuswb xmm0, xmm1 + movdqa [edi], xmm0 + lea edi, [edi + 16] + sub ecx, 16 + ja xloop + + mov al, [edi - 1] + mov [edi], al + pop edi + pop esi + ret + + xloop1: + movdqa xmm0, [esi] + lea esi, [esi + 16] + movdqa [edi], xmm0 + lea edi, [edi + 16] + sub ecx, 16 + ja xloop1 + + mov al, [edi - 1] + mov [edi], al + pop edi + pop esi + ret + + xloop2: + movdqa xmm0, [esi] + movdqa xmm2, [esi + edx] + lea esi, [esi + 16] + pavgb xmm0, xmm2 + movdqa [edi], xmm0 + lea edi, [edi + 16] + sub ecx, 16 + ja xloop2 + + mov al, [edi - 1] + mov [edi], al + pop edi + pop esi + ret + } +} + +// Bilinear row filtering combines 16x2 -> 16x1. SSSE3 version. +#define HAS_SCALEFILTERROWS_SSSE3 +__declspec(naked) +static void ScaleFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + int src_stride, int dst_width, + int source_y_fraction) { + __asm { + push esi + push edi + mov edi, [esp + 8 + 4] // dst_ptr + mov esi, [esp + 8 + 8] // src_ptr + mov edx, [esp + 8 + 12] // src_stride + mov ecx, [esp + 8 + 16] // dst_width + mov eax, [esp + 8 + 20] // source_y_fraction (0..255) + cmp eax, 0 + je xloop1 + cmp eax, 128 + je xloop2 + + shr eax, 1 + mov ah,al + neg al + add al, 128 + movd xmm5, eax + punpcklwd xmm5, xmm5 + pshufd xmm5, xmm5, 0 + + xloop: + movdqa xmm0, [esi] + movdqa xmm2, [esi + edx] + lea esi, [esi + 16] + movdqa xmm1, xmm0 + punpcklbw xmm0, xmm2 + punpckhbw xmm1, xmm2 + pmaddubsw xmm0, xmm5 + pmaddubsw xmm1, xmm5 + psrlw xmm0, 7 + psrlw xmm1, 7 + packuswb xmm0, xmm1 + movdqa [edi], xmm0 + lea edi, [edi + 16] + sub ecx, 16 + ja xloop + + mov al, [edi - 1] + mov [edi], al + pop edi + pop esi + ret + + xloop1: + movdqa xmm0, [esi] + lea esi, [esi + 16] + movdqa [edi], xmm0 + lea edi, [edi + 16] + sub ecx, 16 + ja xloop1 + + mov al, [edi - 1] + mov [edi], al + pop edi + pop esi + ret + + xloop2: + movdqa xmm0, [esi] + movdqa xmm2, [esi + edx] + lea esi, [esi + 16] + pavgb xmm0, xmm2 + movdqa [edi], xmm0 + lea edi, [edi + 16] + sub ecx, 16 + ja xloop2 + + mov al, [edi - 1] + mov [edi], al + pop edi + pop esi + ret + + } +} + +// Note that movdqa+palign may be better than movdqu. +// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned. +__declspec(naked) +static void ScaleFilterCols34_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + int dst_width) { + __asm { + mov edx, [esp + 4] // dst_ptr + mov eax, [esp + 8] // src_ptr + mov ecx, [esp + 12] // dst_width + movdqa xmm1, _round34 + movdqa xmm2, _shuf01 + movdqa xmm3, _shuf11 + movdqa xmm4, _shuf21 + movdqa xmm5, _madd01 + movdqa xmm6, _madd11 + movdqa xmm7, _madd21 + + wloop: + movdqa xmm0, [eax] // pixels 0..7 + pshufb xmm0, xmm2 + pmaddubsw xmm0, xmm5 + paddsw xmm0, xmm1 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edx], xmm0 + movdqu xmm0, [eax+8] // pixels 8..15 + pshufb xmm0, xmm3 + pmaddubsw xmm0, xmm6 + paddsw xmm0, xmm1 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edx+8], xmm0 + movdqa xmm0, [eax+16] // pixels 16..23 + lea eax, [eax+32] + pshufb xmm0, xmm4 + pmaddubsw xmm0, xmm7 + paddsw xmm0, xmm1 + psrlw xmm0, 2 + packuswb xmm0, xmm0 + movq qword ptr [edx+16], xmm0 + lea edx, [edx+24] + sub ecx, 24 + ja wloop + ret + } +} + +#elif (defined(__x86_64__) || defined(__i386__)) && !defined(YUV_DISABLE_ASM) + +// GCC versions of row functions are verbatim conversions from Visual C. +// Generated using gcc disassembly on Visual C object file: +// objdump -D yuvscaler.obj >yuvscaler.txt +#define HAS_SCALEROWDOWN2_SSE2 +static void ScaleRowDown2_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "lea 0x20(%0),%0 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,(%1) \n" + "lea 0x10(%1),%1 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "memory", "cc" +); +} + +static void ScaleRowDown2Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "movdqa (%0,%3,1),%%xmm2 \n" + "movdqa 0x10(%0,%3,1),%%xmm3 \n" + "lea 0x20(%0),%0 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "psrlw $0x8,%%xmm0 \n" + "movdqa %%xmm1,%%xmm3 \n" + "psrlw $0x8,%%xmm1 \n" + "pand %%xmm5,%%xmm2 \n" + "pand %%xmm5,%%xmm3 \n" + "pavgw %%xmm2,%%xmm0 \n" + "pavgw %%xmm3,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,(%1) \n" + "lea 0x10(%1),%1 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc" +); +} + +#define HAS_SCALEROWDOWN4_SSE2 +static void ScaleRowDown4_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrld $0x18,%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "lea 0x20(%0),%0 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "lea 0x8(%1),%1 \n" + "sub $0x8,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "memory", "cc" +); +} + +static void ScaleRowDown4Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + intptr_t temp = 0; + asm volatile ( + "pcmpeqb %%xmm7,%%xmm7 \n" + "psrlw $0x8,%%xmm7 \n" + "lea (%4,%4,2),%3 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "movdqa (%0,%4,1),%%xmm2 \n" + "movdqa 0x10(%0,%4,1),%%xmm3 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa (%0,%4,2),%%xmm2 \n" + "movdqa 0x10(%0,%4,2),%%xmm3 \n" + "movdqa (%0,%3,1),%%xmm4 \n" + "movdqa 0x10(%0,%3,1),%%xmm5 \n" + "lea 0x20(%0),%0 \n" + "pavgb %%xmm4,%%xmm2 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm5,%%xmm3 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "psrlw $0x8,%%xmm0 \n" + "movdqa %%xmm1,%%xmm3 \n" + "psrlw $0x8,%%xmm1 \n" + "pand %%xmm7,%%xmm2 \n" + "pand %%xmm7,%%xmm3 \n" + "pavgw %%xmm2,%%xmm0 \n" + "pavgw %%xmm3,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "psrlw $0x8,%%xmm0 \n" + "pand %%xmm7,%%xmm2 \n" + "pavgw %%xmm2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "lea 0x8(%1),%1 \n" + "sub $0x8,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(temp) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc" +#if defined(__x86_64__) + , "xmm6", "xmm7" +#endif +); +} + +#define HAS_SCALEROWDOWN8_SSE2 +static void ScaleRowDown8_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlq $0x38,%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "lea 0x20(%0),%0 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0,(%1) \n" + "lea 0x4(%1),%1 \n" + "sub $0x4,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "memory", "cc" +); +} + +#if defined(__i386__) +void ScaleRowDown8Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown8Int_SSE2) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%ebx \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "lea (%ebx,%ebx,2),%edx \n" + "pxor %xmm7,%xmm7 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa 0x10(%esi),%xmm1 \n" + "movdqa (%esi,%ebx,1),%xmm2 \n" + "movdqa 0x10(%esi,%ebx,1),%xmm3 \n" + "pavgb %xmm2,%xmm0 \n" + "pavgb %xmm3,%xmm1 \n" + "movdqa (%esi,%ebx,2),%xmm2 \n" + "movdqa 0x10(%esi,%ebx,2),%xmm3 \n" + "movdqa (%esi,%edx,1),%xmm4 \n" + "movdqa 0x10(%esi,%edx,1),%xmm5 \n" + "lea (%esi,%ebx,4),%ebp \n" + "lea 0x20(%esi),%esi \n" + "pavgb %xmm4,%xmm2 \n" + "pavgb %xmm5,%xmm3 \n" + "pavgb %xmm2,%xmm0 \n" + "pavgb %xmm3,%xmm1 \n" + "movdqa 0x0(%ebp),%xmm2 \n" + "movdqa 0x10(%ebp),%xmm3 \n" + "movdqa 0x0(%ebp,%ebx,1),%xmm4 \n" + "movdqa 0x10(%ebp,%ebx,1),%xmm5 \n" + "pavgb %xmm4,%xmm2 \n" + "pavgb %xmm5,%xmm3 \n" + "movdqa 0x0(%ebp,%ebx,2),%xmm4 \n" + "movdqa 0x10(%ebp,%ebx,2),%xmm5 \n" + "movdqa 0x0(%ebp,%edx,1),%xmm6 \n" + "pavgb %xmm6,%xmm4 \n" + "movdqa 0x10(%ebp,%edx,1),%xmm6 \n" + "pavgb %xmm6,%xmm5 \n" + "pavgb %xmm4,%xmm2 \n" + "pavgb %xmm5,%xmm3 \n" + "pavgb %xmm2,%xmm0 \n" + "pavgb %xmm3,%xmm1 \n" + "psadbw %xmm7,%xmm0 \n" + "psadbw %xmm7,%xmm1 \n" + "pshufd $0xd8,%xmm0,%xmm0 \n" + "pshufd $0x8d,%xmm1,%xmm1 \n" + "por %xmm1,%xmm0 \n" + "psrlw $0x3,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movd %xmm0,(%edi) \n" + "lea 0x4(%edi),%edi \n" + "sub $0x4,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); + +// fpic is used for magiccam plugin +#if !defined(__PIC__) +#define HAS_SCALEROWDOWN34_SSSE3 +void ScaleRowDown34_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown34_SSSE3) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "movdqa _shuf0,%xmm3 \n" + "movdqa _shuf1,%xmm4 \n" + "movdqa _shuf2,%xmm5 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa 0x10(%esi),%xmm2 \n" + "lea 0x20(%esi),%esi \n" + "movdqa %xmm2,%xmm1 \n" + "palignr $0x8,%xmm0,%xmm1 \n" + "pshufb %xmm3,%xmm0 \n" + "pshufb %xmm4,%xmm1 \n" + "pshufb %xmm5,%xmm2 \n" + "movq %xmm0,(%edi) \n" + "movq %xmm1,0x8(%edi) \n" + "movq %xmm2,0x10(%edi) \n" + "lea 0x18(%edi),%edi \n" + "sub $0x18,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); + +void ScaleRowDown34_1_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown34_1_Int_SSSE3) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%ebp \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "movdqa _shuf01,%xmm2 \n" + "movdqa _shuf11,%xmm3 \n" + "movdqa _shuf21,%xmm4 \n" + "movdqa _madd01,%xmm5 \n" + "movdqa _madd11,%xmm6 \n" + "movdqa _round34,%xmm7 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%ebp),%xmm1 \n" + "pavgb %xmm1,%xmm0 \n" + "pshufb %xmm2,%xmm0 \n" + "pmaddubsw %xmm5,%xmm0 \n" + "paddsw %xmm7,%xmm0 \n" + "psrlw $0x2,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movq %xmm0,(%edi) \n" + "movdqu 0x8(%esi),%xmm0 \n" + "movdqu 0x8(%esi,%ebp),%xmm1 \n" + "pavgb %xmm1,%xmm0 \n" + "pshufb %xmm3,%xmm0 \n" + "pmaddubsw %xmm6,%xmm0 \n" + "paddsw %xmm7,%xmm0 \n" + "psrlw $0x2,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movq %xmm0,0x8(%edi) \n" + "movdqa 0x10(%esi),%xmm0 \n" + "movdqa 0x10(%esi,%ebp),%xmm1 \n" + "lea 0x20(%esi),%esi \n" + "pavgb %xmm1,%xmm0 \n" + "pshufb %xmm4,%xmm0 \n" + "movdqa _madd21,%xmm1 \n" + "pmaddubsw %xmm1,%xmm0 \n" + "paddsw %xmm7,%xmm0 \n" + "psrlw $0x2,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movq %xmm0,0x10(%edi) \n" + "lea 0x18(%edi),%edi \n" + "sub $0x18,%ecx \n" + "ja 1b \n" + + "popa \n" + "ret \n" +); + +void ScaleRowDown34_0_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown34_0_Int_SSSE3) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%ebp \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "movdqa _shuf01,%xmm2 \n" + "movdqa _shuf11,%xmm3 \n" + "movdqa _shuf21,%xmm4 \n" + "movdqa _madd01,%xmm5 \n" + "movdqa _madd11,%xmm6 \n" + "movdqa _round34,%xmm7 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%ebp,1),%xmm1 \n" + "pavgb %xmm0,%xmm1 \n" + "pavgb %xmm1,%xmm0 \n" + "pshufb %xmm2,%xmm0 \n" + "pmaddubsw %xmm5,%xmm0 \n" + "paddsw %xmm7,%xmm0 \n" + "psrlw $0x2,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movq %xmm0,(%edi) \n" + "movdqu 0x8(%esi),%xmm0 \n" + "movdqu 0x8(%esi,%ebp,1),%xmm1 \n" + "pavgb %xmm0,%xmm1 \n" + "pavgb %xmm1,%xmm0 \n" + "pshufb %xmm3,%xmm0 \n" + "pmaddubsw %xmm6,%xmm0 \n" + "paddsw %xmm7,%xmm0 \n" + "psrlw $0x2,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movq %xmm0,0x8(%edi) \n" + "movdqa 0x10(%esi),%xmm0 \n" + "movdqa 0x10(%esi,%ebp,1),%xmm1 \n" + "lea 0x20(%esi),%esi \n" + "pavgb %xmm0,%xmm1 \n" + "pavgb %xmm1,%xmm0 \n" + "pshufb %xmm4,%xmm0 \n" + "movdqa _madd21,%xmm1 \n" + "pmaddubsw %xmm1,%xmm0 \n" + "paddsw %xmm7,%xmm0 \n" + "psrlw $0x2,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movq %xmm0,0x10(%edi) \n" + "lea 0x18(%edi),%edi \n" + "sub $0x18,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); + +#define HAS_SCALEROWDOWN38_SSSE3 +void ScaleRowDown38_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown38_SSSE3) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%edx \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "movdqa _shuf38a ,%xmm4 \n" + "movdqa _shuf38b ,%xmm5 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa 0x10(%esi),%xmm1 \n" + "lea 0x20(%esi),%esi \n" + "pshufb %xmm4,%xmm0 \n" + "pshufb %xmm5,%xmm1 \n" + "paddusb %xmm1,%xmm0 \n" + "movq %xmm0,(%edi) \n" + "movhlps %xmm0,%xmm1 \n" + "movd %xmm1,0x8(%edi) \n" + "lea 0xc(%edi),%edi \n" + "sub $0xc,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); + +void ScaleRowDown38_3_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown38_3_Int_SSSE3) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%edx \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "movdqa _shufac0,%xmm4 \n" + "movdqa _shufac3,%xmm5 \n" + "movdqa _scaleac3,%xmm6 \n" + "pxor %xmm7,%xmm7 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%edx,1),%xmm2 \n" + "movhlps %xmm0,%xmm1 \n" + "movhlps %xmm2,%xmm3 \n" + "punpcklbw %xmm7,%xmm0 \n" + "punpcklbw %xmm7,%xmm1 \n" + "punpcklbw %xmm7,%xmm2 \n" + "punpcklbw %xmm7,%xmm3 \n" + "paddusw %xmm2,%xmm0 \n" + "paddusw %xmm3,%xmm1 \n" + "movdqa (%esi,%edx,2),%xmm2 \n" + "lea 0x10(%esi),%esi \n" + "movhlps %xmm2,%xmm3 \n" + "punpcklbw %xmm7,%xmm2 \n" + "punpcklbw %xmm7,%xmm3 \n" + "paddusw %xmm2,%xmm0 \n" + "paddusw %xmm3,%xmm1 \n" + "movdqa %xmm0,%xmm2 \n" + "psrldq $0x2,%xmm0 \n" + "paddusw %xmm0,%xmm2 \n" + "psrldq $0x2,%xmm0 \n" + "paddusw %xmm0,%xmm2 \n" + "pshufb %xmm4,%xmm2 \n" + "movdqa %xmm1,%xmm3 \n" + "psrldq $0x2,%xmm1 \n" + "paddusw %xmm1,%xmm3 \n" + "psrldq $0x2,%xmm1 \n" + "paddusw %xmm1,%xmm3 \n" + "pshufb %xmm5,%xmm3 \n" + "paddusw %xmm3,%xmm2 \n" + "pmulhuw %xmm6,%xmm2 \n" + "packuswb %xmm2,%xmm2 \n" + "movd %xmm2,(%edi) \n" + "pextrw $0x2,%xmm2,%eax \n" + "mov %ax,0x4(%edi) \n" + "lea 0x6(%edi),%edi \n" + "sub $0x6,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); + +void ScaleRowDown38_2_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + asm( + DECLARE_FUNCTION(ScaleRowDown38_2_Int_SSSE3) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%edx \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "movdqa _shufab0,%xmm4 \n" + "movdqa _shufab1,%xmm5 \n" + "movdqa _shufab2,%xmm6 \n" + "movdqa _scaleab2,%xmm7 \n" + +"1:" + "movdqa (%esi),%xmm2 \n" + "pavgb (%esi,%edx,1),%xmm2 \n" + "lea 0x10(%esi),%esi \n" + "movdqa %xmm2,%xmm0 \n" + "pshufb %xmm4,%xmm0 \n" + "movdqa %xmm2,%xmm1 \n" + "pshufb %xmm5,%xmm1 \n" + "paddusw %xmm1,%xmm0 \n" + "pshufb %xmm6,%xmm2 \n" + "paddusw %xmm2,%xmm0 \n" + "pmulhuw %xmm7,%xmm0 \n" + "packuswb %xmm0,%xmm0 \n" + "movd %xmm0,(%edi) \n" + "pextrw $0x2,%xmm0,%eax \n" + "mov %ax,0x4(%edi) \n" + "lea 0x6(%edi),%edi \n" + "sub $0x6,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); +#endif // __PIC__ + +#define HAS_SCALEADDROWS_SSE2 +void ScaleAddRows_SSE2(const uint8* src_ptr, int src_stride, + uint16* dst_ptr, int src_width, + int src_height); + asm( + DECLARE_FUNCTION(ScaleAddRows_SSE2) + "pusha \n" + "mov 0x24(%esp),%esi \n" + "mov 0x28(%esp),%edx \n" + "mov 0x2c(%esp),%edi \n" + "mov 0x30(%esp),%ecx \n" + "mov 0x34(%esp),%ebx \n" + "pxor %xmm5,%xmm5 \n" + +"1:" + "movdqa (%esi),%xmm2 \n" + "lea (%esi,%edx,1),%eax \n" + "movhlps %xmm2,%xmm3 \n" + "lea -0x1(%ebx),%ebp \n" + "punpcklbw %xmm5,%xmm2 \n" + "punpcklbw %xmm5,%xmm3 \n" + +"2:" + "movdqa (%eax),%xmm0 \n" + "lea (%eax,%edx,1),%eax \n" + "movhlps %xmm0,%xmm1 \n" + "punpcklbw %xmm5,%xmm0 \n" + "punpcklbw %xmm5,%xmm1 \n" + "paddusw %xmm0,%xmm2 \n" + "paddusw %xmm1,%xmm3 \n" + "sub $0x1,%ebp \n" + "ja 2b \n" + + "movdqa %xmm2,(%edi) \n" + "movdqa %xmm3,0x10(%edi) \n" + "lea 0x20(%edi),%edi \n" + "lea 0x10(%esi),%esi \n" + "sub $0x10,%ecx \n" + "ja 1b \n" + "popa \n" + "ret \n" +); + +// Bilinear row filtering combines 16x2 -> 16x1. SSE2 version +#define HAS_SCALEFILTERROWS_SSE2 +void ScaleFilterRows_SSE2(uint8* dst_ptr, + const uint8* src_ptr, int src_stride, + int dst_width, int source_y_fraction); + asm( + DECLARE_FUNCTION(ScaleFilterRows_SSE2) + "push %esi \n" + "push %edi \n" + "mov 0xc(%esp),%edi \n" + "mov 0x10(%esp),%esi \n" + "mov 0x14(%esp),%edx \n" + "mov 0x18(%esp),%ecx \n" + "mov 0x1c(%esp),%eax \n" + "cmp $0x0,%eax \n" + "je 2f \n" + "cmp $0x80,%eax \n" + "je 3f \n" + "movd %eax,%xmm6 \n" + "punpcklwd %xmm6,%xmm6 \n" + "pshufd $0x0,%xmm6,%xmm6 \n" + "neg %eax \n" + "add $0x100,%eax \n" + "movd %eax,%xmm5 \n" + "punpcklwd %xmm5,%xmm5 \n" + "pshufd $0x0,%xmm5,%xmm5 \n" + "pxor %xmm7,%xmm7 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%edx,1),%xmm2 \n" + "lea 0x10(%esi),%esi \n" + "movdqa %xmm0,%xmm1 \n" + "movdqa %xmm2,%xmm3 \n" + "punpcklbw %xmm7,%xmm0 \n" + "punpcklbw %xmm7,%xmm2 \n" + "punpckhbw %xmm7,%xmm1 \n" + "punpckhbw %xmm7,%xmm3 \n" + "pmullw %xmm5,%xmm0 \n" + "pmullw %xmm5,%xmm1 \n" + "pmullw %xmm6,%xmm2 \n" + "pmullw %xmm6,%xmm3 \n" + "paddusw %xmm2,%xmm0 \n" + "paddusw %xmm3,%xmm1 \n" + "psrlw $0x8,%xmm0 \n" + "psrlw $0x8,%xmm1 \n" + "packuswb %xmm1,%xmm0 \n" + "movdqa %xmm0,(%edi) \n" + "lea 0x10(%edi),%edi \n" + "sub $0x10,%ecx \n" + "ja 1b \n" + "mov -0x1(%edi),%al \n" + "mov %al,(%edi) \n" + "pop %edi \n" + "pop %esi \n" + "ret \n" + +"2:" + "movdqa (%esi),%xmm0 \n" + "lea 0x10(%esi),%esi \n" + "movdqa %xmm0,(%edi) \n" + "lea 0x10(%edi),%edi \n" + "sub $0x10,%ecx \n" + "ja 2b \n" + + "mov -0x1(%edi),%al \n" + "mov %al,(%edi) \n" + "pop %edi \n" + "pop %esi \n" + "ret \n" + +"3:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%edx,1),%xmm2 \n" + "lea 0x10(%esi),%esi \n" + "pavgb %xmm2,%xmm0 \n" + "movdqa %xmm0,(%edi) \n" + "lea 0x10(%edi),%edi \n" + "sub $0x10,%ecx \n" + "ja 3b \n" + + "mov -0x1(%edi),%al \n" + "mov %al,(%edi) \n" + "pop %edi \n" + "pop %esi \n" + "ret \n" +); + +// Bilinear row filtering combines 16x2 -> 16x1. SSSE3 version +#define HAS_SCALEFILTERROWS_SSSE3 +void ScaleFilterRows_SSSE3(uint8* dst_ptr, + const uint8* src_ptr, int src_stride, + int dst_width, int source_y_fraction); + asm( + DECLARE_FUNCTION(ScaleFilterRows_SSSE3) + "push %esi \n" + "push %edi \n" + "mov 0xc(%esp),%edi \n" + "mov 0x10(%esp),%esi \n" + "mov 0x14(%esp),%edx \n" + "mov 0x18(%esp),%ecx \n" + "mov 0x1c(%esp),%eax \n" + "cmp $0x0,%eax \n" + "je 2f \n" + "cmp $0x80,%eax \n" + "je 3f \n" + "shr %eax \n" + "mov %al,%ah \n" + "neg %al \n" + "add $0x80,%al \n" + "movd %eax,%xmm5 \n" + "punpcklwd %xmm5,%xmm5 \n" + "pshufd $0x0,%xmm5,%xmm5 \n" + +"1:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%edx,1),%xmm2 \n" + "lea 0x10(%esi),%esi \n" + "movdqa %xmm0,%xmm1 \n" + "punpcklbw %xmm2,%xmm0 \n" + "punpckhbw %xmm2,%xmm1 \n" + "pmaddubsw %xmm5,%xmm0 \n" + "pmaddubsw %xmm5,%xmm1 \n" + "psrlw $0x7,%xmm0 \n" + "psrlw $0x7,%xmm1 \n" + "packuswb %xmm1,%xmm0 \n" + "movdqa %xmm0,(%edi) \n" + "lea 0x10(%edi),%edi \n" + "sub $0x10,%ecx \n" + "ja 1b \n" + "mov -0x1(%edi),%al \n" + "mov %al,(%edi) \n" + "pop %edi \n" + "pop %esi \n" + "ret \n" + +"2:" + "movdqa (%esi),%xmm0 \n" + "lea 0x10(%esi),%esi \n" + "movdqa %xmm0,(%edi) \n" + "lea 0x10(%edi),%edi \n" + "sub $0x10,%ecx \n" + "ja 2b \n" + "mov -0x1(%edi),%al \n" + "mov %al,(%edi) \n" + "pop %edi \n" + "pop %esi \n" + "ret \n" + +"3:" + "movdqa (%esi),%xmm0 \n" + "movdqa (%esi,%edx,1),%xmm2 \n" + "lea 0x10(%esi),%esi \n" + "pavgb %xmm2,%xmm0 \n" + "movdqa %xmm0,(%edi) \n" + "lea 0x10(%edi),%edi \n" + "sub $0x10,%ecx \n" + "ja 3b \n" + "mov -0x1(%edi),%al \n" + "mov %al,(%edi) \n" + "pop %edi \n" + "pop %esi \n" + "ret \n" +); + +#elif defined(__x86_64__) +static void ScaleRowDown8Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "lea (%3,%3,2),%%r10 \n" + "pxor %%xmm7,%%xmm7 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "movdqa (%0,%3,1),%%xmm2 \n" + "movdqa 0x10(%0,%3,1),%%xmm3 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa (%0,%3,2),%%xmm2 \n" + "movdqa 0x10(%0,%3,2),%%xmm3 \n" + "movdqa (%0,%%r10,1),%%xmm4 \n" + "movdqa 0x10(%0,%%r10,1),%%xmm5 \n" + "lea (%0,%3,4),%%r11 \n" + "lea 0x20(%0),%0 \n" + "pavgb %%xmm4,%%xmm2 \n" + "pavgb %%xmm5,%%xmm3 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa 0x0(%%r11),%%xmm2 \n" + "movdqa 0x10(%%r11),%%xmm3 \n" + "movdqa 0x0(%%r11,%3,1),%%xmm4 \n" + "movdqa 0x10(%%r11,%3,1),%%xmm5 \n" + "pavgb %%xmm4,%%xmm2 \n" + "pavgb %%xmm5,%%xmm3 \n" + "movdqa 0x0(%%r11,%3,2),%%xmm4 \n" + "movdqa 0x10(%%r11,%3,2),%%xmm5 \n" + "movdqa 0x0(%%r11,%%r10,1),%%xmm6 \n" + "pavgb %%xmm6,%%xmm4 \n" + "movdqa 0x10(%%r11,%%r10,1),%%xmm6 \n" + "pavgb %%xmm6,%%xmm5 \n" + "pavgb %%xmm4,%%xmm2 \n" + "pavgb %%xmm5,%%xmm3 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "psadbw %%xmm7,%%xmm0 \n" + "psadbw %%xmm7,%%xmm1 \n" + "pshufd $0xd8,%%xmm0,%%xmm0 \n" + "pshufd $0x8d,%%xmm1,%%xmm1 \n" + "por %%xmm1,%%xmm0 \n" + "psrlw $0x3,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0,(%1) \n" + "lea 0x4(%1),%1 \n" + "sub $0x4,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", "r10", "r11", "xmm6", "xmm7" +); +} + +#define HAS_SCALEROWDOWN34_SSSE3 +static void ScaleRowDown34_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa (%3),%%xmm3 \n" + "movdqa (%4),%%xmm4 \n" + "movdqa (%5),%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm2 \n" + "lea 0x20(%0),%0 \n" + "movdqa %%xmm2,%%xmm1 \n" + "palignr $0x8,%%xmm0,%%xmm1 \n" + "pshufb %%xmm3,%%xmm0 \n" + "pshufb %%xmm4,%%xmm1 \n" + "pshufb %%xmm5,%%xmm2 \n" + "movq %%xmm0,(%1) \n" + "movq %%xmm1,0x8(%1) \n" + "movq %%xmm2,0x10(%1) \n" + "lea 0x18(%1),%1 \n" + "sub $0x18,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"(_shuf0), // %3 + "r"(_shuf1), // %4 + "r"(_shuf2) // %5 + : "memory", "cc" +); +} + +static void ScaleRowDown34_1_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa (%4),%%xmm2 \n" // _shuf01 + "movdqa (%5),%%xmm3 \n" // _shuf11 + "movdqa (%6),%%xmm4 \n" // _shuf21 + "movdqa (%7),%%xmm5 \n" // _madd01 + "movdqa (%8),%%xmm6 \n" // _madd11 + "movdqa (%9),%%xmm7 \n" // _round34 + "movdqa (%10),%%xmm8 \n" // _madd21 +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa (%0,%3),%%xmm1 \n" + "pavgb %%xmm1,%%xmm0 \n" + "pshufb %%xmm2,%%xmm0 \n" + "pmaddubsw %%xmm5,%%xmm0 \n" + "paddsw %%xmm7,%%xmm0 \n" + "psrlw $0x2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "movdqu 0x8(%0),%%xmm0 \n" + "movdqu 0x8(%0,%3),%%xmm1 \n" + "pavgb %%xmm1,%%xmm0 \n" + "pshufb %%xmm3,%%xmm0 \n" + "pmaddubsw %%xmm6,%%xmm0 \n" + "paddsw %%xmm7,%%xmm0 \n" + "psrlw $0x2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,0x8(%1) \n" + "movdqa 0x10(%0),%%xmm0 \n" + "movdqa 0x10(%0,%3),%%xmm1 \n" + "lea 0x20(%0),%0 \n" + "pavgb %%xmm1,%%xmm0 \n" + "pshufb %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm8,%%xmm0 \n" + "paddsw %%xmm7,%%xmm0 \n" + "psrlw $0x2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,0x10(%1) \n" + "lea 0x18(%1),%1 \n" + "sub $0x18,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"(_shuf01), // %4 + "r"(_shuf11), // %5 + "r"(_shuf21), // %6 + "r"(_madd01), // %7 + "r"(_madd11), // %8 + "r"(_round34), // %9 + "r"(_madd21) // %10 + : "memory", "cc", "xmm6", "xmm7", "xmm8" +); +} + +static void ScaleRowDown34_0_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa (%4),%%xmm2 \n" // _shuf01 + "movdqa (%5),%%xmm3 \n" // _shuf11 + "movdqa (%6),%%xmm4 \n" // _shuf21 + "movdqa (%7),%%xmm5 \n" // _madd01 + "movdqa (%8),%%xmm6 \n" // _madd11 + "movdqa (%9),%%xmm7 \n" // _round34 + "movdqa (%10),%%xmm8 \n" // _madd21 +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa (%0,%3,1),%%xmm1 \n" + "pavgb %%xmm0,%%xmm1 \n" + "pavgb %%xmm1,%%xmm0 \n" + "pshufb %%xmm2,%%xmm0 \n" + "pmaddubsw %%xmm5,%%xmm0 \n" + "paddsw %%xmm7,%%xmm0 \n" + "psrlw $0x2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "movdqu 0x8(%0),%%xmm0 \n" + "movdqu 0x8(%0,%3,1),%%xmm1 \n" + "pavgb %%xmm0,%%xmm1 \n" + "pavgb %%xmm1,%%xmm0 \n" + "pshufb %%xmm3,%%xmm0 \n" + "pmaddubsw %%xmm6,%%xmm0 \n" + "paddsw %%xmm7,%%xmm0 \n" + "psrlw $0x2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,0x8(%1) \n" + "movdqa 0x10(%0),%%xmm0 \n" + "movdqa 0x10(%0,%3,1),%%xmm1 \n" + "lea 0x20(%0),%0 \n" + "pavgb %%xmm0,%%xmm1 \n" + "pavgb %%xmm1,%%xmm0 \n" + "pshufb %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm8,%%xmm0 \n" + "paddsw %%xmm7,%%xmm0 \n" + "psrlw $0x2,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,0x10(%1) \n" + "lea 0x18(%1),%1 \n" + "sub $0x18,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"(_shuf01), // %4 + "r"(_shuf11), // %5 + "r"(_shuf21), // %6 + "r"(_madd01), // %7 + "r"(_madd11), // %8 + "r"(_round34), // %9 + "r"(_madd21) // %10 + : "memory", "cc", "xmm6", "xmm7", "xmm8" +); +} + +#define HAS_SCALEROWDOWN38_SSSE3 +static void ScaleRowDown38_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa (%3),%%xmm4 \n" + "movdqa (%4),%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa 0x10(%0),%%xmm1 \n" + "lea 0x20(%0),%0 \n" + "pshufb %%xmm4,%%xmm0 \n" + "pshufb %%xmm5,%%xmm1 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "movhlps %%xmm0,%%xmm1 \n" + "movd %%xmm1,0x8(%1) \n" + "lea 0xc(%1),%1 \n" + "sub $0xc,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"(_shuf38a), // %3 + "r"(_shuf38b) // %4 + : "memory", "cc" +); +} + +static void ScaleRowDown38_3_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa (%4),%%xmm4 \n" + "movdqa (%5),%%xmm5 \n" + "movdqa (%6),%%xmm6 \n" + "pxor %%xmm7,%%xmm7 \n" +"1:" + "movdqa (%0),%%xmm0 \n" + "movdqa (%0,%3,1),%%xmm2 \n" + "movhlps %%xmm0,%%xmm1 \n" + "movhlps %%xmm2,%%xmm3 \n" + "punpcklbw %%xmm7,%%xmm0 \n" + "punpcklbw %%xmm7,%%xmm1 \n" + "punpcklbw %%xmm7,%%xmm2 \n" + "punpcklbw %%xmm7,%%xmm3 \n" + "paddusw %%xmm2,%%xmm0 \n" + "paddusw %%xmm3,%%xmm1 \n" + "movdqa (%0,%3,2),%%xmm2 \n" + "lea 0x10(%0),%0 \n" + "movhlps %%xmm2,%%xmm3 \n" + "punpcklbw %%xmm7,%%xmm2 \n" + "punpcklbw %%xmm7,%%xmm3 \n" + "paddusw %%xmm2,%%xmm0 \n" + "paddusw %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "psrldq $0x2,%%xmm0 \n" + "paddusw %%xmm0,%%xmm2 \n" + "psrldq $0x2,%%xmm0 \n" + "paddusw %%xmm0,%%xmm2 \n" + "pshufb %%xmm4,%%xmm2 \n" + "movdqa %%xmm1,%%xmm3 \n" + "psrldq $0x2,%%xmm1 \n" + "paddusw %%xmm1,%%xmm3 \n" + "psrldq $0x2,%%xmm1 \n" + "paddusw %%xmm1,%%xmm3 \n" + "pshufb %%xmm5,%%xmm3 \n" + "paddusw %%xmm3,%%xmm2 \n" + "pmulhuw %%xmm6,%%xmm2 \n" + "packuswb %%xmm2,%%xmm2 \n" + "movd %%xmm2,(%1) \n" + "pextrw $0x2,%%xmm2,%%eax \n" + "mov %%ax,0x4(%1) \n" + "lea 0x6(%1),%1 \n" + "sub $0x6,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"(_shufac0), // %4 + "r"(_shufac3), // %5 + "r"(_scaleac3) // %6 + : "memory", "cc", "rax", "xmm6", "xmm7" +); +} + +static void ScaleRowDown38_2_Int_SSSE3(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa (%4),%%xmm4 \n" + "movdqa (%5),%%xmm5 \n" + "movdqa (%6),%%xmm6 \n" + "movdqa (%7),%%xmm7 \n" +"1:" + "movdqa (%0),%%xmm2 \n" + "pavgb (%0,%3,1),%%xmm2 \n" + "lea 0x10(%0),%0 \n" + "movdqa %%xmm2,%%xmm0 \n" + "pshufb %%xmm4,%%xmm0 \n" + "movdqa %%xmm2,%%xmm1 \n" + "pshufb %%xmm5,%%xmm1 \n" + "paddusw %%xmm1,%%xmm0 \n" + "pshufb %%xmm6,%%xmm2 \n" + "paddusw %%xmm2,%%xmm0 \n" + "pmulhuw %%xmm7,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0,(%1) \n" + "pextrw $0x2,%%xmm0,%%eax \n" + "mov %%ax,0x4(%1) \n" + "lea 0x6(%1),%1 \n" + "sub $0x6,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"(_shufab0), // %4 + "r"(_shufab1), // %5 + "r"(_shufab2), // %6 + "r"(_scaleab2) // %7 + : "memory", "cc", "rax", "xmm6", "xmm7" +); +} + +#define HAS_SCALEADDROWS_SSE2 +static void ScaleAddRows_SSE2(const uint8* src_ptr, int src_stride, + uint16* dst_ptr, int src_width, + int src_height) { + asm volatile ( + "pxor %%xmm5,%%xmm5 \n" +"1:" + "movdqa (%0),%%xmm2 \n" + "lea (%0,%4,1),%%r10 \n" + "movhlps %%xmm2,%%xmm3 \n" + "lea -0x1(%3),%%r11 \n" + "punpcklbw %%xmm5,%%xmm2 \n" + "punpcklbw %%xmm5,%%xmm3 \n" + +"2:" + "movdqa (%%r10),%%xmm0 \n" + "lea (%%r10,%4,1),%%r10 \n" + "movhlps %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpcklbw %%xmm5,%%xmm1 \n" + "paddusw %%xmm0,%%xmm2 \n" + "paddusw %%xmm1,%%xmm3 \n" + "sub $0x1,%%r11 \n" + "ja 2b \n" + + "movdqa %%xmm2,(%1) \n" + "movdqa %%xmm3,0x10(%1) \n" + "lea 0x20(%1),%1 \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(src_width), // %2 + "+r"(src_height) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc", "r10", "r11" +); +} + +// Bilinear row filtering combines 16x2 -> 16x1. SSE2 version +#define HAS_SCALEFILTERROWS_SSE2 +static void ScaleFilterRows_SSE2(uint8* dst_ptr, + const uint8* src_ptr, int src_stride, + int dst_width, int source_y_fraction) { + if (source_y_fraction == 0) { + asm volatile ( + "1:" + "movdqa (%1),%%xmm0 \n" + "lea 0x10(%1),%1 \n" + "movdqa %%xmm0,(%0) \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + "mov -0x1(%0),%%al \n" + "mov %%al,(%0) \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width) // %2 + : + : "memory", "cc", "rax" + ); + return; + } else if (source_y_fraction == 128) { + asm volatile ( + "1:" + "movdqa (%1),%%xmm0 \n" + "movdqa (%1,%3,1),%%xmm2 \n" + "lea 0x10(%1),%1 \n" + "pavgb %%xmm2,%%xmm0 \n" + "movdqa %%xmm0,(%0) \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + "mov -0x1(%0),%%al \n" + "mov %%al,(%0) \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", "rax" + ); + return; + } else { + asm volatile ( + "mov %3,%%eax \n" + "movd %%eax,%%xmm6 \n" + "punpcklwd %%xmm6,%%xmm6 \n" + "pshufd $0x0,%%xmm6,%%xmm6 \n" + "neg %%eax \n" + "add $0x100,%%eax \n" + "movd %%eax,%%xmm5 \n" + "punpcklwd %%xmm5,%%xmm5 \n" + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "pxor %%xmm7,%%xmm7 \n" + "1:" + "movdqa (%1),%%xmm0 \n" + "movdqa (%1,%4,1),%%xmm2 \n" + "lea 0x10(%1),%1 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm3 \n" + "punpcklbw %%xmm7,%%xmm0 \n" + "punpcklbw %%xmm7,%%xmm2 \n" + "punpckhbw %%xmm7,%%xmm1 \n" + "punpckhbw %%xmm7,%%xmm3 \n" + "pmullw %%xmm5,%%xmm0 \n" + "pmullw %%xmm5,%%xmm1 \n" + "pmullw %%xmm6,%%xmm2 \n" + "pmullw %%xmm6,%%xmm3 \n" + "paddusw %%xmm2,%%xmm0 \n" + "paddusw %%xmm3,%%xmm1 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,(%0) \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + "mov -0x1(%0),%%al \n" + "mov %%al,(%0) \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(source_y_fraction) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc", "rax", "xmm6", "xmm7" + ); + } + return; +} + +// Bilinear row filtering combines 16x2 -> 16x1. SSSE3 version +#define HAS_SCALEFILTERROWS_SSSE3 +static void ScaleFilterRows_SSSE3(uint8* dst_ptr, + const uint8* src_ptr, int src_stride, + int dst_width, int source_y_fraction) { + if (source_y_fraction == 0) { + asm volatile ( + "1:" + "movdqa (%1),%%xmm0 \n" + "lea 0x10(%1),%1 \n" + "movdqa %%xmm0,(%0) \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + "mov -0x1(%0),%%al \n" + "mov %%al,(%0) \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width) // %2 + : + : "memory", "cc", "rax" + ); + return; + } else if (source_y_fraction == 128) { + asm volatile ( + "1:" + "movdqa (%1),%%xmm0 \n" + "movdqa (%1,%3,1),%%xmm2 \n" + "lea 0x10(%1),%1 \n" + "pavgb %%xmm2,%%xmm0 \n" + "movdqa %%xmm0,(%0) \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + "mov -0x1(%0),%%al \n" + "mov %%al,(%0) \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", "rax" + ); + return; + } else { + asm volatile ( + "mov %3,%%eax \n" + "shr %%eax \n" + "mov %%al,%%ah \n" + "neg %%al \n" + "add $0x80,%%al \n" + "movd %%eax,%%xmm5 \n" + "punpcklwd %%xmm5,%%xmm5 \n" + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "1:" + "movdqa (%1),%%xmm0 \n" + "movdqa (%1,%4,1),%%xmm2 \n" + "lea 0x10(%1),%1 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm2,%%xmm0 \n" + "punpckhbw %%xmm2,%%xmm1 \n" + "pmaddubsw %%xmm5,%%xmm0 \n" + "pmaddubsw %%xmm5,%%xmm1 \n" + "psrlw $0x7,%%xmm0 \n" + "psrlw $0x7,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,(%0) \n" + "lea 0x10(%0),%0 \n" + "sub $0x10,%2 \n" + "ja 1b \n" + "mov -0x1(%0),%%al \n" + "mov %%al,(%0) \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(source_y_fraction) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc", "rax" + ); + } + return; +} +#endif +#endif + +// CPU agnostic row functions +static void ScaleRowDown2_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + int x; + for (x = 0; x < dst_width; ++x) { + *dst++ = *src_ptr; + src_ptr += 2; + } +} + +static void ScaleRowDown2Int_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + int x; + for (x = 0; x < dst_width; ++x) { + *dst++ = (src_ptr[0] + src_ptr[1] + + src_ptr[src_stride] + src_ptr[src_stride + 1] + 2) >> 2; + src_ptr += 2; + } +} + +static void ScaleRowDown4_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + int x; + for (x = 0; x < dst_width; ++x) { + *dst++ = *src_ptr; + src_ptr += 4; + } +} + +static void ScaleRowDown4Int_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + int x; + for (x = 0; x < dst_width; ++x) { + *dst++ = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] + + src_ptr[src_stride + 0] + src_ptr[src_stride + 1] + + src_ptr[src_stride + 2] + src_ptr[src_stride + 3] + + src_ptr[src_stride * 2 + 0] + src_ptr[src_stride * 2 + 1] + + src_ptr[src_stride * 2 + 2] + src_ptr[src_stride * 2 + 3] + + src_ptr[src_stride * 3 + 0] + src_ptr[src_stride * 3 + 1] + + src_ptr[src_stride * 3 + 2] + src_ptr[src_stride * 3 + 3] + + 8) >> 4; + src_ptr += 4; + } +} + +// 640 output pixels is enough to allow 5120 input pixels with 1/8 scale down. +// Keeping the total buffer under 4096 bytes avoids a stackcheck, saving 4% cpu. +// The following 2 lines cause error on Windows. +//static const int kMaxOutputWidth = 640; +//static const int kMaxRow12 = 1280; //kMaxOutputWidth * 2; +#define kMaxOutputWidth 640 +#define kMaxRow12 1280 + +static void ScaleRowDown8_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + int x; + for (x = 0; x < dst_width; ++x) { + *dst++ = *src_ptr; + src_ptr += 8; + } +} + +// Note calling code checks width is less than max and if not +// uses ScaleRowDown8_C instead. +static void ScaleRowDown8Int_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + ALIGN16(uint8 src_row[kMaxRow12 * 2]); + assert(dst_width <= kMaxOutputWidth); + ScaleRowDown4Int_C(src_ptr, src_stride, src_row, dst_width * 2); + ScaleRowDown4Int_C(src_ptr + src_stride * 4, src_stride, + src_row + kMaxOutputWidth, + dst_width * 2); + ScaleRowDown2Int_C(src_row, kMaxOutputWidth, dst, dst_width); +} + +static void ScaleRowDown34_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + uint8* dend; + assert((dst_width % 3 == 0) && (dst_width > 0)); + dend = dst + dst_width; + do { + dst[0] = src_ptr[0]; + dst[1] = src_ptr[1]; + dst[2] = src_ptr[3]; + dst += 3; + src_ptr += 4; + } while (dst < dend); +} + +// Filter rows 0 and 1 together, 3 : 1 +static void ScaleRowDown34_0_Int_C(const uint8* src_ptr, int src_stride, + uint8* d, int dst_width) { + uint8* dend; + const uint8* s; + const uint8* t; + assert((dst_width % 3 == 0) && (dst_width > 0)); + dend = d + dst_width; + s = src_ptr; + t = src_ptr + src_stride; + do { + uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; + uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; + uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; + uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; + uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; + uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; + d[0] = (a0 * 3 + b0 + 2) >> 2; + d[1] = (a1 * 3 + b1 + 2) >> 2; + d[2] = (a2 * 3 + b2 + 2) >> 2; + d += 3; + s += 4; + t += 4; + } while (d < dend); +} + +// Filter rows 1 and 2 together, 1 : 1 +static void ScaleRowDown34_1_Int_C(const uint8* src_ptr, int src_stride, + uint8* d, int dst_width) { + uint8* dend; + const uint8* s; + const uint8* t; + assert((dst_width % 3 == 0) && (dst_width > 0)); + dend = d + dst_width; + s = src_ptr; + t = src_ptr + src_stride; + do { + uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; + uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; + uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; + uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; + uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; + uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; + d[0] = (a0 + b0 + 1) >> 1; + d[1] = (a1 + b1 + 1) >> 1; + d[2] = (a2 + b2 + 1) >> 1; + d += 3; + s += 4; + t += 4; + } while (d < dend); +} + +#if defined(HAS_SCALEFILTERROWS_SSE2) +// Filter row to 3/4 +static void ScaleFilterCols34_C(uint8* dst_ptr, const uint8* src_ptr, + int dst_width) { + uint8* dend; + const uint8* s; + assert((dst_width % 3 == 0) && (dst_width > 0)); + dend = dst_ptr + dst_width; + s = src_ptr; + do { + dst_ptr[0] = (s[0] * 3 + s[1] * 1 + 2) >> 2; + dst_ptr[1] = (s[1] * 1 + s[2] * 1 + 1) >> 1; + dst_ptr[2] = (s[2] * 1 + s[3] * 3 + 2) >> 2; + dst_ptr += 3; + s += 4; + } while (dst_ptr < dend); +} +#endif + +static void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int dx) { + int x = 0; + int j; + for (j = 0; j < dst_width; ++j) { + int xi = x >> 16; + int xf1 = x & 0xffff; + int xf0 = 65536 - xf1; + + *dst_ptr++ = (src_ptr[xi] * xf0 + src_ptr[xi + 1] * xf1) >> 16; + x += dx; + } +} + +//Not work on Windows +//static const int kMaxInputWidth = 2560; +#define kMaxInputWidth 2560 +#if defined(HAS_SCALEFILTERROWS_SSE2) +#define HAS_SCALEROWDOWN34_SSE2 +// Filter rows 0 and 1 together, 3 : 1 +static void ScaleRowDown34_0_Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + ALIGN16(uint8 row[kMaxInputWidth]); + assert((dst_width % 3 == 0) && (dst_width > 0)); + ScaleFilterRows_SSE2(row, src_ptr, src_stride, dst_width * 4 / 3, 256 / 4); + ScaleFilterCols34_C(dst_ptr, row, dst_width); +} + +// Filter rows 1 and 2 together, 1 : 1 +static void ScaleRowDown34_1_Int_SSE2(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + ALIGN16(uint8 row[kMaxInputWidth]); + assert((dst_width % 3 == 0) && (dst_width > 0)); + ScaleFilterRows_SSE2(row, src_ptr, src_stride, dst_width * 4 / 3, 256 / 2); + ScaleFilterCols34_C(dst_ptr, row, dst_width); +} +#endif + +static void ScaleRowDown38_C(const uint8* src_ptr, int src_stride, + uint8* dst, int dst_width) { + int x; + assert(dst_width % 3 == 0); + for (x = 0; x < dst_width; x += 3) { + dst[0] = src_ptr[0]; + dst[1] = src_ptr[3]; + dst[2] = src_ptr[6]; + dst += 3; + src_ptr += 8; + } +} + +// 8x3 -> 3x1 +static void ScaleRowDown38_3_Int_C(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + int i; + assert((dst_width % 3 == 0) && (dst_width > 0)); + for (i = 0; i < dst_width; i+=3) { + dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + + src_ptr[src_stride + 0] + src_ptr[src_stride + 1] + + src_ptr[src_stride + 2] + src_ptr[src_stride * 2 + 0] + + src_ptr[src_stride * 2 + 1] + src_ptr[src_stride * 2 + 2]) * + (65536 / 9) >> 16; + dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + + src_ptr[src_stride + 3] + src_ptr[src_stride + 4] + + src_ptr[src_stride + 5] + src_ptr[src_stride * 2 + 3] + + src_ptr[src_stride * 2 + 4] + src_ptr[src_stride * 2 + 5]) * + (65536 / 9) >> 16; + dst_ptr[2] = (src_ptr[6] + src_ptr[7] + + src_ptr[src_stride + 6] + src_ptr[src_stride + 7] + + src_ptr[src_stride * 2 + 6] + src_ptr[src_stride * 2 + 7]) * + (65536 / 6) >> 16; + src_ptr += 8; + dst_ptr += 3; + } +} + +// 8x2 -> 3x1 +static void ScaleRowDown38_2_Int_C(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width) { + int i; + assert((dst_width % 3 == 0) && (dst_width > 0)); + for (i = 0; i < dst_width; i+=3) { + dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + + src_ptr[src_stride + 0] + src_ptr[src_stride + 1] + + src_ptr[src_stride + 2]) * (65536 / 6) >> 16; + dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + + src_ptr[src_stride + 3] + src_ptr[src_stride + 4] + + src_ptr[src_stride + 5]) * (65536 / 6) >> 16; + dst_ptr[2] = (src_ptr[6] + src_ptr[7] + + src_ptr[src_stride + 6] + src_ptr[src_stride + 7]) * + (65536 / 4) >> 16; + src_ptr += 8; + dst_ptr += 3; + } +} + +// C version 8x2 -> 8x1 +static void ScaleFilterRows_C(uint8* dst_ptr, + const uint8* src_ptr, int src_stride, + int dst_width, int source_y_fraction) { + int y1_fraction; + int y0_fraction; + const uint8* src_ptr1; + uint8* end; + assert(dst_width > 0); + y1_fraction = source_y_fraction; + y0_fraction = 256 - y1_fraction; + src_ptr1 = src_ptr + src_stride; + end = dst_ptr + dst_width; + do { + dst_ptr[0] = (src_ptr[0] * y0_fraction + src_ptr1[0] * y1_fraction) >> 8; + dst_ptr[1] = (src_ptr[1] * y0_fraction + src_ptr1[1] * y1_fraction) >> 8; + dst_ptr[2] = (src_ptr[2] * y0_fraction + src_ptr1[2] * y1_fraction) >> 8; + dst_ptr[3] = (src_ptr[3] * y0_fraction + src_ptr1[3] * y1_fraction) >> 8; + dst_ptr[4] = (src_ptr[4] * y0_fraction + src_ptr1[4] * y1_fraction) >> 8; + dst_ptr[5] = (src_ptr[5] * y0_fraction + src_ptr1[5] * y1_fraction) >> 8; + dst_ptr[6] = (src_ptr[6] * y0_fraction + src_ptr1[6] * y1_fraction) >> 8; + dst_ptr[7] = (src_ptr[7] * y0_fraction + src_ptr1[7] * y1_fraction) >> 8; + src_ptr += 8; + src_ptr1 += 8; + dst_ptr += 8; + } while (dst_ptr < end); + dst_ptr[0] = dst_ptr[-1]; +} + +void ScaleAddRows_C(const uint8* src_ptr, int src_stride, + uint16* dst_ptr, int src_width, int src_height) { + int x,y; + assert(src_width > 0); + assert(src_height > 0); + for (x = 0; x < src_width; ++x) { + const uint8* s = src_ptr + x; + int sum = 0; + for (y = 0; y < src_height; ++y) { + sum += s[0]; + s += src_stride; + } + dst_ptr[x] = sum; + } +} + +/** + * Scale plane, 1/2 + * + * This is an optimized version for scaling down a plane to 1/2 of + * its original size. + * + */ +static void ScalePlaneDown2(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + void (*ScaleRowDown2)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + assert(IS_ALIGNED(src_width, 2)); + assert(IS_ALIGNED(src_height, 2)); + +#if defined(HAS_SCALEROWDOWN2_NEON) + if (TestCpuFlag(kCpuHasNEON) && + IS_ALIGNED(dst_width, 16)) { + ScaleRowDown2 = filtering ? ScaleRowDown2Int_NEON : ScaleRowDown2_NEON; + } else +#endif +#if defined(HAS_SCALEROWDOWN2_SSE2) + if (TestCpuFlag(kCpuHasSSE2) && + IS_ALIGNED(dst_width, 16) && + IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) && + IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) { + ScaleRowDown2 = filtering ? ScaleRowDown2Int_SSE2 : ScaleRowDown2_SSE2; + } else +#endif + { + ScaleRowDown2 = filtering ? ScaleRowDown2Int_C : ScaleRowDown2_C; + } + + { + int y; + for (y = 0; y < dst_height; ++y) { + ScaleRowDown2(src_ptr, src_stride, dst_ptr, dst_width); + src_ptr += (src_stride << 1); + dst_ptr += dst_stride; + } + } +} + +/** + * Scale plane, 1/4 + * + * This is an optimized version for scaling down a plane to 1/4 of + * its original size. + */ +static void ScalePlaneDown4(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + void (*ScaleRowDown4)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + assert(IS_ALIGNED(src_width, 4)); + assert(IS_ALIGNED(src_height, 4)); + +#if defined(HAS_SCALEROWDOWN4_NEON) + if (TestCpuFlag(kCpuHasNEON) && + IS_ALIGNED(dst_width, 4)) { + ScaleRowDown4 = filtering ? ScaleRowDown4Int_NEON : ScaleRowDown4_NEON; + } else +#endif +#if defined(HAS_SCALEROWDOWN4_SSE2) + if (TestCpuFlag(kCpuHasSSE2) && + IS_ALIGNED(dst_width, 8) && + IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) && + IS_ALIGNED(dst_ptr, 8) && IS_ALIGNED(dst_stride, 8)) { + ScaleRowDown4 = filtering ? ScaleRowDown4Int_SSE2 : ScaleRowDown4_SSE2; + } else +#endif + { + ScaleRowDown4 = filtering ? ScaleRowDown4Int_C : ScaleRowDown4_C; + } + + { + int y; + for (y = 0; y < dst_height; ++y) { + ScaleRowDown4(src_ptr, src_stride, dst_ptr, dst_width); + src_ptr += (src_stride << 2); + dst_ptr += dst_stride; + } + } +} + +/** + * Scale plane, 1/8 + * + * This is an optimized version for scaling down a plane to 1/8 + * of its original size. + * + */ +static void ScalePlaneDown8(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + void (*ScaleRowDown8)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + assert(IS_ALIGNED(src_width, 8)); + assert(IS_ALIGNED(src_height, 8)); + +#if defined(HAS_SCALEROWDOWN8_SSE2) + if (TestCpuFlag(kCpuHasSSE2) && + IS_ALIGNED(dst_width, 4) && + IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) && + IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { + ScaleRowDown8 = filtering ? ScaleRowDown8Int_SSE2 : ScaleRowDown8_SSE2; + } else +#endif + { + ScaleRowDown8 = filtering && (dst_width <= kMaxOutputWidth) ? + ScaleRowDown8Int_C : ScaleRowDown8_C; + } + + { + int y; + for (y = 0; y < dst_height; ++y) { + ScaleRowDown8(src_ptr, src_stride, dst_ptr, dst_width); + src_ptr += (src_stride << 3); + dst_ptr += dst_stride; + } + } +} + +/** + * Scale plane down, 3/4 + * + * Provided by Frank Barchard (fbarchard@google.com) + * + */ +static void ScalePlaneDown34(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + void (*ScaleRowDown34_0)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + void (*ScaleRowDown34_1)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + assert(dst_width % 3 == 0); +#if defined(HAS_SCALEROWDOWN34_NEON) + if (TestCpuFlag(kCpuHasNEON) && + (dst_width % 24 == 0)) { + if (!filtering) { + ScaleRowDown34_0 = ScaleRowDown34_NEON; + ScaleRowDown34_1 = ScaleRowDown34_NEON; + } else { + ScaleRowDown34_0 = ScaleRowDown34_0_Int_NEON; + ScaleRowDown34_1 = ScaleRowDown34_1_Int_NEON; + } + } else +#endif + +#if defined(HAS_SCALEROWDOWN34_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3) && + (dst_width % 24 == 0) && + IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) && + IS_ALIGNED(dst_ptr, 8) && IS_ALIGNED(dst_stride, 8)) { + if (!filtering) { + ScaleRowDown34_0 = ScaleRowDown34_SSSE3; + ScaleRowDown34_1 = ScaleRowDown34_SSSE3; + } else { + ScaleRowDown34_0 = ScaleRowDown34_0_Int_SSSE3; + ScaleRowDown34_1 = ScaleRowDown34_1_Int_SSSE3; + } + } else +#endif +#if defined(HAS_SCALEROWDOWN34_SSE2) + if (TestCpuFlag(kCpuHasSSE2) && + (dst_width % 24 == 0) && IS_ALIGNED(src_stride, 16) && + IS_ALIGNED(dst_stride, 8) && + IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(dst_ptr, 8) && + filtering) { + ScaleRowDown34_0 = ScaleRowDown34_0_Int_SSE2; + ScaleRowDown34_1 = ScaleRowDown34_1_Int_SSE2; + } else +#endif + { + if (!filtering) { + ScaleRowDown34_0 = ScaleRowDown34_C; + ScaleRowDown34_1 = ScaleRowDown34_C; + } else { + ScaleRowDown34_0 = ScaleRowDown34_0_Int_C; + ScaleRowDown34_1 = ScaleRowDown34_1_Int_C; + } + } + { + int src_row = 0; + int y; + for (y = 0; y < dst_height; ++y) { + switch (src_row) { + case 0: + ScaleRowDown34_0(src_ptr, src_stride, dst_ptr, dst_width); + break; + + case 1: + ScaleRowDown34_1(src_ptr, src_stride, dst_ptr, dst_width); + break; + + case 2: + ScaleRowDown34_0(src_ptr + src_stride, -src_stride, + dst_ptr, dst_width); + break; + } + ++src_row; + src_ptr += src_stride; + dst_ptr += dst_stride; + if (src_row >= 3) { + src_ptr += src_stride; + src_row = 0; + } + } +} +} + +/** + * Scale plane, 3/8 + * + * This is an optimized version for scaling down a plane to 3/8 + * of its original size. + * + * Reduces 16x3 to 6x1 + */ +static void ScalePlaneDown38(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + void (*ScaleRowDown38_3)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + void (*ScaleRowDown38_2)(const uint8* src_ptr, int src_stride, + uint8* dst_ptr, int dst_width); + assert(dst_width % 3 == 0); +#if defined(HAS_SCALEROWDOWN38_NEON) + if (TestCpuFlag(kCpuHasNEON) && + (dst_width % 12 == 0)) { + if (!filtering) { + ScaleRowDown38_3 = ScaleRowDown38_NEON; + ScaleRowDown38_2 = ScaleRowDown38_NEON; + } else { + ScaleRowDown38_3 = ScaleRowDown38_3_Int_NEON; + ScaleRowDown38_2 = ScaleRowDown38_2_Int_NEON; + } + } else +#endif + +#if defined(HAS_SCALEROWDOWN38_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3) && + (dst_width % 24 == 0) && IS_ALIGNED(src_stride, 16) && + IS_ALIGNED(dst_stride, 8) && + IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(dst_ptr, 8)) { + if (!filtering) { + ScaleRowDown38_3 = ScaleRowDown38_SSSE3; + ScaleRowDown38_2 = ScaleRowDown38_SSSE3; + } else { + ScaleRowDown38_3 = ScaleRowDown38_3_Int_SSSE3; + ScaleRowDown38_2 = ScaleRowDown38_2_Int_SSSE3; + } + } else +#endif + { + if (!filtering) { + ScaleRowDown38_3 = ScaleRowDown38_C; + ScaleRowDown38_2 = ScaleRowDown38_C; + } else { + ScaleRowDown38_3 = ScaleRowDown38_3_Int_C; + ScaleRowDown38_2 = ScaleRowDown38_2_Int_C; + } + } + { + int src_row = 0; + int y; + for (y = 0; y < dst_height; ++y) { + switch (src_row) { + case 0: + case 1: + ScaleRowDown38_3(src_ptr, src_stride, dst_ptr, dst_width); + src_ptr += src_stride * 3; + ++src_row; + break; + + case 2: + ScaleRowDown38_2(src_ptr, src_stride, dst_ptr, dst_width); + src_ptr += src_stride * 2; + src_row = 0; + break; + } + dst_ptr += dst_stride; + } +} +} + +__inline static uint32 SumBox(int iboxwidth, int iboxheight, + int src_stride, const uint8* src_ptr) { + int x, y; + uint32 sum; + assert(iboxwidth > 0); + assert(iboxheight > 0); + sum = 0u; + for (y = 0; y < iboxheight; ++y) { + for (x = 0; x < iboxwidth; ++x) { + sum += src_ptr[x]; + } + src_ptr += src_stride; + } + return sum; +} + +static void ScalePlaneBoxRow(int dst_width, int boxheight, + int dx, int src_stride, + const uint8* src_ptr, uint8* dst_ptr) { + int x = 0; + int i; + for (i = 0; i < dst_width; ++i) { + int ix = x >> 16; + int boxwidth; + x += dx; + boxwidth = (x >> 16) - ix; + *dst_ptr++ = SumBox(boxwidth, boxheight, src_stride, src_ptr + ix) / + (boxwidth * boxheight); + } +} + +__inline static uint32 SumPixels(int iboxwidth, const uint16* src_ptr) { + uint32 sum; + int x; + assert(iboxwidth > 0); + sum = 0u; + for (x = 0; x < iboxwidth; ++x) { + sum += src_ptr[x]; + } + return sum; +} + +static void ScaleAddCols2_C(int dst_width, int boxheight, int dx, + const uint16* src_ptr, uint8* dst_ptr) { + int scaletbl[2]; + int minboxwidth = (dx >> 16); + scaletbl[0] = 65536 / (minboxwidth * boxheight); + scaletbl[1] = 65536 / ((minboxwidth + 1) * boxheight); + { + int *scaleptr = scaletbl - minboxwidth; + int x = 0; + int i; + for (i = 0; i < dst_width; ++i) { + int ix = x >> 16; + int boxwidth; + x += dx; + boxwidth = (x >> 16) - ix; + *dst_ptr++ = SumPixels(boxwidth, src_ptr + ix) * scaleptr[boxwidth] >> 16; + } + } +} + +static void ScaleAddCols1_C(int dst_width, int boxheight, int dx, + const uint16* src_ptr, uint8* dst_ptr) { + int boxwidth = (dx >> 16); + int scaleval = 65536 / (boxwidth * boxheight); + int x = 0; + int i; + for (i = 0; i < dst_width; ++i) { + *dst_ptr++ = SumPixels(boxwidth, src_ptr + x) * scaleval >> 16; + x += boxwidth; + } +} + +/** + * Scale plane down to any dimensions, with interpolation. + * (boxfilter). + * + * Same method as SimpleScale, which is fixed point, outputting + * one pixel of destination using fixed point (16.16) to step + * through source, sampling a box of pixel with simple + * averaging. + */ +static void ScalePlaneBox(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr) { + int dx, dy; + assert(dst_width > 0); + assert(dst_height > 0); + dy = (src_height << 16) / dst_height; + dx = (src_width << 16) / dst_width; + if (!IS_ALIGNED(src_width, 16) || (src_width > kMaxInputWidth) || + dst_height * 2 > src_height) { + uint8* dst = dst_ptr; + int dy = (src_height << 16) / dst_height; + int dx = (src_width << 16) / dst_width; + int y = 0; + int j; + for (j = 0; j < dst_height; ++j) { + int iy = y >> 16; + const uint8* const src = src_ptr + iy * src_stride; + int boxheight; + y += dy; + if (y > (src_height << 16)) { + y = (src_height << 16); + } + boxheight = (y >> 16) - iy; + ScalePlaneBoxRow(dst_width, boxheight, + dx, src_stride, + src, dst); + + dst += dst_stride; + } + } else { + ALIGN16(uint16 row[kMaxInputWidth]); + void (*ScaleAddRows)(const uint8* src_ptr, int src_stride, + uint16* dst_ptr, int src_width, int src_height); + void (*ScaleAddCols)(int dst_width, int boxheight, int dx, + const uint16* src_ptr, uint8* dst_ptr); +#if defined(HAS_SCALEADDROWS_SSE2) + if (TestCpuFlag(kCpuHasSSE2) && + IS_ALIGNED(src_stride, 16) && IS_ALIGNED(src_ptr, 16) && + IS_ALIGNED(src_width, 16)) { + ScaleAddRows = ScaleAddRows_SSE2; + } else +#endif + { + ScaleAddRows = ScaleAddRows_C; + } + if (dx & 0xffff) { + ScaleAddCols = ScaleAddCols2_C; + } else { + ScaleAddCols = ScaleAddCols1_C; + } + + { + int y = 0; + int j; + for (j = 0; j < dst_height; ++j) { + int iy = y >> 16; + const uint8* const src = src_ptr + iy * src_stride; + int boxheight; + y += dy; + if (y > (src_height << 16)) { + y = (src_height << 16); + } + boxheight = (y >> 16) - iy; + ScaleAddRows(src, src_stride, row, src_width, boxheight); + ScaleAddCols(dst_width, boxheight, dx, row, dst_ptr); + dst_ptr += dst_stride; + } + } + } +} + +/** + * Scale plane to/from any dimensions, with interpolation. + */ +static void ScalePlaneBilinearSimple(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr) { + int i, j; + uint8* dst = dst_ptr; + int dx = (src_width << 16) / dst_width; + int dy = (src_height << 16) / dst_height; + int maxx = ((src_width - 1) << 16) - 1; + int maxy = ((src_height - 1) << 16) - 1; + int y = (dst_height < src_height) ? 32768 : + (src_height << 16) / dst_height - 32768; + for (i = 0; i < dst_height; ++i) { + int cy = (y < 0) ? 0 : y; + int yi = cy >> 16; + int yf = cy & 0xffff; + const uint8* const src = src_ptr + yi * src_stride; + int x = (dst_width < src_width) ? 32768 : + (src_width << 16) / dst_width - 32768; + for (j = 0; j < dst_width; ++j) { + int cx = (x < 0) ? 0 : x; + int xi = cx >> 16; + int xf = cx & 0xffff; + int r0 = (src[xi] * (65536 - xf) + src[xi + 1] * xf) >> 16; + int r1 = (src[xi + src_stride] * (65536 - xf) + + src[xi + src_stride + 1] * xf) >> 16; + *dst++ = (r0 * (65536 - yf) + r1 * yf) >> 16; + x += dx; + if (x > maxx) + x = maxx; + } + dst += dst_stride - dst_width; + y += dy; + if (y > maxy) + y = maxy; + } +} + +/** + * Scale plane to/from any dimensions, with bilinear + * interpolation. + */ +static void ScalePlaneBilinear(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr) { + int dy; + int dx; + assert(dst_width > 0); + assert(dst_height > 0); + dy = (src_height << 16) / dst_height; + dx = (src_width << 16) / dst_width; + if (!IS_ALIGNED(src_width, 8) || (src_width > kMaxInputWidth)) { + ScalePlaneBilinearSimple(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src_ptr, dst_ptr); + + } else { + ALIGN16(uint8 row[kMaxInputWidth + 1]); + void (*ScaleFilterRows)(uint8* dst_ptr, const uint8* src_ptr, + int src_stride, + int dst_width, int source_y_fraction); + void (*ScaleFilterCols)(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int dx); +#if defined(HAS_SCALEFILTERROWS_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3) && + IS_ALIGNED(src_stride, 16) && IS_ALIGNED(src_ptr, 16) && + IS_ALIGNED(src_width, 16)) { + ScaleFilterRows = ScaleFilterRows_SSSE3; + } else +#endif +#if defined(HAS_SCALEFILTERROWS_SSE2) + if (TestCpuFlag(kCpuHasSSE2) && + IS_ALIGNED(src_stride, 16) && IS_ALIGNED(src_ptr, 16) && + IS_ALIGNED(src_width, 16)) { + ScaleFilterRows = ScaleFilterRows_SSE2; + } else +#endif + { + ScaleFilterRows = ScaleFilterRows_C; + } + ScaleFilterCols = ScaleFilterCols_C; + + { + int y = 0; + int maxy = ((src_height - 1) << 16) - 1; // max is filter of last 2 rows. + int j; + for (j = 0; j < dst_height; ++j) { + int iy = y >> 16; + int fy = (y >> 8) & 255; + const uint8* const src = src_ptr + iy * src_stride; + ScaleFilterRows(row, src, src_stride, src_width, fy); + ScaleFilterCols(dst_ptr, row, dst_width, dx); + dst_ptr += dst_stride; + y += dy; + if (y > maxy) { + y = maxy; + } + } + } +} +} + +/** + * Scale plane to/from any dimensions, without interpolation. + * Fixed point math is used for performance: The upper 16 bits + * of x and dx is the integer part of the source position and + * the lower 16 bits are the fixed decimal part. + */ +static void ScalePlaneSimple(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr) { + uint8* dst = dst_ptr; + int dx = (src_width << 16) / dst_width; + int y; + for (y = 0; y < dst_height; ++y) { + const uint8* const src = src_ptr + (y * src_height / dst_height) * + src_stride; + // TODO(fbarchard): Round X coordinate by setting x=0x8000. + int x = 0; + int i; + for (i = 0; i < dst_width; ++i) { + *dst++ = src[x >> 16]; + x += dx; + } + dst += dst_stride - dst_width; + } +} + +/** + * Scale plane to/from any dimensions. + */ +static void ScalePlaneAnySize(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + if (!filtering) { + ScalePlaneSimple(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src_ptr, dst_ptr); + } else { + // fall back to non-optimized version + ScalePlaneBilinear(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src_ptr, dst_ptr); + } +} + +/** + * Scale plane down, any size + * + * This is an optimized version for scaling down a plane to any size. + * The current implementation is ~10 times faster compared to the + * reference implementation for e.g. XGA->LowResPAL + * + */ +static void ScalePlaneDown(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr, + FilterMode filtering) { + if (!filtering) { + ScalePlaneSimple(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src_ptr, dst_ptr); + } else if (filtering == kFilterBilinear || src_height * 2 > dst_height) { + // between 1/2x and 1x use bilinear + ScalePlaneBilinear(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src_ptr, dst_ptr); + } else { + ScalePlaneBox(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src_ptr, dst_ptr); + } +} + +/** + * Copy plane, no scaling + * + * This simply copies the given plane without scaling. + * The current implementation is ~115 times faster + * compared to the reference implementation. + * + */ +static void CopyPlane(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr) { + if (src_stride == src_width && dst_stride == dst_width) { + // All contiguous, so can use REALLY fast path. + memcpy(dst_ptr, src_ptr, src_width * src_height); + } else { + // Not all contiguous; must copy scanlines individually + const uint8* src = src_ptr; + uint8* dst = dst_ptr; + int i; + for (i = 0; i < src_height; ++i) { + memcpy(dst, src, src_width); + dst += dst_stride; + src += src_stride; + } + } +} + +static void ScalePlane(const uint8* src, int src_stride, + int src_width, int src_height, + uint8* dst, int dst_stride, + int dst_width, int dst_height, + FilterMode filtering, int use_ref) { + // Use specialized scales to improve performance for common resolutions. + // For example, all the 1/2 scalings will use ScalePlaneDown2() + if (dst_width == src_width && dst_height == src_height) { + // Straight copy. + CopyPlane(src_width, src_height, dst_width, dst_height, src_stride, + dst_stride, src, dst); + } else if (dst_width <= src_width && dst_height <= src_height) { + // Scale down. + if (use_ref) { + // For testing, allow the optimized versions to be disabled. + ScalePlaneDown(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } else if (4 * dst_width == 3 * src_width && + 4 * dst_height == 3 * src_height) { + // optimized, 3/4 + ScalePlaneDown34(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } else if (2 * dst_width == src_width && 2 * dst_height == src_height) { + // optimized, 1/2 + ScalePlaneDown2(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + // 3/8 rounded up for odd sized chroma height. + } else if (8 * dst_width == 3 * src_width && + dst_height == ((src_height * 3 + 7) / 8)) { + // optimized, 3/8 + ScalePlaneDown38(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } else if (4 * dst_width == src_width && 4 * dst_height == src_height) { + // optimized, 1/4 + ScalePlaneDown4(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } else if (8 * dst_width == src_width && 8 * dst_height == src_height) { + // optimized, 1/8 + ScalePlaneDown8(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } else { + // Arbitrary downsample + ScalePlaneDown(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } + } else { + // Arbitrary scale up and/or down. + ScalePlaneAnySize(src_width, src_height, dst_width, dst_height, + src_stride, dst_stride, src, dst, filtering); + } +} + +/** + * Scale a plane. + * + * This function in turn calls a scaling function + * suitable for handling the desired resolutions. + * + */ + +int I420Scale(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + int src_width, int src_height, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int dst_width, int dst_height, + FilterMode filtering) { + if (!src_y || !src_u || !src_v || src_width <= 0 || src_height == 0 || + !dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) { + return -1; + } + // Negative height means invert the image. + if (src_height < 0) { + int halfheight; + src_height = -src_height; + halfheight = (src_height + 1) >> 1; + src_y = src_y + (src_height - 1) * src_stride_y; + src_u = src_u + (halfheight - 1) * src_stride_u; + src_v = src_v + (halfheight - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + { + int src_halfwidth = (src_width + 1) >> 1; + int src_halfheight = (src_height + 1) >> 1; + int dst_halfwidth = (dst_width + 1) >> 1; + int dst_halfheight = (dst_height + 1) >> 1; + + ScalePlane(src_y, src_stride_y, src_width, src_height, + dst_y, dst_stride_y, dst_width, dst_height, + filtering, use_reference_impl_); + ScalePlane(src_u, src_stride_u, src_halfwidth, src_halfheight, + dst_u, dst_stride_u, dst_halfwidth, dst_halfheight, + filtering, use_reference_impl_); + ScalePlane(src_v, src_stride_v, src_halfwidth, src_halfheight, + dst_v, dst_stride_v, dst_halfwidth, dst_halfheight, + filtering, use_reference_impl_); + } + return 0; +} + +// Deprecated api +int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v, + int src_stride_y, int src_stride_u, int src_stride_v, + int src_width, int src_height, + uint8* dst_y, uint8* dst_u, uint8* dst_v, + int dst_stride_y, int dst_stride_u, int dst_stride_v, + int dst_width, int dst_height, + int interpolate) { + if (!src_y || !src_u || !src_v || src_width <= 0 || src_height == 0 || + !dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) { + return -1; + } + // Negative height means invert the image. + if (src_height < 0) { + int halfheight; + src_height = -src_height; + halfheight = (src_height + 1) >> 1; + src_y = src_y + (src_height - 1) * src_stride_y; + src_u = src_u + (halfheight - 1) * src_stride_u; + src_v = src_v + (halfheight - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + { + int src_halfwidth = (src_width + 1) >> 1; + int src_halfheight = (src_height + 1) >> 1; + int dst_halfwidth = (dst_width + 1) >> 1; + int dst_halfheight = (dst_height + 1) >> 1; + FilterMode filtering = interpolate ? kFilterBox : kFilterNone; + + ScalePlane(src_y, src_stride_y, src_width, src_height, + dst_y, dst_stride_y, dst_width, dst_height, + filtering, use_reference_impl_); + ScalePlane(src_u, src_stride_u, src_halfwidth, src_halfheight, + dst_u, dst_stride_u, dst_halfwidth, dst_halfheight, + filtering, use_reference_impl_); + ScalePlane(src_v, src_stride_v, src_halfwidth, src_halfheight, + dst_v, dst_stride_v, dst_halfwidth, dst_halfheight, + filtering, use_reference_impl_); + } + return 0; +} + +// Deprecated api +int ScaleOffset(const uint8* src, int src_width, int src_height, + uint8* dst, int dst_width, int dst_height, int dst_yoffset, + int interpolate) { + if (!src || src_width <= 0 || src_height <= 0 || + !dst || dst_width <= 0 || dst_height <= 0 || dst_yoffset < 0 || + dst_yoffset >= dst_height) { + return -1; + } + dst_yoffset = dst_yoffset & ~1; // chroma requires offset to multiple of 2. + { + int src_halfwidth = (src_width + 1) >> 1; + int src_halfheight = (src_height + 1) >> 1; + int dst_halfwidth = (dst_width + 1) >> 1; + int dst_halfheight = (dst_height + 1) >> 1; + int aheight = dst_height - dst_yoffset * 2; // actual output height + const uint8* const src_y = src; + const uint8* const src_u = src + src_width * src_height; + const uint8* const src_v = src + src_width * src_height + + src_halfwidth * src_halfheight; + uint8* dst_y = dst + dst_yoffset * dst_width; + uint8* dst_u = dst + dst_width * dst_height + + (dst_yoffset >> 1) * dst_halfwidth; + uint8* dst_v = dst + dst_width * dst_height + dst_halfwidth * dst_halfheight + + (dst_yoffset >> 1) * dst_halfwidth; + return Scale(src_y, src_u, src_v, src_width, src_halfwidth, src_halfwidth, + src_width, src_height, dst_y, dst_u, dst_v, dst_width, + dst_halfwidth, dst_halfwidth, dst_width, aheight, interpolate); + } +} + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/tools/author_first_release.sh b/tools/author_first_release.sh new file mode 100755 index 0000000..7b0b797 --- /dev/null +++ b/tools/author_first_release.sh @@ -0,0 +1,15 @@ +#!/bin/bash +## +## List the release each author first contributed to. +## +## Usage: author_first_release.sh [TAGS] +## +## If the TAGS arguments are unspecified, all tags reported by `git tag` +## will be considered. +## +tags=${@:-$(git tag)} +for tag in $tags; do + git shortlog -n -e -s $tag | + cut -f2- | + awk "{print \"${tag#v}\t\"\$0}" +done | sort -k2 | uniq -f2 diff --git a/tools/ftfy.sh b/tools/ftfy.sh new file mode 100755 index 0000000..95fd397 --- /dev/null +++ b/tools/ftfy.sh @@ -0,0 +1,160 @@ +#!/bin/sh +self="$0" +dirname_self=$(dirname "$self") + +usage() { + cat <&2 +Usage: $self [option] + +This script applies a whitespace transformation to the commit at HEAD. If no +options are given, then the modified files are left in the working tree. + +Options: + -h, --help Shows this message + -n, --dry-run Shows a diff of the changes to be made. + --amend Squashes the changes into the commit at HEAD + This option will also reformat the commit message. + --commit Creates a new commit containing only the whitespace changes + --msg-only Reformat the commit message only, ignore the patch itself. + +EOF + rm -f ${CLEAN_FILES} + exit 1 +} + + +log() { + echo "${self##*/}: $@" >&2 +} + + +vpx_style() { + astyle --style=bsd --min-conditional-indent=0 --break-blocks \ + --pad-oper --pad-header --unpad-paren \ + --align-pointer=name \ + --indent-preprocessor --convert-tabs --indent-labels \ + --suffix=none --quiet "$@" + sed -i 's/[[:space:]]\{1,\},/,/g' "$@" +} + + +apply() { + [ $INTERSECT_RESULT -ne 0 ] && patch -p1 < "$1" +} + + +commit() { + LAST_CHANGEID=$(git show | awk '/Change-Id:/{print $2}') + if [ -z "$LAST_CHANGEID" ]; then + log "HEAD doesn't have a Change-Id, unable to generate a new commit" + exit 1 + fi + + # Build a deterministic Change-Id from the parent's + NEW_CHANGEID=${LAST_CHANGEID}-styled + NEW_CHANGEID=I$(echo $NEW_CHANGEID | git hash-object --stdin) + + # Commit, preserving authorship from the parent commit. + git commit -a -C HEAD > /dev/null + git commit --amend -F- << EOF +Cosmetic: Fix whitespace in change ${LAST_CHANGEID:0:9} + +Change-Id: ${NEW_CHANGEID} +EOF +} + + +show_commit_msg_diff() { + if [ $DIFF_MSG_RESULT -ne 0 ]; then + log "Modified commit message:" + diff -u "$ORIG_COMMIT_MSG" "$NEW_COMMIT_MSG" | tail -n +3 + fi +} + + +amend() { + show_commit_msg_diff + if [ $DIFF_MSG_RESULT -ne 0 ] || [ $INTERSECT_RESULT -ne 0 ]; then + git commit -a --amend -F "$NEW_COMMIT_MSG" + fi +} + + +diff_msg() { + git log -1 --format=%B > "$ORIG_COMMIT_MSG" + "${dirname_self}"/wrap-commit-msg.py \ + < "$ORIG_COMMIT_MSG" > "$NEW_COMMIT_MSG" + cmp -s "$ORIG_COMMIT_MSG" "$NEW_COMMIT_MSG" + DIFF_MSG_RESULT=$? +} + + +# Temporary files +ORIG_DIFF=orig.diff.$$ +MODIFIED_DIFF=modified.diff.$$ +FINAL_DIFF=final.diff.$$ +ORIG_COMMIT_MSG=orig.commit-msg.$$ +NEW_COMMIT_MSG=new.commit-msg.$$ +CLEAN_FILES="${ORIG_DIFF} ${MODIFIED_DIFF} ${FINAL_DIFF}" +CLEAN_FILES="${CLEAN_FILES} ${ORIG_COMMIT_MSG} ${NEW_COMMIT_MSG}" + +# Preconditions +[ $# -lt 2 ] || usage + +# Check that astyle supports pad-header and align-pointer=name +if ! astyle --pad-header --align-pointer=name < /dev/null; then + log "Install astyle v1.24 or newer" + exit 1 +fi + +if ! git diff --quiet HEAD; then + log "Working tree is dirty, commit your changes first" + exit 1 +fi + +# Need to be in the root +cd "$(git rev-parse --show-toplevel)" + +# Collect the original diff +git show > "${ORIG_DIFF}" + +# Apply the style guide on new and modified files and collect its diff +for f in $(git diff HEAD^ --name-only -M90 --diff-filter=AM \ + | grep '\.[ch]$'); do + case "$f" in + third_party/*) continue;; + nestegg/*) continue;; + esac + vpx_style "$f" +done +git diff --no-color --no-ext-diff > "${MODIFIED_DIFF}" + +# Intersect the two diffs +"${dirname_self}"/intersect-diffs.py \ + "${ORIG_DIFF}" "${MODIFIED_DIFF}" > "${FINAL_DIFF}" +INTERSECT_RESULT=$? +git reset --hard >/dev/null + +# Fixup the commit message +diff_msg + +# Handle options +if [ -n "$1" ]; then + case "$1" in + -h|--help) usage;; + -n|--dry-run) cat "${FINAL_DIFF}"; show_commit_msg_diff;; + --commit) apply "${FINAL_DIFF}"; commit;; + --amend) apply "${FINAL_DIFF}"; amend;; + --msg-only) amend;; + *) usage;; + esac +else + apply "${FINAL_DIFF}" + if ! git diff --quiet; then + log "Formatting changes applied, verify and commit." + log "See also: http://www.webmproject.org/code/contribute/conventions/" + git diff --stat + fi +fi + +rm -f ${CLEAN_FILES} diff --git a/tools/gen_authors.sh b/tools/gen_authors.sh new file mode 100755 index 0000000..e1246f0 --- /dev/null +++ b/tools/gen_authors.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Add organization names manually. + +cat <" | sort | uniq) +Google Inc. +The Mozilla Foundation +The Xiph.Org Foundation +EOF diff --git a/tools/intersect-diffs.py b/tools/intersect-diffs.py new file mode 100755 index 0000000..be9dea5 --- /dev/null +++ b/tools/intersect-diffs.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python +## Copyright (c) 2012 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## +"""Calculates the "intersection" of two unified diffs. + +Given two diffs, A and B, it finds all hunks in B that had non-context lines +in A and prints them to stdout. This is useful to determine the hunks in B that +are relevant to A. The resulting file can be applied with patch(1) on top of A. +""" + +__author__ = "jkoleszar@google.com" + +import re +import sys + + +class DiffLines(object): + """A container for one half of a diff.""" + + def __init__(self, filename, offset, length): + self.filename = filename + self.offset = offset + self.length = length + self.lines = [] + self.delta_line_nums = [] + + def Append(self, line): + l = len(self.lines) + if line[0] != " ": + self.delta_line_nums.append(self.offset + l) + self.lines.append(line[1:]) + assert l+1 <= self.length + + def Complete(self): + return len(self.lines) == self.length + + def __contains__(self, item): + return item >= self.offset and item <= self.offset + self.length - 1 + + +class DiffHunk(object): + """A container for one diff hunk, consisting of two DiffLines.""" + + def __init__(self, header, file_a, file_b, start_a, len_a, start_b, len_b): + self.header = header + self.left = DiffLines(file_a, start_a, len_a) + self.right = DiffLines(file_b, start_b, len_b) + self.lines = [] + + def Append(self, line): + """Adds a line to the DiffHunk and its DiffLines children.""" + if line[0] == "-": + self.left.Append(line) + elif line[0] == "+": + self.right.Append(line) + elif line[0] == " ": + self.left.Append(line) + self.right.Append(line) + else: + assert False, ("Unrecognized character at start of diff line " + "%r" % line[0]) + self.lines.append(line) + + def Complete(self): + return self.left.Complete() and self.right.Complete() + + def __repr__(self): + return "DiffHunk(%s, %s, len %d)" % ( + self.left.filename, self.right.filename, + max(self.left.length, self.right.length)) + + +def ParseDiffHunks(stream): + """Walk a file-like object, yielding DiffHunks as they're parsed.""" + + file_regex = re.compile(r"(\+\+\+|---) (\S+)") + range_regex = re.compile(r"@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?") + hunk = None + while True: + line = stream.readline() + if not line: + break + + if hunk is None: + # Parse file names + diff_file = file_regex.match(line) + if diff_file: + if line.startswith("---"): + a_line = line + a = diff_file.group(2) + continue + if line.startswith("+++"): + b_line = line + b = diff_file.group(2) + continue + + # Parse offset/lengths + diffrange = range_regex.match(line) + if diffrange: + if diffrange.group(2): + start_a = int(diffrange.group(1)) + len_a = int(diffrange.group(3)) + else: + start_a = 1 + len_a = int(diffrange.group(1)) + + if diffrange.group(5): + start_b = int(diffrange.group(4)) + len_b = int(diffrange.group(6)) + else: + start_b = 1 + len_b = int(diffrange.group(4)) + + header = [a_line, b_line, line] + hunk = DiffHunk(header, a, b, start_a, len_a, start_b, len_b) + else: + # Add the current line to the hunk + hunk.Append(line) + + # See if the whole hunk has been parsed. If so, yield it and prepare + # for the next hunk. + if hunk.Complete(): + yield hunk + hunk = None + + # Partial hunks are a parse error + assert hunk is None + + +def FormatDiffHunks(hunks): + """Re-serialize a list of DiffHunks.""" + r = [] + last_header = None + for hunk in hunks: + this_header = hunk.header[0:2] + if last_header != this_header: + r.extend(hunk.header) + last_header = this_header + else: + r.extend(hunk.header[2]) + r.extend(hunk.lines) + r.append("\n") + return "".join(r) + + +def ZipHunks(rhs_hunks, lhs_hunks): + """Join two hunk lists on filename.""" + for rhs_hunk in rhs_hunks: + rhs_file = rhs_hunk.right.filename.split("/")[1:] + + for lhs_hunk in lhs_hunks: + lhs_file = lhs_hunk.left.filename.split("/")[1:] + if lhs_file != rhs_file: + continue + yield (rhs_hunk, lhs_hunk) + + +def main(): + old_hunks = [x for x in ParseDiffHunks(open(sys.argv[1], "r"))] + new_hunks = [x for x in ParseDiffHunks(open(sys.argv[2], "r"))] + out_hunks = [] + + # Join the right hand side of the older diff with the left hand side of the + # newer diff. + for old_hunk, new_hunk in ZipHunks(old_hunks, new_hunks): + if new_hunk in out_hunks: + continue + old_lines = old_hunk.right + new_lines = new_hunk.left + + # Determine if this hunk overlaps any non-context line from the other + for i in old_lines.delta_line_nums: + if i in new_lines: + out_hunks.append(new_hunk) + break + + if out_hunks: + print FormatDiffHunks(out_hunks) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/tools/wrap-commit-msg.py b/tools/wrap-commit-msg.py new file mode 100755 index 0000000..d5b4b04 --- /dev/null +++ b/tools/wrap-commit-msg.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +## Copyright (c) 2012 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## +"""Wraps paragraphs of text, preserving manual formatting + +This is like fold(1), but has the special convention of not modifying lines +that start with whitespace. This allows you to intersperse blocks with +special formatting, like code blocks, with written prose. The prose will +be wordwrapped, and the manual formatting will be preserved. + + * This won't handle the case of a bulleted (or ordered) list specially, so + manual wrapping must be done. + +Occasionally it's useful to put something with explicit formatting that +doesn't look at all like a block of text inline. + + indicator = has_leading_whitespace(line); + if (indicator) + preserve_formatting(line); + +The intent is that this docstring would make it through the transform +and still be legible and presented as it is in the source. If additional +cases are handled, update this doc to describe the effect. +""" + +__author__ = "jkoleszar@google.com" +import textwrap +import sys + +def wrap(text): + if text: + return textwrap.fill(text, break_long_words=False) + '\n' + return "" + + +def main(fileobj): + text = "" + output = "" + while True: + line = fileobj.readline() + if not line: + break + + if line.lstrip() == line: + text += line + else: + output += wrap(text) + text="" + output += line + output += wrap(text) + + # Replace the file or write to stdout. + if fileobj == sys.stdin: + fileobj = sys.stdout + else: + fileobj.seek(0) + fileobj.truncate(0) + fileobj.write(output) + +if __name__ == "__main__": + if len(sys.argv) > 1: + main(open(sys.argv[1], "r+")) + else: + main(sys.stdin) diff --git a/tools_common.c b/tools_common.c new file mode 100644 index 0000000..6f95028 --- /dev/null +++ b/tools_common.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include +#include "tools_common.h" +#if defined(_WIN32) || defined(__OS2__) +#include +#include + +#ifdef __OS2__ +#define _setmode setmode +#define _fileno fileno +#define _O_BINARY O_BINARY +#endif +#endif + +FILE* set_binary_mode(FILE *stream) +{ + (void)stream; +#if defined(_WIN32) || defined(__OS2__) + _setmode(_fileno(stream), _O_BINARY); +#endif + return stream; +} diff --git a/tools_common.h b/tools_common.h new file mode 100644 index 0000000..80c9747 --- /dev/null +++ b/tools_common.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TOOLS_COMMON_H +#define TOOLS_COMMON_H + +/* Sets a stdio stream into binary mode */ +FILE* set_binary_mode(FILE *stream); + +#endif diff --git a/usage.dox b/usage.dox new file mode 100644 index 0000000..92fd6b2 --- /dev/null +++ b/usage.dox @@ -0,0 +1,208 @@ +/*!\page usage Usage + + The vpx multi-format codec SDK provides a unified interface amongst its + supported codecs. This abstraction allows applications using this SDK to + easily support multiple video formats with minimal code duplication or + "special casing." This section describes the interface common to all codecs. + For codec-specific details, see the \ref codecs page. + + The following sections are common to all codecs: + - \ref usage_types + - \ref usage_features + - \ref usage_init + - \ref usage_errors + + Fore more information on decoder and encoder specific usage, see the + following pages: + \if decoder + - \subpage usage_decode + \endif + \if decoder + - \subpage usage_encode + \endif + + \section usage_types Important Data Types + There are two important data structures to consider in this interface. + + \subsection usage_ctxs Contexts + A context is a storage area allocated by the calling application that the + codec may write into to store details about a single instance of that codec. + Most of the context is implementation specific, and thus opaque to the + application. The context structure as seen by the application is of fixed + size, and thus can be allocated with automatic storage or dynamically + on the heap. + + Most operations require an initialized codec context. Codec context + instances are codec specific. That is, the codec to be used for the encoded + video must be known at initialization time. See #vpx_codec_ctx_t for further + information. + + \subsection usage_ifaces Interfaces + A codec interface is an opaque structure that controls how function calls + into the generic interface are dispatched to their codec-specific + implementations. Applications \ref MUSTNOT attempt to examine or override + this storage, as it contains internal implementation details likely to + change from release to release. + + Each supported codec will expose an interface structure to the application + as an extern reference to a structure of the incomplete type + #vpx_codec_iface_t. + + \section usage_features Features + Several "features" are defined that are optionally implemented by codec + algorithms. Indeed, the same algorithm may support different features on + different platforms. The purpose of defining these features is that when + they are implemented, they conform to a common interface. The features, or + capabilities, of an algorithm can be queried from it's interface by using + the vpx_codec_get_caps() method. Attempts to invoke features not supported + by an algorithm will generally result in #VPX_CODEC_INCAPABLE. + + Currently defined features available in both encoders and decoders include: + - \subpage usage_xma + + \if decoder + Currently defined decoder features include: + - \ref usage_cb + - \ref usage_postproc + \endif + + \section usage_init Initialization + To initialize a codec instance, the address of the codec context + and interface structures are passed to an initialization function. Depending + on the \ref usage_features that the codec supports, the codec could be + initialized in different modes. Most notably, the application may choose to + use \ref usage_xma mode to gain fine grained control over how and where + memory is allocated for the codec. + + To prevent cases of confusion where the ABI of the library changes, + the ABI is versioned. The ABI version number must be passed at + initialization time to ensure the application is using a header file that + matches the library. The current ABI version number is stored in the + preprocessor macros #VPX_CODEC_ABI_VERSION, #VPX_ENCODER_ABI_VERSION, and + #VPX_DECODER_ABI_VERSION. For convenience, each initialization function has + a wrapper macro that inserts the correct version number. These macros are + named like the initialization methods, but without the _ver suffix. + + + The available initialization methods are: + \if encoder - #vpx_codec_enc_init (calls vpx_codec_enc_init_ver()) \endif + \if multi-encoder - #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver()) \endif + \if decoder - #vpx_codec_dec_init (calls vpx_codec_dec_init_ver()) \endif + + + + \section usage_errors Error Handling + Almost all codec functions return an error status of type #vpx_codec_err_t. + The semantics of how each error condition should be processed is clearly + defined in the definitions of each enumerated value. Error values can be + converted into ASCII strings with the vpx_codec_error() and + vpx_codec_err_to_string() methods. The difference between these two methods is + that vpx_codec_error() returns the error state from an initialized context, + whereas vpx_codec_err_to_string() can be used in cases where an error occurs + outside any context. The enumerated value returned from the last call can be + retrieved from the err member of the decoder context as well. + Finally, more detailed error information may be able to be obtained by using + the vpx_codec_error_detail() method. Not all errors produce detailed error + information. + + In addition to error information, the codec library's build configuration + is available at runtime on some platforms. This information can be returned + by calling vpx_codec_build_config(), and is formatted as a base64 coded string + (comprised of characters in the set [a-z_a-Z0-9+/]). This information is not + useful to an application at runtime, but may be of use to vpx for support. + + + \section usage_deadline Deadline + Both the encoding and decoding functions have a deadline + parameter. This parameter indicates the amount of time, in microseconds + (us), that the application wants the codec to spend processing before + returning. This is a soft deadline -- that is, the semantics of the + requested operation take precedence over meeting the deadline. If, for + example, an application sets a deadline of 1000us, and the + frame takes 2000us to decode, the call to vpx_codec_decode() will return + after 2000us. In this case the deadline is not met, but the semantics of the + function are preserved. If, for the same frame, an application instead sets + a deadline of 5000us, the decoder will see that it has 3000us + remaining in its time slice when decoding completes. It could then choose to + run a set of \ref usage_postproc filters, and perhaps would return after + 4000us (instead of the allocated 5000us). In this case the deadline is met, + and the semantics of the call are preserved, as before. + + The special value 0 is reserved to represent an infinite + deadline. In this case, the codec will perform as much processing as + possible to yield the highest quality frame. + + By convention, the value 1 is used to mean "return as fast as + possible." + +*/ + + +/*! \page usage_xma External Memory Allocation + Applications that wish to have fine grained control over how and where + decoders allocate memory \ref MAY make use of the eXternal Memory Allocation + (XMA) interface. Not all codecs support the XMA \ref usage_features. + + To use a decoder in XMA mode, the decoder \ref MUST be initialized with the + vpx_codec_xma_init_ver() function. The amount of memory a decoder needs to + allocate is heavily dependent on the size of the encoded video frames. The + size of the video must be known before requesting the decoder's memory map. + This stream information can be obtained with the vpx_codec_peek_stream_info() + function, which does not require a constructed decoder context. If the exact + stream is not known, a stream info structure can be created that reflects + the maximum size that the decoder instance is required to support. + + Once the decoder instance has been initialized and the stream information + determined, the application calls the vpx_codec_get_mem_map() iterator + repeatedly to get a list of the memory segments requested by the decoder. + The iterator value should be initialized to NULL to request the first + element, and the function will return #VPX_CODEC_LIST_END to signal the end of + the list. + + After each segment is identified, it must be passed to the codec through the + vpx_codec_set_mem_map() function. Segments \ref MUST be passed in the same + order as they are returned from vpx_codec_get_mem_map(), but there is no + requirement that vpx_codec_get_mem_map() must finish iterating before + vpx_codec_set_mem_map() is called. For instance, some applications may choose + to get a list of all requests, construct an optimal heap, and then set all + maps at once with one call. Other applications may set one map at a time, + allocating it immediately after it is returned from vpx_codec_get_mem_map(). + + After all segments have been set using vpx_codec_set_mem_map(), the codec may + be used as it would be in normal internal allocation mode. + + \section usage_xma_seg_id Segment Identifiers + Each requested segment is identified by an identifier unique to + that decoder type. Some of these identifiers are private, while others are + enumerated for application use. Identifiers not enumerated publicly are + subject to change. Identifiers are non-consecutive. + + \section usage_xma_seg_szalign Segment Size and Alignment + The sz (size) and align (alignment) parameters describe the required size + and alignment of the requested segment. Alignment will always be a power of + two. Applications \ref MUST honor the alignment requested. Failure to do so + could result in program crashes or may incur a speed penalty. + + \section usage_xma_seg_flags Segment Flags + The flags member of the segment structure indicates any requirements or + desires of the codec for the particular segment. The #VPX_CODEC_MEM_ZERO flag + indicates that the segment \ref MUST be zeroed by the application prior to + passing it to the application. The #VPX_CODEC_MEM_WRONLY flag indicates that + the segment will only be written into by the decoder, not read. If this flag + is not set, the application \ref MUST insure that the memory segment is + readable. On some platforms, framebuffer memory is writable but not + readable, for example. The #VPX_CODEC_MEM_FAST flag indicates that the segment + will be frequently accessed, and that it should be placed into fast memory, + if any is available. The application \ref MAY choose to place other segments + in fast memory as well, but the most critical segments will be identified by + this flag. + + \section usage_xma_seg_basedtor Segment Base Address and Destructor + For each requested memory segment, the application must determine the + address of a memory segment that meets the requirements of the codec. This + address is set in the base member of the #vpx_codec_mmap + structure. If the application requires processing when the segment is no + longer used by the codec (for instance to deallocate it or close an + associated file descriptor) the dtor and priv + members can be set. +*/ diff --git a/usage_cx.dox b/usage_cx.dox new file mode 100644 index 0000000..62f3e45 --- /dev/null +++ b/usage_cx.dox @@ -0,0 +1,13 @@ +/*! \page usage_encode Encode + + The vpx_codec_encode() function is at the core of the encode loop. It + processes raw images passed by the application, producing packets of + compressed data. The deadline parameter controls the amount + of time in microseconds the encoder should spend working on the frame. For + more information on the deadline parameter, see + \ref usage_deadline. + + + \ref samples + +*/ diff --git a/usage_dx.dox b/usage_dx.dox new file mode 100644 index 0000000..883ce24 --- /dev/null +++ b/usage_dx.dox @@ -0,0 +1,62 @@ +/*! \page usage_decode Decoding + + The vpx_codec_decode() function is at the core of the decode loop. It + processes packets of compressed data passed by the application, producing + decoded images. The decoder expects packets to comprise exactly one image + frame of data. Packets \ref MUST be passed in decode order. If the + application wishes to associate some data with the frame, the + user_priv member may be set. The deadline + parameter controls the amount of time in microseconds the decoder should + spend working on the frame. This is typically used to support adaptive + \ref usage_postproc based on the amount of free CPU time. For more + information on the deadline parameter, see \ref usage_deadline. + + \ref samples + + + \section usage_cb Callback Based Decoding + There are two methods for the application to access decoded frame data. Some + codecs support asynchronous (callback-based) decoding \ref usage_features + that allow the application to register a callback to be invoked by the + decoder when decoded data becomes available. Decoders are not required to + support this feature, however. Like all \ref usage_features, support can be + determined by calling vpx_codec_get_caps(). Callbacks are available in both + frame-based and slice-based variants. Frame based callbacks conform to the + signature of #vpx_codec_put_frame_cb_fn_t and are invoked once the entire + frame has been decoded. Slice based callbacks conform to the signature of + #vpx_codec_put_slice_cb_fn_t and are invoked after a subsection of the frame + is decoded. For example, a slice callback could be issued for each + macroblock row. However, the number and size of slices to return is + implementation specific. Also, the image data passed in a slice callback is + not necessarily in the same memory segment as the data will be when it is + assembled into a full frame. For this reason, the application \ref MUST + examine the rectangles that describe what data is valid to access and what + data has been updated in this call. For all their additional complexity, + slice based decoding callbacks provide substantial speed gains to the + overall application in some cases, due to improved cache behavior. + + + \section usage_frame_iter Frame Iterator Based Decoding + If the codec does not support callback based decoding, or the application + chooses not to make use of that feature, decoded frames are made available + through the vpx_codec_get_frame() iterator. The application initializes the + iterator storage (of type #vpx_codec_iter_t) to NULL, then calls + vpx_codec_get_frame repeatedly until it returns NULL, indicating that all + images have been returned. This process may result in zero, one, or many + frames that are ready for display, depending on the codec. + + + \section usage_postproc Postprocessing + Postprocessing is a process that is applied after a frame is decoded to + enhance the image's appearance by removing artifacts introduced in the + compression process. It is not required to properly decode the frame, and + is generally done only when there is enough spare CPU time to execute + the required filters. Codecs may support a number of different + postprocessing filters, and the available filters may differ from platform + to platform. Embedded devices often do not have enough CPU to implement + postprocessing in software. The filter selection is generally handled + automatically by the codec, depending on the amount of time remaining before + hitting the user-specified \ref usage_deadline after decoding the frame. + + +*/ diff --git a/vp8/common/alloccommon.c b/vp8/common/alloccommon.c new file mode 100644 index 0000000..d58e49c --- /dev/null +++ b/vp8/common/alloccommon.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "blockd.h" +#include "vpx_mem/vpx_mem.h" +#include "onyxc_int.h" +#include "findnearmv.h" +#include "entropymode.h" +#include "systemdependent.h" + + +extern void vp8_init_scan_order_mask(); + +static void update_mode_info_border(MODE_INFO *mi, int rows, int cols) +{ + int i; + vpx_memset(mi - cols - 2, 0, sizeof(MODE_INFO) * (cols + 1)); + + for (i = 0; i < rows; i++) + { + /* TODO(holmer): Bug? This updates the last element of each row + * rather than the border element! + */ + vpx_memset(&mi[i*cols-1], 0, sizeof(MODE_INFO)); + } +} + +void vp8_de_alloc_frame_buffers(VP8_COMMON *oci) +{ + int i; + for (i = 0; i < NUM_YV12_BUFFERS; i++) + vp8_yv12_de_alloc_frame_buffer(&oci->yv12_fb[i]); + + vp8_yv12_de_alloc_frame_buffer(&oci->temp_scale_frame); +#if CONFIG_POSTPROC + vp8_yv12_de_alloc_frame_buffer(&oci->post_proc_buffer); + if (oci->post_proc_buffer_int_used) + vp8_yv12_de_alloc_frame_buffer(&oci->post_proc_buffer_int); +#endif + + vpx_free(oci->above_context); + vpx_free(oci->mip); + vpx_free(oci->prev_mip); + + oci->above_context = 0; + oci->mip = 0; + oci->prev_mip = 0; + +} + +int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) +{ + int i; + + vp8_de_alloc_frame_buffers(oci); + + /* our internal buffers are always multiples of 16 */ + if ((width & 0xf) != 0) + width += 16 - (width & 0xf); + + if ((height & 0xf) != 0) + height += 16 - (height & 0xf); + + + for (i = 0; i < NUM_YV12_BUFFERS; i++) + { + oci->fb_idx_ref_cnt[i] = 0; + oci->yv12_fb[i].flags = 0; + if (vp8_yv12_alloc_frame_buffer(&oci->yv12_fb[i], width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return 1; + } + } + + oci->new_fb_idx = 0; + oci->lst_fb_idx = 1; + oci->gld_fb_idx = 2; + oci->alt_fb_idx = 3; + + oci->fb_idx_ref_cnt[0] = 1; + oci->fb_idx_ref_cnt[1] = 1; + oci->fb_idx_ref_cnt[2] = 1; + oci->fb_idx_ref_cnt[3] = 1; + + if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return 1; + } + +#if CONFIG_POSTPROC + if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return 1; + } + + oci->post_proc_buffer_int_used = 0; + vpx_memset(&oci->postproc_state, 0, sizeof(oci->postproc_state)); + vpx_memset((&oci->post_proc_buffer)->buffer_alloc,128,(&oci->post_proc_buffer)->frame_size); +#endif + + oci->mb_rows = height >> 4; + oci->mb_cols = width >> 4; + oci->MBs = oci->mb_rows * oci->mb_cols; + oci->mode_info_stride = oci->mb_cols + 1; + oci->mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); + + if (!oci->mip) + { + vp8_de_alloc_frame_buffers(oci); + return 1; + } + + oci->mi = oci->mip + oci->mode_info_stride + 1; + + /* allocate memory for last frame MODE_INFO array */ +#if CONFIG_ERROR_CONCEALMENT + oci->prev_mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); + + if (!oci->prev_mip) + { + vp8_de_alloc_frame_buffers(oci); + return 1; + } + + oci->prev_mi = oci->prev_mip + oci->mode_info_stride + 1; +#else + oci->prev_mip = NULL; + oci->prev_mi = NULL; +#endif + + oci->above_context = vpx_calloc(sizeof(ENTROPY_CONTEXT_PLANES) * oci->mb_cols, 1); + + if (!oci->above_context) + { + vp8_de_alloc_frame_buffers(oci); + return 1; + } + + update_mode_info_border(oci->mi, oci->mb_rows, oci->mb_cols); +#if CONFIG_ERROR_CONCEALMENT + update_mode_info_border(oci->prev_mi, oci->mb_rows, oci->mb_cols); +#endif + + return 0; +} +void vp8_setup_version(VP8_COMMON *cm) +{ + switch (cm->version) + { + case 0: + cm->no_lpf = 0; + cm->filter_type = NORMAL_LOOPFILTER; + cm->use_bilinear_mc_filter = 0; + cm->full_pixel = 0; + break; + case 1: + cm->no_lpf = 0; + cm->filter_type = SIMPLE_LOOPFILTER; + cm->use_bilinear_mc_filter = 1; + cm->full_pixel = 0; + break; + case 2: + cm->no_lpf = 1; + cm->filter_type = NORMAL_LOOPFILTER; + cm->use_bilinear_mc_filter = 1; + cm->full_pixel = 0; + break; + case 3: + cm->no_lpf = 1; + cm->filter_type = SIMPLE_LOOPFILTER; + cm->use_bilinear_mc_filter = 1; + cm->full_pixel = 1; + break; + default: + /*4,5,6,7 are reserved for future use*/ + cm->no_lpf = 0; + cm->filter_type = NORMAL_LOOPFILTER; + cm->use_bilinear_mc_filter = 0; + cm->full_pixel = 0; + break; + } +} +void vp8_create_common(VP8_COMMON *oci) +{ + vp8_machine_specific_config(oci); + + vp8_init_mbmode_probs(oci); + vp8_default_bmode_probs(oci->fc.bmode_prob); + + oci->mb_no_coeff_skip = 1; + oci->no_lpf = 0; + oci->filter_type = NORMAL_LOOPFILTER; + oci->use_bilinear_mc_filter = 0; + oci->full_pixel = 0; + oci->multi_token_partition = ONE_PARTITION; + oci->clr_type = REG_YUV; + oci->clamp_type = RECON_CLAMP_REQUIRED; + + /* Initialize reference frame sign bias structure to defaults */ + vpx_memset(oci->ref_frame_sign_bias, 0, sizeof(oci->ref_frame_sign_bias)); + + /* Default disable buffer to buffer copying */ + oci->copy_buffer_to_gf = 0; + oci->copy_buffer_to_arf = 0; +} + +void vp8_remove_common(VP8_COMMON *oci) +{ + vp8_de_alloc_frame_buffers(oci); +} diff --git a/vp8/common/alloccommon.h b/vp8/common/alloccommon.h new file mode 100644 index 0000000..ea93c25 --- /dev/null +++ b/vp8/common/alloccommon.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_ALLOCCOMMON_H +#define __INC_ALLOCCOMMON_H + +#include "onyxc_int.h" + +void vp8_create_common(VP8_COMMON *oci); +void vp8_remove_common(VP8_COMMON *oci); +void vp8_de_alloc_frame_buffers(VP8_COMMON *oci); +int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height); +void vp8_setup_version(VP8_COMMON *oci); + +#endif diff --git a/vp8/common/arm/armv6/bilinearfilter_v6.asm b/vp8/common/arm/armv6/bilinearfilter_v6.asm new file mode 100644 index 0000000..9704b42 --- /dev/null +++ b/vp8/common/arm/armv6/bilinearfilter_v6.asm @@ -0,0 +1,237 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_filter_block2d_bil_first_pass_armv6| + EXPORT |vp8_filter_block2d_bil_second_pass_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code + +;------------------------------------- +; r0 unsigned char *src_ptr, +; r1 unsigned short *dst_ptr, +; r2 unsigned int src_pitch, +; r3 unsigned int height, +; stack unsigned int width, +; stack const short *vp8_filter +;------------------------------------- +; The output is transposed stroed in output array to make it easy for second pass filtering. +|vp8_filter_block2d_bil_first_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r4, [sp, #36] ; width + + mov r12, r3 ; outer-loop counter + + add r7, r2, r4 ; preload next row + pld [r0, r7] + + sub r2, r2, r4 ; src increment for height loop + + ldr r5, [r11] ; load up filter coefficients + + mov r3, r3, lsl #1 ; height*2 + add r3, r3, #2 ; plus 2 to make output buffer 4-bit aligned since height is actually (height+1) + + mov r11, r1 ; save dst_ptr for each row + + cmp r5, #128 ; if filter coef = 128, then skip the filter + beq bil_null_1st_filter + +|bil_height_loop_1st_v6| + ldrb r6, [r0] ; load source data + ldrb r7, [r0, #1] + ldrb r8, [r0, #2] + mov lr, r4, lsr #2 ; 4-in-parellel loop counter + +|bil_width_loop_1st_v6| + ldrb r9, [r0, #3] + ldrb r10, [r0, #4] + + pkhbt r6, r6, r7, lsl #16 ; src[1] | src[0] + pkhbt r7, r7, r8, lsl #16 ; src[2] | src[1] + + smuad r6, r6, r5 ; apply the filter + pkhbt r8, r8, r9, lsl #16 ; src[3] | src[2] + smuad r7, r7, r5 + pkhbt r9, r9, r10, lsl #16 ; src[4] | src[3] + + smuad r8, r8, r5 + smuad r9, r9, r5 + + add r0, r0, #4 + subs lr, lr, #1 + + add r6, r6, #0x40 ; round_shift_and_clamp + add r7, r7, #0x40 + usat r6, #16, r6, asr #7 + usat r7, #16, r7, asr #7 + + strh r6, [r1], r3 ; result is transposed and stored + + add r8, r8, #0x40 ; round_shift_and_clamp + strh r7, [r1], r3 + add r9, r9, #0x40 + usat r8, #16, r8, asr #7 + usat r9, #16, r9, asr #7 + + strh r8, [r1], r3 ; result is transposed and stored + + ldrneb r6, [r0] ; load source data + strh r9, [r1], r3 + + ldrneb r7, [r0, #1] + ldrneb r8, [r0, #2] + + bne bil_width_loop_1st_v6 + + add r0, r0, r2 ; move to next input row + subs r12, r12, #1 + + add r9, r2, r4, lsl #1 ; adding back block width + pld [r0, r9] ; preload next row + + add r11, r11, #2 ; move over to next column + mov r1, r11 + + bne bil_height_loop_1st_v6 + + ldmia sp!, {r4 - r11, pc} + +|bil_null_1st_filter| +|bil_height_loop_null_1st| + mov lr, r4, lsr #2 ; loop counter + +|bil_width_loop_null_1st| + ldrb r6, [r0] ; load data + ldrb r7, [r0, #1] + ldrb r8, [r0, #2] + ldrb r9, [r0, #3] + + strh r6, [r1], r3 ; store it to immediate buffer + add r0, r0, #4 + strh r7, [r1], r3 + subs lr, lr, #1 + strh r8, [r1], r3 + strh r9, [r1], r3 + + bne bil_width_loop_null_1st + + subs r12, r12, #1 + add r0, r0, r2 ; move to next input line + add r11, r11, #2 ; move over to next column + mov r1, r11 + + bne bil_height_loop_null_1st + + ldmia sp!, {r4 - r11, pc} + + ENDP ; |vp8_filter_block2d_bil_first_pass_armv6| + + +;--------------------------------- +; r0 unsigned short *src_ptr, +; r1 unsigned char *dst_ptr, +; r2 int dst_pitch, +; r3 unsigned int height, +; stack unsigned int width, +; stack const short *vp8_filter +;--------------------------------- +|vp8_filter_block2d_bil_second_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r4, [sp, #36] ; width + + ldr r5, [r11] ; load up filter coefficients + mov r12, r4 ; outer-loop counter = width, since we work on transposed data matrix + mov r11, r1 + + cmp r5, #128 ; if filter coef = 128, then skip the filter + beq bil_null_2nd_filter + +|bil_height_loop_2nd| + ldr r6, [r0] ; load the data + ldr r8, [r0, #4] + ldrh r10, [r0, #8] + mov lr, r3, lsr #2 ; loop counter + +|bil_width_loop_2nd| + pkhtb r7, r6, r8 ; src[1] | src[2] + pkhtb r9, r8, r10 ; src[3] | src[4] + + smuad r6, r6, r5 ; apply filter + smuad r8, r8, r5 ; apply filter + + subs lr, lr, #1 + + smuadx r7, r7, r5 ; apply filter + smuadx r9, r9, r5 ; apply filter + + add r0, r0, #8 + + add r6, r6, #0x40 ; round_shift_and_clamp + add r7, r7, #0x40 + usat r6, #8, r6, asr #7 + usat r7, #8, r7, asr #7 + strb r6, [r1], r2 ; the result is transposed back and stored + + add r8, r8, #0x40 ; round_shift_and_clamp + strb r7, [r1], r2 + add r9, r9, #0x40 + usat r8, #8, r8, asr #7 + usat r9, #8, r9, asr #7 + strb r8, [r1], r2 ; the result is transposed back and stored + + ldrne r6, [r0] ; load data + strb r9, [r1], r2 + ldrne r8, [r0, #4] + ldrneh r10, [r0, #8] + + bne bil_width_loop_2nd + + subs r12, r12, #1 + add r0, r0, #4 ; update src for next row + add r11, r11, #1 + mov r1, r11 + + bne bil_height_loop_2nd + ldmia sp!, {r4 - r11, pc} + +|bil_null_2nd_filter| +|bil_height_loop_null_2nd| + mov lr, r3, lsr #2 + +|bil_width_loop_null_2nd| + ldr r6, [r0], #4 ; load data + subs lr, lr, #1 + ldr r8, [r0], #4 + + strb r6, [r1], r2 ; store data + mov r7, r6, lsr #16 + strb r7, [r1], r2 + mov r9, r8, lsr #16 + strb r8, [r1], r2 + strb r9, [r1], r2 + + bne bil_width_loop_null_2nd + + subs r12, r12, #1 + add r0, r0, #4 + add r11, r11, #1 + mov r1, r11 + + bne bil_height_loop_null_2nd + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_filter_block2d_second_pass_armv6| + + END diff --git a/vp8/common/arm/armv6/copymem16x16_v6.asm b/vp8/common/arm/armv6/copymem16x16_v6.asm new file mode 100644 index 0000000..abf048c --- /dev/null +++ b/vp8/common/arm/armv6/copymem16x16_v6.asm @@ -0,0 +1,186 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem16x16_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem16x16_v6( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem16x16_v6| PROC + stmdb sp!, {r4 - r7} + ;push {r4-r7} + + ;preload + pld [r0, #31] ; preload for next 16x16 block + + ands r4, r0, #15 + beq copy_mem16x16_fast + + ands r4, r0, #7 + beq copy_mem16x16_8 + + ands r4, r0, #3 + beq copy_mem16x16_4 + + ;copy one byte each time + ldrb r4, [r0] + ldrb r5, [r0, #1] + ldrb r6, [r0, #2] + ldrb r7, [r0, #3] + + mov r12, #16 + +copy_mem16x16_1_loop + strb r4, [r2] + strb r5, [r2, #1] + strb r6, [r2, #2] + strb r7, [r2, #3] + + ldrb r4, [r0, #4] + ldrb r5, [r0, #5] + ldrb r6, [r0, #6] + ldrb r7, [r0, #7] + + subs r12, r12, #1 + + strb r4, [r2, #4] + strb r5, [r2, #5] + strb r6, [r2, #6] + strb r7, [r2, #7] + + ldrb r4, [r0, #8] + ldrb r5, [r0, #9] + ldrb r6, [r0, #10] + ldrb r7, [r0, #11] + + strb r4, [r2, #8] + strb r5, [r2, #9] + strb r6, [r2, #10] + strb r7, [r2, #11] + + ldrb r4, [r0, #12] + ldrb r5, [r0, #13] + ldrb r6, [r0, #14] + ldrb r7, [r0, #15] + + add r0, r0, r1 + + strb r4, [r2, #12] + strb r5, [r2, #13] + strb r6, [r2, #14] + strb r7, [r2, #15] + + add r2, r2, r3 + + ldrneb r4, [r0] + ldrneb r5, [r0, #1] + ldrneb r6, [r0, #2] + ldrneb r7, [r0, #3] + + pld [r0, #31] ; preload for next 16x16 block + + bne copy_mem16x16_1_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + +;copy 4 bytes each time +copy_mem16x16_4 + ldr r4, [r0] + ldr r5, [r0, #4] + ldr r6, [r0, #8] + ldr r7, [r0, #12] + + mov r12, #16 + +copy_mem16x16_4_loop + subs r12, r12, #1 + add r0, r0, r1 + + str r4, [r2] + str r5, [r2, #4] + str r6, [r2, #8] + str r7, [r2, #12] + + add r2, r2, r3 + + ldrne r4, [r0] + ldrne r5, [r0, #4] + ldrne r6, [r0, #8] + ldrne r7, [r0, #12] + + pld [r0, #31] ; preload for next 16x16 block + + bne copy_mem16x16_4_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + +;copy 8 bytes each time +copy_mem16x16_8 + sub r1, r1, #16 + sub r3, r3, #16 + + mov r12, #16 + +copy_mem16x16_8_loop + ldmia r0!, {r4-r5} + ;ldm r0, {r4-r5} + ldmia r0!, {r6-r7} + + add r0, r0, r1 + + stmia r2!, {r4-r5} + subs r12, r12, #1 + ;stm r2, {r4-r5} + stmia r2!, {r6-r7} + + add r2, r2, r3 + + pld [r0, #31] ; preload for next 16x16 block + bne copy_mem16x16_8_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + +;copy 16 bytes each time +copy_mem16x16_fast + ;sub r1, r1, #16 + ;sub r3, r3, #16 + + mov r12, #16 + +copy_mem16x16_fast_loop + ldmia r0, {r4-r7} + ;ldm r0, {r4-r7} + add r0, r0, r1 + + subs r12, r12, #1 + stmia r2, {r4-r7} + ;stm r2, {r4-r7} + add r2, r2, r3 + + pld [r0, #31] ; preload for next 16x16 block + bne copy_mem16x16_fast_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + + ENDP ; |vp8_copy_mem16x16_v6| + + END diff --git a/vp8/common/arm/armv6/copymem8x4_v6.asm b/vp8/common/arm/armv6/copymem8x4_v6.asm new file mode 100644 index 0000000..d8362ef --- /dev/null +++ b/vp8/common/arm/armv6/copymem8x4_v6.asm @@ -0,0 +1,128 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x4_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void vp8_copy_mem8x4_v6( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x4_v6| PROC + ;push {r4-r5} + stmdb sp!, {r4-r5} + + ;preload + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + ands r4, r0, #7 + beq copy_mem8x4_fast + + ands r4, r0, #3 + beq copy_mem8x4_4 + + ;copy 1 byte each time + ldrb r4, [r0] + ldrb r5, [r0, #1] + + mov r12, #4 + +copy_mem8x4_1_loop + strb r4, [r2] + strb r5, [r2, #1] + + ldrb r4, [r0, #2] + ldrb r5, [r0, #3] + + subs r12, r12, #1 + + strb r4, [r2, #2] + strb r5, [r2, #3] + + ldrb r4, [r0, #4] + ldrb r5, [r0, #5] + + strb r4, [r2, #4] + strb r5, [r2, #5] + + ldrb r4, [r0, #6] + ldrb r5, [r0, #7] + + add r0, r0, r1 + + strb r4, [r2, #6] + strb r5, [r2, #7] + + add r2, r2, r3 + + ldrneb r4, [r0] + ldrneb r5, [r0, #1] + + bne copy_mem8x4_1_loop + + ldmia sp!, {r4 - r5} + ;pop {r4-r5} + mov pc, lr + +;copy 4 bytes each time +copy_mem8x4_4 + ldr r4, [r0] + ldr r5, [r0, #4] + + mov r12, #4 + +copy_mem8x4_4_loop + subs r12, r12, #1 + add r0, r0, r1 + + str r4, [r2] + str r5, [r2, #4] + + add r2, r2, r3 + + ldrne r4, [r0] + ldrne r5, [r0, #4] + + bne copy_mem8x4_4_loop + + ldmia sp!, {r4-r5} + ;pop {r4-r5} + mov pc, lr + +;copy 8 bytes each time +copy_mem8x4_fast + ;sub r1, r1, #8 + ;sub r3, r3, #8 + + mov r12, #4 + +copy_mem8x4_fast_loop + ldmia r0, {r4-r5} + ;ldm r0, {r4-r5} + add r0, r0, r1 + + subs r12, r12, #1 + stmia r2, {r4-r5} + ;stm r2, {r4-r5} + add r2, r2, r3 + + bne copy_mem8x4_fast_loop + + ldmia sp!, {r4-r5} + ;pop {r4-r5} + mov pc, lr + + ENDP ; |vp8_copy_mem8x4_v6| + + END diff --git a/vp8/common/arm/armv6/copymem8x8_v6.asm b/vp8/common/arm/armv6/copymem8x8_v6.asm new file mode 100644 index 0000000..c6a60c6 --- /dev/null +++ b/vp8/common/arm/armv6/copymem8x8_v6.asm @@ -0,0 +1,128 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x8_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem8x8_v6( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x8_v6| PROC + ;push {r4-r5} + stmdb sp!, {r4-r5} + + ;preload + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + ands r4, r0, #7 + beq copy_mem8x8_fast + + ands r4, r0, #3 + beq copy_mem8x8_4 + + ;copy 1 byte each time + ldrb r4, [r0] + ldrb r5, [r0, #1] + + mov r12, #8 + +copy_mem8x8_1_loop + strb r4, [r2] + strb r5, [r2, #1] + + ldrb r4, [r0, #2] + ldrb r5, [r0, #3] + + subs r12, r12, #1 + + strb r4, [r2, #2] + strb r5, [r2, #3] + + ldrb r4, [r0, #4] + ldrb r5, [r0, #5] + + strb r4, [r2, #4] + strb r5, [r2, #5] + + ldrb r4, [r0, #6] + ldrb r5, [r0, #7] + + add r0, r0, r1 + + strb r4, [r2, #6] + strb r5, [r2, #7] + + add r2, r2, r3 + + ldrneb r4, [r0] + ldrneb r5, [r0, #1] + + bne copy_mem8x8_1_loop + + ldmia sp!, {r4 - r5} + ;pop {r4-r5} + mov pc, lr + +;copy 4 bytes each time +copy_mem8x8_4 + ldr r4, [r0] + ldr r5, [r0, #4] + + mov r12, #8 + +copy_mem8x8_4_loop + subs r12, r12, #1 + add r0, r0, r1 + + str r4, [r2] + str r5, [r2, #4] + + add r2, r2, r3 + + ldrne r4, [r0] + ldrne r5, [r0, #4] + + bne copy_mem8x8_4_loop + + ldmia sp!, {r4 - r5} + ;pop {r4-r5} + mov pc, lr + +;copy 8 bytes each time +copy_mem8x8_fast + ;sub r1, r1, #8 + ;sub r3, r3, #8 + + mov r12, #8 + +copy_mem8x8_fast_loop + ldmia r0, {r4-r5} + ;ldm r0, {r4-r5} + add r0, r0, r1 + + subs r12, r12, #1 + stmia r2, {r4-r5} + ;stm r2, {r4-r5} + add r2, r2, r3 + + bne copy_mem8x8_fast_loop + + ldmia sp!, {r4-r5} + ;pop {r4-r5} + mov pc, lr + + ENDP ; |vp8_copy_mem8x8_v6| + + END diff --git a/vp8/common/arm/armv6/dc_only_idct_add_v6.asm b/vp8/common/arm/armv6/dc_only_idct_add_v6.asm new file mode 100644 index 0000000..9aa659f --- /dev/null +++ b/vp8/common/arm/armv6/dc_only_idct_add_v6.asm @@ -0,0 +1,70 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + EXPORT |vp8_dc_only_idct_add_v6| + + AREA |.text|, CODE, READONLY + +;void vp8_dc_only_idct_add_c(short input_dc, unsigned char *pred_ptr, +; int pred_stride, unsigned char *dst_ptr, +; int dst_stride) +; r0 input_dc +; r1 pred_ptr +; r2 pred_stride +; r3 dst_ptr +; sp dst_stride + +|vp8_dc_only_idct_add_v6| PROC + stmdb sp!, {r4 - r7} + + add r0, r0, #4 ; input_dc += 4 + ldr r12, c0x0000FFFF + ldr r4, [r1], r2 + and r0, r12, r0, asr #3 ; input_dc >> 3 + mask + ldr r6, [r1], r2 + orr r0, r0, r0, lsl #16 ; a1 | a1 + + ldr r12, [sp, #16] ; dst stride + + uxtab16 r5, r0, r4 ; a1+2 | a1+0 + uxtab16 r4, r0, r4, ror #8 ; a1+3 | a1+1 + uxtab16 r7, r0, r6 + uxtab16 r6, r0, r6, ror #8 + usat16 r5, #8, r5 + usat16 r4, #8, r4 + usat16 r7, #8, r7 + usat16 r6, #8, r6 + orr r5, r5, r4, lsl #8 + orr r7, r7, r6, lsl #8 + ldr r4, [r1], r2 + str r5, [r3], r12 + ldr r6, [r1] + str r7, [r3], r12 + + uxtab16 r5, r0, r4 + uxtab16 r4, r0, r4, ror #8 + uxtab16 r7, r0, r6 + uxtab16 r6, r0, r6, ror #8 + usat16 r5, #8, r5 + usat16 r4, #8, r4 + usat16 r7, #8, r7 + usat16 r6, #8, r6 + orr r5, r5, r4, lsl #8 + orr r7, r7, r6, lsl #8 + str r5, [r3], r12 + str r7, [r3] + + ldmia sp!, {r4 - r7} + bx lr + + ENDP ; |vp8_dc_only_idct_add_v6| + +; Constant Pool +c0x0000FFFF DCD 0x0000FFFF + END diff --git a/vp8/common/arm/armv6/dequant_idct_v6.asm b/vp8/common/arm/armv6/dequant_idct_v6.asm new file mode 100644 index 0000000..2510ad8 --- /dev/null +++ b/vp8/common/arm/armv6/dequant_idct_v6.asm @@ -0,0 +1,190 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + EXPORT |vp8_dequant_idct_add_v6| + + AREA |.text|, CODE, READONLY +;void vp8_dequant_idct_v6(short *input, short *dq, +; unsigned char *dest, int stride) +; r0 = q +; r1 = dq +; r2 = dst +; r3 = stride + +|vp8_dequant_idct_add_v6| PROC + stmdb sp!, {r4-r11, lr} + + ldr r4, [r0] ;input + ldr r5, [r1], #4 ;dq + + sub sp, sp, #4 + str r3, [sp] + + mov r12, #4 + +vp8_dequant_add_loop + smulbb r6, r4, r5 + smultt r7, r4, r5 + + ldr r4, [r0, #4] ;input + ldr r5, [r1], #4 ;dq + + strh r6, [r0], #2 + strh r7, [r0], #2 + + smulbb r6, r4, r5 + smultt r7, r4, r5 + + subs r12, r12, #1 + + ldrne r4, [r0, #4] + ldrne r5, [r1], #4 + + strh r6, [r0], #2 + strh r7, [r0], #2 + + bne vp8_dequant_add_loop + + sub r0, r0, #32 + mov r1, r0 + +; short_idct4x4llm_v6_dual + ldr r3, cospi8sqrt2minus1 + ldr r4, sinpi8sqrt2 + ldr r6, [r0, #8] + mov r5, #2 +vp8_dequant_idct_loop1_v6 + ldr r12, [r0, #24] + ldr r14, [r0, #16] + smulwt r9, r3, r6 + smulwb r7, r3, r6 + smulwt r10, r4, r6 + smulwb r8, r4, r6 + pkhbt r7, r7, r9, lsl #16 + smulwt r11, r3, r12 + pkhbt r8, r8, r10, lsl #16 + uadd16 r6, r6, r7 + smulwt r7, r4, r12 + smulwb r9, r3, r12 + smulwb r10, r4, r12 + subs r5, r5, #1 + pkhbt r9, r9, r11, lsl #16 + ldr r11, [r0], #4 + pkhbt r10, r10, r7, lsl #16 + uadd16 r7, r12, r9 + usub16 r7, r8, r7 + uadd16 r6, r6, r10 + uadd16 r10, r11, r14 + usub16 r8, r11, r14 + uadd16 r9, r10, r6 + usub16 r10, r10, r6 + uadd16 r6, r8, r7 + usub16 r7, r8, r7 + str r6, [r1, #8] + ldrne r6, [r0, #8] + str r7, [r1, #16] + str r10, [r1, #24] + str r9, [r1], #4 + bne vp8_dequant_idct_loop1_v6 + + mov r5, #2 + sub r0, r1, #8 +vp8_dequant_idct_loop2_v6 + ldr r6, [r0], #4 + ldr r7, [r0], #4 + ldr r8, [r0], #4 + ldr r9, [r0], #4 + smulwt r1, r3, r6 + smulwt r12, r4, r6 + smulwt lr, r3, r8 + smulwt r10, r4, r8 + pkhbt r11, r8, r6, lsl #16 + pkhbt r1, lr, r1, lsl #16 + pkhbt r12, r10, r12, lsl #16 + pkhtb r6, r6, r8, asr #16 + uadd16 r6, r1, r6 + pkhbt lr, r9, r7, lsl #16 + uadd16 r10, r11, lr + usub16 lr, r11, lr + pkhtb r8, r7, r9, asr #16 + subs r5, r5, #1 + smulwt r1, r3, r8 + smulwb r7, r3, r8 + smulwt r11, r4, r8 + smulwb r9, r4, r8 + pkhbt r1, r7, r1, lsl #16 + uadd16 r8, r1, r8 + pkhbt r11, r9, r11, lsl #16 + usub16 r1, r12, r8 + uadd16 r8, r11, r6 + ldr r9, c0x00040004 + ldr r12, [sp] ; get stride from stack + uadd16 r6, r10, r8 + usub16 r7, r10, r8 + uadd16 r7, r7, r9 + uadd16 r6, r6, r9 + uadd16 r10, r14, r1 + usub16 r1, r14, r1 + uadd16 r10, r10, r9 + uadd16 r1, r1, r9 + ldr r11, [r2] ; load input from dst + mov r8, r7, asr #3 + pkhtb r9, r8, r10, asr #19 + mov r8, r1, asr #3 + pkhtb r8, r8, r6, asr #19 + uxtb16 lr, r11, ror #8 + qadd16 r9, r9, lr + uxtb16 lr, r11 + qadd16 r8, r8, lr + usat16 r9, #8, r9 + usat16 r8, #8, r8 + orr r9, r8, r9, lsl #8 + ldr r11, [r2, r12] ; load input from dst + mov r7, r7, lsl #16 + mov r1, r1, lsl #16 + mov r10, r10, lsl #16 + mov r6, r6, lsl #16 + mov r7, r7, asr #3 + pkhtb r7, r7, r10, asr #19 + mov r1, r1, asr #3 + pkhtb r1, r1, r6, asr #19 + uxtb16 r8, r11, ror #8 + qadd16 r7, r7, r8 + uxtb16 r8, r11 + qadd16 r1, r1, r8 + usat16 r7, #8, r7 + usat16 r1, #8, r1 + orr r1, r1, r7, lsl #8 + str r9, [r2], r12 ; store output to dst + str r1, [r2], r12 ; store output to dst + bne vp8_dequant_idct_loop2_v6 + +; vpx_memset + sub r0, r0, #32 + add sp, sp, #4 + + mov r12, #0 + str r12, [r0] + str r12, [r0, #4] + str r12, [r0, #8] + str r12, [r0, #12] + str r12, [r0, #16] + str r12, [r0, #20] + str r12, [r0, #24] + str r12, [r0, #28] + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_dequant_idct_add_v6| + +; Constant Pool +cospi8sqrt2minus1 DCD 0x00004E7B +sinpi8sqrt2 DCD 0x00008A8C +c0x00040004 DCD 0x00040004 + + END diff --git a/vp8/common/arm/armv6/dequantize_v6.asm b/vp8/common/arm/armv6/dequantize_v6.asm new file mode 100644 index 0000000..72f7e0e --- /dev/null +++ b/vp8/common/arm/armv6/dequantize_v6.asm @@ -0,0 +1,69 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_dequantize_b_loop_v6| + + AREA |.text|, CODE, READONLY ; name this block of code +;------------------------------- +;void vp8_dequantize_b_loop_v6(short *Q, short *DQC, short *DQ); +; r0 short *Q, +; r1 short *DQC +; r2 short *DQ +|vp8_dequantize_b_loop_v6| PROC + stmdb sp!, {r4-r9, lr} + + ldr r3, [r0] ;load Q + ldr r4, [r1] ;load DQC + ldr r5, [r0, #4] + ldr r6, [r1, #4] + + mov r12, #2 ;loop counter + +dequant_loop + smulbb r7, r3, r4 ;multiply + smultt r8, r3, r4 + smulbb r9, r5, r6 + smultt lr, r5, r6 + + ldr r3, [r0, #8] + ldr r4, [r1, #8] + ldr r5, [r0, #12] + ldr r6, [r1, #12] + + strh r7, [r2], #2 ;store result + smulbb r7, r3, r4 ;multiply + strh r8, [r2], #2 + smultt r8, r3, r4 + strh r9, [r2], #2 + smulbb r9, r5, r6 + strh lr, [r2], #2 + smultt lr, r5, r6 + + subs r12, r12, #1 + + add r0, r0, #16 + add r1, r1, #16 + + ldrne r3, [r0] + strh r7, [r2], #2 ;store result + ldrne r4, [r1] + strh r8, [r2], #2 + ldrne r5, [r0, #4] + strh r9, [r2], #2 + ldrne r6, [r1, #4] + strh lr, [r2], #2 + + bne dequant_loop + + ldmia sp!, {r4-r9, pc} + ENDP ;|vp8_dequantize_b_loop_v6| + + END diff --git a/vp8/common/arm/armv6/filter_v6.asm b/vp8/common/arm/armv6/filter_v6.asm new file mode 100644 index 0000000..1ba91dd --- /dev/null +++ b/vp8/common/arm/armv6/filter_v6.asm @@ -0,0 +1,624 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_filter_block2d_first_pass_armv6| + EXPORT |vp8_filter_block2d_first_pass_16x16_armv6| + EXPORT |vp8_filter_block2d_first_pass_8x8_armv6| + EXPORT |vp8_filter_block2d_second_pass_armv6| + EXPORT |vp8_filter4_block2d_second_pass_armv6| + EXPORT |vp8_filter_block2d_first_pass_only_armv6| + EXPORT |vp8_filter_block2d_second_pass_only_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code +;------------------------------------- +; r0 unsigned char *src_ptr +; r1 short *output_ptr +; r2 unsigned int src_pixels_per_line +; r3 unsigned int output_width +; stack unsigned int output_height +; stack const short *vp8_filter +;------------------------------------- +; vp8_filter the input and put in the output array. Apply the 6 tap FIR filter with +; the output being a 2 byte value and the intput being a 1 byte value. +|vp8_filter_block2d_first_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r7, [sp, #36] ; output height + + sub r2, r2, r3 ; inside loop increments input array, + ; so the height loop only needs to add + ; r2 - width to the input pointer + + mov r3, r3, lsl #1 ; multiply width by 2 because using shorts + add r12, r3, #16 ; square off the output + sub sp, sp, #4 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + str r1, [sp] ; push destination to stack + mov r7, r7, lsl #16 ; height is top part of counter + +; six tap filter +|height_loop_1st_6| + ldrb r8, [r0, #-2] ; load source data + ldrb r9, [r0, #-1] + ldrb r10, [r0], #2 + orr r7, r7, r3, lsr #2 ; construct loop counter + +|width_loop_1st_6| + ldrb r11, [r0, #-1] + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0] + + smuad lr, lr, r4 ; apply the filter + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + smuad r8, r8, r4 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0, #1] + smlad r8, r11, r5, r8 + ldrb r11, [r0, #2] + + sub r7, r7, #1 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r11, r10, r6, r8 + + ands r10, r7, #0xff ; test loop counter + + add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0, #-2] ; load data for next loop + usat lr, #8, lr, asr #7 + add r11, r11, #0x40 + ldrneb r9, [r0, #-1] + usat r11, #8, r11, asr #7 + + strh lr, [r1], r12 ; result is transposed and stored, which + ; will make second pass filtering easier. + ldrneb r10, [r0], #2 + strh r11, [r1], r12 + + bne width_loop_1st_6 + + ldr r1, [sp] ; load and update dst address + subs r7, r7, #0x10000 + add r0, r0, r2 ; move to next input line + + add r1, r1, #2 ; move over to next column + str r1, [sp] + + bne height_loop_1st_6 + + add sp, sp, #4 + ldmia sp!, {r4 - r11, pc} + + ENDP + +; -------------------------- +; 16x16 version +; ----------------------------- +|vp8_filter_block2d_first_pass_16x16_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r7, [sp, #36] ; output height + + add r4, r2, #18 ; preload next low + pld [r0, r4] + + sub r2, r2, r3 ; inside loop increments input array, + ; so the height loop only needs to add + ; r2 - width to the input pointer + + mov r3, r3, lsl #1 ; multiply width by 2 because using shorts + add r12, r3, #16 ; square off the output + sub sp, sp, #4 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + str r1, [sp] ; push destination to stack + mov r7, r7, lsl #16 ; height is top part of counter + +; six tap filter +|height_loop_1st_16_6| + ldrb r8, [r0, #-2] ; load source data + ldrb r9, [r0, #-1] + ldrb r10, [r0], #2 + orr r7, r7, r3, lsr #2 ; construct loop counter + +|width_loop_1st_16_6| + ldrb r11, [r0, #-1] + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0] + + smuad lr, lr, r4 ; apply the filter + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + smuad r8, r8, r4 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0, #1] + smlad r8, r11, r5, r8 + ldrb r11, [r0, #2] + + sub r7, r7, #1 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r11, r10, r6, r8 + + ands r10, r7, #0xff ; test loop counter + + add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0, #-2] ; load data for next loop + usat lr, #8, lr, asr #7 + add r11, r11, #0x40 + ldrneb r9, [r0, #-1] + usat r11, #8, r11, asr #7 + + strh lr, [r1], r12 ; result is transposed and stored, which + ; will make second pass filtering easier. + ldrneb r10, [r0], #2 + strh r11, [r1], r12 + + bne width_loop_1st_16_6 + + ldr r1, [sp] ; load and update dst address + subs r7, r7, #0x10000 + add r0, r0, r2 ; move to next input line + + add r11, r2, #34 ; adding back block width(=16) + pld [r0, r11] ; preload next low + + add r1, r1, #2 ; move over to next column + str r1, [sp] + + bne height_loop_1st_16_6 + + add sp, sp, #4 + ldmia sp!, {r4 - r11, pc} + + ENDP + +; -------------------------- +; 8x8 version +; ----------------------------- +|vp8_filter_block2d_first_pass_8x8_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r7, [sp, #36] ; output height + + add r4, r2, #10 ; preload next low + pld [r0, r4] + + sub r2, r2, r3 ; inside loop increments input array, + ; so the height loop only needs to add + ; r2 - width to the input pointer + + mov r3, r3, lsl #1 ; multiply width by 2 because using shorts + add r12, r3, #16 ; square off the output + sub sp, sp, #4 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + str r1, [sp] ; push destination to stack + mov r7, r7, lsl #16 ; height is top part of counter + +; six tap filter +|height_loop_1st_8_6| + ldrb r8, [r0, #-2] ; load source data + ldrb r9, [r0, #-1] + ldrb r10, [r0], #2 + orr r7, r7, r3, lsr #2 ; construct loop counter + +|width_loop_1st_8_6| + ldrb r11, [r0, #-1] + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0] + + smuad lr, lr, r4 ; apply the filter + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + smuad r8, r8, r4 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0, #1] + smlad r8, r11, r5, r8 + ldrb r11, [r0, #2] + + sub r7, r7, #1 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r11, r10, r6, r8 + + ands r10, r7, #0xff ; test loop counter + + add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0, #-2] ; load data for next loop + usat lr, #8, lr, asr #7 + add r11, r11, #0x40 + ldrneb r9, [r0, #-1] + usat r11, #8, r11, asr #7 + + strh lr, [r1], r12 ; result is transposed and stored, which + ; will make second pass filtering easier. + ldrneb r10, [r0], #2 + strh r11, [r1], r12 + + bne width_loop_1st_8_6 + + ldr r1, [sp] ; load and update dst address + subs r7, r7, #0x10000 + add r0, r0, r2 ; move to next input line + + add r11, r2, #18 ; adding back block width(=8) + pld [r0, r11] ; preload next low + + add r1, r1, #2 ; move over to next column + str r1, [sp] + + bne height_loop_1st_8_6 + + add sp, sp, #4 + ldmia sp!, {r4 - r11, pc} + + ENDP + +;--------------------------------- +; r0 short *src_ptr, +; r1 unsigned char *output_ptr, +; r2 unsigned int output_pitch, +; r3 unsigned int cnt, +; stack const short *vp8_filter +;--------------------------------- +|vp8_filter_block2d_second_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #36] ; vp8_filter address + sub sp, sp, #4 + mov r7, r3, lsl #16 ; height is top part of counter + str r1, [sp] ; push destination to stack + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + pkhbt r12, r5, r4 ; pack the filter differently + pkhbt r11, r6, r5 + + sub r0, r0, #4 ; offset input buffer + +|height_loop_2nd| + ldr r8, [r0] ; load the data + ldr r9, [r0, #4] + orr r7, r7, r3, lsr #1 ; loop counter + +|width_loop_2nd| + smuad lr, r4, r8 ; apply filter + sub r7, r7, #1 + smulbt r8, r4, r8 + + ldr r10, [r0, #8] + + smlad lr, r5, r9, lr + smladx r8, r12, r9, r8 + + ldrh r9, [r0, #12] + + smlad lr, r6, r10, lr + smladx r8, r11, r10, r8 + + add r0, r0, #4 + smlatb r10, r6, r9, r8 + + add lr, lr, #0x40 ; round_shift_and_clamp + ands r8, r7, #0xff + usat lr, #8, lr, asr #7 + add r10, r10, #0x40 + strb lr, [r1], r2 ; the result is transposed back and stored + usat r10, #8, r10, asr #7 + + ldrne r8, [r0] ; load data for next loop + ldrne r9, [r0, #4] + strb r10, [r1], r2 + + bne width_loop_2nd + + ldr r1, [sp] ; update dst for next loop + subs r7, r7, #0x10000 + add r0, r0, #16 ; updata src for next loop + add r1, r1, #1 + str r1, [sp] + + bne height_loop_2nd + + add sp, sp, #4 + ldmia sp!, {r4 - r11, pc} + + ENDP + +;--------------------------------- +; r0 short *src_ptr, +; r1 unsigned char *output_ptr, +; r2 unsigned int output_pitch, +; r3 unsigned int cnt, +; stack const short *vp8_filter +;--------------------------------- +|vp8_filter4_block2d_second_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #36] ; vp8_filter address + mov r7, r3, lsl #16 ; height is top part of counter + + ldr r4, [r11] ; load up packed filter coefficients + add lr, r1, r3 ; save final destination pointer + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + pkhbt r12, r5, r4 ; pack the filter differently + pkhbt r11, r6, r5 + mov r4, #0x40 ; rounding factor (for smlad{x}) + +|height_loop_2nd_4| + ldrd r8, [r0, #-4] ; load the data + orr r7, r7, r3, lsr #1 ; loop counter + +|width_loop_2nd_4| + ldr r10, [r0, #4]! + smladx r6, r9, r12, r4 ; apply filter + pkhbt r8, r9, r8 + smlad r5, r8, r12, r4 + pkhbt r8, r10, r9 + smladx r6, r10, r11, r6 + sub r7, r7, #1 + smlad r5, r8, r11, r5 + + mov r8, r9 ; shift the data for the next loop + mov r9, r10 + + usat r6, #8, r6, asr #7 ; shift and clamp + usat r5, #8, r5, asr #7 + + strb r5, [r1], r2 ; the result is transposed back and stored + tst r7, #0xff + strb r6, [r1], r2 + + bne width_loop_2nd_4 + + subs r7, r7, #0x10000 + add r0, r0, #16 ; update src for next loop + sub r1, lr, r7, lsr #16 ; update dst for next loop + + bne height_loop_2nd_4 + + ldmia sp!, {r4 - r11, pc} + + ENDP + +;------------------------------------ +; r0 unsigned char *src_ptr +; r1 unsigned char *output_ptr, +; r2 unsigned int src_pixels_per_line +; r3 unsigned int cnt, +; stack unsigned int output_pitch, +; stack const short *vp8_filter +;------------------------------------ +|vp8_filter_block2d_first_pass_only_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + add r7, r2, r3 ; preload next low + add r7, r7, #2 + pld [r0, r7] + + ldr r4, [sp, #36] ; output pitch + ldr r11, [sp, #40] ; HFilter address + sub sp, sp, #8 + + mov r7, r3 + sub r2, r2, r3 ; inside loop increments input array, + ; so the height loop only needs to add + ; r2 - width to the input pointer + + sub r4, r4, r3 + str r4, [sp] ; save modified output pitch + str r2, [sp, #4] + + mov r2, #0x40 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + +; six tap filter +|height_loop_1st_only_6| + ldrb r8, [r0, #-2] ; load data + ldrb r9, [r0, #-1] + ldrb r10, [r0], #2 + + mov r12, r3, lsr #1 ; loop counter + +|width_loop_1st_only_6| + ldrb r11, [r0, #-1] + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0] + +;; smuad lr, lr, r4 + smlad lr, lr, r4, r2 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 +;; smuad r8, r8, r4 + smlad r8, r8, r4, r2 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0, #1] + smlad r8, r11, r5, r8 + ldrb r11, [r0, #2] + + subs r12, r12, #1 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r10, r10, r6, r8 + +;; add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0, #-2] ; load data for next loop + usat lr, #8, lr, asr #7 +;; add r10, r10, #0x40 + strb lr, [r1], #1 ; store the result + usat r10, #8, r10, asr #7 + + ldrneb r9, [r0, #-1] + strb r10, [r1], #1 + ldrneb r10, [r0], #2 + + bne width_loop_1st_only_6 + + ldr lr, [sp] ; load back output pitch + ldr r12, [sp, #4] ; load back output pitch + subs r7, r7, #1 + add r0, r0, r12 ; updata src for next loop + + add r11, r12, r3 ; preload next low + add r11, r11, #2 + pld [r0, r11] + + add r1, r1, lr ; update dst for next loop + + bne height_loop_1st_only_6 + + add sp, sp, #8 + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_filter_block2d_first_pass_only_armv6| + + +;------------------------------------ +; r0 unsigned char *src_ptr, +; r1 unsigned char *output_ptr, +; r2 unsigned int src_pixels_per_line +; r3 unsigned int cnt, +; stack unsigned int output_pitch, +; stack const short *vp8_filter +;------------------------------------ +|vp8_filter_block2d_second_pass_only_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; VFilter address + ldr r12, [sp, #36] ; output pitch + + mov r7, r3, lsl #16 ; height is top part of counter + sub r0, r0, r2, lsl #1 ; need 6 elements for filtering, 2 before, 3 after + + sub sp, sp, #8 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + str r0, [sp] ; save r0 to stack + str r1, [sp, #4] ; save dst to stack + +; six tap filter +|width_loop_2nd_only_6| + ldrb r8, [r0], r2 ; load data + orr r7, r7, r3 ; loop counter + ldrb r9, [r0], r2 + ldrb r10, [r0], r2 + +|height_loop_2nd_only_6| + ; filter first column in this inner loop, than, move to next colum. + ldrb r11, [r0], r2 + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0], r2 + + smuad lr, lr, r4 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + smuad r8, r8, r4 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0], r2 + smlad r8, r11, r5, r8 + ldrb r11, [r0] + + sub r7, r7, #2 + sub r0, r0, r2, lsl #2 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r10, r10, r6, r8 + + ands r9, r7, #0xff + + add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0], r2 ; load data for next loop + usat lr, #8, lr, asr #7 + add r10, r10, #0x40 + strb lr, [r1], r12 ; store the result for the column + usat r10, #8, r10, asr #7 + + ldrneb r9, [r0], r2 + strb r10, [r1], r12 + ldrneb r10, [r0], r2 + + bne height_loop_2nd_only_6 + + ldr r0, [sp] + ldr r1, [sp, #4] + subs r7, r7, #0x10000 + add r0, r0, #1 ; move to filter next column + str r0, [sp] + add r1, r1, #1 + str r1, [sp, #4] + + bne width_loop_2nd_only_6 + + add sp, sp, #8 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_filter_block2d_second_pass_only_armv6| + + END diff --git a/vp8/common/arm/armv6/idct_blk_v6.c b/vp8/common/arm/armv6/idct_blk_v6.c new file mode 100644 index 0000000..6002c0f --- /dev/null +++ b/vp8/common/arm/armv6/idct_blk_v6.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" + + +void vp8_dequant_idct_add_y_block_v6(short *q, short *dq, + unsigned char *dst, + int stride, char *eobs) +{ + int i; + + for (i = 0; i < 4; i++) + { + if (eobs[0] > 1) + vp8_dequant_idct_add_v6 (q, dq, dst, stride); + else if (eobs[0] == 1) + { + vp8_dc_only_idct_add_v6 (q[0]*dq[0], dst, stride, dst, stride); + ((int *)q)[0] = 0; + } + + if (eobs[1] > 1) + vp8_dequant_idct_add_v6 (q+16, dq, dst+4, stride); + else if (eobs[1] == 1) + { + vp8_dc_only_idct_add_v6 (q[16]*dq[0], dst+4, stride, dst+4, stride); + ((int *)(q+16))[0] = 0; + } + + if (eobs[2] > 1) + vp8_dequant_idct_add_v6 (q+32, dq, dst+8, stride); + else if (eobs[2] == 1) + { + vp8_dc_only_idct_add_v6 (q[32]*dq[0], dst+8, stride, dst+8, stride); + ((int *)(q+32))[0] = 0; + } + + if (eobs[3] > 1) + vp8_dequant_idct_add_v6 (q+48, dq, dst+12, stride); + else if (eobs[3] == 1) + { + vp8_dc_only_idct_add_v6 (q[48]*dq[0], dst+12, stride,dst+12,stride); + ((int *)(q+48))[0] = 0; + } + + q += 64; + dst += 4*stride; + eobs += 4; + } +} + +void vp8_dequant_idct_add_uv_block_v6(short *q, short *dq, + unsigned char *dstu, + unsigned char *dstv, + int stride, char *eobs) +{ + int i; + + for (i = 0; i < 2; i++) + { + if (eobs[0] > 1) + vp8_dequant_idct_add_v6 (q, dq, dstu, stride); + else if (eobs[0] == 1) + { + vp8_dc_only_idct_add_v6 (q[0]*dq[0], dstu, stride, dstu, stride); + ((int *)q)[0] = 0; + } + + if (eobs[1] > 1) + vp8_dequant_idct_add_v6 (q+16, dq, dstu+4, stride); + else if (eobs[1] == 1) + { + vp8_dc_only_idct_add_v6 (q[16]*dq[0], dstu+4, stride, + dstu+4, stride); + ((int *)(q+16))[0] = 0; + } + + q += 32; + dstu += 4*stride; + eobs += 2; + } + + for (i = 0; i < 2; i++) + { + if (eobs[0] > 1) + vp8_dequant_idct_add_v6 (q, dq, dstv, stride); + else if (eobs[0] == 1) + { + vp8_dc_only_idct_add_v6 (q[0]*dq[0], dstv, stride, dstv, stride); + ((int *)q)[0] = 0; + } + + if (eobs[1] > 1) + vp8_dequant_idct_add_v6 (q+16, dq, dstv+4, stride); + else if (eobs[1] == 1) + { + vp8_dc_only_idct_add_v6 (q[16]*dq[0], dstv+4, stride, + dstv+4, stride); + ((int *)(q+16))[0] = 0; + } + + q += 32; + dstv += 4*stride; + eobs += 2; + } +} diff --git a/vp8/common/arm/armv6/idct_v6.asm b/vp8/common/arm/armv6/idct_v6.asm new file mode 100644 index 0000000..b4d44cb --- /dev/null +++ b/vp8/common/arm/armv6/idct_v6.asm @@ -0,0 +1,202 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_short_idct4x4llm_v6_dual| + + AREA |.text|, CODE, READONLY + + +; void vp8_short_idct4x4llm_c(short *input, unsigned char *pred, int pitch, +; unsigned char *dst, int stride) +; r0 short* input +; r1 unsigned char* pred +; r2 int pitch +; r3 unsigned char* dst +; sp int stride + +|vp8_short_idct4x4llm_v6_dual| PROC + stmdb sp!, {r4-r11, lr} + + sub sp, sp, #4 + + mov r4, #0x00008A00 ; sin + orr r4, r4, #0x0000008C ; sinpi8sqrt2 + + mov r5, #0x00004E00 ; cos + orr r5, r5, #0x0000007B ; cospi8sqrt2minus1 + orr r5, r5, #1<<31 ; loop counter on top bit + +loop1_dual + ldr r6, [r0, #(4*2)] ; i5 | i4 + ldr r12, [r0, #(12*2)] ; i13|i12 + ldr r14, [r0, #(8*2)] ; i9 | i8 + + smulbt r9, r5, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 + smulbb r7, r5, r6 ; (ip[4] * cospi8sqrt2minus1) >> 16 + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 + smulwb r8, r4, r6 ; (ip[4] * sinpi8sqrt2) >> 16 + + smulbt r11, r5, r12 ; (ip[13] * cospi8sqrt2minus1) >> 16 + pkhtb r7, r9, r7, asr #16 ; 5c | 4c + pkhbt r8, r8, r10, lsl #16 ; 5s | 4s + uadd16 r6, r6, r7 ; 5c+5 | 4c+4 + + smulwt r7, r4, r12 ; (ip[13] * sinpi8sqrt2) >> 16 + smulbb r9, r5, r12 ; (ip[12] * cospi8sqrt2minus1) >> 16 + smulwb r10, r4, r12 ; (ip[12] * sinpi8sqrt2) >> 16 + + subs r5, r5, #1<<31 ; i-- + + pkhtb r9, r11, r9, asr #16 ; 13c | 12c + ldr r11, [r0] ; i1 | i0 + pkhbt r10, r10, r7, lsl #16 ; 13s | 12s + uadd16 r7, r12, r9 ; 13c+13 | 12c+12 + + usub16 r7, r8, r7 ; c + uadd16 r6, r6, r10 ; d + uadd16 r10, r11, r14 ; a + usub16 r8, r11, r14 ; b + + uadd16 r9, r10, r6 ; a+d + usub16 r10, r10, r6 ; a-d + uadd16 r6, r8, r7 ; b+c + usub16 r7, r8, r7 ; b-c + + ; use input buffer to store intermediate results + str r6, [r0, #(4*2)] ; o5 | o4 + str r7, [r0, #(8*2)] ; o9 | o8 + str r10,[r0, #(12*2)] ; o13|o12 + str r9, [r0], #4 ; o1 | o0 + + bcs loop1_dual + + sub r0, r0, #8 ; reset input/output + str r0, [sp] + +loop2_dual + + ldr r6, [r0, #(4*2)] ; i5 | i4 + ldr r12,[r0, #(2*2)] ; i3 | i2 + ldr r14,[r0, #(6*2)] ; i7 | i6 + ldr r0, [r0, #(0*2)] ; i1 | i0 + + smulbt r9, r5, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 + smulbt r7, r5, r0 ; (ip[1] * cospi8sqrt2minus1) >> 16 + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 + smulwt r8, r4, r0 ; (ip[1] * sinpi8sqrt2) >> 16 + + pkhbt r11, r6, r0, lsl #16 ; i0 | i4 + pkhtb r7, r7, r9, asr #16 ; 1c | 5c + pkhtb r0, r0, r6, asr #16 ; i1 | i5 + pkhbt r8, r10, r8, lsl #16 ; 1s | 5s = temp1 + + uadd16 r0, r7, r0 ; 1c+1 | 5c+5 = temp2 + pkhbt r9, r14, r12, lsl #16 ; i2 | i6 + uadd16 r10, r11, r9 ; a + usub16 r9, r11, r9 ; b + pkhtb r6, r12, r14, asr #16 ; i3 | i7 + + subs r5, r5, #1<<31 ; i-- + + smulbt r7, r5, r6 ; (ip[3] * cospi8sqrt2minus1) >> 16 + smulwt r11, r4, r6 ; (ip[3] * sinpi8sqrt2) >> 16 + smulbb r12, r5, r6 ; (ip[7] * cospi8sqrt2minus1) >> 16 + smulwb r14, r4, r6 ; (ip[7] * sinpi8sqrt2) >> 16 + + pkhtb r7, r7, r12, asr #16 ; 3c | 7c + pkhbt r11, r14, r11, lsl #16 ; 3s | 7s = temp1 + + uadd16 r6, r7, r6 ; 3c+3 | 7c+7 = temp2 + usub16 r12, r8, r6 ; c (o1 | o5) + uadd16 r6, r11, r0 ; d (o3 | o7) + uadd16 r7, r10, r6 ; a+d + + mov r8, #4 ; set up 4's + orr r8, r8, #0x40000 ; 4|4 + + usub16 r6, r10, r6 ; a-d + uadd16 r6, r6, r8 ; a-d+4, 3|7 + uadd16 r7, r7, r8 ; a+d+4, 0|4 + uadd16 r10, r9, r12 ; b+c + usub16 r0, r9, r12 ; b-c + uadd16 r10, r10, r8 ; b+c+4, 1|5 + uadd16 r8, r0, r8 ; b-c+4, 2|6 + + ldr lr, [sp, #40] ; dst stride + + ldrb r0, [r1] ; pred p0 + ldrb r11, [r1, #1] ; pred p1 + ldrb r12, [r1, #2] ; pred p2 + + add r0, r0, r7, asr #19 ; p0 + o0 + add r11, r11, r10, asr #19 ; p1 + o1 + add r12, r12, r8, asr #19 ; p2 + o2 + + usat r0, #8, r0 ; d0 = clip8(p0 + o0) + usat r11, #8, r11 ; d1 = clip8(p1 + o1) + usat r12, #8, r12 ; d2 = clip8(p2 + o2) + + add r0, r0, r11, lsl #8 ; |--|--|d1|d0| + + ldrb r11, [r1, #3] ; pred p3 + + add r0, r0, r12, lsl #16 ; |--|d2|d1|d0| + + add r11, r11, r6, asr #19 ; p3 + o3 + + sxth r7, r7 ; + sxth r10, r10 ; + + usat r11, #8, r11 ; d3 = clip8(p3 + o3) + + sxth r8, r8 ; + sxth r6, r6 ; + + add r0, r0, r11, lsl #24 ; |d3|d2|d1|d0| + + ldrb r12, [r1, r2]! ; pred p4 + str r0, [r3], lr + ldrb r11, [r1, #1] ; pred p5 + + add r12, r12, r7, asr #3 ; p4 + o4 + add r11, r11, r10, asr #3 ; p5 + o5 + + usat r12, #8, r12 ; d4 = clip8(p4 + o4) + usat r11, #8, r11 ; d5 = clip8(p5 + o5) + + ldrb r7, [r1, #2] ; pred p6 + ldrb r10, [r1, #3] ; pred p6 + + add r12, r12, r11, lsl #8 ; |--|--|d5|d4| + + add r7, r7, r8, asr #3 ; p6 + o6 + add r10, r10, r6, asr #3 ; p7 + o7 + + ldr r0, [sp] ; load input pointer + + usat r7, #8, r7 ; d6 = clip8(p6 + o6) + usat r10, #8, r10 ; d7 = clip8(p7 + o7) + + add r12, r12, r7, lsl #16 ; |--|d6|d5|d4| + add r12, r12, r10, lsl #24 ; |d7|d6|d5|d4| + + str r12, [r3], lr + add r0, r0, #16 + add r1, r1, r2 ; pred + pitch + + bcs loop2_dual + + add sp, sp, #4 ; idct_output buffer + ldmia sp!, {r4 - r11, pc} + + ENDP + + END diff --git a/vp8/common/arm/armv6/intra4x4_predict_v6.asm b/vp8/common/arm/armv6/intra4x4_predict_v6.asm new file mode 100644 index 0000000..a974cd1 --- /dev/null +++ b/vp8/common/arm/armv6/intra4x4_predict_v6.asm @@ -0,0 +1,606 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_intra4x4_predict_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + + +;void vp8_intra4x4_predict(unsigned char *src, int src_stride, int b_mode, +; unsigned char *dst, int dst_stride) + +|vp8_intra4x4_predict_armv6| PROC + push {r4-r12, lr} + + + cmp r2, #10 + addlt pc, pc, r2, lsl #2 ; position independent switch + pop {r4-r12, pc} ; default + b b_dc_pred + b b_tm_pred + b b_ve_pred + b b_he_pred + b b_ld_pred + b b_rd_pred + b b_vr_pred + b b_vl_pred + b b_hd_pred + b b_hu_pred + +b_dc_pred + ; load values + ldr r8, [r0, -r1] ; Above + ldrb r4, [r0, #-1]! ; Left[0] + mov r9, #0 + ldrb r5, [r0, r1] ; Left[1] + ldrb r6, [r0, r1, lsl #1]! ; Left[2] + usad8 r12, r8, r9 + ldrb r7, [r0, r1] ; Left[3] + + ; calculate dc + add r4, r4, r5 + add r4, r4, r6 + add r4, r4, r7 + add r4, r4, r12 + add r4, r4, #4 + ldr r0, [sp, #40] ; load stride + mov r12, r4, asr #3 ; (expected_dc + 4) >> 3 + + add r12, r12, r12, lsl #8 + add r3, r3, r0 + add r12, r12, r12, lsl #16 + + ; store values + str r12, [r3, -r0] + str r12, [r3] + str r12, [r3, r0] + str r12, [r3, r0, lsl #1] + + pop {r4-r12, pc} + +b_tm_pred + sub r10, r0, #1 ; Left + ldr r8, [r0, -r1] ; Above + ldrb r9, [r10, -r1] ; top_left + ldrb r4, [r0, #-1]! ; Left[0] + ldrb r5, [r10, r1]! ; Left[1] + ldrb r6, [r0, r1, lsl #1] ; Left[2] + ldrb r7, [r10, r1, lsl #1] ; Left[3] + ldr r0, [sp, #40] ; load stride + + + add r9, r9, r9, lsl #16 ; [tl|tl] + uxtb16 r10, r8 ; a[2|0] + uxtb16 r11, r8, ror #8 ; a[3|1] + ssub16 r10, r10, r9 ; a[2|0] - [tl|tl] + ssub16 r11, r11, r9 ; a[3|1] - [tl|tl] + + add r4, r4, r4, lsl #16 ; l[0|0] + add r5, r5, r5, lsl #16 ; l[1|1] + add r6, r6, r6, lsl #16 ; l[2|2] + add r7, r7, r7, lsl #16 ; l[3|3] + + sadd16 r1, r4, r10 ; l[0|0] + a[2|0] - [tl|tl] + sadd16 r2, r4, r11 ; l[0|0] + a[3|1] - [tl|tl] + usat16 r1, #8, r1 + usat16 r2, #8, r2 + + sadd16 r4, r5, r10 ; l[1|1] + a[2|0] - [tl|tl] + sadd16 r5, r5, r11 ; l[1|1] + a[3|1] - [tl|tl] + + add r12, r1, r2, lsl #8 ; [3|2|1|0] + str r12, [r3], r0 + + usat16 r4, #8, r4 + usat16 r5, #8, r5 + + sadd16 r1, r6, r10 ; l[2|2] + a[2|0] - [tl|tl] + sadd16 r2, r6, r11 ; l[2|2] + a[3|1] - [tl|tl] + + add r12, r4, r5, lsl #8 ; [3|2|1|0] + str r12, [r3], r0 + + usat16 r1, #8, r1 + usat16 r2, #8, r2 + + sadd16 r4, r7, r10 ; l[3|3] + a[2|0] - [tl|tl] + sadd16 r5, r7, r11 ; l[3|3] + a[3|1] - [tl|tl] + + add r12, r1, r2, lsl #8 ; [3|2|1|0] + + usat16 r4, #8, r4 + usat16 r5, #8, r5 + + str r12, [r3], r0 + + add r12, r4, r5, lsl #8 ; [3|2|1|0] + str r12, [r3], r0 + + pop {r4-r12, pc} + +b_ve_pred + ldr r8, [r0, -r1]! ; a[3|2|1|0] + ldr r11, c00FF00FF + ldrb r9, [r0, #-1] ; top_left + ldrb r10, [r0, #4] ; a[4] + + ldr r0, c00020002 + + uxtb16 r4, r8 ; a[2|0] + uxtb16 r5, r8, ror #8 ; a[3|1] + ldr r2, [sp, #40] ; stride + pkhbt r9, r9, r5, lsl #16 ; a[1|-1] + + add r9, r9, r4, lsl #1 ;[a[1]+2*a[2] | tl+2*a[0] ] + uxtab16 r9, r9, r5 ;[a[1]+2*a[2]+a[3] | tl+2*a[0]+a[1] ] + uxtab16 r9, r9, r0 ;[a[1]+2*a[2]+a[3]+2| tl+2*a[0]+a[1]+2] + + add r0, r0, r10, lsl #16 ;[a[4]+2 | 2] + add r0, r0, r4, asr #16 ;[a[4]+2 | a[2]+2] + add r0, r0, r5, lsl #1 ;[a[4]+2*a[3]+2 | a[2]+2*a[1]+2] + uadd16 r4, r4, r0 ;[a[4]+2*a[3]+a[2]+2|a[2]+2*a[1]+a[0]+2] + + and r9, r11, r9, asr #2 + and r4, r11, r4, asr #2 + add r3, r3, r2 ; dst + dst_stride + add r9, r9, r4, lsl #8 + + ; store values + str r9, [r3, -r2] + str r9, [r3] + str r9, [r3, r2] + str r9, [r3, r2, lsl #1] + + pop {r4-r12, pc} + + +b_he_pred + sub r10, r0, #1 ; Left + ldrb r4, [r0, #-1]! ; Left[0] + ldrb r8, [r10, -r1] ; top_left + ldrb r5, [r10, r1]! ; Left[1] + ldrb r6, [r0, r1, lsl #1] ; Left[2] + ldrb r7, [r10, r1, lsl #1] ; Left[3] + + add r8, r8, r4 ; tl + l[0] + add r9, r4, r5 ; l[0] + l[1] + add r10, r5, r6 ; l[1] + l[2] + add r11, r6, r7 ; l[2] + l[3] + + mov r0, #2<<14 + + add r8, r8, r9 ; tl + 2*l[0] + l[1] + add r4, r9, r10 ; l[0] + 2*l[1] + l[2] + add r5, r10, r11 ; l[1] + 2*l[2] + l[3] + add r6, r11, r7, lsl #1 ; l[2] + 2*l[3] + l[3] + + + add r8, r0, r8, lsl #14 ; (tl + 2*l[0] + l[1])>>2 in top half + add r9, r0, r4, lsl #14 ; (l[0] + 2*l[1] + l[2])>>2 in top half + add r10,r0, r5, lsl #14 ; (l[1] + 2*l[2] + l[3])>>2 in top half + add r11,r0, r6, lsl #14 ; (l[2] + 2*l[3] + l[3])>>2 in top half + + pkhtb r8, r8, r8, asr #16 ; l[-|0|-|0] + pkhtb r9, r9, r9, asr #16 ; l[-|1|-|1] + pkhtb r10, r10, r10, asr #16 ; l[-|2|-|2] + pkhtb r11, r11, r11, asr #16 ; l[-|3|-|3] + + ldr r0, [sp, #40] ; stride + + add r8, r8, r8, lsl #8 ; l[0|0|0|0] + add r9, r9, r9, lsl #8 ; l[1|1|1|1] + add r10, r10, r10, lsl #8 ; l[2|2|2|2] + add r11, r11, r11, lsl #8 ; l[3|3|3|3] + + ; store values + str r8, [r3], r0 + str r9, [r3] + str r10, [r3, r0] + str r11, [r3, r0, lsl #1] + + pop {r4-r12, pc} + +b_ld_pred + ldr r4, [r0, -r1]! ; Above + ldr r12, c00020002 + ldr r5, [r0, #4] + ldr lr, c00FF00FF + + uxtb16 r6, r4 ; a[2|0] + uxtb16 r7, r4, ror #8 ; a[3|1] + uxtb16 r8, r5 ; a[6|4] + uxtb16 r9, r5, ror #8 ; a[7|5] + pkhtb r10, r6, r8 ; a[2|4] + pkhtb r11, r7, r9 ; a[3|5] + + + add r4, r6, r7, lsl #1 ; [a2+2*a3 | a0+2*a1] + add r4, r4, r10, ror #16 ; [a2+2*a3+a4 | a0+2*a1+a2] + uxtab16 r4, r4, r12 ; [a2+2*a3+a4+2 | a0+2*a1+a2+2] + + add r5, r7, r10, ror #15 ; [a3+2*a4 | a1+2*a2] + add r5, r5, r11, ror #16 ; [a3+2*a4+a5 | a1+2*a2+a3] + uxtab16 r5, r5, r12 ; [a3+2*a4+a5+2 | a1+2*a2+a3+2] + + pkhtb r7, r9, r8, asr #16 + add r6, r8, r9, lsl #1 ; [a6+2*a7 | a4+2*a5] + uadd16 r6, r6, r7 ; [a6+2*a7+a7 | a4+2*a5+a6] + uxtab16 r6, r6, r12 ; [a6+2*a7+a7+2 | a4+2*a5+a6+2] + + uxth r7, r9 ; [ a5] + add r7, r7, r8, asr #15 ; [ a5+2*a6] + add r7, r7, r9, asr #16 ; [ a5+2*a6+a7] + uxtah r7, r7, r12 ; [ a5+2*a6+a7+2] + + ldr r0, [sp, #40] ; stride + + ; scale down + and r4, lr, r4, asr #2 + and r5, lr, r5, asr #2 + and r6, lr, r6, asr #2 + mov r7, r7, asr #2 + + add r8, r4, r5, lsl #8 ; [3|2|1|0] + str r8, [r3], r0 + + mov r9, r8, lsr #8 + add r9, r9, r6, lsl #24 ; [4|3|2|1] + str r9, [r3], r0 + + mov r10, r9, lsr #8 + add r10, r10, r7, lsl #24 ; [5|4|3|2] + str r10, [r3], r0 + + mov r6, r6, lsr #16 + mov r11, r10, lsr #8 + add r11, r11, r6, lsl #24 ; [6|5|4|3] + str r11, [r3], r0 + + pop {r4-r12, pc} + +b_rd_pred + sub r12, r0, r1 ; Above = src - src_stride + ldrb r7, [r0, #-1]! ; l[0] = pp[3] + ldr lr, [r12] ; Above = pp[8|7|6|5] + ldrb r8, [r12, #-1]! ; tl = pp[4] + ldrb r6, [r12, r1, lsl #1] ; l[1] = pp[2] + ldrb r5, [r0, r1, lsl #1] ; l[2] = pp[1] + ldrb r4, [r12, r1, lsl #2] ; l[3] = pp[0] + + + uxtb16 r9, lr ; p[7|5] + uxtb16 r10, lr, ror #8 ; p[8|6] + add r4, r4, r6, lsl #16 ; p[2|0] + add r5, r5, r7, lsl #16 ; p[3|1] + add r6, r6, r8, lsl #16 ; p[4|2] + pkhbt r7, r7, r9, lsl #16 ; p[5|3] + pkhbt r8, r8, r10, lsl #16 ; p[6|4] + + ldr r12, c00020002 + ldr lr, c00FF00FF + + add r4, r4, r5, lsl #1 ; [p2+2*p3 | p0+2*p1] + add r4, r4, r6 ; [p2+2*p3+p4 | p0+2*p1+p2] + uxtab16 r4, r4, r12 ; [p2+2*p3+p4+2 | p0+2*p1+p2+2] + + add r5, r5, r6, lsl #1 ; [p3+2*p4 | p1+2*p2] + add r5, r5, r7 ; [p3+2*p4+p5 | p1+2*p2+p3] + uxtab16 r5, r5, r12 ; [p3+2*p4+p5+2 | p1+2*p2+p3+2] + + add r6, r7, r8, lsl #1 ; [p5+2*p6 | p3+2*p4] + add r6, r6, r9 ; [p5+2*p6+p7 | p3+2*p4+p5] + uxtab16 r6, r6, r12 ; [p5+2*p6+p7+2 | p3+2*p4+p5+2] + + add r7, r8, r9, lsl #1 ; [p6+2*p7 | p4+2*p5] + add r7, r7, r10 ; [p6+2*p7+p8 | p4+2*p5+p6] + uxtab16 r7, r7, r12 ; [p6+2*p7+p8+2 | p4+2*p5+p6+2] + + ldr r0, [sp, #40] ; stride + + ; scale down + and r7, lr, r7, asr #2 + and r6, lr, r6, asr #2 + and r5, lr, r5, asr #2 + and r4, lr, r4, asr #2 + + add r8, r6, r7, lsl #8 ; [6|5|4|3] + str r8, [r3], r0 + + mov r9, r8, lsl #8 ; [5|4|3|-] + uxtab r9, r9, r4, ror #16 ; [5|4|3|2] + str r9, [r3], r0 + + mov r10, r9, lsl #8 ; [4|3|2|-] + uxtab r10, r10, r5 ; [4|3|2|1] + str r10, [r3], r0 + + mov r11, r10, lsl #8 ; [3|2|1|-] + uxtab r11, r11, r4 ; [3|2|1|0] + str r11, [r3], r0 + + pop {r4-r12, pc} + +b_vr_pred + sub r12, r0, r1 ; Above = src - src_stride + ldrb r7, [r0, #-1]! ; l[0] = pp[3] + ldr lr, [r12] ; Above = pp[8|7|6|5] + ldrb r8, [r12, #-1]! ; tl = pp[4] + ldrb r6, [r12, r1, lsl #1] ; l[1] = pp[2] + ldrb r5, [r0, r1, lsl #1] ; l[2] = pp[1] + ldrb r4, [r12, r1, lsl #2] ; l[3] = pp[0] + + add r5, r5, r7, lsl #16 ; p[3|1] + add r6, r6, r8, lsl #16 ; p[4|2] + uxtb16 r9, lr ; p[7|5] + uxtb16 r10, lr, ror #8 ; p[8|6] + pkhbt r7, r7, r9, lsl #16 ; p[5|3] + pkhbt r8, r8, r10, lsl #16 ; p[6|4] + + ldr r4, c00010001 + ldr r12, c00020002 + ldr lr, c00FF00FF + + add r5, r5, r6, lsl #1 ; [p3+2*p4 | p1+2*p2] + add r5, r5, r7 ; [p3+2*p4+p5 | p1+2*p2+p3] + uxtab16 r5, r5, r12 ; [p3+2*p4+p5+2 | p1+2*p2+p3+2] + + add r6, r6, r7, lsl #1 ; [p4+2*p5 | p2+2*p3] + add r6, r6, r8 ; [p4+2*p5+p6 | p2+2*p3+p4] + uxtab16 r6, r6, r12 ; [p4+2*p5+p6+2 | p2+2*p3+p4+2] + + uadd16 r11, r8, r9 ; [p6+p7 | p4+p5] + uhadd16 r11, r11, r4 ; [(p6+p7+1)>>1 | (p4+p5+1)>>1] + ; [F|E] + + add r7, r7, r8, lsl #1 ; [p5+2*p6 | p3+2*p4] + add r7, r7, r9 ; [p5+2*p6+p7 | p3+2*p4+p5] + uxtab16 r7, r7, r12 ; [p5+2*p6+p7+2 | p3+2*p4+p5+2] + + uadd16 r2, r9, r10 ; [p7+p8 | p5+p6] + uhadd16 r2, r2, r4 ; [(p7+p8+1)>>1 | (p5+p6+1)>>1] + ; [J|I] + + add r8, r8, r9, lsl #1 ; [p6+2*p7 | p4+2*p5] + add r8, r8, r10 ; [p6+2*p7+p8 | p4+2*p5+p6] + uxtab16 r8, r8, r12 ; [p6+2*p7+p8+2 | p4+2*p5+p6+2] + + ldr r0, [sp, #40] ; stride + + ; scale down + and r5, lr, r5, asr #2 ; [B|A] + and r6, lr, r6, asr #2 ; [D|C] + and r7, lr, r7, asr #2 ; [H|G] + and r8, lr, r8, asr #2 ; [L|K] + + add r12, r11, r2, lsl #8 ; [J|F|I|E] + str r12, [r3], r0 + + add r12, r7, r8, lsl #8 ; [L|H|K|G] + str r12, [r3], r0 + + pkhbt r2, r6, r2, lsl #16 ; [-|I|-|C] + add r2, r2, r11, lsl #8 ; [F|I|E|C] + + pkhtb r12, r6, r5 ; [-|D|-|A] + pkhtb r10, r7, r5, asr #16 ; [-|H|-|B] + str r2, [r3], r0 + add r12, r12, r10, lsl #8 ; [H|D|B|A] + str r12, [r3], r0 + + pop {r4-r12, pc} + +b_vl_pred + ldr r4, [r0, -r1]! ; [3|2|1|0] + ldr r12, c00020002 + ldr r5, [r0, #4] ; [7|6|5|4] + ldr lr, c00FF00FF + ldr r2, c00010001 + + mov r0, r4, lsr #16 ; [-|-|3|2] + add r0, r0, r5, lsl #16 ; [5|4|3|2] + uxtb16 r6, r4 ; [2|0] + uxtb16 r7, r4, ror #8 ; [3|1] + uxtb16 r8, r0 ; [4|2] + uxtb16 r9, r0, ror #8 ; [5|3] + uxtb16 r10, r5 ; [6|4] + uxtb16 r11, r5, ror #8 ; [7|5] + + uadd16 r4, r6, r7 ; [p2+p3 | p0+p1] + uhadd16 r4, r4, r2 ; [(p2+p3+1)>>1 | (p0+p1+1)>>1] + ; [B|A] + + add r5, r6, r7, lsl #1 ; [p2+2*p3 | p0+2*p1] + add r5, r5, r8 ; [p2+2*p3+p4 | p0+2*p1+p2] + uxtab16 r5, r5, r12 ; [p2+2*p3+p4+2 | p0+2*p1+p2+2] + + uadd16 r6, r7, r8 ; [p3+p4 | p1+p2] + uhadd16 r6, r6, r2 ; [(p3+p4+1)>>1 | (p1+p2+1)>>1] + ; [F|E] + + add r7, r7, r8, lsl #1 ; [p3+2*p4 | p1+2*p2] + add r7, r7, r9 ; [p3+2*p4+p5 | p1+2*p2+p3] + uxtab16 r7, r7, r12 ; [p3+2*p4+p5+2 | p1+2*p2+p3+2] + + add r8, r8, r9, lsl #1 ; [p4+2*p5 | p2+2*p3] + add r8, r8, r10 ; [p4+2*p5+p6 | p2+2*p3+p4] + uxtab16 r8, r8, r12 ; [p4+2*p5+p6+2 | p2+2*p3+p4+2] + + add r9, r9, r10, lsl #1 ; [p5+2*p6 | p3+2*p4] + add r9, r9, r11 ; [p5+2*p6+p7 | p3+2*p4+p5] + uxtab16 r9, r9, r12 ; [p5+2*p6+p7+2 | p3+2*p4+p5+2] + + ldr r0, [sp, #40] ; stride + + ; scale down + and r5, lr, r5, asr #2 ; [D|C] + and r7, lr, r7, asr #2 ; [H|G] + and r8, lr, r8, asr #2 ; [I|D] + and r9, lr, r9, asr #2 ; [J|H] + + + add r10, r4, r6, lsl #8 ; [F|B|E|A] + str r10, [r3], r0 + + add r5, r5, r7, lsl #8 ; [H|C|G|D] + str r5, [r3], r0 + + pkhtb r12, r8, r4, asr #16 ; [-|I|-|B] + pkhtb r10, r9, r8 ; [-|J|-|D] + + add r12, r6, r12, lsl #8 ; [I|F|B|E] + str r12, [r3], r0 + + add r10, r7, r10, lsl #8 ; [J|H|D|G] + str r10, [r3], r0 + + pop {r4-r12, pc} + +b_hd_pred + sub r12, r0, r1 ; Above = src - src_stride + ldrb r7, [r0, #-1]! ; l[0] = pp[3] + ldr lr, [r12] ; Above = pp[8|7|6|5] + ldrb r8, [r12, #-1]! ; tl = pp[4] + ldrb r6, [r0, r1] ; l[1] = pp[2] + ldrb r5, [r0, r1, lsl #1] ; l[2] = pp[1] + ldrb r4, [r12, r1, lsl #2] ; l[3] = pp[0] + + uxtb16 r9, lr ; p[7|5] + uxtb16 r10, lr, ror #8 ; p[8|6] + + add r4, r4, r5, lsl #16 ; p[1|0] + add r5, r5, r6, lsl #16 ; p[2|1] + add r6, r6, r7, lsl #16 ; p[3|2] + add r7, r7, r8, lsl #16 ; p[4|3] + + ldr r12, c00020002 + ldr lr, c00FF00FF + ldr r2, c00010001 + + pkhtb r8, r7, r9 ; p[4|5] + pkhtb r1, r9, r10 ; p[7|6] + pkhbt r10, r8, r10, lsl #16 ; p[6|5] + + + uadd16 r11, r4, r5 ; [p1+p2 | p0+p1] + uhadd16 r11, r11, r2 ; [(p1+p2+1)>>1 | (p0+p1+1)>>1] + ; [B|A] + + add r4, r4, r5, lsl #1 ; [p1+2*p2 | p0+2*p1] + add r4, r4, r6 ; [p1+2*p2+p3 | p0+2*p1+p2] + uxtab16 r4, r4, r12 ; [p1+2*p2+p3+2 | p0+2*p1+p2+2] + + uadd16 r0, r6, r7 ; [p3+p4 | p2+p3] + uhadd16 r0, r0, r2 ; [(p3+p4+1)>>1 | (p2+p3+1)>>1] + ; [F|E] + + add r5, r6, r7, lsl #1 ; [p3+2*p4 | p2+2*p3] + add r5, r5, r8, ror #16 ; [p3+2*p4+p5 | p2+2*p3+p4] + uxtab16 r5, r5, r12 ; [p3+2*p4+p5+2 | p2+2*p3+p4+2] + + add r6, r12, r8, ror #16 ; [p5+2 | p4+2] + add r6, r6, r10, lsl #1 ; [p5+2+2*p6 | p4+2+2*p5] + uxtab16 r6, r6, r1 ; [p5+2+2*p6+p7 | p4+2+2*p5+p6] + + ; scale down + and r4, lr, r4, asr #2 ; [D|C] + and r5, lr, r5, asr #2 ; [H|G] + and r6, lr, r6, asr #2 ; [J|I] + + ldr lr, [sp, #40] ; stride + + pkhtb r2, r0, r6 ; [-|F|-|I] + pkhtb r12, r6, r5, asr #16 ; [-|J|-|H] + add r12, r12, r2, lsl #8 ; [F|J|I|H] + add r2, r0, r5, lsl #8 ; [H|F|G|E] + mov r12, r12, ror #24 ; [J|I|H|F] + str r12, [r3], lr + + + mov r7, r11, asr #16 ; [-|-|-|B] + str r2, [r3], lr + add r7, r7, r0, lsl #16 ; [-|E|-|B] + add r7, r7, r4, asr #8 ; [-|E|D|B] + add r7, r7, r5, lsl #24 ; [G|E|D|B] + str r7, [r3], lr + + add r5, r11, r4, lsl #8 ; [D|B|C|A] + str r5, [r3], lr + + pop {r4-r12, pc} + + + +b_hu_pred + ldrb r4, [r0, #-1]! ; Left[0] + ldr r12, c00020002 + ldrb r5, [r0, r1]! ; Left[1] + ldr lr, c00FF00FF + ldrb r6, [r0, r1]! ; Left[2] + ldr r2, c00010001 + ldrb r7, [r0, r1] ; Left[3] + + + add r4, r4, r5, lsl #16 ; [1|0] + add r5, r5, r6, lsl #16 ; [2|1] + add r9, r6, r7, lsl #16 ; [3|2] + + uadd16 r8, r4, r5 ; [p1+p2 | p0+p1] + uhadd16 r8, r8, r2 ; [(p1+p2+1)>>1 | (p0+p1+1)>>1] + ; [B|A] + + add r4, r4, r5, lsl #1 ; [p1+2*p2 | p0+2*p1] + add r4, r4, r9 ; [p1+2*p2+p3 | p0+2*p1+p2] + uxtab16 r4, r4, r12 ; [p1+2*p2+p3+2 | p0+2*p1+p2+2] + ldr r2, [sp, #40] ; stride + and r4, lr, r4, asr #2 ; [D|C] + + add r10, r6, r7 ; [p2+p3] + add r11, r10, r7, lsl #1 ; [p2+3*p3] + add r10, r10, #1 + add r11, r11, #2 + mov r10, r10, asr #1 ; [E] + mov r11, r11, asr #2 ; [F] + + add r9, r7, r9, asr #8 ; [-|-|G|G] + add r0, r8, r4, lsl #8 ; [D|B|C|A] + add r7, r9, r9, lsl #16 ; [G|G|G|G] + + str r0, [r3], r2 + + mov r1, r8, asr #16 ; [-|-|-|B] + add r1, r1, r4, asr #8 ; [-|-|D|B] + add r1, r1, r10, lsl #16 ; [-|E|D|B] + add r1, r1, r11, lsl #24 ; [F|E|D|B] + str r1, [r3], r2 + + add r10, r11, lsl #8 ; [-|-|F|E] + add r10, r10, r9, lsl #16 ; [G|G|F|E] + str r10, [r3] + + str r7, [r3, r2] + + pop {r4-r12, pc} + + ENDP + +; constants +c00010001 + DCD 0x00010001 +c00020002 + DCD 0x00020002 +c00FF00FF + DCD 0x00FF00FF + + END diff --git a/vp8/common/arm/armv6/iwalsh_v6.asm b/vp8/common/arm/armv6/iwalsh_v6.asm new file mode 100644 index 0000000..31ef09c --- /dev/null +++ b/vp8/common/arm/armv6/iwalsh_v6.asm @@ -0,0 +1,136 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + EXPORT |vp8_short_inv_walsh4x4_v6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code + +;short vp8_short_inv_walsh4x4_v6(short *input, short *mb_dqcoeff) +|vp8_short_inv_walsh4x4_v6| PROC + + stmdb sp!, {r4 - r12, lr} + + ldr r2, [r0, #0] ; [1 | 0] + ldr r3, [r0, #4] ; [3 | 2] + ldr r4, [r0, #8] ; [5 | 4] + ldr r5, [r0, #12] ; [7 | 6] + ldr r6, [r0, #16] ; [9 | 8] + ldr r7, [r0, #20] ; [11 | 10] + ldr r8, [r0, #24] ; [13 | 12] + ldr r9, [r0, #28] ; [15 | 14] + + qadd16 r10, r2, r8 ; a1 [1+13 | 0+12] + qadd16 r11, r4, r6 ; b1 [5+9 | 4+8] + qsub16 r12, r4, r6 ; c1 [5-9 | 4-8] + qsub16 lr, r2, r8 ; d1 [1-13 | 0-12] + + qadd16 r2, r10, r11 ; a1 + b1 [1 | 0] + qadd16 r4, r12, lr ; c1 + d1 [5 | 4] + qsub16 r6, r10, r11 ; a1 - b1 [9 | 8] + qsub16 r8, lr, r12 ; d1 - c1 [13 | 12] + + qadd16 r10, r3, r9 ; a1 [3+15 | 2+14] + qadd16 r11, r5, r7 ; b1 [7+11 | 6+10] + qsub16 r12, r5, r7 ; c1 [7-11 | 6-10] + qsub16 lr, r3, r9 ; d1 [3-15 | 2-14] + + qadd16 r3, r10, r11 ; a1 + b1 [3 | 2] + qadd16 r5, r12, lr ; c1 + d1 [7 | 6] + qsub16 r7, r10, r11 ; a1 - b1 [11 | 10] + qsub16 r9, lr, r12 ; d1 - c1 [15 | 14] + + ; first transform complete + + qsubaddx r10, r2, r3 ; [c1|a1] [1-2 | 0+3] + qaddsubx r11, r2, r3 ; [b1|d1] [1+2 | 0-3] + qsubaddx r12, r4, r5 ; [c1|a1] [5-6 | 4+7] + qaddsubx lr, r4, r5 ; [b1|d1] [5+6 | 4-7] + + qaddsubx r2, r10, r11 ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r3, r11, r10 ; [a2|d2] [b1+a1 | d1-c1] + ldr r10, c0x00030003 + qaddsubx r4, r12, lr ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r5, lr, r12 ; [a2|d2] [b1+a1 | d1-c1] + + qadd16 r2, r2, r10 ; [b2+3|c2+3] + qadd16 r3, r3, r10 ; [a2+3|d2+3] + qadd16 r4, r4, r10 ; [b2+3|c2+3] + qadd16 r5, r5, r10 ; [a2+3|d2+3] + + asr r12, r3, #19 ; [0] + strh r12, [r1], #32 + asr lr, r2, #19 ; [1] + strh lr, [r1], #32 + sxth r2, r2 + sxth r3, r3 + asr r2, r2, #3 ; [2] + strh r2, [r1], #32 + asr r3, r3, #3 ; [3] + strh r3, [r1], #32 + + asr r12, r5, #19 ; [4] + strh r12, [r1], #32 + asr lr, r4, #19 ; [5] + strh lr, [r1], #32 + sxth r4, r4 + sxth r5, r5 + asr r4, r4, #3 ; [6] + strh r4, [r1], #32 + asr r5, r5, #3 ; [7] + strh r5, [r1], #32 + + qsubaddx r2, r6, r7 ; [c1|a1] [9-10 | 8+11] + qaddsubx r3, r6, r7 ; [b1|d1] [9+10 | 8-11] + qsubaddx r4, r8, r9 ; [c1|a1] [13-14 | 12+15] + qaddsubx r5, r8, r9 ; [b1|d1] [13+14 | 12-15] + + qaddsubx r6, r2, r3 ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r7, r3, r2 ; [a2|d2] [b1+a1 | d1-c1] + qaddsubx r8, r4, r5 ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r9, r5, r4 ; [a2|d2] [b1+a1 | d1-c1] + + qadd16 r6, r6, r10 ; [b2+3|c2+3] + qadd16 r7, r7, r10 ; [a2+3|d2+3] + qadd16 r8, r8, r10 ; [b2+3|c2+3] + qadd16 r9, r9, r10 ; [a2+3|d2+3] + + asr r12, r7, #19 ; [8] + strh r12, [r1], #32 + asr lr, r6, #19 ; [9] + strh lr, [r1], #32 + sxth r6, r6 + sxth r7, r7 + asr r6, r6, #3 ; [10] + strh r6, [r1], #32 + asr r7, r7, #3 ; [11] + strh r7, [r1], #32 + + asr r12, r9, #19 ; [12] + strh r12, [r1], #32 + asr lr, r8, #19 ; [13] + strh lr, [r1], #32 + sxth r8, r8 + sxth r9, r9 + asr r8, r8, #3 ; [14] + strh r8, [r1], #32 + asr r9, r9, #3 ; [15] + strh r9, [r1], #32 + + ldmia sp!, {r4 - r12, pc} + ENDP ; |vp8_short_inv_walsh4x4_v6| + + +; Constant Pool +c0x00030003 DCD 0x00030003 + END diff --git a/vp8/common/arm/armv6/loopfilter_v6.asm b/vp8/common/arm/armv6/loopfilter_v6.asm new file mode 100644 index 0000000..1cbbbcd --- /dev/null +++ b/vp8/common/arm/armv6/loopfilter_v6.asm @@ -0,0 +1,1282 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_horizontal_edge_armv6| + EXPORT |vp8_mbloop_filter_horizontal_edge_armv6| + EXPORT |vp8_loop_filter_vertical_edge_armv6| + EXPORT |vp8_mbloop_filter_vertical_edge_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code + + MACRO + TRANSPOSE_MATRIX $a0, $a1, $a2, $a3, $b0, $b1, $b2, $b3 + ; input: $a0, $a1, $a2, $a3; output: $b0, $b1, $b2, $b3 + ; a0: 03 02 01 00 + ; a1: 13 12 11 10 + ; a2: 23 22 21 20 + ; a3: 33 32 31 30 + ; b3 b2 b1 b0 + + uxtb16 $b1, $a1 ; xx 12 xx 10 + uxtb16 $b0, $a0 ; xx 02 xx 00 + uxtb16 $b3, $a3 ; xx 32 xx 30 + uxtb16 $b2, $a2 ; xx 22 xx 20 + orr $b1, $b0, $b1, lsl #8 ; 12 02 10 00 + orr $b3, $b2, $b3, lsl #8 ; 32 22 30 20 + + uxtb16 $a1, $a1, ror #8 ; xx 13 xx 11 + uxtb16 $a3, $a3, ror #8 ; xx 33 xx 31 + uxtb16 $a0, $a0, ror #8 ; xx 03 xx 01 + uxtb16 $a2, $a2, ror #8 ; xx 23 xx 21 + orr $a0, $a0, $a1, lsl #8 ; 13 03 11 01 + orr $a2, $a2, $a3, lsl #8 ; 33 23 31 21 + + pkhtb $b2, $b3, $b1, asr #16 ; 32 22 12 02 -- p1 + pkhbt $b0, $b1, $b3, lsl #16 ; 30 20 10 00 -- p3 + + pkhtb $b3, $a2, $a0, asr #16 ; 33 23 13 03 -- p0 + pkhbt $b1, $a0, $a2, lsl #16 ; 31 21 11 01 -- p2 + MEND + + +src RN r0 +pstep RN r1 +count RN r5 + +;r0 unsigned char *src_ptr, +;r1 int src_pixel_step, +;r2 const char *blimit, +;r3 const char *limit, +;stack const char *thresh, +;stack int count + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_horizontal_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r6, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r9, [src], pstep ; p3 + ldrb r4, [r2] ; blimit + ldr r10, [src], pstep ; p2 + ldrb r2, [r3] ; limit + ldr r11, [src], pstep ; p1 + orr r4, r4, r4, lsl #8 + ldrb r3, [r6] ; thresh + orr r2, r2, r2, lsl #8 + mov count, count, lsl #1 ; 4-in-parallel + orr r4, r4, r4, lsl #16 + orr r3, r3, r3, lsl #8 + orr r2, r2, r2, lsl #16 + orr r3, r3, r3, lsl #16 + +|Hnext8| + ; vp8_filter_mask() function + ; calculate breakout conditions + ldr r12, [src], pstep ; p0 + + uqsub8 r6, r9, r10 ; p3 - p2 + uqsub8 r7, r10, r9 ; p2 - p3 + uqsub8 r8, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + + orr r6, r6, r7 ; abs (p3-p2) + orr r8, r8, r10 ; abs (p2-p1) + uqsub8 lr, r6, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r8, r8, r2 ; compare to limit + uqsub8 r6, r11, r12 ; p1 - p0 + orr lr, lr, r8 + uqsub8 r7, r12, r11 ; p0 - p1 + ldr r9, [src], pstep ; q0 + ldr r10, [src], pstep ; q1 + orr r6, r6, r7 ; abs (p1-p0) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r8, r6, r3 ; compare to thresh -- save r8 for later + orr lr, lr, r7 + + uqsub8 r6, r11, r10 ; p1 - q1 + uqsub8 r7, r10, r11 ; q1 - p1 + uqsub8 r11, r12, r9 ; p0 - q0 + uqsub8 r12, r9, r12 ; q0 - p0 + orr r6, r6, r7 ; abs (p1-q1) + ldr r7, c0x7F7F7F7F + orr r12, r11, r12 ; abs (p0-q0) + ldr r11, [src], pstep ; q2 + uqadd8 r12, r12, r12 ; abs (p0-q0) * 2 + and r6, r7, r6, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r7, r9, r10 ; q0 - q1 + uqadd8 r12, r12, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r6, r10, r9 ; q1 - q0 + uqsub8 r12, r12, r4 ; compare to flimit + uqsub8 r9, r11, r10 ; q2 - q1 + + orr lr, lr, r12 + + ldr r12, [src], pstep ; q3 + uqsub8 r10, r10, r11 ; q1 - q2 + orr r6, r7, r6 ; abs (q1-q0) + orr r10, r9, r10 ; abs (q2-q1) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r10, r10, r2 ; compare to limit + uqsub8 r6, r6, r3 ; compare to thresh -- save r6 for later + orr lr, lr, r7 + orr lr, lr, r10 + + uqsub8 r10, r12, r11 ; q3 - q2 + uqsub8 r9, r11, r12 ; q2 - q3 + + mvn r11, #0 ; r11 == -1 + + orr r10, r10, r9 ; abs (q3-q2) + uqsub8 r10, r10, r2 ; compare to limit + + mov r12, #0 + orr lr, lr, r10 + sub src, src, pstep, lsl #2 + + usub8 lr, r12, lr ; use usub8 instead of ssub8 + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq hskip_filter ; skip filtering + + sub src, src, pstep, lsl #1 ; move src pointer down by 6 lines + + ;vp8_hevmask() function + ;calculate high edge variance + orr r10, r6, r8 ; calculate vp8_hevmask + + ldr r7, [src], pstep ; p1 + + usub8 r10, r12, r10 ; use usub8 instead of ssub8 + sel r6, r12, r11 ; obtain vp8_hevmask: r6 + + ;vp8_filter() function + ldr r8, [src], pstep ; p0 + ldr r12, c0x80808080 + ldr r9, [src], pstep ; q0 + ldr r10, [src], pstep ; q1 + + eor r7, r7, r12 ; p1 offset to convert to a signed value + eor r8, r8, r12 ; p0 offset to convert to a signed value + eor r9, r9, r12 ; q0 offset to convert to a signed value + eor r10, r10, r12 ; q1 offset to convert to a signed value + + str r9, [sp] ; store qs0 temporarily + str r8, [sp, #4] ; store ps0 temporarily + str r10, [sp, #8] ; store qs1 temporarily + str r7, [sp, #12] ; store ps1 temporarily + + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + qsub8 r8, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + + and r7, r7, r6 ; vp8_filter (r7) &= hev + + qadd8 r7, r7, r8 + ldr r9, c0x03030303 ; r9 = 3 --modified for vp8 + + qadd8 r7, r7, r8 + ldr r10, c0x04040404 + + qadd8 r7, r7, r8 + and r7, r7, lr ; vp8_filter &= mask; + + ;modify code for vp8 -- Filter1 = vp8_filter (r7) + qadd8 r8 , r7 , r9 ; Filter2 (r8) = vp8_signed_char_clamp(vp8_filter+3) + qadd8 r7 , r7 , r10 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + + mov r9, #0 + shadd8 r8 , r8 , r9 ; Filter2 >>= 3 + shadd8 r7 , r7 , r9 ; vp8_filter >>= 3 + shadd8 r8 , r8 , r9 + shadd8 r7 , r7 , r9 + shadd8 lr , r8 , r9 ; lr: Filter2 + shadd8 r7 , r7 , r9 ; r7: filter + + ;usub8 lr, r8, r10 ; s = (s==4)*-1 + ;sel lr, r11, r9 + ;usub8 r8, r10, r8 + ;sel r8, r11, r9 + ;and r8, r8, lr ; -1 for each element that equals 4 + + ;calculate output + ;qadd8 lr, r8, r7 ; u = vp8_signed_char_clamp(s + vp8_filter) + + ldr r8, [sp] ; load qs0 + ldr r9, [sp, #4] ; load ps0 + + ldr r10, c0x01010101 + + qsub8 r8 ,r8, r7 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) + qadd8 r9, r9, lr ; u = vp8_signed_char_clamp(ps0 + Filter2) + + ;end of modification for vp8 + + mov lr, #0 + sadd8 r7, r7 , r10 ; vp8_filter += 1 + shadd8 r7, r7, lr ; vp8_filter >>= 1 + + ldr r11, [sp, #12] ; load ps1 + ldr r10, [sp, #8] ; load qs1 + + bic r7, r7, r6 ; vp8_filter &= ~hev + sub src, src, pstep, lsl #2 + + qadd8 r11, r11, r7 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + qsub8 r10, r10,r7 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + + eor r11, r11, r12 ; *op1 = u^0x80 + str r11, [src], pstep ; store op1 + eor r9, r9, r12 ; *op0 = u^0x80 + str r9, [src], pstep ; store op0 result + eor r8, r8, r12 ; *oq0 = u^0x80 + str r8, [src], pstep ; store oq0 result + eor r10, r10, r12 ; *oq1 = u^0x80 + str r10, [src], pstep ; store oq1 + + sub src, src, pstep, lsl #1 + +|hskip_filter| + add src, src, #4 + sub src, src, pstep, lsl #2 + + subs count, count, #1 + + ldrne r9, [src], pstep ; p3 + ldrne r10, [src], pstep ; p2 + ldrne r11, [src], pstep ; p1 + + bne Hnext8 + + add sp, sp, #16 + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_horizontal_edge_armv6| + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_mbloop_filter_horizontal_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r6, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r9, [src], pstep ; p3 + ldrb r4, [r2] ; blimit + ldr r10, [src], pstep ; p2 + ldrb r2, [r3] ; limit + ldr r11, [src], pstep ; p1 + orr r4, r4, r4, lsl #8 + ldrb r3, [r6] ; thresh + orr r2, r2, r2, lsl #8 + mov count, count, lsl #1 ; 4-in-parallel + orr r4, r4, r4, lsl #16 + orr r3, r3, r3, lsl #8 + orr r2, r2, r2, lsl #16 + orr r3, r3, r3, lsl #16 + +|MBHnext8| + + ; vp8_filter_mask() function + ; calculate breakout conditions + ldr r12, [src], pstep ; p0 + + uqsub8 r6, r9, r10 ; p3 - p2 + uqsub8 r7, r10, r9 ; p2 - p3 + uqsub8 r8, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + + orr r6, r6, r7 ; abs (p3-p2) + orr r8, r8, r10 ; abs (p2-p1) + uqsub8 lr, r6, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r8, r8, r2 ; compare to limit + + uqsub8 r6, r11, r12 ; p1 - p0 + orr lr, lr, r8 + uqsub8 r7, r12, r11 ; p0 - p1 + ldr r9, [src], pstep ; q0 + ldr r10, [src], pstep ; q1 + orr r6, r6, r7 ; abs (p1-p0) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r8, r6, r3 ; compare to thresh -- save r8 for later + orr lr, lr, r7 + + uqsub8 r6, r11, r10 ; p1 - q1 + uqsub8 r7, r10, r11 ; q1 - p1 + uqsub8 r11, r12, r9 ; p0 - q0 + uqsub8 r12, r9, r12 ; q0 - p0 + orr r6, r6, r7 ; abs (p1-q1) + ldr r7, c0x7F7F7F7F + orr r12, r11, r12 ; abs (p0-q0) + ldr r11, [src], pstep ; q2 + uqadd8 r12, r12, r12 ; abs (p0-q0) * 2 + and r6, r7, r6, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r7, r9, r10 ; q0 - q1 + uqadd8 r12, r12, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r6, r10, r9 ; q1 - q0 + uqsub8 r12, r12, r4 ; compare to flimit + uqsub8 r9, r11, r10 ; q2 - q1 + + orr lr, lr, r12 + + ldr r12, [src], pstep ; q3 + + uqsub8 r10, r10, r11 ; q1 - q2 + orr r6, r7, r6 ; abs (q1-q0) + orr r10, r9, r10 ; abs (q2-q1) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r10, r10, r2 ; compare to limit + uqsub8 r6, r6, r3 ; compare to thresh -- save r6 for later + orr lr, lr, r7 + orr lr, lr, r10 + + uqsub8 r10, r12, r11 ; q3 - q2 + uqsub8 r9, r11, r12 ; q2 - q3 + + mvn r11, #0 ; r11 == -1 + + orr r10, r10, r9 ; abs (q3-q2) + uqsub8 r10, r10, r2 ; compare to limit + + mov r12, #0 + + orr lr, lr, r10 + + usub8 lr, r12, lr ; use usub8 instead of ssub8 + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq mbhskip_filter ; skip filtering + + ;vp8_hevmask() function + ;calculate high edge variance + sub src, src, pstep, lsl #2 ; move src pointer down by 6 lines + sub src, src, pstep, lsl #1 + + orr r10, r6, r8 + ldr r7, [src], pstep ; p1 + + usub8 r10, r12, r10 + sel r6, r12, r11 ; hev mask: r6 + + ;vp8_mbfilter() function + ;p2, q2 are only needed at the end. Don't need to load them in now. + ldr r8, [src], pstep ; p0 + ldr r12, c0x80808080 + ldr r9, [src], pstep ; q0 + ldr r10, [src] ; q1 + + eor r7, r7, r12 ; ps1 + eor r8, r8, r12 ; ps0 + eor r9, r9, r12 ; qs0 + eor r10, r10, r12 ; qs1 + + qsub8 r12, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + str r7, [sp, #12] ; store ps1 temporarily + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + str r10, [sp, #8] ; store qs1 temporarily + qadd8 r7, r7, r12 + str r9, [sp] ; store qs0 temporarily + qadd8 r7, r7, r12 + str r8, [sp, #4] ; store ps0 temporarily + qadd8 r7, r7, r12 ; vp8_filter: r7 + + ldr r10, c0x03030303 ; r10 = 3 --modified for vp8 + ldr r9, c0x04040404 + + and r7, r7, lr ; vp8_filter &= mask (lr is free) + + mov r12, r7 ; Filter2: r12 + and r12, r12, r6 ; Filter2 &= hev + + ;modify code for vp8 + ;save bottom 3 bits so that we round one side +4 and the other +3 + qadd8 r8 , r12 , r9 ; Filter1 (r8) = vp8_signed_char_clamp(Filter2+4) + qadd8 r12 , r12 , r10 ; Filter2 (r12) = vp8_signed_char_clamp(Filter2+3) + + mov r10, #0 + shadd8 r8 , r8 , r10 ; Filter1 >>= 3 + shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + shadd8 r8 , r8 , r10 + shadd8 r12 , r12 , r10 + shadd8 r8 , r8 , r10 ; r8: Filter1 + shadd8 r12 , r12 , r10 ; r12: Filter2 + + ldr r9, [sp] ; load qs0 + ldr r11, [sp, #4] ; load ps0 + + qsub8 r9 , r9, r8 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + qadd8 r11, r11, r12 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) + + ;save bottom 3 bits so that we round one side +4 and the other +3 + ;and r8, r12, r10 ; s = Filter2 & 7 (s: r8) + ;qadd8 r12 , r12 , r9 ; Filter2 = vp8_signed_char_clamp(Filter2+4) + ;mov r10, #0 + ;shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + ;usub8 lr, r8, r9 ; s = (s==4)*-1 + ;sel lr, r11, r10 + ;shadd8 r12 , r12 , r10 + ;usub8 r8, r9, r8 + ;sel r8, r11, r10 + ;ldr r9, [sp] ; load qs0 + ;ldr r11, [sp, #4] ; load ps0 + ;shadd8 r12 , r12 , r10 + ;and r8, r8, lr ; -1 for each element that equals 4 + ;qadd8 r10, r8, r12 ; u = vp8_signed_char_clamp(s + Filter2) + ;qsub8 r9 , r9, r12 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) + ;qadd8 r11, r11, r10 ; ps0 = vp8_signed_char_clamp(ps0 + u) + + ;end of modification for vp8 + + bic r12, r7, r6 ; vp8_filter &= ~hev ( r6 is free) + ;mov r12, r7 + + ;roughly 3/7th difference across boundary + mov lr, #0x1b ; 27 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r7, r10, lr, r7 + smultb r10, r10, lr + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + add r10, r10, #63 + ssat r7, #8, r7, asr #7 + ssat r10, #8, r10, asr #7 + + ldr lr, c0x80808080 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r7, r10, lsl #16 + uxtb16 r6, r6 + uxtb16 r10, r10 + + sub src, src, pstep + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs0 - u) + qadd8 r10, r11, r10 ; s = vp8_signed_char_clamp(ps0 + u) + eor r8, r8, lr ; *oq0 = s^0x80 + str r8, [src] ; store *oq0 + sub src, src, pstep + eor r10, r10, lr ; *op0 = s^0x80 + str r10, [src] ; store *op0 + + ;roughly 2/7th difference across boundary + mov lr, #0x12 ; 18 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r9, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r9, #8, r9, asr #7 + ssat r10, #8, r10, asr #7 + + ldr lr, c0x80808080 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r9, r10, lsl #16 + + ldr r9, [sp, #8] ; load qs1 + ldr r11, [sp, #12] ; load ps1 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + sub src, src, pstep + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + + qadd8 r11, r11, r10 ; s = vp8_signed_char_clamp(ps1 + u) + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs1 - u) + eor r11, r11, lr ; *op1 = s^0x80 + str r11, [src], pstep ; store *op1 + eor r8, r8, lr ; *oq1 = s^0x80 + add src, src, pstep, lsl #1 + + mov r7, #0x3f ; 63 + + str r8, [src], pstep ; store *oq1 + + ;roughly 1/7th difference across boundary + mov lr, #0x9 ; 9 + ldr r9, [src] ; load q2 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r12, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r12, #8, r12, asr #7 + ssat r10, #8, r10, asr #7 + + sub src, src, pstep, lsl #2 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r12, r10, lsl #16 + + sub src, src, pstep + ldr lr, c0x80808080 + + ldr r11, [src] ; load p2 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + eor r9, r9, lr + eor r11, r11, lr + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + + qadd8 r8, r11, r10 ; s = vp8_signed_char_clamp(ps2 + u) + qsub8 r10, r9, r10 ; s = vp8_signed_char_clamp(qs2 - u) + eor r8, r8, lr ; *op2 = s^0x80 + str r8, [src], pstep, lsl #2 ; store *op2 + add src, src, pstep + eor r10, r10, lr ; *oq2 = s^0x80 + str r10, [src], pstep, lsl #1 ; store *oq2 + +|mbhskip_filter| + add src, src, #4 + sub src, src, pstep, lsl #3 + subs count, count, #1 + + ldrne r9, [src], pstep ; p3 + ldrne r10, [src], pstep ; p2 + ldrne r11, [src], pstep ; p1 + + bne MBHnext8 + + add sp, sp, #16 + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_mbloop_filter_horizontal_edge_armv6| + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_vertical_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, #4 ; move src pointer down by 4 + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r12, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r6, [src], pstep ; load source data + ldrb r4, [r2] ; blimit + ldr r7, [src], pstep + ldrb r2, [r3] ; limit + ldr r8, [src], pstep + orr r4, r4, r4, lsl #8 + ldrb r3, [r12] ; thresh + orr r2, r2, r2, lsl #8 + ldr lr, [src], pstep + mov count, count, lsl #1 ; 4-in-parallel + orr r4, r4, r4, lsl #16 + orr r3, r3, r3, lsl #8 + orr r2, r2, r2, lsl #16 + orr r3, r3, r3, lsl #16 + +|Vnext8| + + ; vp8_filter_mask() function + ; calculate breakout conditions + ; transpose the source data for 4-in-parallel operation + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + uqsub8 r7, r9, r10 ; p3 - p2 + uqsub8 r8, r10, r9 ; p2 - p3 + uqsub8 r9, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + orr r7, r7, r8 ; abs (p3-p2) + orr r10, r9, r10 ; abs (p2-p1) + uqsub8 lr, r7, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r10, r10, r2 ; compare to limit + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr lr, lr, r10 + + uqsub8 r6, r11, r12 ; p1 - p0 + uqsub8 r7, r12, r11 ; p0 - p1 + add src, src, #4 ; move src pointer up by 4 + orr r6, r6, r7 ; abs (p1-p0) + str r11, [sp, #12] ; save p1 + uqsub8 r10, r6, r2 ; compare to limit + uqsub8 r11, r6, r3 ; compare to thresh + orr lr, lr, r10 + + ; transpose uses 8 regs(r6 - r12 and lr). Need to save reg value now + ; transpose the source data for 4-in-parallel operation + ldr r6, [src], pstep ; load source data + str r11, [sp] ; push r11 to stack + ldr r7, [src], pstep + str r12, [sp, #4] ; save current reg before load q0 - q3 data + ldr r8, [src], pstep + str lr, [sp, #8] + ldr lr, [src], pstep + + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + ldr lr, [sp, #8] ; load back (f)limit accumulator + + uqsub8 r6, r12, r11 ; q3 - q2 + uqsub8 r7, r11, r12 ; q2 - q3 + uqsub8 r12, r11, r10 ; q2 - q1 + uqsub8 r11, r10, r11 ; q1 - q2 + orr r6, r6, r7 ; abs (q3-q2) + orr r7, r12, r11 ; abs (q2-q1) + uqsub8 r6, r6, r2 ; compare to limit + uqsub8 r7, r7, r2 ; compare to limit + ldr r11, [sp, #4] ; load back p0 + ldr r12, [sp, #12] ; load back p1 + orr lr, lr, r6 + orr lr, lr, r7 + + uqsub8 r6, r11, r9 ; p0 - q0 + uqsub8 r7, r9, r11 ; q0 - p0 + uqsub8 r8, r12, r10 ; p1 - q1 + uqsub8 r11, r10, r12 ; q1 - p1 + orr r6, r6, r7 ; abs (p0-q0) + ldr r7, c0x7F7F7F7F + orr r8, r8, r11 ; abs (p1-q1) + uqadd8 r6, r6, r6 ; abs (p0-q0) * 2 + and r8, r7, r8, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r11, r10, r9 ; q1 - q0 + uqadd8 r6, r8, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r12, r9, r10 ; q0 - q1 + uqsub8 r6, r6, r4 ; compare to flimit + + orr r9, r11, r12 ; abs (q1-q0) + uqsub8 r8, r9, r2 ; compare to limit + uqsub8 r10, r9, r3 ; compare to thresh + orr lr, lr, r6 + orr lr, lr, r8 + + mvn r11, #0 ; r11 == -1 + mov r12, #0 + + usub8 lr, r12, lr + ldr r9, [sp] ; load the compared result + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq vskip_filter ; skip filtering + + ;vp8_hevmask() function + ;calculate high edge variance + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr r9, r9, r10 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + usub8 r9, r12, r9 + sel r6, r12, r11 ; hev mask: r6 + + ;vp8_filter() function + ; load soure data to r6, r11, r12, lr + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + pkhbt r12, r7, r8, lsl #16 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + pkhbt r11, r9, r10, lsl #16 + + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + ; Transpose needs 8 regs(r6 - r12, and lr). Save r6 and lr first + str r6, [sp] + str lr, [sp, #4] + + pkhbt r6, r7, r8, lsl #16 + pkhbt lr, r9, r10, lsl #16 + + ;transpose r12, r11, r6, lr to r7, r8, r9, r10 + TRANSPOSE_MATRIX r12, r11, r6, lr, r7, r8, r9, r10 + + ;load back hev_mask r6 and filter_mask lr + ldr r12, c0x80808080 + ldr r6, [sp] + ldr lr, [sp, #4] + + eor r7, r7, r12 ; p1 offset to convert to a signed value + eor r8, r8, r12 ; p0 offset to convert to a signed value + eor r9, r9, r12 ; q0 offset to convert to a signed value + eor r10, r10, r12 ; q1 offset to convert to a signed value + + str r9, [sp] ; store qs0 temporarily + str r8, [sp, #4] ; store ps0 temporarily + str r10, [sp, #8] ; store qs1 temporarily + str r7, [sp, #12] ; store ps1 temporarily + + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + qsub8 r8, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + + and r7, r7, r6 ; vp8_filter (r7) &= hev (r7 : filter) + + qadd8 r7, r7, r8 + ldr r9, c0x03030303 ; r9 = 3 --modified for vp8 + + qadd8 r7, r7, r8 + ldr r10, c0x04040404 + + qadd8 r7, r7, r8 + ;mvn r11, #0 ; r11 == -1 + + and r7, r7, lr ; vp8_filter &= mask + + ;modify code for vp8 -- Filter1 = vp8_filter (r7) + qadd8 r8 , r7 , r9 ; Filter2 (r8) = vp8_signed_char_clamp(vp8_filter+3) + qadd8 r7 , r7 , r10 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + + mov r9, #0 + shadd8 r8 , r8 , r9 ; Filter2 >>= 3 + shadd8 r7 , r7 , r9 ; vp8_filter >>= 3 + shadd8 r8 , r8 , r9 + shadd8 r7 , r7 , r9 + shadd8 lr , r8 , r9 ; lr: filter2 + shadd8 r7 , r7 , r9 ; r7: filter + + ;usub8 lr, r8, r10 ; s = (s==4)*-1 + ;sel lr, r11, r9 + ;usub8 r8, r10, r8 + ;sel r8, r11, r9 + ;and r8, r8, lr ; -1 for each element that equals 4 -- r8: s + + ;calculate output + ;qadd8 lr, r8, r7 ; u = vp8_signed_char_clamp(s + vp8_filter) + + ldr r8, [sp] ; load qs0 + ldr r9, [sp, #4] ; load ps0 + + ldr r10, c0x01010101 + + qsub8 r8, r8, r7 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) + qadd8 r9, r9, lr ; u = vp8_signed_char_clamp(ps0 + Filter2) + ;end of modification for vp8 + + eor r8, r8, r12 + eor r9, r9, r12 + + mov lr, #0 + + sadd8 r7, r7, r10 + shadd8 r7, r7, lr + + ldr r10, [sp, #8] ; load qs1 + ldr r11, [sp, #12] ; load ps1 + + bic r7, r7, r6 ; r7: vp8_filter + + qsub8 r10 , r10, r7 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + qadd8 r11, r11, r7 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + eor r10, r10, r12 + eor r11, r11, r12 + + sub src, src, pstep, lsl #2 + + ;we can use TRANSPOSE_MATRIX macro to transpose output - input: q1, q0, p0, p1 + ;output is b0, b1, b2, b3 + ;b0: 03 02 01 00 + ;b1: 13 12 11 10 + ;b2: 23 22 21 20 + ;b3: 33 32 31 30 + ; p1 p0 q0 q1 + ; (a3 a2 a1 a0) + TRANSPOSE_MATRIX r11, r9, r8, r10, r6, r7, r12, lr + + strh r6, [src, #-2] ; store the result + mov r6, r6, lsr #16 + strh r6, [src], pstep + + strh r7, [src, #-2] + mov r7, r7, lsr #16 + strh r7, [src], pstep + + strh r12, [src, #-2] + mov r12, r12, lsr #16 + strh r12, [src], pstep + + strh lr, [src, #-2] + mov lr, lr, lsr #16 + strh lr, [src], pstep + +|vskip_filter| + sub src, src, #4 + subs count, count, #1 + + ldrne r6, [src], pstep ; load source data + ldrne r7, [src], pstep + ldrne r8, [src], pstep + ldrne lr, [src], pstep + + bne Vnext8 + + add sp, sp, #16 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_vertical_edge_armv6| + + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_mbloop_filter_vertical_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, #4 ; move src pointer down by 4 + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r12, [sp, #36] ; load thresh address + pld [src, #23] ; preload for next block + sub sp, sp, #16 ; create temp buffer + + ldr r6, [src], pstep ; load source data + ldrb r4, [r2] ; blimit + pld [src, #23] + ldr r7, [src], pstep + ldrb r2, [r3] ; limit + pld [src, #23] + ldr r8, [src], pstep + orr r4, r4, r4, lsl #8 + ldrb r3, [r12] ; thresh + orr r2, r2, r2, lsl #8 + pld [src, #23] + ldr lr, [src], pstep + mov count, count, lsl #1 ; 4-in-parallel + orr r4, r4, r4, lsl #16 + orr r3, r3, r3, lsl #8 + orr r2, r2, r2, lsl #16 + orr r3, r3, r3, lsl #16 + +|MBVnext8| + ; vp8_filter_mask() function + ; calculate breakout conditions + ; transpose the source data for 4-in-parallel operation + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + uqsub8 r7, r9, r10 ; p3 - p2 + uqsub8 r8, r10, r9 ; p2 - p3 + uqsub8 r9, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + orr r7, r7, r8 ; abs (p3-p2) + orr r10, r9, r10 ; abs (p2-p1) + uqsub8 lr, r7, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r10, r10, r2 ; compare to limit + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr lr, lr, r10 + + uqsub8 r6, r11, r12 ; p1 - p0 + uqsub8 r7, r12, r11 ; p0 - p1 + add src, src, #4 ; move src pointer up by 4 + orr r6, r6, r7 ; abs (p1-p0) + str r11, [sp, #12] ; save p1 + uqsub8 r10, r6, r2 ; compare to limit + uqsub8 r11, r6, r3 ; compare to thresh + orr lr, lr, r10 + + ; transpose uses 8 regs(r6 - r12 and lr). Need to save reg value now + ; transpose the source data for 4-in-parallel operation + ldr r6, [src], pstep ; load source data + str r11, [sp] ; push r11 to stack + ldr r7, [src], pstep + str r12, [sp, #4] ; save current reg before load q0 - q3 data + ldr r8, [src], pstep + str lr, [sp, #8] + ldr lr, [src], pstep + + + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + ldr lr, [sp, #8] ; load back (f)limit accumulator + + uqsub8 r6, r12, r11 ; q3 - q2 + uqsub8 r7, r11, r12 ; q2 - q3 + uqsub8 r12, r11, r10 ; q2 - q1 + uqsub8 r11, r10, r11 ; q1 - q2 + orr r6, r6, r7 ; abs (q3-q2) + orr r7, r12, r11 ; abs (q2-q1) + uqsub8 r6, r6, r2 ; compare to limit + uqsub8 r7, r7, r2 ; compare to limit + ldr r11, [sp, #4] ; load back p0 + ldr r12, [sp, #12] ; load back p1 + orr lr, lr, r6 + orr lr, lr, r7 + + uqsub8 r6, r11, r9 ; p0 - q0 + uqsub8 r7, r9, r11 ; q0 - p0 + uqsub8 r8, r12, r10 ; p1 - q1 + uqsub8 r11, r10, r12 ; q1 - p1 + orr r6, r6, r7 ; abs (p0-q0) + ldr r7, c0x7F7F7F7F + orr r8, r8, r11 ; abs (p1-q1) + uqadd8 r6, r6, r6 ; abs (p0-q0) * 2 + and r8, r7, r8, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r11, r10, r9 ; q1 - q0 + uqadd8 r6, r8, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r12, r9, r10 ; q0 - q1 + uqsub8 r6, r6, r4 ; compare to flimit + + orr r9, r11, r12 ; abs (q1-q0) + uqsub8 r8, r9, r2 ; compare to limit + uqsub8 r10, r9, r3 ; compare to thresh + orr lr, lr, r6 + orr lr, lr, r8 + + mvn r11, #0 ; r11 == -1 + mov r12, #0 + + usub8 lr, r12, lr + ldr r9, [sp] ; load the compared result + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq mbvskip_filter ; skip filtering + + + + ;vp8_hevmask() function + ;calculate high edge variance + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr r9, r9, r10 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + usub8 r9, r12, r9 + sel r6, r12, r11 ; hev mask: r6 + + + ; vp8_mbfilter() function + ; p2, q2 are only needed at the end. Don't need to load them in now. + ; Transpose needs 8 regs(r6 - r12, and lr). Save r6 and lr first + ; load soure data to r6, r11, r12, lr + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + pkhbt r12, r7, r8, lsl #16 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + pkhbt r11, r9, r10, lsl #16 + + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + str r6, [sp] ; save r6 + str lr, [sp, #4] ; save lr + + pkhbt r6, r7, r8, lsl #16 + pkhbt lr, r9, r10, lsl #16 + + ;transpose r12, r11, r6, lr to p1, p0, q0, q1 + TRANSPOSE_MATRIX r12, r11, r6, lr, r7, r8, r9, r10 + + ;load back hev_mask r6 and filter_mask lr + ldr r12, c0x80808080 + ldr r6, [sp] + ldr lr, [sp, #4] + + eor r7, r7, r12 ; ps1 + eor r8, r8, r12 ; ps0 + eor r9, r9, r12 ; qs0 + eor r10, r10, r12 ; qs1 + + qsub8 r12, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + str r7, [sp, #12] ; store ps1 temporarily + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + str r10, [sp, #8] ; store qs1 temporarily + qadd8 r7, r7, r12 + str r9, [sp] ; store qs0 temporarily + qadd8 r7, r7, r12 + str r8, [sp, #4] ; store ps0 temporarily + qadd8 r7, r7, r12 ; vp8_filter: r7 + + ldr r10, c0x03030303 ; r10 = 3 --modified for vp8 + ldr r9, c0x04040404 + ;mvn r11, #0 ; r11 == -1 + + and r7, r7, lr ; vp8_filter &= mask (lr is free) + + mov r12, r7 ; Filter2: r12 + and r12, r12, r6 ; Filter2 &= hev + + ;modify code for vp8 + ;save bottom 3 bits so that we round one side +4 and the other +3 + qadd8 r8 , r12 , r9 ; Filter1 (r8) = vp8_signed_char_clamp(Filter2+4) + qadd8 r12 , r12 , r10 ; Filter2 (r12) = vp8_signed_char_clamp(Filter2+3) + + mov r10, #0 + shadd8 r8 , r8 , r10 ; Filter1 >>= 3 + shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + shadd8 r8 , r8 , r10 + shadd8 r12 , r12 , r10 + shadd8 r8 , r8 , r10 ; r8: Filter1 + shadd8 r12 , r12 , r10 ; r12: Filter2 + + ldr r9, [sp] ; load qs0 + ldr r11, [sp, #4] ; load ps0 + + qsub8 r9 , r9, r8 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + qadd8 r11, r11, r12 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) + + ;save bottom 3 bits so that we round one side +4 and the other +3 + ;and r8, r12, r10 ; s = Filter2 & 7 (s: r8) + ;qadd8 r12 , r12 , r9 ; Filter2 = vp8_signed_char_clamp(Filter2+4) + ;mov r10, #0 + ;shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + ;usub8 lr, r8, r9 ; s = (s==4)*-1 + ;sel lr, r11, r10 + ;shadd8 r12 , r12 , r10 + ;usub8 r8, r9, r8 + ;sel r8, r11, r10 + ;ldr r9, [sp] ; load qs0 + ;ldr r11, [sp, #4] ; load ps0 + ;shadd8 r12 , r12 , r10 + ;and r8, r8, lr ; -1 for each element that equals 4 + ;qadd8 r10, r8, r12 ; u = vp8_signed_char_clamp(s + Filter2) + ;qsub8 r9 , r9, r12 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) + ;qadd8 r11, r11, r10 ; ps0 = vp8_signed_char_clamp(ps0 + u) + + ;end of modification for vp8 + + bic r12, r7, r6 ;vp8_filter &= ~hev ( r6 is free) + ;mov r12, r7 + + ;roughly 3/7th difference across boundary + mov lr, #0x1b ; 27 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r7, r10, lr, r7 + smultb r10, r10, lr + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + add r10, r10, #63 + ssat r7, #8, r7, asr #7 + ssat r10, #8, r10, asr #7 + + ldr lr, c0x80808080 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r7, r10, lsl #16 + uxtb16 r6, r6 + uxtb16 r10, r10 + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs0 - u) + qadd8 r10, r11, r10 ; s = vp8_signed_char_clamp(ps0 + u) + eor r8, r8, lr ; *oq0 = s^0x80 + eor r10, r10, lr ; *op0 = s^0x80 + + strb r10, [src, #-1] ; store op0 result + strb r8, [src], pstep ; store oq0 result + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + strb r10, [src, #-1] + strb r8, [src], pstep + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + strb r10, [src, #-1] + strb r8, [src], pstep + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + strb r10, [src, #-1] + strb r8, [src], pstep + + ;roughly 2/7th difference across boundary + mov lr, #0x12 ; 18 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r9, r10, lr, r7 + + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r9, #8, r9, asr #7 + ssat r10, #8, r10, asr #7 + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r9, r10, lsl #16 + + ldr r9, [sp, #8] ; load qs1 + ldr r11, [sp, #12] ; load ps1 + ldr lr, c0x80808080 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + add src, src, #2 + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs1 - u) + qadd8 r10, r11, r10 ; s = vp8_signed_char_clamp(ps1 + u) + eor r8, r8, lr ; *oq1 = s^0x80 + eor r10, r10, lr ; *op1 = s^0x80 + + ldrb r11, [src, #-5] ; load p2 for 1/7th difference across boundary + strb r10, [src, #-4] ; store op1 + strb r8, [src, #-1] ; store oq1 + ldrb r9, [src], pstep ; load q2 for 1/7th difference across boundary + + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + + ldrb r6, [src, #-5] + strb r10, [src, #-4] + strb r8, [src, #-1] + ldrb r7, [src], pstep + + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + orr r11, r11, r6, lsl #8 + orr r9, r9, r7, lsl #8 + + ldrb r6, [src, #-5] + strb r10, [src, #-4] + strb r8, [src, #-1] + ldrb r7, [src], pstep + + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + orr r11, r11, r6, lsl #16 + orr r9, r9, r7, lsl #16 + + ldrb r6, [src, #-5] + strb r10, [src, #-4] + strb r8, [src, #-1] + ldrb r7, [src], pstep + orr r11, r11, r6, lsl #24 + orr r9, r9, r7, lsl #24 + + ;roughly 1/7th difference across boundary + eor r9, r9, lr + eor r11, r11, lr + + mov lr, #0x9 ; 9 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r12, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r12, #8, r12, asr #7 + ssat r10, #8, r10, asr #7 + + sub src, src, pstep, lsl #2 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r12, r10, lsl #16 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + ldr lr, c0x80808080 + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + + qadd8 r8, r11, r10 ; s = vp8_signed_char_clamp(ps2 + u) + qsub8 r10, r9, r10 ; s = vp8_signed_char_clamp(qs2 - u) + eor r8, r8, lr ; *op2 = s^0x80 + eor r10, r10, lr ; *oq2 = s^0x80 + + strb r8, [src, #-5] ; store *op2 + strb r10, [src], pstep ; store *oq2 + mov r8, r8, lsr #8 + mov r10, r10, lsr #8 + strb r8, [src, #-5] + strb r10, [src], pstep + mov r8, r8, lsr #8 + mov r10, r10, lsr #8 + strb r8, [src, #-5] + strb r10, [src], pstep + mov r8, r8, lsr #8 + mov r10, r10, lsr #8 + strb r8, [src, #-5] + strb r10, [src], pstep + + ;adjust src pointer for next loop + sub src, src, #2 + +|mbvskip_filter| + sub src, src, #4 + subs count, count, #1 + + pld [src, #23] ; preload for next block + ldrne r6, [src], pstep ; load source data + pld [src, #23] + ldrne r7, [src], pstep + pld [src, #23] + ldrne r8, [src], pstep + pld [src, #23] + ldrne lr, [src], pstep + + bne MBVnext8 + + add sp, sp, #16 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_mbloop_filter_vertical_edge_armv6| + +; Constant Pool +c0x80808080 DCD 0x80808080 +c0x03030303 DCD 0x03030303 +c0x04040404 DCD 0x04040404 +c0x01010101 DCD 0x01010101 +c0x7F7F7F7F DCD 0x7F7F7F7F + + END diff --git a/vp8/common/arm/armv6/simpleloopfilter_v6.asm b/vp8/common/arm/armv6/simpleloopfilter_v6.asm new file mode 100644 index 0000000..5e00cf0 --- /dev/null +++ b/vp8/common/arm/armv6/simpleloopfilter_v6.asm @@ -0,0 +1,286 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_simple_horizontal_edge_armv6| + EXPORT |vp8_loop_filter_simple_vertical_edge_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code + + MACRO + TRANSPOSE_MATRIX $a0, $a1, $a2, $a3, $b0, $b1, $b2, $b3 + ; input: $a0, $a1, $a2, $a3; output: $b0, $b1, $b2, $b3 + ; a0: 03 02 01 00 + ; a1: 13 12 11 10 + ; a2: 23 22 21 20 + ; a3: 33 32 31 30 + ; b3 b2 b1 b0 + + uxtb16 $b1, $a1 ; xx 12 xx 10 + uxtb16 $b0, $a0 ; xx 02 xx 00 + uxtb16 $b3, $a3 ; xx 32 xx 30 + uxtb16 $b2, $a2 ; xx 22 xx 20 + orr $b1, $b0, $b1, lsl #8 ; 12 02 10 00 + orr $b3, $b2, $b3, lsl #8 ; 32 22 30 20 + + uxtb16 $a1, $a1, ror #8 ; xx 13 xx 11 + uxtb16 $a3, $a3, ror #8 ; xx 33 xx 31 + uxtb16 $a0, $a0, ror #8 ; xx 03 xx 01 + uxtb16 $a2, $a2, ror #8 ; xx 23 xx 21 + orr $a0, $a0, $a1, lsl #8 ; 13 03 11 01 + orr $a2, $a2, $a3, lsl #8 ; 33 23 31 21 + + pkhtb $b2, $b3, $b1, asr #16 ; 32 22 12 02 -- p1 + pkhbt $b0, $b1, $b3, lsl #16 ; 30 20 10 00 -- p3 + + pkhtb $b3, $a2, $a0, asr #16 ; 33 23 13 03 -- p0 + pkhbt $b1, $a0, $a2, lsl #16 ; 31 21 11 01 -- p2 + MEND + + + +src RN r0 +pstep RN r1 + +;r0 unsigned char *src_ptr, +;r1 int src_pixel_step, +;r2 const char *blimit + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_simple_horizontal_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + ldrb r12, [r2] ; blimit + ldr r3, [src, -pstep, lsl #1] ; p1 + ldr r4, [src, -pstep] ; p0 + ldr r5, [src] ; q0 + ldr r6, [src, pstep] ; q1 + orr r12, r12, r12, lsl #8 ; blimit + ldr r2, c0x80808080 + orr r12, r12, r12, lsl #16 ; blimit + mov r9, #4 ; double the count. we're doing 4 at a time + mov lr, #0 ; need 0 in a couple places + +|simple_hnext8| + ; vp8_simple_filter_mask() + + uqsub8 r7, r3, r6 ; p1 - q1 + uqsub8 r8, r6, r3 ; q1 - p1 + uqsub8 r10, r4, r5 ; p0 - q0 + uqsub8 r11, r5, r4 ; q0 - p0 + orr r8, r8, r7 ; abs(p1 - q1) + orr r10, r10, r11 ; abs(p0 - q0) + uqadd8 r10, r10, r10 ; abs(p0 - q0) * 2 + uhadd8 r8, r8, lr ; abs(p1 - q2) >> 1 + uqadd8 r10, r10, r8 ; abs(p0 - q0)*2 + abs(p1 - q1)/2 + mvn r8, #0 + usub8 r10, r12, r10 ; compare to flimit. usub8 sets GE flags + sel r10, r8, lr ; filter mask: F or 0 + cmp r10, #0 + beq simple_hskip_filter ; skip filtering if all masks are 0x00 + + ;vp8_simple_filter() + + eor r3, r3, r2 ; p1 offset to convert to a signed value + eor r6, r6, r2 ; q1 offset to convert to a signed value + eor r4, r4, r2 ; p0 offset to convert to a signed value + eor r5, r5, r2 ; q0 offset to convert to a signed value + + qsub8 r3, r3, r6 ; vp8_filter = p1 - q1 + qsub8 r6, r5, r4 ; q0 - p0 + qadd8 r3, r3, r6 ; += q0 - p0 + ldr r7, c0x04040404 + qadd8 r3, r3, r6 ; += q0 - p0 + ldr r8, c0x03030303 + qadd8 r3, r3, r6 ; vp8_filter = p1-q1 + 3*(q0-p0)) + ;STALL + and r3, r3, r10 ; vp8_filter &= mask + + qadd8 r7 , r3 , r7 ; Filter1 = vp8_filter + 4 + qadd8 r8 , r3 , r8 ; Filter2 = vp8_filter + 3 + + shadd8 r7 , r7 , lr + shadd8 r8 , r8 , lr + shadd8 r7 , r7 , lr + shadd8 r8 , r8 , lr + shadd8 r7 , r7 , lr ; Filter1 >>= 3 + shadd8 r8 , r8 , lr ; Filter2 >>= 3 + + qsub8 r5 ,r5, r7 ; u = q0 - Filter1 + qadd8 r4, r4, r8 ; u = p0 + Filter2 + eor r5, r5, r2 ; *oq0 = u^0x80 + str r5, [src] ; store oq0 result + eor r4, r4, r2 ; *op0 = u^0x80 + str r4, [src, -pstep] ; store op0 result + +|simple_hskip_filter| + subs r9, r9, #1 + addne src, src, #4 ; next row + + ldrne r3, [src, -pstep, lsl #1] ; p1 + ldrne r4, [src, -pstep] ; p0 + ldrne r5, [src] ; q0 + ldrne r6, [src, pstep] ; q1 + + bne simple_hnext8 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_simple_horizontal_edge_armv6| + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_simple_vertical_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + ldrb r12, [r2] ; r12: blimit + ldr r2, c0x80808080 + orr r12, r12, r12, lsl #8 + + ; load soure data to r7, r8, r9, r10 + ldrh r3, [src, #-2] + pld [src, #23] ; preload for next block + ldrh r4, [src], pstep + orr r12, r12, r12, lsl #16 + + ldrh r5, [src, #-2] + pld [src, #23] + ldrh r6, [src], pstep + + pkhbt r7, r3, r4, lsl #16 + + ldrh r3, [src, #-2] + pld [src, #23] + ldrh r4, [src], pstep + + pkhbt r8, r5, r6, lsl #16 + + ldrh r5, [src, #-2] + pld [src, #23] + ldrh r6, [src], pstep + mov r11, #4 ; double the count. we're doing 4 at a time + +|simple_vnext8| + ; vp8_simple_filter_mask() function + pkhbt r9, r3, r4, lsl #16 + pkhbt r10, r5, r6, lsl #16 + + ;transpose r7, r8, r9, r10 to r3, r4, r5, r6 + TRANSPOSE_MATRIX r7, r8, r9, r10, r3, r4, r5, r6 + + uqsub8 r7, r3, r6 ; p1 - q1 + uqsub8 r8, r6, r3 ; q1 - p1 + uqsub8 r9, r4, r5 ; p0 - q0 + uqsub8 r10, r5, r4 ; q0 - p0 + orr r7, r7, r8 ; abs(p1 - q1) + orr r9, r9, r10 ; abs(p0 - q0) + mov r8, #0 + uqadd8 r9, r9, r9 ; abs(p0 - q0) * 2 + uhadd8 r7, r7, r8 ; abs(p1 - q1) / 2 + uqadd8 r7, r7, r9 ; abs(p0 - q0)*2 + abs(p1 - q1)/2 + mvn r10, #0 ; r10 == -1 + + usub8 r7, r12, r7 ; compare to flimit + sel lr, r10, r8 ; filter mask + + cmp lr, #0 + beq simple_vskip_filter ; skip filtering + + ;vp8_simple_filter() function + eor r3, r3, r2 ; p1 offset to convert to a signed value + eor r6, r6, r2 ; q1 offset to convert to a signed value + eor r4, r4, r2 ; p0 offset to convert to a signed value + eor r5, r5, r2 ; q0 offset to convert to a signed value + + qsub8 r3, r3, r6 ; vp8_filter = p1 - q1 + qsub8 r6, r5, r4 ; q0 - p0 + + qadd8 r3, r3, r6 ; vp8_filter += q0 - p0 + ldr r9, c0x03030303 ; r9 = 3 + + qadd8 r3, r3, r6 ; vp8_filter += q0 - p0 + ldr r7, c0x04040404 + + qadd8 r3, r3, r6 ; vp8_filter = p1-q1 + 3*(q0-p0)) + ;STALL + and r3, r3, lr ; vp8_filter &= mask + + qadd8 r9 , r3 , r9 ; Filter2 = vp8_filter + 3 + qadd8 r3 , r3 , r7 ; Filter1 = vp8_filter + 4 + + shadd8 r9 , r9 , r8 + shadd8 r3 , r3 , r8 + shadd8 r9 , r9 , r8 + shadd8 r3 , r3 , r8 + shadd8 r9 , r9 , r8 ; Filter2 >>= 3 + shadd8 r3 , r3 , r8 ; Filter1 >>= 3 + + ;calculate output + sub src, src, pstep, lsl #2 + + qadd8 r4, r4, r9 ; u = p0 + Filter2 + qsub8 r5, r5, r3 ; u = q0 - Filter1 + eor r4, r4, r2 ; *op0 = u^0x80 + eor r5, r5, r2 ; *oq0 = u^0x80 + + strb r4, [src, #-1] ; store the result + mov r4, r4, lsr #8 + strb r5, [src], pstep + mov r5, r5, lsr #8 + + strb r4, [src, #-1] + mov r4, r4, lsr #8 + strb r5, [src], pstep + mov r5, r5, lsr #8 + + strb r4, [src, #-1] + mov r4, r4, lsr #8 + strb r5, [src], pstep + mov r5, r5, lsr #8 + + strb r4, [src, #-1] + strb r5, [src], pstep + +|simple_vskip_filter| + subs r11, r11, #1 + + ; load soure data to r7, r8, r9, r10 + ldrneh r3, [src, #-2] + pld [src, #23] ; preload for next block + ldrneh r4, [src], pstep + + ldrneh r5, [src, #-2] + pld [src, #23] + ldrneh r6, [src], pstep + + pkhbt r7, r3, r4, lsl #16 + + ldrneh r3, [src, #-2] + pld [src, #23] + ldrneh r4, [src], pstep + + pkhbt r8, r5, r6, lsl #16 + + ldrneh r5, [src, #-2] + pld [src, #23] + ldrneh r6, [src], pstep + + bne simple_vnext8 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_simple_vertical_edge_armv6| + +; Constant Pool +c0x80808080 DCD 0x80808080 +c0x03030303 DCD 0x03030303 +c0x04040404 DCD 0x04040404 + + END diff --git a/vp8/common/arm/armv6/sixtappredict8x4_v6.asm b/vp8/common/arm/armv6/sixtappredict8x4_v6.asm new file mode 100644 index 0000000..e81aef5 --- /dev/null +++ b/vp8/common/arm/armv6/sixtappredict8x4_v6.asm @@ -0,0 +1,273 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict8x4_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code +;------------------------------------- +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack unsigned char *dst_ptr, +; stack int dst_pitch +;------------------------------------- +;note: In first pass, store the result in transpose(8linesx9columns) on stack. Temporary stack size is 184. +;Line width is 20 that is 9 short data plus 2 to make it 4bytes aligned. In second pass, load data from stack, +;and the result is stored in transpose. +|vp8_sixtap_predict8x4_armv6| PROC + stmdb sp!, {r4 - r11, lr} + str r3, [sp, #-184]! ;reserve space on stack for temporary storage, store yoffset + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + add lr, sp, #4 ;point to temporary buffer + beq skip_firstpass_filter + +;first-pass filter + adr r12, filter8_coeff + sub r0, r0, r1, lsl #1 + + add r3, r1, #10 ; preload next low + pld [r0, r3] + + add r2, r12, r2, lsl #4 ;calculate filter location + add r0, r0, #3 ;adjust src only for loading convinience + + ldr r3, [r2] ; load up packed filter coefficients + ldr r4, [r2, #4] + ldr r5, [r2, #8] + + mov r2, #0x90000 ; height=9 is top part of counter + + sub r1, r1, #8 + +|first_pass_hloop_v6| + ldrb r6, [r0, #-5] ; load source data + ldrb r7, [r0, #-4] + ldrb r8, [r0, #-3] + ldrb r9, [r0, #-2] + ldrb r10, [r0, #-1] + + orr r2, r2, #0x4 ; construct loop counter. width=8=4x2 + + pkhbt r6, r6, r7, lsl #16 ; r7 | r6 + pkhbt r7, r7, r8, lsl #16 ; r8 | r7 + + pkhbt r8, r8, r9, lsl #16 ; r9 | r8 + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + +|first_pass_wloop_v6| + smuad r11, r6, r3 ; vp8_filter[0], vp8_filter[1] + smuad r12, r7, r3 + + ldrb r6, [r0], #1 + + smlad r11, r8, r4, r11 ; vp8_filter[2], vp8_filter[3] + ldrb r7, [r0], #1 + smlad r12, r9, r4, r12 + + pkhbt r10, r10, r6, lsl #16 ; r10 | r9 + pkhbt r6, r6, r7, lsl #16 ; r11 | r10 + smlad r11, r10, r5, r11 ; vp8_filter[4], vp8_filter[5] + smlad r12, r6, r5, r12 + + sub r2, r2, #1 + + add r11, r11, #0x40 ; round_shift_and_clamp + tst r2, #0xff ; test loop counter + usat r11, #8, r11, asr #7 + add r12, r12, #0x40 + strh r11, [lr], #20 ; result is transposed and stored, which + usat r12, #8, r12, asr #7 + + strh r12, [lr], #20 + + movne r11, r6 + movne r12, r7 + + movne r6, r8 + movne r7, r9 + movne r8, r10 + movne r9, r11 + movne r10, r12 + + bne first_pass_wloop_v6 + + ;;add r9, ppl, #30 ; attempt to load 2 adjacent cache lines + ;;IF ARCHITECTURE=6 + ;pld [src, ppl] + ;;pld [src, r9] + ;;ENDIF + + subs r2, r2, #0x10000 + + sub lr, lr, #158 + + add r0, r0, r1 ; move to next input line + + add r11, r1, #18 ; preload next low. adding back block width(=8), which is subtracted earlier + pld [r0, r11] + + bne first_pass_hloop_v6 + +;second pass filter +secondpass_filter + ldr r3, [sp], #4 ; load back yoffset + ldr r0, [sp, #216] ; load dst address from stack 180+36 + ldr r1, [sp, #220] ; load dst stride from stack 180+40 + + cmp r3, #0 + beq skip_secondpass_filter + + adr r12, filter8_coeff + add lr, r12, r3, lsl #4 ;calculate filter location + + mov r2, #0x00080000 + + ldr r3, [lr] ; load up packed filter coefficients + ldr r4, [lr, #4] + ldr r5, [lr, #8] + + pkhbt r12, r4, r3 ; pack the filter differently + pkhbt r11, r5, r4 + +second_pass_hloop_v6 + ldr r6, [sp] ; load the data + ldr r7, [sp, #4] + + orr r2, r2, #2 ; loop counter + +second_pass_wloop_v6 + smuad lr, r3, r6 ; apply filter + smulbt r10, r3, r6 + + ldr r8, [sp, #8] + + smlad lr, r4, r7, lr + smladx r10, r12, r7, r10 + + ldrh r9, [sp, #12] + + smlad lr, r5, r8, lr + smladx r10, r11, r8, r10 + + add sp, sp, #4 + smlatb r10, r5, r9, r10 + + sub r2, r2, #1 + + add lr, lr, #0x40 ; round_shift_and_clamp + tst r2, #0xff + usat lr, #8, lr, asr #7 + add r10, r10, #0x40 + strb lr, [r0], r1 ; the result is transposed back and stored + usat r10, #8, r10, asr #7 + + strb r10, [r0],r1 + + movne r6, r7 + movne r7, r8 + + bne second_pass_wloop_v6 + + subs r2, r2, #0x10000 + add sp, sp, #12 ; updata src for next loop (20-8) + sub r0, r0, r1, lsl #2 + add r0, r0, #1 + + bne second_pass_hloop_v6 + + add sp, sp, #20 + ldmia sp!, {r4 - r11, pc} + +;-------------------- +skip_firstpass_filter + sub r0, r0, r1, lsl #1 + sub r1, r1, #8 + mov r2, #9 + +skip_firstpass_hloop + ldrb r4, [r0], #1 ; load data + subs r2, r2, #1 + ldrb r5, [r0], #1 + strh r4, [lr], #20 ; store it to immediate buffer + ldrb r6, [r0], #1 ; load data + strh r5, [lr], #20 + ldrb r7, [r0], #1 + strh r6, [lr], #20 + ldrb r8, [r0], #1 + strh r7, [lr], #20 + ldrb r9, [r0], #1 + strh r8, [lr], #20 + ldrb r10, [r0], #1 + strh r9, [lr], #20 + ldrb r11, [r0], #1 + strh r10, [lr], #20 + add r0, r0, r1 ; move to next input line + strh r11, [lr], #20 + + sub lr, lr, #158 ; move over to next column + bne skip_firstpass_hloop + + b secondpass_filter + +;-------------------- +skip_secondpass_filter + mov r2, #8 + add sp, sp, #4 ;start from src[0] instead of src[-2] + +skip_secondpass_hloop + ldr r6, [sp], #4 + subs r2, r2, #1 + ldr r8, [sp], #4 + + mov r7, r6, lsr #16 ; unpack + strb r6, [r0], r1 + mov r9, r8, lsr #16 + strb r7, [r0], r1 + add sp, sp, #12 ; 20-8 + strb r8, [r0], r1 + strb r9, [r0], r1 + + sub r0, r0, r1, lsl #2 + add r0, r0, #1 + + bne skip_secondpass_hloop + + add sp, sp, #16 ; 180 - (160 +4) + + ldmia sp!, {r4 - r11, pc} + + ENDP + +;----------------- +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +filter8_coeff + DCD 0x00000000, 0x00000080, 0x00000000, 0x00000000 + DCD 0xfffa0000, 0x000c007b, 0x0000ffff, 0x00000000 + DCD 0xfff50002, 0x0024006c, 0x0001fff8, 0x00000000 + DCD 0xfff70000, 0x0032005d, 0x0000fffa, 0x00000000 + DCD 0xfff00003, 0x004d004d, 0x0003fff0, 0x00000000 + DCD 0xfffa0000, 0x005d0032, 0x0000fff7, 0x00000000 + DCD 0xfff80001, 0x006c0024, 0x0002fff5, 0x00000000 + DCD 0xffff0000, 0x007b000c, 0x0000fffa, 0x00000000 + + ;DCD 0, 0, 128, 0, 0, 0 + ;DCD 0, -6, 123, 12, -1, 0 + ;DCD 2, -11, 108, 36, -8, 1 + ;DCD 0, -9, 93, 50, -6, 0 + ;DCD 3, -16, 77, 77, -16, 3 + ;DCD 0, -6, 50, 93, -9, 0 + ;DCD 1, -8, 36, 108, -11, 2 + ;DCD 0, -1, 12, 123, -6, 0 + + END diff --git a/vp8/common/arm/armv6/vp8_sad16x16_armv6.asm b/vp8/common/arm/armv6/vp8_sad16x16_armv6.asm new file mode 100644 index 0000000..1b4f5cf --- /dev/null +++ b/vp8/common/arm/armv6/vp8_sad16x16_armv6.asm @@ -0,0 +1,96 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sad16x16_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 const unsigned char *src_ptr +; r1 int src_stride +; r2 const unsigned char *ref_ptr +; r3 int ref_stride +; stack max_sad (not used) +|vp8_sad16x16_armv6| PROC + stmfd sp!, {r4-r12, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + pld [r0, r1, lsl #1] + pld [r2, r3, lsl #1] + + mov r4, #0 ; sad = 0; + mov r5, #8 ; loop count + +loop + ; 1st row + ldr r6, [r0, #0x0] ; load 4 src pixels (1A) + ldr r8, [r2, #0x0] ; load 4 ref pixels (1A) + ldr r7, [r0, #0x4] ; load 4 src pixels (1A) + ldr r9, [r2, #0x4] ; load 4 ref pixels (1A) + ldr r10, [r0, #0x8] ; load 4 src pixels (1B) + ldr r11, [r0, #0xC] ; load 4 src pixels (1B) + + usada8 r4, r8, r6, r4 ; calculate sad for 4 pixels + usad8 r8, r7, r9 ; calculate sad for 4 pixels + + ldr r12, [r2, #0x8] ; load 4 ref pixels (1B) + ldr lr, [r2, #0xC] ; load 4 ref pixels (1B) + + add r0, r0, r1 ; set src pointer to next row + add r2, r2, r3 ; set dst pointer to next row + + pld [r0, r1, lsl #1] + pld [r2, r3, lsl #1] + + usada8 r4, r10, r12, r4 ; calculate sad for 4 pixels + usada8 r8, r11, lr, r8 ; calculate sad for 4 pixels + + ldr r6, [r0, #0x0] ; load 4 src pixels (2A) + ldr r7, [r0, #0x4] ; load 4 src pixels (2A) + add r4, r4, r8 ; add partial sad values + + ; 2nd row + ldr r8, [r2, #0x0] ; load 4 ref pixels (2A) + ldr r9, [r2, #0x4] ; load 4 ref pixels (2A) + ldr r10, [r0, #0x8] ; load 4 src pixels (2B) + ldr r11, [r0, #0xC] ; load 4 src pixels (2B) + + usada8 r4, r6, r8, r4 ; calculate sad for 4 pixels + usad8 r8, r7, r9 ; calculate sad for 4 pixels + + ldr r12, [r2, #0x8] ; load 4 ref pixels (2B) + ldr lr, [r2, #0xC] ; load 4 ref pixels (2B) + + add r0, r0, r1 ; set src pointer to next row + add r2, r2, r3 ; set dst pointer to next row + + usada8 r4, r10, r12, r4 ; calculate sad for 4 pixels + usada8 r8, r11, lr, r8 ; calculate sad for 4 pixels + + pld [r0, r1, lsl #1] + pld [r2, r3, lsl #1] + + subs r5, r5, #1 ; decrement loop counter + add r4, r4, r8 ; add partial sad values + + bne loop + + mov r0, r4 ; return sad + ldmfd sp!, {r4-r12, pc} + + ENDP + + END + diff --git a/vp8/common/arm/armv6/vp8_variance16x16_armv6.asm b/vp8/common/arm/armv6/vp8_variance16x16_armv6.asm new file mode 100644 index 0000000..dc84c30 --- /dev/null +++ b/vp8/common/arm/armv6/vp8_variance16x16_armv6.asm @@ -0,0 +1,154 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance16x16_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance16x16_armv6| PROC + + stmfd sp!, {r4-r12, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + + mov r8, #0 ; initialize sum = 0 + mov r11, #0 ; initialize sse = 0 + mov r12, #16 ; set loop counter to 16 (=block height) + +loop + ; 1st 4 pixels + ldr r4, [r0, #0] ; load 4 src pixels + ldr r5, [r2, #0] ; load 4 ref pixels + + mov lr, #0 ; constant zero + + usub8 r6, r4, r5 ; calculate difference + pld [r0, r1, lsl #1] + sel r7, r6, lr ; select bytes with positive difference + usub8 r9, r5, r4 ; calculate difference with reversed operands + pld [r2, r3, lsl #1] + sel r6, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + ; calculate total sum + adds r8, r8, r4 ; add positive differences to sum + subs r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r10, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 2nd 4 pixels + ldr r4, [r0, #4] ; load 4 src pixels + ldr r5, [r2, #4] ; load 4 ref pixels + smlad r11, r10, r10, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r9, r5, r4 ; calculate difference with reversed operands + sel r6, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r10, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 3rd 4 pixels + ldr r4, [r0, #8] ; load 4 src pixels + ldr r5, [r2, #8] ; load 4 ref pixels + smlad r11, r10, r10, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r9, r5, r4 ; calculate difference with reversed operands + sel r6, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r10, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 4th 4 pixels + ldr r4, [r0, #12] ; load 4 src pixels + ldr r5, [r2, #12] ; load 4 ref pixels + smlad r11, r10, r10, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + add r0, r0, r1 ; set src_ptr to next row + sel r7, r6, lr ; select bytes with positive difference + usub8 r9, r5, r4 ; calculate difference with reversed operands + add r2, r2, r3 ; set dst_ptr to next row + sel r6, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r10, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + smlad r11, r10, r10, r11 ; dual signed multiply, add and accumulate (2) + + + subs r12, r12, #1 + + bne loop + + ; return stuff + ldr r6, [sp, #40] ; get address of sse + mul r0, r8, r8 ; sum * sum + str r11, [r6] ; store sse + sub r0, r11, r0, lsr #8 ; return (sse - ((sum * sum) >> 8)) + + ldmfd sp!, {r4-r12, pc} + + ENDP + + END + diff --git a/vp8/common/arm/armv6/vp8_variance8x8_armv6.asm b/vp8/common/arm/armv6/vp8_variance8x8_armv6.asm new file mode 100644 index 0000000..adc353d --- /dev/null +++ b/vp8/common/arm/armv6/vp8_variance8x8_armv6.asm @@ -0,0 +1,101 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance8x8_armv6| + + ARM + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance8x8_armv6| PROC + + push {r4-r10, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + + mov r12, #8 ; set loop counter to 8 (=block height) + mov r4, #0 ; initialize sum = 0 + mov r5, #0 ; initialize sse = 0 + +loop + ; 1st 4 pixels + ldr r6, [r0, #0x0] ; load 4 src pixels + ldr r7, [r2, #0x0] ; load 4 ref pixels + + mov lr, #0 ; constant zero + + usub8 r8, r6, r7 ; calculate difference + pld [r0, r1, lsl #1] + sel r10, r8, lr ; select bytes with positive difference + usub8 r9, r7, r6 ; calculate difference with reversed operands + pld [r2, r3, lsl #1] + sel r8, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r6, r10, lr ; calculate sum of positive differences + usad8 r7, r8, lr ; calculate sum of negative differences + orr r8, r8, r10 ; differences of all 4 pixels + ; calculate total sum + add r4, r4, r6 ; add positive differences to sum + sub r4, r4, r7 ; substract negative differences from sum + + ; calculate sse + uxtb16 r7, r8 ; byte (two pixels) to halfwords + uxtb16 r10, r8, ror #8 ; another two pixels to halfwords + smlad r5, r7, r7, r5 ; dual signed multiply, add and accumulate (1) + + ; 2nd 4 pixels + ldr r6, [r0, #0x4] ; load 4 src pixels + ldr r7, [r2, #0x4] ; load 4 ref pixels + smlad r5, r10, r10, r5 ; dual signed multiply, add and accumulate (2) + + usub8 r8, r6, r7 ; calculate difference + add r0, r0, r1 ; set src_ptr to next row + sel r10, r8, lr ; select bytes with positive difference + usub8 r9, r7, r6 ; calculate difference with reversed operands + add r2, r2, r3 ; set dst_ptr to next row + sel r8, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r6, r10, lr ; calculate sum of positive differences + usad8 r7, r8, lr ; calculate sum of negative differences + orr r8, r8, r10 ; differences of all 4 pixels + + ; calculate total sum + add r4, r4, r6 ; add positive differences to sum + sub r4, r4, r7 ; substract negative differences from sum + + ; calculate sse + uxtb16 r7, r8 ; byte (two pixels) to halfwords + uxtb16 r10, r8, ror #8 ; another two pixels to halfwords + smlad r5, r7, r7, r5 ; dual signed multiply, add and accumulate (1) + subs r12, r12, #1 ; next row + smlad r5, r10, r10, r5 ; dual signed multiply, add and accumulate (2) + + bne loop + + ; return stuff + ldr r8, [sp, #32] ; get address of sse + mul r1, r4, r4 ; sum * sum + str r5, [r8] ; store sse + sub r0, r5, r1, ASR #6 ; return (sse - ((sum * sum) >> 6)) + + pop {r4-r10, pc} + + ENDP + + END diff --git a/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_h_armv6.asm b/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_h_armv6.asm new file mode 100644 index 0000000..dd2ce68 --- /dev/null +++ b/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_h_armv6.asm @@ -0,0 +1,182 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance_halfpixvar16x16_h_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance_halfpixvar16x16_h_armv6| PROC + + stmfd sp!, {r4-r12, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + + mov r8, #0 ; initialize sum = 0 + ldr r10, c80808080 + mov r11, #0 ; initialize sse = 0 + mov r12, #16 ; set loop counter to 16 (=block height) + mov lr, #0 ; constant zero +loop + ; 1st 4 pixels + ldr r4, [r0, #0] ; load 4 src pixels + ldr r6, [r0, #1] ; load 4 src pixels with 1 byte offset + ldr r5, [r2, #0] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + usub8 r6, r4, r5 ; calculate difference + pld [r0, r1, lsl #1] + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + pld [r2, r3, lsl #1] + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + ; calculate total sum + adds r8, r8, r4 ; add positive differences to sum + subs r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 2nd 4 pixels + ldr r4, [r0, #4] ; load 4 src pixels + ldr r6, [r0, #5] ; load 4 src pixels with 1 byte offset + ldr r5, [r2, #4] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 3rd 4 pixels + ldr r4, [r0, #8] ; load 4 src pixels + ldr r6, [r0, #9] ; load 4 src pixels with 1 byte offset + ldr r5, [r2, #8] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 4th 4 pixels + ldr r4, [r0, #12] ; load 4 src pixels + ldr r6, [r0, #13] ; load 4 src pixels with 1 byte offset + ldr r5, [r2, #12] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + add r0, r0, r1 ; set src_ptr to next row + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + add r2, r2, r3 ; set dst_ptr to next row + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + subs r12, r12, #1 + + bne loop + + ; return stuff + ldr r6, [sp, #40] ; get address of sse + mul r0, r8, r8 ; sum * sum + str r11, [r6] ; store sse + sub r0, r11, r0, lsr #8 ; return (sse - ((sum * sum) >> 8)) + + ldmfd sp!, {r4-r12, pc} + + ENDP + +c80808080 + DCD 0x80808080 + + END + diff --git a/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_hv_armv6.asm b/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_hv_armv6.asm new file mode 100644 index 0000000..f972d9b --- /dev/null +++ b/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_hv_armv6.asm @@ -0,0 +1,222 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance_halfpixvar16x16_hv_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance_halfpixvar16x16_hv_armv6| PROC + + stmfd sp!, {r4-r12, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + + mov r8, #0 ; initialize sum = 0 + ldr r10, c80808080 + mov r11, #0 ; initialize sse = 0 + mov r12, #16 ; set loop counter to 16 (=block height) + mov lr, #0 ; constant zero +loop + add r9, r0, r1 ; pointer to pixels on the next row + ; 1st 4 pixels + ldr r4, [r0, #0] ; load source pixels a, row N + ldr r6, [r0, #1] ; load source pixels b, row N + ldr r5, [r9, #0] ; load source pixels c, row N+1 + ldr r7, [r9, #1] ; load source pixels d, row N+1 + + ; x = (a + b + 1) >> 1, interpolate pixels horizontally on row N + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + ; y = (c + d + 1) >> 1, interpolate pixels horizontally on row N+1 + mvn r7, r7 + uhsub8 r5, r5, r7 + eor r5, r5, r10 + ; z = (x + y + 1) >> 1, interpolate half pixel values vertically + mvn r5, r5 + uhsub8 r4, r4, r5 + ldr r5, [r2, #0] ; load 4 ref pixels + eor r4, r4, r10 + + usub8 r6, r4, r5 ; calculate difference + pld [r0, r1, lsl #1] + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + pld [r2, r3, lsl #1] + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + ; calculate total sum + adds r8, r8, r4 ; add positive differences to sum + subs r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 2nd 4 pixels + ldr r4, [r0, #4] ; load source pixels a, row N + ldr r6, [r0, #5] ; load source pixels b, row N + ldr r5, [r9, #4] ; load source pixels c, row N+1 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + ldr r7, [r9, #5] ; load source pixels d, row N+1 + + ; x = (a + b + 1) >> 1, interpolate pixels horizontally on row N + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + ; y = (c + d + 1) >> 1, interpolate pixels horizontally on row N+1 + mvn r7, r7 + uhsub8 r5, r5, r7 + eor r5, r5, r10 + ; z = (x + y + 1) >> 1, interpolate half pixel values vertically + mvn r5, r5 + uhsub8 r4, r4, r5 + ldr r5, [r2, #4] ; load 4 ref pixels + eor r4, r4, r10 + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 3rd 4 pixels + ldr r4, [r0, #8] ; load source pixels a, row N + ldr r6, [r0, #9] ; load source pixels b, row N + ldr r5, [r9, #8] ; load source pixels c, row N+1 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + ldr r7, [r9, #9] ; load source pixels d, row N+1 + + ; x = (a + b + 1) >> 1, interpolate pixels horizontally on row N + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + ; y = (c + d + 1) >> 1, interpolate pixels horizontally on row N+1 + mvn r7, r7 + uhsub8 r5, r5, r7 + eor r5, r5, r10 + ; z = (x + y + 1) >> 1, interpolate half pixel values vertically + mvn r5, r5 + uhsub8 r4, r4, r5 + ldr r5, [r2, #8] ; load 4 ref pixels + eor r4, r4, r10 + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 4th 4 pixels + ldr r4, [r0, #12] ; load source pixels a, row N + ldr r6, [r0, #13] ; load source pixels b, row N + ldr r5, [r9, #12] ; load source pixels c, row N+1 + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + ldr r7, [r9, #13] ; load source pixels d, row N+1 + + ; x = (a + b + 1) >> 1, interpolate pixels horizontally on row N + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + ; y = (c + d + 1) >> 1, interpolate pixels horizontally on row N+1 + mvn r7, r7 + uhsub8 r5, r5, r7 + eor r5, r5, r10 + ; z = (x + y + 1) >> 1, interpolate half pixel values vertically + mvn r5, r5 + uhsub8 r4, r4, r5 + ldr r5, [r2, #12] ; load 4 ref pixels + eor r4, r4, r10 + + usub8 r6, r4, r5 ; calculate difference + add r0, r0, r1 ; set src_ptr to next row + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + add r2, r2, r3 ; set dst_ptr to next row + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + subs r12, r12, #1 + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + bne loop + + ; return stuff + ldr r6, [sp, #40] ; get address of sse + mul r0, r8, r8 ; sum * sum + str r11, [r6] ; store sse + sub r0, r11, r0, lsr #8 ; return (sse - ((sum * sum) >> 8)) + + ldmfd sp!, {r4-r12, pc} + + ENDP + +c80808080 + DCD 0x80808080 + + END diff --git a/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_v_armv6.asm b/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_v_armv6.asm new file mode 100644 index 0000000..f5da9c0 --- /dev/null +++ b/vp8/common/arm/armv6/vp8_variance_halfpixvar16x16_v_armv6.asm @@ -0,0 +1,184 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance_halfpixvar16x16_v_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance_halfpixvar16x16_v_armv6| PROC + + stmfd sp!, {r4-r12, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + + mov r8, #0 ; initialize sum = 0 + ldr r10, c80808080 + mov r11, #0 ; initialize sse = 0 + mov r12, #16 ; set loop counter to 16 (=block height) + mov lr, #0 ; constant zero +loop + add r9, r0, r1 ; set src pointer to next row + ; 1st 4 pixels + ldr r4, [r0, #0] ; load 4 src pixels + ldr r6, [r9, #0] ; load 4 src pixels from next row + ldr r5, [r2, #0] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + usub8 r6, r4, r5 ; calculate difference + pld [r0, r1, lsl #1] + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + pld [r2, r3, lsl #1] + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + ; calculate total sum + adds r8, r8, r4 ; add positive differences to sum + subs r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 2nd 4 pixels + ldr r4, [r0, #4] ; load 4 src pixels + ldr r6, [r9, #4] ; load 4 src pixels from next row + ldr r5, [r2, #4] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 3rd 4 pixels + ldr r4, [r0, #8] ; load 4 src pixels + ldr r6, [r9, #8] ; load 4 src pixels from next row + ldr r5, [r2, #8] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + + ; 4th 4 pixels + ldr r4, [r0, #12] ; load 4 src pixels + ldr r6, [r9, #12] ; load 4 src pixels from next row + ldr r5, [r2, #12] ; load 4 ref pixels + + ; bilinear interpolation + mvn r6, r6 + uhsub8 r4, r4, r6 + eor r4, r4, r10 + + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + usub8 r6, r4, r5 ; calculate difference + add r0, r0, r1 ; set src_ptr to next row + sel r7, r6, lr ; select bytes with positive difference + usub8 r6, r5, r4 ; calculate difference with reversed operands + add r2, r2, r3 ; set dst_ptr to next row + sel r6, r6, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r4, r7, lr ; calculate sum of positive differences + usad8 r5, r6, lr ; calculate sum of negative differences + orr r6, r6, r7 ; differences of all 4 pixels + + ; calculate total sum + add r8, r8, r4 ; add positive differences to sum + sub r8, r8, r5 ; substract negative differences from sum + + ; calculate sse + uxtb16 r5, r6 ; byte (two pixels) to halfwords + uxtb16 r7, r6, ror #8 ; another two pixels to halfwords + smlad r11, r5, r5, r11 ; dual signed multiply, add and accumulate (1) + smlad r11, r7, r7, r11 ; dual signed multiply, add and accumulate (2) + + + subs r12, r12, #1 + + bne loop + + ; return stuff + ldr r6, [sp, #40] ; get address of sse + mul r0, r8, r8 ; sum * sum + str r11, [r6] ; store sse + sub r0, r11, r0, lsr #8 ; return (sse - ((sum * sum) >> 8)) + + ldmfd sp!, {r4-r12, pc} + + ENDP + +c80808080 + DCD 0x80808080 + + END + diff --git a/vp8/common/arm/bilinearfilter_arm.c b/vp8/common/arm/bilinearfilter_arm.c new file mode 100644 index 0000000..c63073c --- /dev/null +++ b/vp8/common/arm/bilinearfilter_arm.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include +#include "vp8/common/filter.h" +#include "bilinearfilter_arm.h" + +void vp8_filter_block2d_bil_armv6 +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + unsigned int src_pitch, + unsigned int dst_pitch, + const short *HFilter, + const short *VFilter, + int Width, + int Height +) +{ + unsigned short FData[36*16]; /* Temp data buffer used in filtering */ + + /* First filter 1-D horizontally... */ + vp8_filter_block2d_bil_first_pass_armv6(src_ptr, FData, src_pitch, Height + 1, Width, HFilter); + + /* then 1-D vertically... */ + vp8_filter_block2d_bil_second_pass_armv6(FData, dst_ptr, dst_pitch, Height, Width, VFilter); +} + + +void vp8_bilinear_predict4x4_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 4, 4); +} + +void vp8_bilinear_predict8x8_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 8); +} + +void vp8_bilinear_predict8x4_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 4); +} + +void vp8_bilinear_predict16x16_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 16, 16); +} diff --git a/vp8/common/arm/bilinearfilter_arm.h b/vp8/common/arm/bilinearfilter_arm.h new file mode 100644 index 0000000..b7155d3 --- /dev/null +++ b/vp8/common/arm/bilinearfilter_arm.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef BILINEARFILTER_ARM_H +#define BILINEARFILTER_ARM_H + +extern void vp8_filter_block2d_bil_first_pass_armv6 +( + const unsigned char *src_ptr, + unsigned short *dst_ptr, + unsigned int src_pitch, + unsigned int height, + unsigned int width, + const short *vp8_filter +); + +extern void vp8_filter_block2d_bil_second_pass_armv6 +( + const unsigned short *src_ptr, + unsigned char *dst_ptr, + int dst_pitch, + unsigned int height, + unsigned int width, + const short *vp8_filter +); + +#endif /* BILINEARFILTER_ARM_H */ diff --git a/vp8/common/arm/dequantize_arm.c b/vp8/common/arm/dequantize_arm.c new file mode 100644 index 0000000..70e72aa --- /dev/null +++ b/vp8/common/arm/dequantize_arm.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vp8/common/blockd.h" + +#if HAVE_NEON +extern void vp8_dequantize_b_loop_neon(short *Q, short *DQC, short *DQ); +#endif + +#if HAVE_MEDIA +extern void vp8_dequantize_b_loop_v6(short *Q, short *DQC, short *DQ); +#endif + +#if HAVE_NEON + +void vp8_dequantize_b_neon(BLOCKD *d, short *DQC) +{ + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + + vp8_dequantize_b_loop_neon(Q, DQC, DQ); +} +#endif + +#if HAVE_MEDIA +void vp8_dequantize_b_v6(BLOCKD *d, short *DQC) +{ + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + + vp8_dequantize_b_loop_v6(Q, DQC, DQ); +} +#endif diff --git a/vp8/common/arm/filter_arm.c b/vp8/common/arm/filter_arm.c new file mode 100644 index 0000000..148951a --- /dev/null +++ b/vp8/common/arm/filter_arm.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include +#include "vp8/common/filter.h" +#include "vpx_ports/mem.h" + +extern void vp8_filter_block2d_first_pass_armv6 +( + unsigned char *src_ptr, + short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_width, + unsigned int output_height, + const short *vp8_filter +); + +// 8x8 +extern void vp8_filter_block2d_first_pass_8x8_armv6 +( + unsigned char *src_ptr, + short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_width, + unsigned int output_height, + const short *vp8_filter +); + +// 16x16 +extern void vp8_filter_block2d_first_pass_16x16_armv6 +( + unsigned char *src_ptr, + short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_width, + unsigned int output_height, + const short *vp8_filter +); + +extern void vp8_filter_block2d_second_pass_armv6 +( + short *src_ptr, + unsigned char *output_ptr, + unsigned int output_pitch, + unsigned int cnt, + const short *vp8_filter +); + +extern void vp8_filter4_block2d_second_pass_armv6 +( + short *src_ptr, + unsigned char *output_ptr, + unsigned int output_pitch, + unsigned int cnt, + const short *vp8_filter +); + +extern void vp8_filter_block2d_first_pass_only_armv6 +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int cnt, + unsigned int output_pitch, + const short *vp8_filter +); + + +extern void vp8_filter_block2d_second_pass_only_armv6 +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int cnt, + unsigned int output_pitch, + const short *vp8_filter +); + +#if HAVE_MEDIA +void vp8_sixtap_predict4x4_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 12*4); /* Temp data buffer used in filtering */ + + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + /* Vfilter is null. First pass only */ + if (xoffset && !yoffset) + { + /*vp8_filter_block2d_first_pass_armv6 ( src_ptr, FData+2, src_pixels_per_line, 4, 4, HFilter ); + vp8_filter_block2d_second_pass_armv6 ( FData+2, dst_ptr, dst_pitch, 4, VFilter );*/ + + vp8_filter_block2d_first_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 4, dst_pitch, HFilter); + } + /* Hfilter is null. Second pass only */ + else if (!xoffset && yoffset) + { + vp8_filter_block2d_second_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 4, dst_pitch, VFilter); + } + else + { + /* Vfilter is a 4 tap filter */ + if (yoffset & 0x1) + { + vp8_filter_block2d_first_pass_armv6(src_ptr - src_pixels_per_line, FData + 1, src_pixels_per_line, 4, 7, HFilter); + vp8_filter4_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 4, VFilter); + } + /* Vfilter is 6 tap filter */ + else + { + vp8_filter_block2d_first_pass_armv6(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 4, 9, HFilter); + vp8_filter_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 4, VFilter); + } + } +} + +void vp8_sixtap_predict8x8_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 16*8); /* Temp data buffer used in filtering */ + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + if (xoffset && !yoffset) + { + vp8_filter_block2d_first_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 8, dst_pitch, HFilter); + } + /* Hfilter is null. Second pass only */ + else if (!xoffset && yoffset) + { + vp8_filter_block2d_second_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 8, dst_pitch, VFilter); + } + else + { + if (yoffset & 0x1) + { + vp8_filter_block2d_first_pass_8x8_armv6(src_ptr - src_pixels_per_line, FData + 1, src_pixels_per_line, 8, 11, HFilter); + vp8_filter4_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 8, VFilter); + } + else + { + vp8_filter_block2d_first_pass_8x8_armv6(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 8, 13, HFilter); + vp8_filter_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 8, VFilter); + } + } +} + + +void vp8_sixtap_predict16x16_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 24*16); /* Temp data buffer used in filtering */ + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + if (xoffset && !yoffset) + { + vp8_filter_block2d_first_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 16, dst_pitch, HFilter); + } + /* Hfilter is null. Second pass only */ + else if (!xoffset && yoffset) + { + vp8_filter_block2d_second_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 16, dst_pitch, VFilter); + } + else + { + if (yoffset & 0x1) + { + vp8_filter_block2d_first_pass_16x16_armv6(src_ptr - src_pixels_per_line, FData + 1, src_pixels_per_line, 16, 19, HFilter); + vp8_filter4_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 16, VFilter); + } + else + { + vp8_filter_block2d_first_pass_16x16_armv6(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 16, 21, HFilter); + vp8_filter_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 16, VFilter); + } + } + +} +#endif diff --git a/vp8/common/arm/loopfilter_arm.c b/vp8/common/arm/loopfilter_arm.c new file mode 100644 index 0000000..b8f9bd9 --- /dev/null +++ b/vp8/common/arm/loopfilter_arm.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vp8/common/loopfilter.h" +#include "vp8/common/onyxc_int.h" + +#define prototype_loopfilter(sym) \ + void sym(unsigned char *src, int pitch, const unsigned char *blimit,\ + const unsigned char *limit, const unsigned char *thresh, int count) + +#if HAVE_MEDIA +extern prototype_loopfilter(vp8_loop_filter_horizontal_edge_armv6); +extern prototype_loopfilter(vp8_loop_filter_vertical_edge_armv6); +extern prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_armv6); +extern prototype_loopfilter(vp8_mbloop_filter_vertical_edge_armv6); +#endif + +#if HAVE_NEON +typedef void loopfilter_y_neon(unsigned char *src, int pitch, + unsigned char blimit, unsigned char limit, unsigned char thresh); +typedef void loopfilter_uv_neon(unsigned char *u, int pitch, + unsigned char blimit, unsigned char limit, unsigned char thresh, + unsigned char *v); + +extern loopfilter_y_neon vp8_loop_filter_horizontal_edge_y_neon; +extern loopfilter_y_neon vp8_loop_filter_vertical_edge_y_neon; +extern loopfilter_y_neon vp8_mbloop_filter_horizontal_edge_y_neon; +extern loopfilter_y_neon vp8_mbloop_filter_vertical_edge_y_neon; + +extern loopfilter_uv_neon vp8_loop_filter_horizontal_edge_uv_neon; +extern loopfilter_uv_neon vp8_loop_filter_vertical_edge_uv_neon; +extern loopfilter_uv_neon vp8_mbloop_filter_horizontal_edge_uv_neon; +extern loopfilter_uv_neon vp8_mbloop_filter_vertical_edge_uv_neon; +#endif + +#if HAVE_MEDIA +/* ARMV6/MEDIA loopfilter functions*/ +/* Horizontal MB filtering */ +void vp8_loop_filter_mbh_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_mbloop_filter_horizontal_edge_armv6(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_armv6(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_armv6(v_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); +} + +/* Vertical MB Filtering */ +void vp8_loop_filter_mbv_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_mbloop_filter_vertical_edge_armv6(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_armv6(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_armv6(v_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); +} + +/* Horizontal B Filtering */ +void vp8_loop_filter_bh_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_loop_filter_horizontal_edge_armv6(y_ptr + 4 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_horizontal_edge_armv6(y_ptr + 8 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_horizontal_edge_armv6(y_ptr + 12 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_armv6(u_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_armv6(v_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); +} + +void vp8_loop_filter_bhs_armv6(unsigned char *y_ptr, int y_stride, + const unsigned char *blimit) +{ + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr + 4 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr + 8 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr + 12 * y_stride, y_stride, blimit); +} + +/* Vertical B Filtering */ +void vp8_loop_filter_bv_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_loop_filter_vertical_edge_armv6(y_ptr + 4, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_vertical_edge_armv6(y_ptr + 8, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_vertical_edge_armv6(y_ptr + 12, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_armv6(u_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_armv6(v_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); +} + +void vp8_loop_filter_bvs_armv6(unsigned char *y_ptr, int y_stride, + const unsigned char *blimit) +{ + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr + 4, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr + 8, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr + 12, y_stride, blimit); +} +#endif + +#if HAVE_NEON +/* NEON loopfilter functions */ +/* Horizontal MB filtering */ +void vp8_loop_filter_mbh_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + unsigned char mblim = *lfi->mblim; + unsigned char lim = *lfi->lim; + unsigned char hev_thr = *lfi->hev_thr; + vp8_mbloop_filter_horizontal_edge_y_neon(y_ptr, y_stride, mblim, lim, hev_thr); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_uv_neon(u_ptr, uv_stride, mblim, lim, hev_thr, v_ptr); +} + +/* Vertical MB Filtering */ +void vp8_loop_filter_mbv_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + unsigned char mblim = *lfi->mblim; + unsigned char lim = *lfi->lim; + unsigned char hev_thr = *lfi->hev_thr; + + vp8_mbloop_filter_vertical_edge_y_neon(y_ptr, y_stride, mblim, lim, hev_thr); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_uv_neon(u_ptr, uv_stride, mblim, lim, hev_thr, v_ptr); +} + +/* Horizontal B Filtering */ +void vp8_loop_filter_bh_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + unsigned char blim = *lfi->blim; + unsigned char lim = *lfi->lim; + unsigned char hev_thr = *lfi->hev_thr; + + vp8_loop_filter_horizontal_edge_y_neon(y_ptr + 4 * y_stride, y_stride, blim, lim, hev_thr); + vp8_loop_filter_horizontal_edge_y_neon(y_ptr + 8 * y_stride, y_stride, blim, lim, hev_thr); + vp8_loop_filter_horizontal_edge_y_neon(y_ptr + 12 * y_stride, y_stride, blim, lim, hev_thr); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_uv_neon(u_ptr + 4 * uv_stride, uv_stride, blim, lim, hev_thr, v_ptr + 4 * uv_stride); +} + +/* Vertical B Filtering */ +void vp8_loop_filter_bv_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + unsigned char blim = *lfi->blim; + unsigned char lim = *lfi->lim; + unsigned char hev_thr = *lfi->hev_thr; + + vp8_loop_filter_vertical_edge_y_neon(y_ptr + 4, y_stride, blim, lim, hev_thr); + vp8_loop_filter_vertical_edge_y_neon(y_ptr + 8, y_stride, blim, lim, hev_thr); + vp8_loop_filter_vertical_edge_y_neon(y_ptr + 12, y_stride, blim, lim, hev_thr); + + if (u_ptr) + vp8_loop_filter_vertical_edge_uv_neon(u_ptr + 4, uv_stride, blim, lim, hev_thr, v_ptr + 4); +} +#endif diff --git a/vp8/common/arm/neon/bilinearpredict16x16_neon.asm b/vp8/common/arm/neon/bilinearpredict16x16_neon.asm new file mode 100644 index 0000000..e392786 --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict16x16_neon.asm @@ -0,0 +1,357 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict16x16_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +|vp8_bilinear_predict16x16_neon| PROC + push {r4-r5, lr} + + adr r12, bifilter16_coeff + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_bfilter16x16_only + + add r2, r12, r2, lsl #3 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {d31}, [r2] ;load first_pass filter + + beq firstpass_bfilter16x16_only + + sub sp, sp, #272 ;reserve space on stack for temporary storage + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + mov lr, sp + vld1.u8 {d5, d6, d7}, [r0], r1 + + mov r2, #3 ;loop counter + vld1.u8 {d8, d9, d10}, [r0], r1 + + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {d11, d12, d13}, [r0], r1 + + vdup.8 d1, d31[4] + +;First Pass: output_height lines x output_width columns (17x16) +filt_blk2d_fp16x16_loop_neon + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vqrshrn.u16 d21, q14, #7 + vld1.u8 {d5, d6, d7}, [r0], r1 + + vst1.u8 {d14, d15, d16, d17}, [lr]! ;store result + vld1.u8 {d8, d9, d10}, [r0], r1 + vst1.u8 {d18, d19, d20, d21}, [lr]! + vld1.u8 {d11, d12, d13}, [r0], r1 + + bne filt_blk2d_fp16x16_loop_neon + +;First-pass filtering for rest 5 lines + vld1.u8 {d14, d15, d16}, [r0], r1 + + vmull.u8 q9, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q10, d3, d0 + vmull.u8 q11, d5, d0 + vmull.u8 q12, d6, d0 + vmull.u8 q13, d8, d0 + vmull.u8 q14, d9, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + + vmlal.u8 q9, d2, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q11, d5, d1 + vmlal.u8 q13, d8, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + + vmlal.u8 q10, d3, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q12, d6, d1 + vmlal.u8 q14, d9, d1 + + vmull.u8 q1, d11, d0 + vmull.u8 q2, d12, d0 + vmull.u8 q3, d14, d0 + vmull.u8 q4, d15, d0 + + vext.8 d11, d11, d12, #1 ;construct src_ptr[1] + vext.8 d14, d14, d15, #1 + + vmlal.u8 q1, d11, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q3, d14, d1 + + vext.8 d12, d12, d13, #1 + vext.8 d15, d15, d16, #1 + + vmlal.u8 q2, d12, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q4, d15, d1 + + vqrshrn.u16 d10, q9, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d11, q10, #7 + vqrshrn.u16 d12, q11, #7 + vqrshrn.u16 d13, q12, #7 + vqrshrn.u16 d14, q13, #7 + vqrshrn.u16 d15, q14, #7 + vqrshrn.u16 d16, q1, #7 + vqrshrn.u16 d17, q2, #7 + vqrshrn.u16 d18, q3, #7 + vqrshrn.u16 d19, q4, #7 + + vst1.u8 {d10, d11, d12, d13}, [lr]! ;store result + vst1.u8 {d14, d15, d16, d17}, [lr]! + vst1.u8 {d18, d19}, [lr]! + +;Second pass: 16x16 +;secondpass_filter + add r3, r12, r3, lsl #3 + sub lr, lr, #272 + + vld1.u32 {d31}, [r3] ;load second_pass filter + + vld1.u8 {d22, d23}, [lr]! ;load src data + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + mov r12, #4 ;loop counter + +filt_blk2d_sp16x16_loop_neon + vld1.u8 {d24, d25}, [lr]! + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vld1.u8 {d26, d27}, [lr]! + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [lr]! + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [lr]! + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + subs r12, r12, #1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r4], r5 ;store result + vst1.u8 {d4, d5}, [r4], r5 + vst1.u8 {d6, d7}, [r4], r5 + vmov q11, q15 + vst1.u8 {d8, d9}, [r4], r5 + + bne filt_blk2d_sp16x16_loop_neon + + add sp, sp, #272 + + pop {r4-r5,pc} + +;-------------------- +firstpass_bfilter16x16_only + mov r2, #4 ;loop counter + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vdup.8 d1, d31[4] + +;First Pass: output_height lines x output_width columns (16x16) +filt_blk2d_fpo16x16_loop_neon + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vld1.u8 {d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10}, [r0], r1 + vld1.u8 {d11, d12, d13}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + vst1.u8 {d14, d15}, [r4], r5 ;store result + vqrshrn.u16 d21, q14, #7 + + vst1.u8 {d16, d17}, [r4], r5 + vst1.u8 {d18, d19}, [r4], r5 + vst1.u8 {d20, d21}, [r4], r5 + + bne filt_blk2d_fpo16x16_loop_neon + pop {r4-r5,pc} + +;--------------------- +secondpass_bfilter16x16_only +;Second pass: 16x16 +;secondpass_filter + add r3, r12, r3, lsl #3 + mov r12, #4 ;loop counter + vld1.u32 {d31}, [r3] ;load second_pass filter + vld1.u8 {d22, d23}, [r0], r1 ;load src data + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + +filt_blk2d_spo16x16_loop_neon + vld1.u8 {d24, d25}, [r0], r1 + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vld1.u8 {d26, d27}, [r0], r1 + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [r0], r1 + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [r0], r1 + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r4], r5 ;store result + subs r12, r12, #1 + vst1.u8 {d4, d5}, [r4], r5 + vmov q11, q15 + vst1.u8 {d6, d7}, [r4], r5 + vst1.u8 {d8, d9}, [r4], r5 + + bne filt_blk2d_spo16x16_loop_neon + pop {r4-r5,pc} + + ENDP + +;----------------- + +bifilter16_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END diff --git a/vp8/common/arm/neon/bilinearpredict4x4_neon.asm b/vp8/common/arm/neon/bilinearpredict4x4_neon.asm new file mode 100644 index 0000000..0ac6243 --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict4x4_neon.asm @@ -0,0 +1,130 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict4x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_bilinear_predict4x4_neon| PROC + push {r4, lr} + + adr r12, bifilter4_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (5x4) + vld1.u8 {d2}, [r0], r1 ;load src data + add r2, r12, r2, lsl #3 ;calculate Hfilter location (2coeffsx4bytes=8bytes) + + vld1.u8 {d3}, [r0], r1 + vld1.u32 {d31}, [r2] ;first_pass filter + + vld1.u8 {d4}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0-d1) + vld1.u8 {d5}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {d6}, [r0], r1 + + vshr.u64 q4, q1, #8 ;construct src_ptr[1] + vshr.u64 q5, q2, #8 + vshr.u64 d12, d6, #8 + + vzip.32 d2, d3 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d4, d5 + vzip.32 d8, d9 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q8, d4, d0 + vmull.u8 q9, d6, d0 + + vmlal.u8 q7, d8, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q8, d10, d1 + vmlal.u8 q9, d12, d1 + + vqrshrn.u16 d28, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d29, q8, #7 + vqrshrn.u16 d30, q9, #7 + +;Second pass: 4x4 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq skip_secondpass_filter + + add r3, r12, r3, lsl #3 ;calculate Vfilter location + vld1.u32 {d31}, [r3] ;load second_pass filter + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d31[4] + + vmull.u8 q1, d28, d0 + vmull.u8 q2, d29, d0 + + vext.8 d26, d28, d29, #4 ;construct src_ptr[pixel_step] + vext.8 d27, d29, d30, #4 + + vmlal.u8 q1, d26, d1 + vmlal.u8 q2, d27, d1 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + + vst1.32 {d2[0]}, [r4] ;store result + vst1.32 {d2[1]}, [r0] + vst1.32 {d3[0]}, [r1] + vst1.32 {d3[1]}, [r2] + + pop {r4, pc} + +;-------------------- +skip_firstpass_filter + + vld1.32 {d28[0]}, [r0], r1 ;load src data + vld1.32 {d28[1]}, [r0], r1 + vld1.32 {d29[0]}, [r0], r1 + vld1.32 {d29[1]}, [r0], r1 + vld1.32 {d30[0]}, [r0], r1 + + b secondpass_filter + +;--------------------- +skip_secondpass_filter + vst1.32 {d28[0]}, [r4], lr ;store result + vst1.32 {d28[1]}, [r4], lr + vst1.32 {d29[0]}, [r4], lr + vst1.32 {d29[1]}, [r4], lr + + pop {r4, pc} + + ENDP + +;----------------- + +bifilter4_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END diff --git a/vp8/common/arm/neon/bilinearpredict8x4_neon.asm b/vp8/common/arm/neon/bilinearpredict8x4_neon.asm new file mode 100644 index 0000000..41f5c45 --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict8x4_neon.asm @@ -0,0 +1,135 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict8x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_bilinear_predict8x4_neon| PROC + push {r4, lr} + + adr r12, bifilter8x4_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (5x8) + add r2, r12, r2, lsl #3 ;calculate filter location + + vld1.u8 {q1}, [r0], r1 ;load src data + vld1.u32 {d31}, [r2] ;load first_pass filter + vld1.u8 {q2}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {q3}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {q4}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vld1.u8 {q5}, [r0], r1 + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + vext.8 d11, d10, d11, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + vmlal.u8 q10, d11, d1 + + vqrshrn.u16 d22, q6, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d23, q7, #7 + vqrshrn.u16 d24, q8, #7 + vqrshrn.u16 d25, q9, #7 + vqrshrn.u16 d26, q10, #7 + +;Second pass: 4x8 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq skip_secondpass_filter + + add r3, r12, r3, lsl #3 + add r0, r4, lr + + vld1.u32 {d31}, [r3] ;load second_pass filter + add r1, r0, lr + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q2, d23, d0 + vmull.u8 q3, d24, d0 + vmull.u8 q4, d25, d0 + + vmlal.u8 q1, d23, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d24, d1 + vmlal.u8 q3, d25, d1 + vmlal.u8 q4, d26, d1 + + add r2, r1, lr + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + + vst1.u8 {d2}, [r4] ;store result + vst1.u8 {d3}, [r0] + vst1.u8 {d4}, [r1] + vst1.u8 {d5}, [r2] + + pop {r4, pc} + +;-------------------- +skip_firstpass_filter + vld1.u8 {d22}, [r0], r1 ;load src data + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + + b secondpass_filter + +;--------------------- +skip_secondpass_filter + vst1.u8 {d22}, [r4], lr ;store result + vst1.u8 {d23}, [r4], lr + vst1.u8 {d24}, [r4], lr + vst1.u8 {d25}, [r4], lr + + pop {r4, pc} + + ENDP + +;----------------- + +bifilter8x4_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END diff --git a/vp8/common/arm/neon/bilinearpredict8x8_neon.asm b/vp8/common/arm/neon/bilinearpredict8x8_neon.asm new file mode 100644 index 0000000..c4711bc --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict8x8_neon.asm @@ -0,0 +1,183 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict8x8_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_bilinear_predict8x8_neon| PROC + push {r4, lr} + + adr r12, bifilter8_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (9x8) + add r2, r12, r2, lsl #3 ;calculate filter location + + vld1.u8 {q1}, [r0], r1 ;load src data + vld1.u32 {d31}, [r2] ;load first_pass filter + vld1.u8 {q2}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {q3}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {q4}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + + vld1.u8 {q1}, [r0], r1 ;load src data + vqrshrn.u16 d22, q6, #7 ;shift/round/saturate to u8 + vld1.u8 {q2}, [r0], r1 + vqrshrn.u16 d23, q7, #7 + vld1.u8 {q3}, [r0], r1 + vqrshrn.u16 d24, q8, #7 + vld1.u8 {q4}, [r0], r1 + vqrshrn.u16 d25, q9, #7 + + ;first_pass filtering on the rest 5-line data + vld1.u8 {q5}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + vext.8 d11, d10, d11, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + vmlal.u8 q10, d11, d1 + + vqrshrn.u16 d26, q6, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d27, q7, #7 + vqrshrn.u16 d28, q8, #7 + vqrshrn.u16 d29, q9, #7 + vqrshrn.u16 d30, q10, #7 + +;Second pass: 8x8 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq skip_secondpass_filter + + add r3, r12, r3, lsl #3 + add r0, r4, lr + + vld1.u32 {d31}, [r3] ;load second_pass filter + add r1, r0, lr + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q2, d23, d0 + vmull.u8 q3, d24, d0 + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d23, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d24, d1 + vmlal.u8 q3, d25, d1 + vmlal.u8 q4, d26, d1 + vmlal.u8 q5, d27, d1 + vmlal.u8 q6, d28, d1 + vmlal.u8 q7, d29, d1 + vmlal.u8 q8, d30, d1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2}, [r4] ;store result + vst1.u8 {d3}, [r0] + vst1.u8 {d4}, [r1], lr + vst1.u8 {d5}, [r1], lr + vst1.u8 {d6}, [r1], lr + vst1.u8 {d7}, [r1], lr + vst1.u8 {d8}, [r1], lr + vst1.u8 {d9}, [r1], lr + + pop {r4, pc} + +;-------------------- +skip_firstpass_filter + vld1.u8 {d22}, [r0], r1 ;load src data + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + vld1.u8 {d27}, [r0], r1 + vld1.u8 {d28}, [r0], r1 + vld1.u8 {d29}, [r0], r1 + vld1.u8 {d30}, [r0], r1 + + b secondpass_filter + +;--------------------- +skip_secondpass_filter + vst1.u8 {d22}, [r4], lr ;store result + vst1.u8 {d23}, [r4], lr + vst1.u8 {d24}, [r4], lr + vst1.u8 {d25}, [r4], lr + vst1.u8 {d26}, [r4], lr + vst1.u8 {d27}, [r4], lr + vst1.u8 {d28}, [r4], lr + vst1.u8 {d29}, [r4], lr + + pop {r4, pc} + + ENDP + +;----------------- + +bifilter8_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END diff --git a/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm b/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm new file mode 100644 index 0000000..e3ea91f --- /dev/null +++ b/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm @@ -0,0 +1,584 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_build_intra_predictors_mby_neon_func| + EXPORT |vp8_build_intra_predictors_mby_s_neon_func| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *y_buffer +; r1 unsigned char *ypred_ptr +; r2 int y_stride +; r3 int mode +; stack int Up +; stack int Left + +|vp8_build_intra_predictors_mby_neon_func| PROC + push {r4-r8, lr} + + cmp r3, #0 + beq case_dc_pred + cmp r3, #1 + beq case_v_pred + cmp r3, #2 + beq case_h_pred + cmp r3, #3 + beq case_tm_pred + +case_dc_pred + ldr r4, [sp, #24] ; Up + ldr r5, [sp, #28] ; Left + + ; Default the DC average to 128 + mov r12, #128 + vdup.u8 q0, r12 + + ; Zero out running sum + mov r12, #0 + + ; compute shift and jump + adds r7, r4, r5 + beq skip_dc_pred_up_left + + ; Load above row, if it exists + cmp r4, #0 + beq skip_dc_pred_up + + sub r6, r0, r2 + vld1.8 {q1}, [r6] + vpaddl.u8 q2, q1 + vpaddl.u16 q3, q2 + vpaddl.u32 q4, q3 + + vmov.32 r4, d8[0] + vmov.32 r6, d9[0] + + add r12, r4, r6 + + ; Move back to interger registers + +skip_dc_pred_up + + cmp r5, #0 + beq skip_dc_pred_left + + sub r0, r0, #1 + + ; Load left row, if it exists + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0] + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + +skip_dc_pred_left + add r7, r7, #3 ; Shift + sub r4, r7, #1 + mov r5, #1 + add r12, r12, r5, lsl r4 + mov r5, r12, lsr r7 ; expected_dc + + vdup.u8 q0, r5 + +skip_dc_pred_up_left + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + + pop {r4-r8,pc} +case_v_pred + ; Copy down above row + sub r6, r0, r2 + vld1.8 {q0}, [r6] + + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + pop {r4-r8,pc} + +case_h_pred + ; Load 4x yleft_col + sub r0, r0, #1 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + pop {r4-r8,pc} + +case_tm_pred + ; Load yabove_row + sub r3, r0, r2 + vld1.8 {q8}, [r3] + + ; Load ytop_left + sub r3, r3, #1 + ldrb r7, [r3] + + vdup.u16 q7, r7 + + ; Compute yabove_row - ytop_left + mov r3, #1 + vdup.u8 q0, r3 + + vmull.u8 q4, d16, d0 + vmull.u8 q5, d17, d0 + + vsub.s16 q4, q4, q7 + vsub.s16 q5, q5, q7 + + ; Load 4x yleft_col + sub r0, r0, #1 + mov r12, #4 + +case_tm_pred_loop + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u16 q0, r3 + vdup.u16 q1, r4 + vdup.u16 q2, r5 + vdup.u16 q3, r6 + + vqadd.s16 q8, q0, q4 + vqadd.s16 q9, q0, q5 + + vqadd.s16 q10, q1, q4 + vqadd.s16 q11, q1, q5 + + vqadd.s16 q12, q2, q4 + vqadd.s16 q13, q2, q5 + + vqadd.s16 q14, q3, q4 + vqadd.s16 q15, q3, q5 + + vqshrun.s16 d0, q8, #0 + vqshrun.s16 d1, q9, #0 + + vqshrun.s16 d2, q10, #0 + vqshrun.s16 d3, q11, #0 + + vqshrun.s16 d4, q12, #0 + vqshrun.s16 d5, q13, #0 + + vqshrun.s16 d6, q14, #0 + vqshrun.s16 d7, q15, #0 + + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + subs r12, r12, #1 + bne case_tm_pred_loop + + pop {r4-r8,pc} + + ENDP + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; r0 unsigned char *y_buffer +; r1 unsigned char *ypred_ptr +; r2 int y_stride +; r3 int mode +; stack int Up +; stack int Left + +|vp8_build_intra_predictors_mby_s_neon_func| PROC + push {r4-r8, lr} + + mov r1, r0 ; unsigned char *ypred_ptr = x->dst.y_buffer; //x->Predictor; + + cmp r3, #0 + beq case_dc_pred_s + cmp r3, #1 + beq case_v_pred_s + cmp r3, #2 + beq case_h_pred_s + cmp r3, #3 + beq case_tm_pred_s + +case_dc_pred_s + ldr r4, [sp, #24] ; Up + ldr r5, [sp, #28] ; Left + + ; Default the DC average to 128 + mov r12, #128 + vdup.u8 q0, r12 + + ; Zero out running sum + mov r12, #0 + + ; compute shift and jump + adds r7, r4, r5 + beq skip_dc_pred_up_left_s + + ; Load above row, if it exists + cmp r4, #0 + beq skip_dc_pred_up_s + + sub r6, r0, r2 + vld1.8 {q1}, [r6] + vpaddl.u8 q2, q1 + vpaddl.u16 q3, q2 + vpaddl.u32 q4, q3 + + vmov.32 r4, d8[0] + vmov.32 r6, d9[0] + + add r12, r4, r6 + + ; Move back to interger registers + +skip_dc_pred_up_s + + cmp r5, #0 + beq skip_dc_pred_left_s + + sub r0, r0, #1 + + ; Load left row, if it exists + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0] + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + +skip_dc_pred_left_s + add r7, r7, #3 ; Shift + sub r4, r7, #1 + mov r5, #1 + add r12, r12, r5, lsl r4 + mov r5, r12, lsr r7 ; expected_dc + + vdup.u8 q0, r5 + +skip_dc_pred_up_left_s + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + + pop {r4-r8,pc} +case_v_pred_s + ; Copy down above row + sub r6, r0, r2 + vld1.8 {q0}, [r6] + + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + pop {r4-r8,pc} + +case_h_pred_s + ; Load 4x yleft_col + sub r0, r0, #1 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + pop {r4-r8,pc} + +case_tm_pred_s + ; Load yabove_row + sub r3, r0, r2 + vld1.8 {q8}, [r3] + + ; Load ytop_left + sub r3, r3, #1 + ldrb r7, [r3] + + vdup.u16 q7, r7 + + ; Compute yabove_row - ytop_left + mov r3, #1 + vdup.u8 q0, r3 + + vmull.u8 q4, d16, d0 + vmull.u8 q5, d17, d0 + + vsub.s16 q4, q4, q7 + vsub.s16 q5, q5, q7 + + ; Load 4x yleft_col + sub r0, r0, #1 + mov r12, #4 + +case_tm_pred_loop_s + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u16 q0, r3 + vdup.u16 q1, r4 + vdup.u16 q2, r5 + vdup.u16 q3, r6 + + vqadd.s16 q8, q0, q4 + vqadd.s16 q9, q0, q5 + + vqadd.s16 q10, q1, q4 + vqadd.s16 q11, q1, q5 + + vqadd.s16 q12, q2, q4 + vqadd.s16 q13, q2, q5 + + vqadd.s16 q14, q3, q4 + vqadd.s16 q15, q3, q5 + + vqshrun.s16 d0, q8, #0 + vqshrun.s16 d1, q9, #0 + + vqshrun.s16 d2, q10, #0 + vqshrun.s16 d3, q11, #0 + + vqshrun.s16 d4, q12, #0 + vqshrun.s16 d5, q13, #0 + + vqshrun.s16 d6, q14, #0 + vqshrun.s16 d7, q15, #0 + + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + subs r12, r12, #1 + bne case_tm_pred_loop_s + + pop {r4-r8,pc} + + ENDP + + + END diff --git a/vp8/common/arm/neon/copymem16x16_neon.asm b/vp8/common/arm/neon/copymem16x16_neon.asm new file mode 100644 index 0000000..bda4b96 --- /dev/null +++ b/vp8/common/arm/neon/copymem16x16_neon.asm @@ -0,0 +1,59 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem16x16_neon| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem16x16_neon( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem16x16_neon| PROC + + vld1.u8 {q0}, [r0], r1 + vld1.u8 {q1}, [r0], r1 + vld1.u8 {q2}, [r0], r1 + vst1.u8 {q0}, [r2], r3 + vld1.u8 {q3}, [r0], r1 + vst1.u8 {q1}, [r2], r3 + vld1.u8 {q4}, [r0], r1 + vst1.u8 {q2}, [r2], r3 + vld1.u8 {q5}, [r0], r1 + vst1.u8 {q3}, [r2], r3 + vld1.u8 {q6}, [r0], r1 + vst1.u8 {q4}, [r2], r3 + vld1.u8 {q7}, [r0], r1 + vst1.u8 {q5}, [r2], r3 + vld1.u8 {q8}, [r0], r1 + vst1.u8 {q6}, [r2], r3 + vld1.u8 {q9}, [r0], r1 + vst1.u8 {q7}, [r2], r3 + vld1.u8 {q10}, [r0], r1 + vst1.u8 {q8}, [r2], r3 + vld1.u8 {q11}, [r0], r1 + vst1.u8 {q9}, [r2], r3 + vld1.u8 {q12}, [r0], r1 + vst1.u8 {q10}, [r2], r3 + vld1.u8 {q13}, [r0], r1 + vst1.u8 {q11}, [r2], r3 + vld1.u8 {q14}, [r0], r1 + vst1.u8 {q12}, [r2], r3 + vld1.u8 {q15}, [r0], r1 + vst1.u8 {q13}, [r2], r3 + vst1.u8 {q14}, [r2], r3 + vst1.u8 {q15}, [r2], r3 + + mov pc, lr + + ENDP ; |vp8_copy_mem16x16_neon| + + END diff --git a/vp8/common/arm/neon/copymem8x4_neon.asm b/vp8/common/arm/neon/copymem8x4_neon.asm new file mode 100644 index 0000000..35c0f67 --- /dev/null +++ b/vp8/common/arm/neon/copymem8x4_neon.asm @@ -0,0 +1,34 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x4_neon| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem8x4_neon( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x4_neon| PROC + vld1.u8 {d0}, [r0], r1 + vld1.u8 {d1}, [r0], r1 + vst1.u8 {d0}, [r2], r3 + vld1.u8 {d2}, [r0], r1 + vst1.u8 {d1}, [r2], r3 + vld1.u8 {d3}, [r0], r1 + vst1.u8 {d2}, [r2], r3 + vst1.u8 {d3}, [r2], r3 + + mov pc, lr + + ENDP ; |vp8_copy_mem8x4_neon| + + END diff --git a/vp8/common/arm/neon/copymem8x8_neon.asm b/vp8/common/arm/neon/copymem8x8_neon.asm new file mode 100644 index 0000000..1f5b941 --- /dev/null +++ b/vp8/common/arm/neon/copymem8x8_neon.asm @@ -0,0 +1,43 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x8_neon| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem8x8_neon( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x8_neon| PROC + + vld1.u8 {d0}, [r0], r1 + vld1.u8 {d1}, [r0], r1 + vst1.u8 {d0}, [r2], r3 + vld1.u8 {d2}, [r0], r1 + vst1.u8 {d1}, [r2], r3 + vld1.u8 {d3}, [r0], r1 + vst1.u8 {d2}, [r2], r3 + vld1.u8 {d4}, [r0], r1 + vst1.u8 {d3}, [r2], r3 + vld1.u8 {d5}, [r0], r1 + vst1.u8 {d4}, [r2], r3 + vld1.u8 {d6}, [r0], r1 + vst1.u8 {d5}, [r2], r3 + vld1.u8 {d7}, [r0], r1 + vst1.u8 {d6}, [r2], r3 + vst1.u8 {d7}, [r2], r3 + + mov pc, lr + + ENDP ; |vp8_copy_mem8x8_neon| + + END diff --git a/vp8/common/arm/neon/dc_only_idct_add_neon.asm b/vp8/common/arm/neon/dc_only_idct_add_neon.asm new file mode 100644 index 0000000..65a4680 --- /dev/null +++ b/vp8/common/arm/neon/dc_only_idct_add_neon.asm @@ -0,0 +1,54 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dc_only_idct_add_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;void vp8_dc_only_idct_add_c(short input_dc, unsigned char *pred_ptr, +; int pred_stride, unsigned char *dst_ptr, +; int dst_stride) + +; r0 input_dc +; r1 pred_ptr +; r2 pred_stride +; r3 dst_ptr +; sp dst_stride + +|vp8_dc_only_idct_add_neon| PROC + add r0, r0, #4 + asr r0, r0, #3 + ldr r12, [sp] + vdup.16 q0, r0 + + vld1.32 {d2[0]}, [r1], r2 + vld1.32 {d2[1]}, [r1], r2 + vld1.32 {d4[0]}, [r1], r2 + vld1.32 {d4[1]}, [r1] + + vaddw.u8 q1, q0, d2 + vaddw.u8 q2, q0, d4 + + vqmovun.s16 d2, q1 + vqmovun.s16 d4, q2 + + vst1.32 {d2[0]}, [r3], r12 + vst1.32 {d2[1]}, [r3], r12 + vst1.32 {d4[0]}, [r3], r12 + vst1.32 {d4[1]}, [r3] + + bx lr + + ENDP + + END diff --git a/vp8/common/arm/neon/dequant_idct_neon.asm b/vp8/common/arm/neon/dequant_idct_neon.asm new file mode 100644 index 0000000..602cce6 --- /dev/null +++ b/vp8/common/arm/neon/dequant_idct_neon.asm @@ -0,0 +1,131 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_dequant_idct_add_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_dequant_idct_add_neon(short *input, short *dq, +; unsigned char *dest, int stride) +; r0 short *input, +; r1 short *dq, +; r2 unsigned char *dest +; r3 int stride + +|vp8_dequant_idct_add_neon| PROC + vld1.16 {q3, q4}, [r0] + vld1.16 {q5, q6}, [r1] + + add r1, r2, r3 ; r1 = dest + stride + lsl r3, #1 ; 2x stride + + vld1.32 {d14[0]}, [r2], r3 + vld1.32 {d14[1]}, [r1], r3 + vld1.32 {d15[0]}, [r2] + vld1.32 {d15[1]}, [r1] + + adr r12, cospi8sqrt2minus1 ; pointer to the first constant + + vmul.i16 q1, q3, q5 ;input for short_idct4x4llm_neon + vmul.i16 q2, q4, q6 + +;|short_idct4x4llm_neon| PROC + vld1.16 {d0}, [r12] + vswp d3, d4 ;q2(vp[4] vp[12]) + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 + vqadd.s16 q4, q4, q2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + +; memset(input, 0, 32) -- 32bytes + vmov.i16 q14, #0 + + vswp d3, d4 + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vmov q15, q14 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 + vqadd.s16 q4, q4, q2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vst1.16 {q14, q15}, [r0] + + vrshr.s16 d2, d2, #3 + vrshr.s16 d3, d3, #3 + vrshr.s16 d4, d4, #3 + vrshr.s16 d5, d5, #3 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vaddw.u8 q1, q1, d14 + vaddw.u8 q2, q2, d15 + + sub r2, r2, r3 + sub r1, r1, r3 + + vqmovun.s16 d0, q1 + vqmovun.s16 d1, q2 + + vst1.32 {d0[0]}, [r2], r3 + vst1.32 {d0[1]}, [r1], r3 + vst1.32 {d1[0]}, [r2] + vst1.32 {d1[1]}, [r1] + + bx lr + + ENDP ; |vp8_dequant_idct_add_neon| + +; Constant Pool +cospi8sqrt2minus1 DCD 0x4e7b4e7b +sinpi8sqrt2 DCD 0x8a8c8a8c + + END diff --git a/vp8/common/arm/neon/dequantizeb_neon.asm b/vp8/common/arm/neon/dequantizeb_neon.asm new file mode 100644 index 0000000..c8e0c31 --- /dev/null +++ b/vp8/common/arm/neon/dequantizeb_neon.asm @@ -0,0 +1,34 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_dequantize_b_loop_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 short *Q, +; r1 short *DQC +; r2 short *DQ +|vp8_dequantize_b_loop_neon| PROC + vld1.16 {q0, q1}, [r0] + vld1.16 {q2, q3}, [r1] + + vmul.i16 q4, q0, q2 + vmul.i16 q5, q1, q3 + + vst1.16 {q4, q5}, [r2] + + bx lr + + ENDP + + END diff --git a/vp8/common/arm/neon/idct_blk_neon.c b/vp8/common/arm/neon/idct_blk_neon.c new file mode 100644 index 0000000..ee7f223 --- /dev/null +++ b/vp8/common/arm/neon/idct_blk_neon.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" + +/* place these declarations here because we don't want to maintain them + * outside of this scope + */ +void idct_dequant_full_2x_neon(short *q, short *dq, + unsigned char *dst, int stride); +void idct_dequant_0_2x_neon(short *q, short dq, + unsigned char *dst, int stride); + + +void vp8_dequant_idct_add_y_block_neon(short *q, short *dq, + unsigned char *dst, + int stride, char *eobs) +{ + int i; + + for (i = 0; i < 4; i++) + { + if (((short *)(eobs))[0]) + { + if (((short *)eobs)[0] & 0xfefe) + idct_dequant_full_2x_neon (q, dq, dst, stride); + else + idct_dequant_0_2x_neon (q, dq[0], dst, stride); + } + + if (((short *)(eobs))[1]) + { + if (((short *)eobs)[1] & 0xfefe) + idct_dequant_full_2x_neon (q+32, dq, dst+8, stride); + else + idct_dequant_0_2x_neon (q+32, dq[0], dst+8, stride); + } + q += 64; + dst += 4*stride; + eobs += 4; + } +} + +void vp8_dequant_idct_add_uv_block_neon(short *q, short *dq, + unsigned char *dstu, + unsigned char *dstv, + int stride, char *eobs) +{ + if (((short *)(eobs))[0]) + { + if (((short *)eobs)[0] & 0xfefe) + idct_dequant_full_2x_neon (q, dq, dstu, stride); + else + idct_dequant_0_2x_neon (q, dq[0], dstu, stride); + } + + q += 32; + dstu += 4*stride; + + if (((short *)(eobs))[1]) + { + if (((short *)eobs)[1] & 0xfefe) + idct_dequant_full_2x_neon (q, dq, dstu, stride); + else + idct_dequant_0_2x_neon (q, dq[0], dstu, stride); + } + + q += 32; + + if (((short *)(eobs))[2]) + { + if (((short *)eobs)[2] & 0xfefe) + idct_dequant_full_2x_neon (q, dq, dstv, stride); + else + idct_dequant_0_2x_neon (q, dq[0], dstv, stride); + } + + q += 32; + dstv += 4*stride; + + if (((short *)(eobs))[3]) + { + if (((short *)eobs)[3] & 0xfefe) + idct_dequant_full_2x_neon (q, dq, dstv, stride); + else + idct_dequant_0_2x_neon (q, dq[0], dstv, stride); + } +} diff --git a/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm b/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm new file mode 100644 index 0000000..6c29c55 --- /dev/null +++ b/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm @@ -0,0 +1,79 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |idct_dequant_0_2x_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void idct_dequant_0_2x_neon(short *q, short dq, +; unsigned char *dst, int stride); +; r0 *q +; r1 dq +; r2 *dst +; r3 stride +|idct_dequant_0_2x_neon| PROC + push {r4, r5} + + add r12, r2, #4 + vld1.32 {d2[0]}, [r2], r3 + vld1.32 {d8[0]}, [r12], r3 + vld1.32 {d2[1]}, [r2], r3 + vld1.32 {d8[1]}, [r12], r3 + vld1.32 {d4[0]}, [r2], r3 + vld1.32 {d10[0]}, [r12], r3 + vld1.32 {d4[1]}, [r2], r3 + vld1.32 {d10[1]}, [r12], r3 + + ldrh r12, [r0] ; lo q + ldrh r4, [r0, #32] ; hi q + mov r5, #0 + strh r5, [r0] + strh r5, [r0, #32] + + sxth r12, r12 ; lo + mul r0, r12, r1 + add r0, r0, #4 + asr r0, r0, #3 + vdup.16 q0, r0 + sxth r4, r4 ; hi + mul r0, r4, r1 + add r0, r0, #4 + asr r0, r0, #3 + vdup.16 q3, r0 + + vaddw.u8 q1, q0, d2 ; lo + vaddw.u8 q2, q0, d4 + vaddw.u8 q4, q3, d8 ; hi + vaddw.u8 q5, q3, d10 + + sub r2, r2, r3, lsl #2 ; dst - 4*stride + add r0, r2, #4 + + vqmovun.s16 d2, q1 ; lo + vqmovun.s16 d4, q2 + vqmovun.s16 d8, q4 ; hi + vqmovun.s16 d10, q5 + + vst1.32 {d2[0]}, [r2], r3 ; lo + vst1.32 {d8[0]}, [r0], r3 ; hi + vst1.32 {d2[1]}, [r2], r3 + vst1.32 {d8[1]}, [r0], r3 + vst1.32 {d4[0]}, [r2], r3 + vst1.32 {d10[0]}, [r0], r3 + vst1.32 {d4[1]}, [r2] + vst1.32 {d10[1]}, [r0] + + pop {r4, r5} + bx lr + + ENDP ; |idct_dequant_0_2x_neon| + END diff --git a/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm b/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm new file mode 100644 index 0000000..d5dce63 --- /dev/null +++ b/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm @@ -0,0 +1,196 @@ +; +; Copyright (c) 2010 The Webm project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |idct_dequant_full_2x_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void idct_dequant_full_2x_neon(short *q, short *dq, +; unsigned char *dst, int stride); +; r0 *q, +; r1 *dq, +; r2 *dst +; r3 stride +|idct_dequant_full_2x_neon| PROC + vld1.16 {q0, q1}, [r1] ; dq (same l/r) + vld1.16 {q2, q3}, [r0] ; l q + add r0, r0, #32 + vld1.16 {q4, q5}, [r0] ; r q + add r12, r2, #4 + + ; interleave the predictors + vld1.32 {d28[0]}, [r2], r3 ; l pre + vld1.32 {d28[1]}, [r12], r3 ; r pre + vld1.32 {d29[0]}, [r2], r3 + vld1.32 {d29[1]}, [r12], r3 + vld1.32 {d30[0]}, [r2], r3 + vld1.32 {d30[1]}, [r12], r3 + vld1.32 {d31[0]}, [r2], r3 + vld1.32 {d31[1]}, [r12] + + adr r1, cospi8sqrt2minus1 ; pointer to the first constant + + ; dequant: q[i] = q[i] * dq[i] + vmul.i16 q2, q2, q0 + vmul.i16 q3, q3, q1 + vmul.i16 q4, q4, q0 + vmul.i16 q5, q5, q1 + + vld1.16 {d0}, [r1] + + ; q2: l0r0 q3: l8r8 + ; q4: l4r4 q5: l12r12 + vswp d5, d8 + vswp d7, d10 + + ; _CONSTANTS_ * 4,12 >> 16 + ; q6: 4 * sinpi : c1/temp1 + ; q7: 12 * sinpi : d1/temp2 + ; q8: 4 * cospi + ; q9: 12 * cospi + vqdmulh.s16 q6, q4, d0[2] ; sinpi8sqrt2 + vqdmulh.s16 q7, q5, d0[2] + vqdmulh.s16 q8, q4, d0[0] ; cospi8sqrt2minus1 + vqdmulh.s16 q9, q5, d0[0] + + vqadd.s16 q10, q2, q3 ; a1 = 0 + 8 + vqsub.s16 q11, q2, q3 ; b1 = 0 - 8 + + ; vqdmulh only accepts signed values. this was a problem because + ; our constant had the high bit set, and was treated as a negative value. + ; vqdmulh also doubles the value before it shifts by 16. we need to + ; compensate for this. in the case of sinpi8sqrt2, the lowest bit is 0, + ; so we can shift the constant without losing precision. this avoids + ; shift again afterward, but also avoids the sign issue. win win! + ; for cospi8sqrt2minus1 the lowest bit is 1, so we lose precision if we + ; pre-shift it + vshr.s16 q8, q8, #1 + vshr.s16 q9, q9, #1 + + ; q4: 4 + 4 * cospi : d1/temp1 + ; q5: 12 + 12 * cospi : c1/temp2 + vqadd.s16 q4, q4, q8 + vqadd.s16 q5, q5, q9 + + ; c1 = temp1 - temp2 + ; d1 = temp1 + temp2 + vqsub.s16 q2, q6, q5 + vqadd.s16 q3, q4, q7 + + ; [0]: a1+d1 + ; [1]: b1+c1 + ; [2]: b1-c1 + ; [3]: a1-d1 + vqadd.s16 q4, q10, q3 + vqadd.s16 q5, q11, q2 + vqsub.s16 q6, q11, q2 + vqsub.s16 q7, q10, q3 + + ; rotate + vtrn.32 q4, q6 + vtrn.32 q5, q7 + vtrn.16 q4, q5 + vtrn.16 q6, q7 + ; idct loop 2 + ; q4: l 0, 4, 8,12 r 0, 4, 8,12 + ; q5: l 1, 5, 9,13 r 1, 5, 9,13 + ; q6: l 2, 6,10,14 r 2, 6,10,14 + ; q7: l 3, 7,11,15 r 3, 7,11,15 + + ; q8: 1 * sinpi : c1/temp1 + ; q9: 3 * sinpi : d1/temp2 + ; q10: 1 * cospi + ; q11: 3 * cospi + vqdmulh.s16 q8, q5, d0[2] ; sinpi8sqrt2 + vqdmulh.s16 q9, q7, d0[2] + vqdmulh.s16 q10, q5, d0[0] ; cospi8sqrt2minus1 + vqdmulh.s16 q11, q7, d0[0] + + vqadd.s16 q2, q4, q6 ; a1 = 0 + 2 + vqsub.s16 q3, q4, q6 ; b1 = 0 - 2 + + ; see note on shifting above + vshr.s16 q10, q10, #1 + vshr.s16 q11, q11, #1 + + ; q10: 1 + 1 * cospi : d1/temp1 + ; q11: 3 + 3 * cospi : c1/temp2 + vqadd.s16 q10, q5, q10 + vqadd.s16 q11, q7, q11 + + ; q8: c1 = temp1 - temp2 + ; q9: d1 = temp1 + temp2 + vqsub.s16 q8, q8, q11 + vqadd.s16 q9, q10, q9 + + ; a1+d1 + ; b1+c1 + ; b1-c1 + ; a1-d1 + vqadd.s16 q4, q2, q9 + vqadd.s16 q5, q3, q8 + vqsub.s16 q6, q3, q8 + vqsub.s16 q7, q2, q9 + + ; +4 >> 3 (rounding) + vrshr.s16 q4, q4, #3 ; lo + vrshr.s16 q5, q5, #3 + vrshr.s16 q6, q6, #3 ; hi + vrshr.s16 q7, q7, #3 + + vtrn.32 q4, q6 + vtrn.32 q5, q7 + vtrn.16 q4, q5 + vtrn.16 q6, q7 + + ; adding pre + ; input is still packed. pre was read interleaved + vaddw.u8 q4, q4, d28 + vaddw.u8 q5, q5, d29 + vaddw.u8 q6, q6, d30 + vaddw.u8 q7, q7, d31 + + vmov.i16 q14, #0 + vmov q15, q14 + vst1.16 {q14, q15}, [r0] ; write over high input + sub r0, r0, #32 + vst1.16 {q14, q15}, [r0] ; write over low input + + sub r2, r2, r3, lsl #2 ; dst - 4*stride + add r1, r2, #4 ; hi + + ;saturate and narrow + vqmovun.s16 d0, q4 ; lo + vqmovun.s16 d1, q5 + vqmovun.s16 d2, q6 ; hi + vqmovun.s16 d3, q7 + + vst1.32 {d0[0]}, [r2], r3 ; lo + vst1.32 {d0[1]}, [r1], r3 ; hi + vst1.32 {d1[0]}, [r2], r3 + vst1.32 {d1[1]}, [r1], r3 + vst1.32 {d2[0]}, [r2], r3 + vst1.32 {d2[1]}, [r1], r3 + vst1.32 {d3[0]}, [r2] + vst1.32 {d3[1]}, [r1] + + bx lr + + ENDP ; |idct_dequant_full_2x_neon| + +; Constant Pool +cospi8sqrt2minus1 DCD 0x4e7b +; because the lowest bit in 0x8a8c is 0, we can pre-shift this +sinpi8sqrt2 DCD 0x4546 + + END diff --git a/vp8/common/arm/neon/iwalsh_neon.asm b/vp8/common/arm/neon/iwalsh_neon.asm new file mode 100644 index 0000000..e8ea2a6 --- /dev/null +++ b/vp8/common/arm/neon/iwalsh_neon.asm @@ -0,0 +1,87 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + EXPORT |vp8_short_inv_walsh4x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code + +;short vp8_short_inv_walsh4x4_neon(short *input, short *mb_dqcoeff) +|vp8_short_inv_walsh4x4_neon| PROC + + ; read in all four lines of values: d0->d3 + vld1.i16 {q0-q1}, [r0@128] + + ; first for loop + vadd.s16 d4, d0, d3 ;a = [0] + [12] + vadd.s16 d6, d1, d2 ;b = [4] + [8] + vsub.s16 d5, d0, d3 ;d = [0] - [12] + vsub.s16 d7, d1, d2 ;c = [4] - [8] + + vadd.s16 q0, q2, q3 ; a+b d+c + vsub.s16 q1, q2, q3 ; a-b d-c + + vtrn.32 d0, d2 ;d0: 0 1 8 9 + ;d2: 2 3 10 11 + vtrn.32 d1, d3 ;d1: 4 5 12 13 + ;d3: 6 7 14 15 + + vtrn.16 d0, d1 ;d0: 0 4 8 12 + ;d1: 1 5 9 13 + vtrn.16 d2, d3 ;d2: 2 6 10 14 + ;d3: 3 7 11 15 + + ; second for loop + + vadd.s16 d4, d0, d3 ;a = [0] + [3] + vadd.s16 d6, d1, d2 ;b = [1] + [2] + vsub.s16 d5, d0, d3 ;d = [0] - [3] + vsub.s16 d7, d1, d2 ;c = [1] - [2] + + vmov.i16 q8, #3 + + vadd.s16 q0, q2, q3 ; a+b d+c + vsub.s16 q1, q2, q3 ; a-b d-c + + vadd.i16 q0, q0, q8 ;e/f += 3 + vadd.i16 q1, q1, q8 ;g/h += 3 + + vshr.s16 q0, q0, #3 ;e/f >> 3 + vshr.s16 q1, q1, #3 ;g/h >> 3 + + mov r2, #64 + add r3, r1, #32 + + vst1.i16 d0[0], [r1],r2 + vst1.i16 d1[0], [r3],r2 + vst1.i16 d2[0], [r1],r2 + vst1.i16 d3[0], [r3],r2 + + vst1.i16 d0[1], [r1],r2 + vst1.i16 d1[1], [r3],r2 + vst1.i16 d2[1], [r1],r2 + vst1.i16 d3[1], [r3],r2 + + vst1.i16 d0[2], [r1],r2 + vst1.i16 d1[2], [r3],r2 + vst1.i16 d2[2], [r1],r2 + vst1.i16 d3[2], [r3],r2 + + vst1.i16 d0[3], [r1],r2 + vst1.i16 d1[3], [r3],r2 + vst1.i16 d2[3], [r1] + vst1.i16 d3[3], [r3] + + bx lr + ENDP ; |vp8_short_inv_walsh4x4_neon| + + END diff --git a/vp8/common/arm/neon/loopfilter_neon.asm b/vp8/common/arm/neon/loopfilter_neon.asm new file mode 100644 index 0000000..e44be0a --- /dev/null +++ b/vp8/common/arm/neon/loopfilter_neon.asm @@ -0,0 +1,397 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_horizontal_edge_y_neon| + EXPORT |vp8_loop_filter_horizontal_edge_uv_neon| + EXPORT |vp8_loop_filter_vertical_edge_y_neon| + EXPORT |vp8_loop_filter_vertical_edge_uv_neon| + ARM + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src +; r1 int pitch +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, +|vp8_loop_filter_horizontal_edge_y_neon| PROC + push {lr} + vdup.u8 q0, r2 ; duplicate blimit + vdup.u8 q1, r3 ; duplicate limit + sub r2, r0, r1, lsl #2 ; move src pointer down by 4 lines + ldr r3, [sp, #4] ; load thresh + add r12, r2, r1 + add r1, r1, r1 + + vdup.u8 q2, r3 ; duplicate thresh + + vld1.u8 {q3}, [r2@128], r1 ; p3 + vld1.u8 {q4}, [r12@128], r1 ; p2 + vld1.u8 {q5}, [r2@128], r1 ; p1 + vld1.u8 {q6}, [r12@128], r1 ; p0 + vld1.u8 {q7}, [r2@128], r1 ; q0 + vld1.u8 {q8}, [r12@128], r1 ; q1 + vld1.u8 {q9}, [r2@128] ; q2 + vld1.u8 {q10}, [r12@128] ; q3 + + sub r2, r2, r1, lsl #1 + sub r12, r12, r1, lsl #1 + + bl vp8_loop_filter_neon + + vst1.u8 {q5}, [r2@128], r1 ; store op1 + vst1.u8 {q6}, [r12@128], r1 ; store op0 + vst1.u8 {q7}, [r2@128], r1 ; store oq0 + vst1.u8 {q8}, [r12@128], r1 ; store oq1 + + pop {pc} + ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| + + +; r0 unsigned char *u, +; r1 int pitch, +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, +; sp+4 unsigned char *v +|vp8_loop_filter_horizontal_edge_uv_neon| PROC + push {lr} + vdup.u8 q0, r2 ; duplicate blimit + vdup.u8 q1, r3 ; duplicate limit + ldr r12, [sp, #4] ; load thresh + ldr r2, [sp, #8] ; load v ptr + vdup.u8 q2, r12 ; duplicate thresh + + sub r3, r0, r1, lsl #2 ; move u pointer down by 4 lines + sub r12, r2, r1, lsl #2 ; move v pointer down by 4 lines + + vld1.u8 {d6}, [r3@64], r1 ; p3 + vld1.u8 {d7}, [r12@64], r1 ; p3 + vld1.u8 {d8}, [r3@64], r1 ; p2 + vld1.u8 {d9}, [r12@64], r1 ; p2 + vld1.u8 {d10}, [r3@64], r1 ; p1 + vld1.u8 {d11}, [r12@64], r1 ; p1 + vld1.u8 {d12}, [r3@64], r1 ; p0 + vld1.u8 {d13}, [r12@64], r1 ; p0 + vld1.u8 {d14}, [r3@64], r1 ; q0 + vld1.u8 {d15}, [r12@64], r1 ; q0 + vld1.u8 {d16}, [r3@64], r1 ; q1 + vld1.u8 {d17}, [r12@64], r1 ; q1 + vld1.u8 {d18}, [r3@64], r1 ; q2 + vld1.u8 {d19}, [r12@64], r1 ; q2 + vld1.u8 {d20}, [r3@64] ; q3 + vld1.u8 {d21}, [r12@64] ; q3 + + bl vp8_loop_filter_neon + + sub r0, r0, r1, lsl #1 + sub r2, r2, r1, lsl #1 + + vst1.u8 {d10}, [r0@64], r1 ; store u op1 + vst1.u8 {d11}, [r2@64], r1 ; store v op1 + vst1.u8 {d12}, [r0@64], r1 ; store u op0 + vst1.u8 {d13}, [r2@64], r1 ; store v op0 + vst1.u8 {d14}, [r0@64], r1 ; store u oq0 + vst1.u8 {d15}, [r2@64], r1 ; store v oq0 + vst1.u8 {d16}, [r0@64] ; store u oq1 + vst1.u8 {d17}, [r2@64] ; store v oq1 + + pop {pc} + ENDP ; |vp8_loop_filter_horizontal_edge_uv_neon| + +; void vp8_loop_filter_vertical_edge_y_neon(unsigned char *src, int pitch, +; const signed char *flimit, +; const signed char *limit, +; const signed char *thresh, +; int count) +; r0 unsigned char *src +; r1 int pitch +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, + +|vp8_loop_filter_vertical_edge_y_neon| PROC + push {lr} + vdup.u8 q0, r2 ; duplicate blimit + vdup.u8 q1, r3 ; duplicate limit + sub r2, r0, #4 ; src ptr down by 4 columns + add r1, r1, r1 + ldr r3, [sp, #4] ; load thresh + add r12, r2, r1, asr #1 + + vld1.u8 {d6}, [r2], r1 + vld1.u8 {d8}, [r12], r1 + vld1.u8 {d10}, [r2], r1 + vld1.u8 {d12}, [r12], r1 + vld1.u8 {d14}, [r2], r1 + vld1.u8 {d16}, [r12], r1 + vld1.u8 {d18}, [r2], r1 + vld1.u8 {d20}, [r12], r1 + + vld1.u8 {d7}, [r2], r1 ; load second 8-line src data + vld1.u8 {d9}, [r12], r1 + vld1.u8 {d11}, [r2], r1 + vld1.u8 {d13}, [r12], r1 + vld1.u8 {d15}, [r2], r1 + vld1.u8 {d17}, [r12], r1 + vld1.u8 {d19}, [r2] + vld1.u8 {d21}, [r12] + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vdup.u8 q2, r3 ; duplicate thresh + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + bl vp8_loop_filter_neon + + vswp d12, d11 + vswp d16, d13 + + sub r0, r0, #2 ; dst ptr + + vswp d14, d12 + vswp d16, d15 + + add r12, r0, r1, asr #1 + + ;store op1, op0, oq0, oq1 + vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 + vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r12], r1 + vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1 + vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r12], r1 + vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1 + vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r12], r1 + vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1 + vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r12], r1 + + vst4.8 {d14[0], d15[0], d16[0], d17[0]}, [r0], r1 + vst4.8 {d14[1], d15[1], d16[1], d17[1]}, [r12], r1 + vst4.8 {d14[2], d15[2], d16[2], d17[2]}, [r0], r1 + vst4.8 {d14[3], d15[3], d16[3], d17[3]}, [r12], r1 + vst4.8 {d14[4], d15[4], d16[4], d17[4]}, [r0], r1 + vst4.8 {d14[5], d15[5], d16[5], d17[5]}, [r12], r1 + vst4.8 {d14[6], d15[6], d16[6], d17[6]}, [r0] + vst4.8 {d14[7], d15[7], d16[7], d17[7]}, [r12] + + pop {pc} + ENDP ; |vp8_loop_filter_vertical_edge_y_neon| + +; void vp8_loop_filter_vertical_edge_uv_neon(unsigned char *u, int pitch +; const signed char *flimit, +; const signed char *limit, +; const signed char *thresh, +; unsigned char *v) +; r0 unsigned char *u, +; r1 int pitch, +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, +; sp+4 unsigned char *v +|vp8_loop_filter_vertical_edge_uv_neon| PROC + push {lr} + vdup.u8 q0, r2 ; duplicate blimit + sub r12, r0, #4 ; move u pointer down by 4 columns + ldr r2, [sp, #8] ; load v ptr + vdup.u8 q1, r3 ; duplicate limit + sub r3, r2, #4 ; move v pointer down by 4 columns + + vld1.u8 {d6}, [r12], r1 ;load u data + vld1.u8 {d7}, [r3], r1 ;load v data + vld1.u8 {d8}, [r12], r1 + vld1.u8 {d9}, [r3], r1 + vld1.u8 {d10}, [r12], r1 + vld1.u8 {d11}, [r3], r1 + vld1.u8 {d12}, [r12], r1 + vld1.u8 {d13}, [r3], r1 + vld1.u8 {d14}, [r12], r1 + vld1.u8 {d15}, [r3], r1 + vld1.u8 {d16}, [r12], r1 + vld1.u8 {d17}, [r3], r1 + vld1.u8 {d18}, [r12], r1 + vld1.u8 {d19}, [r3], r1 + vld1.u8 {d20}, [r12] + vld1.u8 {d21}, [r3] + + ldr r12, [sp, #4] ; load thresh + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vdup.u8 q2, r12 ; duplicate thresh + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + bl vp8_loop_filter_neon + + vswp d12, d11 + vswp d16, d13 + vswp d14, d12 + vswp d16, d15 + + sub r0, r0, #2 + sub r2, r2, #2 + + ;store op1, op0, oq0, oq1 + vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 + vst4.8 {d14[0], d15[0], d16[0], d17[0]}, [r2], r1 + vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r0], r1 + vst4.8 {d14[1], d15[1], d16[1], d17[1]}, [r2], r1 + vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1 + vst4.8 {d14[2], d15[2], d16[2], d17[2]}, [r2], r1 + vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r0], r1 + vst4.8 {d14[3], d15[3], d16[3], d17[3]}, [r2], r1 + vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1 + vst4.8 {d14[4], d15[4], d16[4], d17[4]}, [r2], r1 + vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1 + vst4.8 {d14[5], d15[5], d16[5], d17[5]}, [r2], r1 + vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1 + vst4.8 {d14[6], d15[6], d16[6], d17[6]}, [r2], r1 + vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r0] + vst4.8 {d14[7], d15[7], d16[7], d17[7]}, [r2] + + pop {pc} + ENDP ; |vp8_loop_filter_vertical_edge_uv_neon| + +; void vp8_loop_filter_neon(); +; This is a helper function for the loopfilters. The invidual functions do the +; necessary load, transpose (if necessary) and store. + +; r0-r3 PRESERVE +; q0 flimit +; q1 limit +; q2 thresh +; q3 p3 +; q4 p2 +; q5 p1 +; q6 p0 +; q7 q0 +; q8 q1 +; q9 q2 +; q10 q3 +|vp8_loop_filter_neon| PROC + + ; vp8_filter_mask + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q4, q10, q9 ; abs(q3 - q2) + + vmax.u8 q11, q11, q12 + vmax.u8 q12, q13, q14 + vmax.u8 q3, q3, q4 + vmax.u8 q15, q11, q12 + + vabd.u8 q9, q6, q7 ; abs(p0 - q0) + + ; vp8_hevmask + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + vmax.u8 q15, q15, q3 + + vmov.u8 q10, #0x80 ; 0x80 + + vabd.u8 q2, q5, q8 ; a = abs(p1 - q1) + vqadd.u8 q9, q9, q9 ; b = abs(p0 - q0) * 2 + + vcge.u8 q15, q1, q15 + + ; vp8_filter() function + ; convert to signed + veor q7, q7, q10 ; qs0 + vshr.u8 q2, q2, #1 ; a = a / 2 + veor q6, q6, q10 ; ps0 + + veor q5, q5, q10 ; ps1 + vqadd.u8 q9, q9, q2 ; a = b + a + + veor q8, q8, q10 ; qs1 + + vmov.u8 q10, #3 ; #3 + + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q11, d15, d13 + + vcge.u8 q9, q0, q9 ; (a > flimit * 2 + limit) * -1 + + vmovl.u8 q4, d20 + + vqsub.s8 q1, q5, q8 ; vp8_filter = clamp(ps1-qs1) + vorr q14, q13, q14 ; vp8_hevmask + + vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0) + vmul.i16 q11, q11, q4 + + vand q1, q1, q14 ; vp8_filter &= hev + vand q15, q15, q9 ; vp8_filter_mask + + vaddw.s8 q2, q2, d2 + vaddw.s8 q11, q11, d3 + + vmov.u8 q9, #4 ; #4 + + ; vp8_filter = clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d2, q2 + vqmovn.s16 d3, q11 + vand q1, q1, q15 ; vp8_filter &= mask + + vqadd.s8 q2, q1, q10 ; Filter2 = clamp(vp8_filter+3) + vqadd.s8 q1, q1, q9 ; Filter1 = clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q1, q1, #3 ; Filter1 >>= 3 + + + vqadd.s8 q11, q6, q2 ; u = clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q1 ; u = clamp(qs0 - Filter1) + + ; outer tap adjustments: ++vp8_filter >> 1 + vrshr.s8 q1, q1, #1 + vbic q1, q1, q14 ; vp8_filter &= ~hev + vmov.u8 q0, #0x80 ; 0x80 + vqadd.s8 q13, q5, q1 ; u = clamp(ps1 + vp8_filter) + vqsub.s8 q12, q8, q1 ; u = clamp(qs1 - vp8_filter) + + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q5, q13, q0 ; *op1 = u^0x80 + veor q8, q12, q0 ; *oq1 = u^0x80 + + bx lr + ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| + +;----------------- + + END diff --git a/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm b/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm new file mode 100644 index 0000000..adf848b --- /dev/null +++ b/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm @@ -0,0 +1,117 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + ;EXPORT |vp8_loop_filter_simple_horizontal_edge_neon| + EXPORT |vp8_loop_filter_bhs_neon| + EXPORT |vp8_loop_filter_mbhs_neon| + ARM + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *s, PRESERVE +; r1 int p, PRESERVE +; q1 limit, PRESERVE + +|vp8_loop_filter_simple_horizontal_edge_neon| PROC + + sub r3, r0, r1, lsl #1 ; move src pointer down by 2 lines + + vld1.u8 {q7}, [r0@128], r1 ; q0 + vld1.u8 {q5}, [r3@128], r1 ; p0 + vld1.u8 {q8}, [r0@128] ; q1 + vld1.u8 {q6}, [r3@128] ; p1 + + vabd.u8 q15, q6, q7 ; abs(p0 - q0) + vabd.u8 q14, q5, q8 ; abs(p1 - q1) + + vqadd.u8 q15, q15, q15 ; abs(p0 - q0) * 2 + vshr.u8 q14, q14, #1 ; abs(p1 - q1) / 2 + vmov.u8 q0, #0x80 ; 0x80 + vmov.s16 q13, #3 + vqadd.u8 q15, q15, q14 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value + + vcge.u8 q15, q1, q15 ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > limit)*-1 + + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q3, d15, d13 + + vqsub.s8 q4, q5, q8 ; q4: vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + vmul.s16 q2, q2, q13 ; 3 * ( qs0 - ps0) + vmul.s16 q3, q3, q13 + + vmov.u8 q10, #0x03 ; 0x03 + vmov.u8 q9, #0x04 ; 0x04 + + vaddw.s8 q2, q2, d8 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q3, q3, d9 + + vqmovn.s16 d8, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d9, q3 + + vand q14, q4, q15 ; vp8_filter &= mask + + vqadd.s8 q2, q14, q10 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q3, q14, q9 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q4, q3, #3 ; Filter1 >>= 3 + + sub r0, r0, r1 + + ;calculate output + vqadd.s8 q11, q6, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q4 ; u = vp8_signed_char_clamp(qs0 - Filter1) + + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + + vst1.u8 {q6}, [r3@128] ; store op0 + vst1.u8 {q7}, [r0@128] ; store oq0 + + bx lr + ENDP ; |vp8_loop_filter_simple_horizontal_edge_neon| + +; r0 unsigned char *y +; r1 int ystride +; r2 const unsigned char *blimit + +|vp8_loop_filter_bhs_neon| PROC + push {r4, lr} + ldrb r3, [r2] ; load blim from mem + vdup.s8 q1, r3 ; duplicate blim + + add r0, r0, r1, lsl #2 ; src = y_ptr + 4 * y_stride + bl vp8_loop_filter_simple_horizontal_edge_neon + ; vp8_loop_filter_simple_horizontal_edge_neon preserves r0, r1 and q1 + add r0, r0, r1, lsl #2 ; src = y_ptr + 8* y_stride + bl vp8_loop_filter_simple_horizontal_edge_neon + add r0, r0, r1, lsl #2 ; src = y_ptr + 12 * y_stride + pop {r4, lr} + b vp8_loop_filter_simple_horizontal_edge_neon + ENDP ;|vp8_loop_filter_bhs_neon| + +; r0 unsigned char *y +; r1 int ystride +; r2 const unsigned char *blimit + +|vp8_loop_filter_mbhs_neon| PROC + ldrb r3, [r2] ; load blim from mem + vdup.s8 q1, r3 ; duplicate mblim + b vp8_loop_filter_simple_horizontal_edge_neon + ENDP ;|vp8_loop_filter_bhs_neon| + + END diff --git a/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm b/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm new file mode 100644 index 0000000..e690df2 --- /dev/null +++ b/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm @@ -0,0 +1,154 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + ;EXPORT |vp8_loop_filter_simple_vertical_edge_neon| + EXPORT |vp8_loop_filter_bvs_neon| + EXPORT |vp8_loop_filter_mbvs_neon| + ARM + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *s, PRESERVE +; r1 int p, PRESERVE +; q1 limit, PRESERVE + +|vp8_loop_filter_simple_vertical_edge_neon| PROC + sub r0, r0, #2 ; move src pointer down by 2 columns + add r12, r1, r1 + add r3, r0, r1 + + vld4.8 {d6[0], d7[0], d8[0], d9[0]}, [r0], r12 + vld4.8 {d6[1], d7[1], d8[1], d9[1]}, [r3], r12 + vld4.8 {d6[2], d7[2], d8[2], d9[2]}, [r0], r12 + vld4.8 {d6[3], d7[3], d8[3], d9[3]}, [r3], r12 + vld4.8 {d6[4], d7[4], d8[4], d9[4]}, [r0], r12 + vld4.8 {d6[5], d7[5], d8[5], d9[5]}, [r3], r12 + vld4.8 {d6[6], d7[6], d8[6], d9[6]}, [r0], r12 + vld4.8 {d6[7], d7[7], d8[7], d9[7]}, [r3], r12 + + vld4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r12 + vld4.8 {d10[1], d11[1], d12[1], d13[1]}, [r3], r12 + vld4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r12 + vld4.8 {d10[3], d11[3], d12[3], d13[3]}, [r3], r12 + vld4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r12 + vld4.8 {d10[5], d11[5], d12[5], d13[5]}, [r3], r12 + vld4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r12 + vld4.8 {d10[7], d11[7], d12[7], d13[7]}, [r3] + + vswp d7, d10 + vswp d12, d9 + + ;vp8_filter_mask() function + ;vp8_hevmask() function + sub r0, r0, r1, lsl #4 + vabd.u8 q15, q5, q4 ; abs(p0 - q0) + vabd.u8 q14, q3, q6 ; abs(p1 - q1) + + vqadd.u8 q15, q15, q15 ; abs(p0 - q0) * 2 + vshr.u8 q14, q14, #1 ; abs(p1 - q1) / 2 + vmov.u8 q0, #0x80 ; 0x80 + vmov.s16 q11, #3 + vqadd.u8 q15, q15, q14 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + + veor q4, q4, q0 ; qs0: q0 offset to convert to a signed value + veor q5, q5, q0 ; ps0: p0 offset to convert to a signed value + veor q3, q3, q0 ; ps1: p1 offset to convert to a signed value + veor q6, q6, q0 ; qs1: q1 offset to convert to a signed value + + vcge.u8 q15, q1, q15 ; abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + + vsubl.s8 q2, d8, d10 ; ( qs0 - ps0) + vsubl.s8 q13, d9, d11 + + vqsub.s8 q14, q3, q6 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + vmul.s16 q2, q2, q11 ; 3 * ( qs0 - ps0) + vmul.s16 q13, q13, q11 + + vmov.u8 q11, #0x03 ; 0x03 + vmov.u8 q12, #0x04 ; 0x04 + + vaddw.s8 q2, q2, d28 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d29 + + vqmovn.s16 d28, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d29, q13 + + add r0, r0, #1 + add r3, r0, r1 + + vand q14, q14, q15 ; vp8_filter &= mask + + vqadd.s8 q2, q14, q11 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q3, q14, q12 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q14, q3, #3 ; Filter1 >>= 3 + + ;calculate output + vqadd.s8 q11, q5, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q4, q14 ; u = vp8_signed_char_clamp(qs0 - Filter1) + + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + add r12, r1, r1 + vswp d13, d14 + + ;store op1, op0, oq0, oq1 + vst2.8 {d12[0], d13[0]}, [r0], r12 + vst2.8 {d12[1], d13[1]}, [r3], r12 + vst2.8 {d12[2], d13[2]}, [r0], r12 + vst2.8 {d12[3], d13[3]}, [r3], r12 + vst2.8 {d12[4], d13[4]}, [r0], r12 + vst2.8 {d12[5], d13[5]}, [r3], r12 + vst2.8 {d12[6], d13[6]}, [r0], r12 + vst2.8 {d12[7], d13[7]}, [r3], r12 + vst2.8 {d14[0], d15[0]}, [r0], r12 + vst2.8 {d14[1], d15[1]}, [r3], r12 + vst2.8 {d14[2], d15[2]}, [r0], r12 + vst2.8 {d14[3], d15[3]}, [r3], r12 + vst2.8 {d14[4], d15[4]}, [r0], r12 + vst2.8 {d14[5], d15[5]}, [r3], r12 + vst2.8 {d14[6], d15[6]}, [r0], r12 + vst2.8 {d14[7], d15[7]}, [r3] + + bx lr + ENDP ; |vp8_loop_filter_simple_vertical_edge_neon| + +; r0 unsigned char *y +; r1 int ystride +; r2 const unsigned char *blimit + +|vp8_loop_filter_bvs_neon| PROC + push {r4, lr} + ldrb r3, [r2] ; load blim from mem + mov r4, r0 + add r0, r0, #4 + vdup.s8 q1, r3 ; duplicate blim + bl vp8_loop_filter_simple_vertical_edge_neon + ; vp8_loop_filter_simple_vertical_edge_neon preserves r1 and q1 + add r0, r4, #8 + bl vp8_loop_filter_simple_vertical_edge_neon + add r0, r4, #12 + pop {r4, lr} + b vp8_loop_filter_simple_vertical_edge_neon + ENDP ;|vp8_loop_filter_bvs_neon| + +; r0 unsigned char *y +; r1 int ystride +; r2 const unsigned char *blimit + +|vp8_loop_filter_mbvs_neon| PROC + ldrb r3, [r2] ; load mblim from mem + vdup.s8 q1, r3 ; duplicate mblim + b vp8_loop_filter_simple_vertical_edge_neon + ENDP ;|vp8_loop_filter_bvs_neon| + END diff --git a/vp8/common/arm/neon/mbloopfilter_neon.asm b/vp8/common/arm/neon/mbloopfilter_neon.asm new file mode 100644 index 0000000..f41c156 --- /dev/null +++ b/vp8/common/arm/neon/mbloopfilter_neon.asm @@ -0,0 +1,469 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_mbloop_filter_horizontal_edge_y_neon| + EXPORT |vp8_mbloop_filter_horizontal_edge_uv_neon| + EXPORT |vp8_mbloop_filter_vertical_edge_y_neon| + EXPORT |vp8_mbloop_filter_vertical_edge_uv_neon| + ARM + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; void vp8_mbloop_filter_horizontal_edge_y_neon(unsigned char *src, int pitch, +; const unsigned char *blimit, +; const unsigned char *limit, +; const unsigned char *thresh) +; r0 unsigned char *src, +; r1 int pitch, +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, +|vp8_mbloop_filter_horizontal_edge_y_neon| PROC + push {lr} + add r1, r1, r1 ; double stride + ldr r12, [sp, #4] ; load thresh + sub r0, r0, r1, lsl #1 ; move src pointer down by 4 lines + vdup.u8 q2, r12 ; thresh + add r12, r0, r1, lsr #1 ; move src pointer up by 1 line + + vld1.u8 {q3}, [r0@128], r1 ; p3 + vld1.u8 {q4}, [r12@128], r1 ; p2 + vld1.u8 {q5}, [r0@128], r1 ; p1 + vld1.u8 {q6}, [r12@128], r1 ; p0 + vld1.u8 {q7}, [r0@128], r1 ; q0 + vld1.u8 {q8}, [r12@128], r1 ; q1 + vld1.u8 {q9}, [r0@128], r1 ; q2 + vld1.u8 {q10}, [r12@128], r1 ; q3 + + bl vp8_mbloop_filter_neon + + sub r12, r12, r1, lsl #2 + add r0, r12, r1, lsr #1 + + vst1.u8 {q4}, [r12@128],r1 ; store op2 + vst1.u8 {q5}, [r0@128],r1 ; store op1 + vst1.u8 {q6}, [r12@128], r1 ; store op0 + vst1.u8 {q7}, [r0@128],r1 ; store oq0 + vst1.u8 {q8}, [r12@128] ; store oq1 + vst1.u8 {q9}, [r0@128] ; store oq2 + + pop {pc} + ENDP ; |vp8_mbloop_filter_horizontal_edge_y_neon| + +; void vp8_mbloop_filter_horizontal_edge_uv_neon(unsigned char *u, int pitch, +; const unsigned char *blimit, +; const unsigned char *limit, +; const unsigned char *thresh, +; unsigned char *v) +; r0 unsigned char *u, +; r1 int pitch, +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, +; sp+4 unsigned char *v + +|vp8_mbloop_filter_horizontal_edge_uv_neon| PROC + push {lr} + ldr r12, [sp, #4] ; load thresh + sub r0, r0, r1, lsl #2 ; move u pointer down by 4 lines + vdup.u8 q2, r12 ; thresh + ldr r12, [sp, #8] ; load v ptr + sub r12, r12, r1, lsl #2 ; move v pointer down by 4 lines + + vld1.u8 {d6}, [r0@64], r1 ; p3 + vld1.u8 {d7}, [r12@64], r1 ; p3 + vld1.u8 {d8}, [r0@64], r1 ; p2 + vld1.u8 {d9}, [r12@64], r1 ; p2 + vld1.u8 {d10}, [r0@64], r1 ; p1 + vld1.u8 {d11}, [r12@64], r1 ; p1 + vld1.u8 {d12}, [r0@64], r1 ; p0 + vld1.u8 {d13}, [r12@64], r1 ; p0 + vld1.u8 {d14}, [r0@64], r1 ; q0 + vld1.u8 {d15}, [r12@64], r1 ; q0 + vld1.u8 {d16}, [r0@64], r1 ; q1 + vld1.u8 {d17}, [r12@64], r1 ; q1 + vld1.u8 {d18}, [r0@64], r1 ; q2 + vld1.u8 {d19}, [r12@64], r1 ; q2 + vld1.u8 {d20}, [r0@64], r1 ; q3 + vld1.u8 {d21}, [r12@64], r1 ; q3 + + bl vp8_mbloop_filter_neon + + sub r0, r0, r1, lsl #3 + sub r12, r12, r1, lsl #3 + + add r0, r0, r1 + add r12, r12, r1 + + vst1.u8 {d8}, [r0@64], r1 ; store u op2 + vst1.u8 {d9}, [r12@64], r1 ; store v op2 + vst1.u8 {d10}, [r0@64], r1 ; store u op1 + vst1.u8 {d11}, [r12@64], r1 ; store v op1 + vst1.u8 {d12}, [r0@64], r1 ; store u op0 + vst1.u8 {d13}, [r12@64], r1 ; store v op0 + vst1.u8 {d14}, [r0@64], r1 ; store u oq0 + vst1.u8 {d15}, [r12@64], r1 ; store v oq0 + vst1.u8 {d16}, [r0@64], r1 ; store u oq1 + vst1.u8 {d17}, [r12@64], r1 ; store v oq1 + vst1.u8 {d18}, [r0@64], r1 ; store u oq2 + vst1.u8 {d19}, [r12@64], r1 ; store v oq2 + + pop {pc} + ENDP ; |vp8_mbloop_filter_horizontal_edge_uv_neon| + +; void vp8_mbloop_filter_vertical_edge_y_neon(unsigned char *src, int pitch, +; const unsigned char *blimit, +; const unsigned char *limit, +; const unsigned char *thresh) +; r0 unsigned char *src, +; r1 int pitch, +; r2 unsigned char blimit +; r3 unsigned char limit +; sp unsigned char thresh, +|vp8_mbloop_filter_vertical_edge_y_neon| PROC + push {lr} + ldr r12, [sp, #4] ; load thresh + sub r0, r0, #4 ; move src pointer down by 4 columns + vdup.s8 q2, r12 ; thresh + add r12, r0, r1, lsl #3 ; move src pointer down by 8 lines + + vld1.u8 {d6}, [r0], r1 ; load first 8-line src data + vld1.u8 {d7}, [r12], r1 ; load second 8-line src data + vld1.u8 {d8}, [r0], r1 + vld1.u8 {d9}, [r12], r1 + vld1.u8 {d10}, [r0], r1 + vld1.u8 {d11}, [r12], r1 + vld1.u8 {d12}, [r0], r1 + vld1.u8 {d13}, [r12], r1 + vld1.u8 {d14}, [r0], r1 + vld1.u8 {d15}, [r12], r1 + vld1.u8 {d16}, [r0], r1 + vld1.u8 {d17}, [r12], r1 + vld1.u8 {d18}, [r0], r1 + vld1.u8 {d19}, [r12], r1 + vld1.u8 {d20}, [r0], r1 + vld1.u8 {d21}, [r12], r1 + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + sub r0, r0, r1, lsl #3 + + bl vp8_mbloop_filter_neon + + sub r12, r12, r1, lsl #3 + + ;transpose to 16x8 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + ;store op2, op1, op0, oq0, oq1, oq2 + vst1.8 {d6}, [r0], r1 + vst1.8 {d7}, [r12], r1 + vst1.8 {d8}, [r0], r1 + vst1.8 {d9}, [r12], r1 + vst1.8 {d10}, [r0], r1 + vst1.8 {d11}, [r12], r1 + vst1.8 {d12}, [r0], r1 + vst1.8 {d13}, [r12], r1 + vst1.8 {d14}, [r0], r1 + vst1.8 {d15}, [r12], r1 + vst1.8 {d16}, [r0], r1 + vst1.8 {d17}, [r12], r1 + vst1.8 {d18}, [r0], r1 + vst1.8 {d19}, [r12], r1 + vst1.8 {d20}, [r0] + vst1.8 {d21}, [r12] + + pop {pc} + ENDP ; |vp8_mbloop_filter_vertical_edge_y_neon| + +; void vp8_mbloop_filter_vertical_edge_uv_neon(unsigned char *u, int pitch, +; const unsigned char *blimit, +; const unsigned char *limit, +; const unsigned char *thresh, +; unsigned char *v) +; r0 unsigned char *u, +; r1 int pitch, +; r2 const signed char *flimit, +; r3 const signed char *limit, +; sp const signed char *thresh, +; sp+4 unsigned char *v +|vp8_mbloop_filter_vertical_edge_uv_neon| PROC + push {lr} + ldr r12, [sp, #4] ; load thresh + sub r0, r0, #4 ; move u pointer down by 4 columns + vdup.u8 q2, r12 ; thresh + ldr r12, [sp, #8] ; load v ptr + sub r12, r12, #4 ; move v pointer down by 4 columns + + vld1.u8 {d6}, [r0], r1 ;load u data + vld1.u8 {d7}, [r12], r1 ;load v data + vld1.u8 {d8}, [r0], r1 + vld1.u8 {d9}, [r12], r1 + vld1.u8 {d10}, [r0], r1 + vld1.u8 {d11}, [r12], r1 + vld1.u8 {d12}, [r0], r1 + vld1.u8 {d13}, [r12], r1 + vld1.u8 {d14}, [r0], r1 + vld1.u8 {d15}, [r12], r1 + vld1.u8 {d16}, [r0], r1 + vld1.u8 {d17}, [r12], r1 + vld1.u8 {d18}, [r0], r1 + vld1.u8 {d19}, [r12], r1 + vld1.u8 {d20}, [r0], r1 + vld1.u8 {d21}, [r12], r1 + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + sub r0, r0, r1, lsl #3 + + bl vp8_mbloop_filter_neon + + sub r12, r12, r1, lsl #3 + + ;transpose to 16x8 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + ;store op2, op1, op0, oq0, oq1, oq2 + vst1.8 {d6}, [r0], r1 + vst1.8 {d7}, [r12], r1 + vst1.8 {d8}, [r0], r1 + vst1.8 {d9}, [r12], r1 + vst1.8 {d10}, [r0], r1 + vst1.8 {d11}, [r12], r1 + vst1.8 {d12}, [r0], r1 + vst1.8 {d13}, [r12], r1 + vst1.8 {d14}, [r0], r1 + vst1.8 {d15}, [r12], r1 + vst1.8 {d16}, [r0], r1 + vst1.8 {d17}, [r12], r1 + vst1.8 {d18}, [r0], r1 + vst1.8 {d19}, [r12], r1 + vst1.8 {d20}, [r0] + vst1.8 {d21}, [r12] + + pop {pc} + ENDP ; |vp8_mbloop_filter_vertical_edge_uv_neon| + +; void vp8_mbloop_filter_neon() +; This is a helper function for the macroblock loopfilters. The individual +; functions do the necessary load, transpose (if necessary), preserve (if +; necessary) and store. + +; r0,r1 PRESERVE +; r2 mblimit +; r3 limit + +; q2 thresh +; q3 p3 PRESERVE +; q4 p2 +; q5 p1 +; q6 p0 +; q7 q0 +; q8 q1 +; q9 q2 +; q10 q3 PRESERVE + +|vp8_mbloop_filter_neon| PROC + + ; vp8_filter_mask + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q1, q9, q8 ; abs(q2 - q1) + vabd.u8 q0, q10, q9 ; abs(q3 - q2) + + vmax.u8 q11, q11, q12 + vmax.u8 q12, q13, q14 + vmax.u8 q1, q1, q0 + vmax.u8 q15, q11, q12 + + vabd.u8 q12, q6, q7 ; abs(p0 - q0) + + ; vp8_hevmask + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh) * -1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh) * -1 + vmax.u8 q15, q15, q1 + + vdup.u8 q1, r3 ; limit + vdup.u8 q2, r2 ; mblimit + + vmov.u8 q0, #0x80 ; 0x80 + + vcge.u8 q15, q1, q15 + + vabd.u8 q1, q5, q8 ; a = abs(p1 - q1) + vqadd.u8 q12, q12, q12 ; b = abs(p0 - q0) * 2 + vmov.u16 q11, #3 ; #3 + + ; vp8_filter + ; convert to signed + veor q7, q7, q0 ; qs0 + vshr.u8 q1, q1, #1 ; a = a / 2 + veor q6, q6, q0 ; ps0 + veor q5, q5, q0 ; ps1 + + vqadd.u8 q12, q12, q1 ; a = b + a + + veor q8, q8, q0 ; qs1 + veor q4, q4, q0 ; ps2 + veor q9, q9, q0 ; qs2 + + vorr q14, q13, q14 ; vp8_hevmask + + vcge.u8 q12, q2, q12 ; (a > flimit * 2 + limit) * -1 + + vsubl.s8 q2, d14, d12 ; qs0 - ps0 + vsubl.s8 q13, d15, d13 + + vqsub.s8 q1, q5, q8 ; vp8_filter = clamp(ps1-qs1) + + vmul.i16 q2, q2, q11 ; 3 * ( qs0 - ps0) + + vand q15, q15, q12 ; vp8_filter_mask + + vmul.i16 q13, q13, q11 + + vmov.u8 q12, #3 ; #3 + + vaddw.s8 q2, q2, d2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d3 + + vmov.u8 q11, #4 ; #4 + + ; vp8_filter = clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d2, q2 + vqmovn.s16 d3, q13 + + vand q1, q1, q15 ; vp8_filter &= mask + + vmov.u16 q15, #63 ; #63 + + vand q13, q1, q14 ; Filter2 &= hev + + vqadd.s8 q2, q13, q11 ; Filter1 = clamp(Filter2+4) + vqadd.s8 q13, q13, q12 ; Filter2 = clamp(Filter2+3) + + vmov q0, q15 + + vshr.s8 q2, q2, #3 ; Filter1 >>= 3 + vshr.s8 q13, q13, #3 ; Filter2 >>= 3 + + vmov q11, q15 + vmov q12, q15 + + vqsub.s8 q7, q7, q2 ; qs0 = clamp(qs0 - Filter1) + + vqadd.s8 q6, q6, q13 ; ps0 = clamp(ps0 + Filter2) + + vbic q1, q1, q14 ; vp8_filter &= ~hev + + ; roughly 1/7th difference across boundary + ; roughly 2/7th difference across boundary + ; roughly 3/7th difference across boundary + + vmov.u8 d5, #9 ; #9 + vmov.u8 d4, #18 ; #18 + + vmov q13, q15 + vmov q14, q15 + + vmlal.s8 q0, d2, d5 ; 63 + Filter2 * 9 + vmlal.s8 q11, d3, d5 + vmov.u8 d5, #27 ; #27 + vmlal.s8 q12, d2, d4 ; 63 + Filter2 * 18 + vmlal.s8 q13, d3, d4 + vmlal.s8 q14, d2, d5 ; 63 + Filter2 * 27 + vmlal.s8 q15, d3, d5 + + vqshrn.s16 d0, q0, #7 ; u = clamp((63 + Filter2 * 9)>>7) + vqshrn.s16 d1, q11, #7 + vqshrn.s16 d24, q12, #7 ; u = clamp((63 + Filter2 * 18)>>7) + vqshrn.s16 d25, q13, #7 + vqshrn.s16 d28, q14, #7 ; u = clamp((63 + Filter2 * 27)>>7) + vqshrn.s16 d29, q15, #7 + + vmov.u8 q1, #0x80 ; 0x80 + + vqsub.s8 q11, q9, q0 ; s = clamp(qs2 - u) + vqadd.s8 q0, q4, q0 ; s = clamp(ps2 + u) + vqsub.s8 q13, q8, q12 ; s = clamp(qs1 - u) + vqadd.s8 q12, q5, q12 ; s = clamp(ps1 + u) + vqsub.s8 q15, q7, q14 ; s = clamp(qs0 - u) + vqadd.s8 q14, q6, q14 ; s = clamp(ps0 + u) + + veor q9, q11, q1 ; *oq2 = s^0x80 + veor q4, q0, q1 ; *op2 = s^0x80 + veor q8, q13, q1 ; *oq1 = s^0x80 + veor q5, q12, q1 ; *op2 = s^0x80 + veor q7, q15, q1 ; *oq0 = s^0x80 + veor q6, q14, q1 ; *op0 = s^0x80 + + bx lr + ENDP ; |vp8_mbloop_filter_neon| + +;----------------- + + END diff --git a/vp8/common/arm/neon/sad16_neon.asm b/vp8/common/arm/neon/sad16_neon.asm new file mode 100644 index 0000000..d7c590e --- /dev/null +++ b/vp8/common/arm/neon/sad16_neon.asm @@ -0,0 +1,207 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sad16x16_neon| + EXPORT |vp8_sad16x8_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int src_stride +; r2 unsigned char *ref_ptr +; r3 int ref_stride +|vp8_sad16x16_neon| PROC +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabdl.u8 q12, d0, d8 + vabdl.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0] + vld1.8 {q7}, [r2] + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vadd.u16 q0, q12, q13 + + vpaddl.u16 q1, q0 + vpaddl.u32 q0, q1 + + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;============================== +;unsigned int vp8_sad16x8_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +|vp8_sad16x8_neon| PROC + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabdl.u8 q12, d0, d8 + vabdl.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vadd.u16 q0, q12, q13 + + vpaddl.u16 q1, q0 + vpaddl.u32 q0, q1 + + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + + END diff --git a/vp8/common/arm/neon/sad8_neon.asm b/vp8/common/arm/neon/sad8_neon.asm new file mode 100644 index 0000000..23ba6df --- /dev/null +++ b/vp8/common/arm/neon/sad8_neon.asm @@ -0,0 +1,209 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sad8x8_neon| + EXPORT |vp8_sad8x16_neon| + EXPORT |vp8_sad4x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; unsigned int vp8_sad8x8_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) + +|vp8_sad8x8_neon| PROC + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabdl.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q12, d6, d14 + + vpaddl.u16 q1, q12 + vpaddl.u32 q0, q1 + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;============================ +;unsigned int vp8_sad8x16_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) + +|vp8_sad8x16_neon| PROC + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabdl.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q12, d6, d14 + + vpaddl.u16 q1, q12 + vpaddl.u32 q0, q1 + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;=========================== +;unsigned int vp8_sad4x4_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) + +|vp8_sad4x4_neon| PROC + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabdl.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q12, d6, d14 + + vpaddl.u16 d1, d24 + vpaddl.u32 d0, d1 + vmov.32 r0, d0[0] + + bx lr + + ENDP + + END diff --git a/vp8/common/arm/neon/save_reg_neon.asm b/vp8/common/arm/neon/save_reg_neon.asm new file mode 100644 index 0000000..fd7002e --- /dev/null +++ b/vp8/common/arm/neon/save_reg_neon.asm @@ -0,0 +1,36 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_push_neon| + EXPORT |vp8_pop_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +|vp8_push_neon| PROC + vst1.i64 {d8, d9, d10, d11}, [r0]! + vst1.i64 {d12, d13, d14, d15}, [r0]! + bx lr + + ENDP + +|vp8_pop_neon| PROC + vld1.i64 {d8, d9, d10, d11}, [r0]! + vld1.i64 {d12, d13, d14, d15}, [r0]! + bx lr + + ENDP + + END + diff --git a/vp8/common/arm/neon/shortidct4x4llm_neon.asm b/vp8/common/arm/neon/shortidct4x4llm_neon.asm new file mode 100644 index 0000000..67d2ab0 --- /dev/null +++ b/vp8/common/arm/neon/shortidct4x4llm_neon.asm @@ -0,0 +1,139 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_short_idct4x4llm_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;************************************************************* +;void vp8_short_idct4x4llm_c(short *input, unsigned char *pred, int pitch, +; unsigned char *dst, int stride) +;r0 short * input +;r1 short * pred +;r2 int pitch +;r3 unsigned char dst +;sp int stride +;************************************************************* + +; static const int cospi8sqrt2minus1=20091; +; static const int sinpi8sqrt2 =35468; +; static const int rounding = 0; + +; Optimization note: The resulted data from dequantization are signed +; 13-bit data that is in the range of [-4096, 4095]. This allows to +; use "vqdmulh"(neon) instruction since it won't go out of range +; (13+16+1=30bits<32bits). This instruction gives the high half +; result of the multiplication that is needed in IDCT. + +|vp8_short_idct4x4llm_neon| PROC + adr r12, idct_coeff + vld1.16 {q1, q2}, [r0] + vld1.16 {d0}, [r12] + + vswp d3, d4 ;q2(vp[4] vp[12]) + ldr r0, [sp] ; stride + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + ;d6 - c1:temp1 + ;d7 - d1:temp2 + ;d8 - d1:temp1 + ;d9 - c1:temp2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vswp d3, d4 + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vrshr.s16 d2, d2, #3 + vrshr.s16 d3, d3, #3 + vrshr.s16 d4, d4, #3 + vrshr.s16 d5, d5, #3 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + ; load prediction data + vld1.32 d6[0], [r1], r2 + vld1.32 d6[1], [r1], r2 + vld1.32 d7[0], [r1], r2 + vld1.32 d7[1], [r1], r2 + + ; add prediction and residual + vaddw.u8 q1, q1, d6 + vaddw.u8 q2, q2, d7 + + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + + ; store to destination + vst1.32 d1[0], [r3], r0 + vst1.32 d1[1], [r3], r0 + vst1.32 d2[0], [r3], r0 + vst1.32 d2[1], [r3], r0 + + bx lr + + ENDP + +;----------------- + +idct_coeff + DCD 0x4e7b4e7b, 0x8a8c8a8c + +;20091, 20091, 35468, 35468 + + END diff --git a/vp8/common/arm/neon/sixtappredict16x16_neon.asm b/vp8/common/arm/neon/sixtappredict16x16_neon.asm new file mode 100644 index 0000000..9fdafd3 --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict16x16_neon.asm @@ -0,0 +1,490 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict16x16_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +filter16_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +;Note: To take advantage of 8-bit mulplication instruction in NEON. First apply abs() to +; filter coeffs to make them u8. Then, use vmlsl for negtive coeffs. After multiplication, +; the result can be negtive. So, I treat the result as s16. But, since it is also possible +; that the result can be a large positive number (> 2^15-1), which could be confused as a +; negtive number. To avoid that error, apply filter coeffs in the order of 0, 1, 4 ,5 ,2, +; which ensures that the result stays in s16 range. Finally, saturated add the result by +; applying 3rd filter coeff. Same applys to other filter functions. + +|vp8_sixtap_predict16x16_neon| PROC + push {r4-r5, lr} + + adr r12, filter16_coeff + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter16x16_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter16x16_only + + sub sp, sp, #336 ;reserve space on stack for temporary storage + mov lr, sp + + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #7 ;loop counter + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + sub r0, r0, r1, lsl #1 + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First Pass: output_height lines x output_width columns (21x16) +filt_blk2d_fp16x16_loop_neon + vld1.u8 {d6, d7, d8}, [r0], r1 ;load src data + vld1.u8 {d9, d10, d11}, [r0], r1 + vld1.u8 {d12, d13, d14}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q9, d7, d0 + vmull.u8 q10, d9, d0 + vmull.u8 q11, d10, d0 + vmull.u8 q12, d12, d0 + vmull.u8 q13, d13, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d9, d10, #1 + vext.8 d30, d12, d13, #1 + + vmlsl.u8 q8, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q10, d29, d1 + vmlsl.u8 q12, d30, d1 + + vext.8 d28, d7, d8, #1 + vext.8 d29, d10, d11, #1 + vext.8 d30, d13, d14, #1 + + vmlsl.u8 q9, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q11, d29, d1 + vmlsl.u8 q13, d30, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d9, d10, #4 + vext.8 d30, d12, d13, #4 + + vmlsl.u8 q8, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q10, d29, d4 + vmlsl.u8 q12, d30, d4 + + vext.8 d28, d7, d8, #4 + vext.8 d29, d10, d11, #4 + vext.8 d30, d13, d14, #4 + + vmlsl.u8 q9, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q11, d29, d4 + vmlsl.u8 q13, d30, d4 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d9, d10, #5 + vext.8 d30, d12, d13, #5 + + vmlal.u8 q8, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q10, d29, d5 + vmlal.u8 q12, d30, d5 + + vext.8 d28, d7, d8, #5 + vext.8 d29, d10, d11, #5 + vext.8 d30, d13, d14, #5 + + vmlal.u8 q9, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q11, d29, d5 + vmlal.u8 q13, d30, d5 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d9, d10, #2 + vext.8 d30, d12, d13, #2 + + vmlal.u8 q8, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q10, d29, d2 + vmlal.u8 q12, d30, d2 + + vext.8 d28, d7, d8, #2 + vext.8 d29, d10, d11, #2 + vext.8 d30, d13, d14, #2 + + vmlal.u8 q9, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q11, d29, d2 + vmlal.u8 q13, d30, d2 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d9, d10, #3 + vext.8 d30, d12, d13, #3 + + vext.8 d15, d7, d8, #3 + vext.8 d31, d10, d11, #3 + vext.8 d6, d13, d14, #3 + + vmull.u8 q4, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q5, d29, d3 + vmull.u8 q6, d30, d3 + + vqadd.s16 q8, q4 ;sum of all (src_data*filter_parameters) + vqadd.s16 q10, q5 + vqadd.s16 q12, q6 + + vmull.u8 q6, d15, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q7, d31, d3 + vmull.u8 q3, d6, d3 + + subs r2, r2, #1 + + vqadd.s16 q9, q6 + vqadd.s16 q11, q7 + vqadd.s16 q13, q3 + + vqrshrun.s16 d6, q8, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q9, #7 + vqrshrun.s16 d8, q10, #7 + vqrshrun.s16 d9, q11, #7 + vqrshrun.s16 d10, q12, #7 + vqrshrun.s16 d11, q13, #7 + + vst1.u8 {d6, d7, d8}, [lr]! ;store result + vst1.u8 {d9, d10, d11}, [lr]! + + bne filt_blk2d_fp16x16_loop_neon + +;Second pass: 16x16 +;secondpass_filter - do first 8-columns and then second 8-columns + add r3, r12, r3, lsl #5 + sub lr, lr, #336 + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + mov r3, #2 ;loop counter + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + mov r2, #16 + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + +filt_blk2d_sp16x16_outloop_neon + vld1.u8 {d18}, [lr], r2 ;load src data + vld1.u8 {d19}, [lr], r2 + vld1.u8 {d20}, [lr], r2 + vld1.u8 {d21}, [lr], r2 + mov r12, #4 ;loop counter + vld1.u8 {d22}, [lr], r2 + +secondpass_inner_loop_neon + vld1.u8 {d23}, [lr], r2 ;load src data + vld1.u8 {d24}, [lr], r2 + vld1.u8 {d25}, [lr], r2 + vld1.u8 {d26}, [lr], r2 + + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r12, r12, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vmov q9, q11 + vst1.u8 {d7}, [r4], r5 + vmov q10, q12 + vst1.u8 {d8}, [r4], r5 + vmov d22, d26 + vst1.u8 {d9}, [r4], r5 + + bne secondpass_inner_loop_neon + + subs r3, r3, #1 + sub lr, lr, #336 + add lr, lr, #8 + + sub r4, r4, r5, lsl #4 + add r4, r4, #8 + + bne filt_blk2d_sp16x16_outloop_neon + + add sp, sp, #336 + pop {r4-r5,pc} + +;-------------------- +firstpass_filter16x16_only + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #8 ;loop counter + sub r0, r0, #2 ;move srcptr back to (column-2) + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First Pass: output_height lines x output_width columns (16x16) +filt_blk2d_fpo16x16_loop_neon + vld1.u8 {d6, d7, d8}, [r0], r1 ;load src data + vld1.u8 {d9, d10, d11}, [r0], r1 + + pld [r0] + pld [r0, r1] + + vmull.u8 q6, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q7, d7, d0 + vmull.u8 q8, d9, d0 + vmull.u8 q9, d10, d0 + + vext.8 d20, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d21, d9, d10, #1 + vext.8 d22, d7, d8, #1 + vext.8 d23, d10, d11, #1 + vext.8 d24, d6, d7, #4 ;construct src_ptr[2] + vext.8 d25, d9, d10, #4 + vext.8 d26, d7, d8, #4 + vext.8 d27, d10, d11, #4 + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d9, d10, #5 + + vmlsl.u8 q6, d20, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d21, d1 + vmlsl.u8 q7, d22, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q9, d23, d1 + vmlsl.u8 q6, d24, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d25, d4 + vmlsl.u8 q7, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q9, d27, d4 + vmlal.u8 q6, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + + vext.8 d20, d7, d8, #5 + vext.8 d21, d10, d11, #5 + vext.8 d22, d6, d7, #2 ;construct src_ptr[0] + vext.8 d23, d9, d10, #2 + vext.8 d24, d7, d8, #2 + vext.8 d25, d10, d11, #2 + + vext.8 d26, d6, d7, #3 ;construct src_ptr[1] + vext.8 d27, d9, d10, #3 + vext.8 d28, d7, d8, #3 + vext.8 d29, d10, d11, #3 + + vmlal.u8 q7, d20, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q9, d21, d5 + vmlal.u8 q6, d22, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d23, d2 + vmlal.u8 q7, d24, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q9, d25, d2 + + vmull.u8 q10, d26, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q11, d27, d3 + vmull.u8 q12, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q15, d29, d3 + + vqadd.s16 q6, q10 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q11 + vqadd.s16 q7, q12 + vqadd.s16 q9, q15 + + subs r2, r2, #1 + + vqrshrun.s16 d6, q6, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q7, #7 + vqrshrun.s16 d8, q8, #7 + vqrshrun.s16 d9, q9, #7 + + vst1.u8 {q3}, [r4], r5 ;store result + vst1.u8 {q4}, [r4], r5 + + bne filt_blk2d_fpo16x16_loop_neon + + pop {r4-r5,pc} + +;-------------------- +secondpass_filter16x16_only +;Second pass: 16x16 + add r3, r12, r3, lsl #5 + sub r0, r0, r1, lsl #1 + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + mov r3, #2 ;loop counter + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + +filt_blk2d_spo16x16_outloop_neon + vld1.u8 {d18}, [r0], r1 ;load src data + vld1.u8 {d19}, [r0], r1 + vld1.u8 {d20}, [r0], r1 + vld1.u8 {d21}, [r0], r1 + mov r12, #4 ;loop counter + vld1.u8 {d22}, [r0], r1 + +secondpass_only_inner_loop_neon + vld1.u8 {d23}, [r0], r1 ;load src data + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r12, r12, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vmov q9, q11 + vst1.u8 {d7}, [r4], r5 + vmov q10, q12 + vst1.u8 {d8}, [r4], r5 + vmov d22, d26 + vst1.u8 {d9}, [r4], r5 + + bne secondpass_only_inner_loop_neon + + subs r3, r3, #1 + sub r0, r0, r1, lsl #4 + sub r0, r0, r1, lsl #2 + sub r0, r0, r1 + add r0, r0, #8 + + sub r4, r4, r5, lsl #4 + add r4, r4, #8 + + bne filt_blk2d_spo16x16_outloop_neon + + pop {r4-r5,pc} + + ENDP + +;----------------- + END diff --git a/vp8/common/arm/neon/sixtappredict4x4_neon.asm b/vp8/common/arm/neon/sixtappredict4x4_neon.asm new file mode 100644 index 0000000..a4222bc --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict4x4_neon.asm @@ -0,0 +1,422 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict4x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +filter4_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_sixtap_predict4x4_neon| PROC + push {r4, lr} + + adr r12, filter4_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter4x4_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter4x4_only + + vabs.s32 q12, q14 ;get abs(filer_parameters) + vabs.s32 q13, q15 + + sub r0, r0, #2 ;go back 2 columns of src data + sub r0, r0, r1, lsl #1 ;go back 2 lines of src data + +;First pass: output_height lines x output_width columns (9x4) + vld1.u8 {q3}, [r0], r1 ;load first 4-line src data + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vld1.u8 {q4}, [r0], r1 + vdup.8 d1, d24[4] + vld1.u8 {q5}, [r0], r1 + vdup.8 d2, d25[0] + vld1.u8 {q6}, [r0], r1 + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vext.8 d18, d6, d7, #5 ;construct src_ptr[3] + vext.8 d19, d8, d9, #5 + vext.8 d20, d10, d11, #5 + vext.8 d21, d12, d13, #5 + + vswp d7, d8 ;discard 2nd half data after src_ptr[3] is done + vswp d11, d12 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[3]) + vzip.32 d20, d21 + vmull.u8 q7, d18, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q8, d20, d5 + + vmov q4, q3 ;keep original src data in q4 q6 + vmov q6, q5 + + vzip.32 d6, d7 ;construct src_ptr[-2], and put 2-line data together + vzip.32 d10, d11 + vshr.u64 q9, q4, #8 ;construct src_ptr[-1] + vshr.u64 q10, q6, #8 + vmlal.u8 q7, d6, d0 ;+(src_ptr[-2] * vp8_filter[0]) + vmlal.u8 q8, d10, d0 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[-1]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #32 ;construct src_ptr[2] + vshr.u64 q5, q6, #32 + vmlsl.u8 q7, d18, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d20, d1 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[2]) + vzip.32 d10, d11 + vshr.u64 q9, q4, #16 ;construct src_ptr[0] + vshr.u64 q10, q6, #16 + vmlsl.u8 q7, d6, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d10, d4 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #24 ;construct src_ptr[1] + vshr.u64 q5, q6, #24 + vmlal.u8 q7, d18, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d20, d2 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + vmull.u8 q9, d6, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q10, d10, d3 + + vld1.u8 {q3}, [r0], r1 ;load rest 5-line src data + vld1.u8 {q4}, [r0], r1 + + vqadd.s16 q7, q9 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q10 + + vld1.u8 {q5}, [r0], r1 + vld1.u8 {q6}, [r0], r1 + + vqrshrun.s16 d27, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d28, q8, #7 + + ;First Pass on rest 5-line data + vld1.u8 {q11}, [r0], r1 + + vext.8 d18, d6, d7, #5 ;construct src_ptr[3] + vext.8 d19, d8, d9, #5 + vext.8 d20, d10, d11, #5 + vext.8 d21, d12, d13, #5 + + vswp d7, d8 ;discard 2nd half data after src_ptr[3] is done + vswp d11, d12 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[3]) + vzip.32 d20, d21 + vext.8 d31, d22, d23, #5 ;construct src_ptr[3] + vmull.u8 q7, d18, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q8, d20, d5 + vmull.u8 q12, d31, d5 ;(src_ptr[3] * vp8_filter[5]) + + vmov q4, q3 ;keep original src data in q4 q6 + vmov q6, q5 + + vzip.32 d6, d7 ;construct src_ptr[-2], and put 2-line data together + vzip.32 d10, d11 + vshr.u64 q9, q4, #8 ;construct src_ptr[-1] + vshr.u64 q10, q6, #8 + + vmlal.u8 q7, d6, d0 ;+(src_ptr[-2] * vp8_filter[0]) + vmlal.u8 q8, d10, d0 + vmlal.u8 q12, d22, d0 ;(src_ptr[-2] * vp8_filter[0]) + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[-1]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #32 ;construct src_ptr[2] + vshr.u64 q5, q6, #32 + vext.8 d31, d22, d23, #1 ;construct src_ptr[-1] + + vmlsl.u8 q7, d18, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d20, d1 + vmlsl.u8 q12, d31, d1 ;-(src_ptr[-1] * vp8_filter[1]) + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[2]) + vzip.32 d10, d11 + vshr.u64 q9, q4, #16 ;construct src_ptr[0] + vshr.u64 q10, q6, #16 + vext.8 d31, d22, d23, #4 ;construct src_ptr[2] + + vmlsl.u8 q7, d6, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d10, d4 + vmlsl.u8 q12, d31, d4 ;-(src_ptr[2] * vp8_filter[4]) + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #24 ;construct src_ptr[1] + vshr.u64 q5, q6, #24 + vext.8 d31, d22, d23, #2 ;construct src_ptr[0] + + vmlal.u8 q7, d18, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d20, d2 + vmlal.u8 q12, d31, d2 ;(src_ptr[0] * vp8_filter[2]) + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + vext.8 d31, d22, d23, #3 ;construct src_ptr[1] + vmull.u8 q9, d6, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q10, d10, d3 + vmull.u8 q11, d31, d3 ;(src_ptr[1] * vp8_filter[3]) + + add r3, r12, r3, lsl #5 + + vqadd.s16 q7, q9 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q10 + vqadd.s16 q12, q11 + + vext.8 d23, d27, d28, #4 + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + + vqrshrun.s16 d29, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d30, q8, #7 + vqrshrun.s16 d31, q12, #7 + +;Second pass: 4x4 + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vext.8 d24, d28, d29, #4 + vext.8 d25, d29, d30, #4 + vext.8 d26, d30, d31, #4 + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + + vmull.u8 q3, d27, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d28, d0 + + vmull.u8 q5, d25, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q6, d26, d5 + + vmlsl.u8 q3, d29, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d30, d4 + + vmlsl.u8 q5, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q6, d24, d1 + + vmlal.u8 q3, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d29, d2 + + vmlal.u8 q5, d24, d3 ;(src_ptr[1] * vp8_filter[3]) + vmlal.u8 q6, d25, d3 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqadd.s16 q5, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q6, q4 + + vqrshrun.s16 d3, q5, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d4, q6, #7 + + vst1.32 {d3[0]}, [r4] ;store result + vst1.32 {d3[1]}, [r0] + vst1.32 {d4[0]}, [r1] + vst1.32 {d4[1]}, [r2] + + pop {r4, pc} + + +;--------------------- +firstpass_filter4x4_only + vabs.s32 q12, q14 ;get abs(filer_parameters) + vabs.s32 q13, q15 + + sub r0, r0, #2 ;go back 2 columns of src data + +;First pass: output_height lines x output_width columns (4x4) + vld1.u8 {q3}, [r0], r1 ;load first 4-line src data + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vld1.u8 {q4}, [r0], r1 + vdup.8 d1, d24[4] + vld1.u8 {q5}, [r0], r1 + vdup.8 d2, d25[0] + vld1.u8 {q6}, [r0], r1 + + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + + vext.8 d18, d6, d7, #5 ;construct src_ptr[3] + vext.8 d19, d8, d9, #5 + vext.8 d20, d10, d11, #5 + vext.8 d21, d12, d13, #5 + + vswp d7, d8 ;discard 2nd half data after src_ptr[3] is done + vswp d11, d12 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[3]) + vzip.32 d20, d21 + vmull.u8 q7, d18, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q8, d20, d5 + + vmov q4, q3 ;keep original src data in q4 q6 + vmov q6, q5 + + vzip.32 d6, d7 ;construct src_ptr[-2], and put 2-line data together + vzip.32 d10, d11 + vshr.u64 q9, q4, #8 ;construct src_ptr[-1] + vshr.u64 q10, q6, #8 + vmlal.u8 q7, d6, d0 ;+(src_ptr[-2] * vp8_filter[0]) + vmlal.u8 q8, d10, d0 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[-1]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #32 ;construct src_ptr[2] + vshr.u64 q5, q6, #32 + vmlsl.u8 q7, d18, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d20, d1 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[2]) + vzip.32 d10, d11 + vshr.u64 q9, q4, #16 ;construct src_ptr[0] + vshr.u64 q10, q6, #16 + vmlsl.u8 q7, d6, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d10, d4 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #24 ;construct src_ptr[1] + vshr.u64 q5, q6, #24 + vmlal.u8 q7, d18, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d20, d2 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + vmull.u8 q9, d6, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q10, d10, d3 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqadd.s16 q7, q9 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q10 + + vqrshrun.s16 d27, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d28, q8, #7 + + vst1.32 {d27[0]}, [r4] ;store result + vst1.32 {d27[1]}, [r0] + vst1.32 {d28[0]}, [r1] + vst1.32 {d28[1]}, [r2] + + pop {r4, pc} + + +;--------------------- +secondpass_filter4x4_only + sub r0, r0, r1, lsl #1 + add r3, r12, r3, lsl #5 + + vld1.32 {d27[0]}, [r0], r1 ;load src data + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vld1.32 {d27[1]}, [r0], r1 + vabs.s32 q7, q5 + vld1.32 {d28[0]}, [r0], r1 + vabs.s32 q8, q6 + vld1.32 {d28[1]}, [r0], r1 + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vld1.32 {d29[0]}, [r0], r1 + vdup.8 d1, d14[4] + vld1.32 {d29[1]}, [r0], r1 + vdup.8 d2, d15[0] + vld1.32 {d30[0]}, [r0], r1 + vdup.8 d3, d15[4] + vld1.32 {d30[1]}, [r0], r1 + vdup.8 d4, d16[0] + vld1.32 {d31[0]}, [r0], r1 + vdup.8 d5, d16[4] + + vext.8 d23, d27, d28, #4 + vext.8 d24, d28, d29, #4 + vext.8 d25, d29, d30, #4 + vext.8 d26, d30, d31, #4 + + vmull.u8 q3, d27, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d28, d0 + + vmull.u8 q5, d25, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q6, d26, d5 + + vmlsl.u8 q3, d29, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d30, d4 + + vmlsl.u8 q5, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q6, d24, d1 + + vmlal.u8 q3, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d29, d2 + + vmlal.u8 q5, d24, d3 ;(src_ptr[1] * vp8_filter[3]) + vmlal.u8 q6, d25, d3 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqadd.s16 q5, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q6, q4 + + vqrshrun.s16 d3, q5, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d4, q6, #7 + + vst1.32 {d3[0]}, [r4] ;store result + vst1.32 {d3[1]}, [r0] + vst1.32 {d4[0]}, [r1] + vst1.32 {d4[1]}, [r2] + + pop {r4, pc} + + ENDP + +;----------------- + + END diff --git a/vp8/common/arm/neon/sixtappredict8x4_neon.asm b/vp8/common/arm/neon/sixtappredict8x4_neon.asm new file mode 100644 index 0000000..a57ec01 --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict8x4_neon.asm @@ -0,0 +1,473 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict8x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +filter8_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +|vp8_sixtap_predict8x4_neon| PROC + push {r4-r5, lr} + + adr r12, filter8_coeff + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter8x4_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter8x4_only + + sub sp, sp, #32 ;reserve space on stack for temporary storage + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + mov lr, sp + sub r0, r0, r1, lsl #1 + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + +;First pass: output_height lines x output_width columns (9x8) + vld1.u8 {q3}, [r0], r1 ;load src data + vdup.8 d3, d25[4] + vld1.u8 {q4}, [r0], r1 + vdup.8 d4, d26[0] + vld1.u8 {q5}, [r0], r1 + vdup.8 d5, d26[4] + vld1.u8 {q6}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vld1.u8 {q3}, [r0], r1 ;load src data + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vld1.u8 {q4}, [r0], r1 + vst1.u8 {d22}, [lr]! ;store result + vld1.u8 {q5}, [r0], r1 + vst1.u8 {d23}, [lr]! + vld1.u8 {q6}, [r0], r1 + vst1.u8 {d24}, [lr]! + vld1.u8 {q7}, [r0], r1 + vst1.u8 {d25}, [lr]! + + ;first_pass filtering on the rest 5-line data + vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + vmull.u8 q11, d12, d0 + vmull.u8 q12, d14, d0 + + vext.8 d27, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d28, d8, d9, #1 + vext.8 d29, d10, d11, #1 + vext.8 d30, d12, d13, #1 + vext.8 d31, d14, d15, #1 + + vmlsl.u8 q8, d27, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q9, d28, d1 + vmlsl.u8 q10, d29, d1 + vmlsl.u8 q11, d30, d1 + vmlsl.u8 q12, d31, d1 + + vext.8 d27, d6, d7, #4 ;construct src_ptr[2] + vext.8 d28, d8, d9, #4 + vext.8 d29, d10, d11, #4 + vext.8 d30, d12, d13, #4 + vext.8 d31, d14, d15, #4 + + vmlsl.u8 q8, d27, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q9, d28, d4 + vmlsl.u8 q10, d29, d4 + vmlsl.u8 q11, d30, d4 + vmlsl.u8 q12, d31, d4 + + vext.8 d27, d6, d7, #2 ;construct src_ptr[0] + vext.8 d28, d8, d9, #2 + vext.8 d29, d10, d11, #2 + vext.8 d30, d12, d13, #2 + vext.8 d31, d14, d15, #2 + + vmlal.u8 q8, d27, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q9, d28, d2 + vmlal.u8 q10, d29, d2 + vmlal.u8 q11, d30, d2 + vmlal.u8 q12, d31, d2 + + vext.8 d27, d6, d7, #5 ;construct src_ptr[3] + vext.8 d28, d8, d9, #5 + vext.8 d29, d10, d11, #5 + vext.8 d30, d12, d13, #5 + vext.8 d31, d14, d15, #5 + + vmlal.u8 q8, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q9, d28, d5 + vmlal.u8 q10, d29, d5 + vmlal.u8 q11, d30, d5 + vmlal.u8 q12, d31, d5 + + vext.8 d27, d6, d7, #3 ;construct src_ptr[1] + vext.8 d28, d8, d9, #3 + vext.8 d29, d10, d11, #3 + vext.8 d30, d12, d13, #3 + vext.8 d31, d14, d15, #3 + + vmull.u8 q3, d27, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d28, d3 + vmull.u8 q5, d29, d3 + vmull.u8 q6, d30, d3 + vmull.u8 q7, d31, d3 + + vqadd.s16 q8, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q9, q4 + vqadd.s16 q10, q5 + vqadd.s16 q11, q6 + vqadd.s16 q12, q7 + + vqrshrun.s16 d26, q8, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d27, q9, #7 + vqrshrun.s16 d28, q10, #7 + vqrshrun.s16 d29, q11, #7 ;load intermediate data from stack + vqrshrun.s16 d30, q12, #7 + +;Second pass: 8x4 +;secondpass_filter + add r3, r12, r3, lsl #5 + sub lr, lr, #32 + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vld1.u8 {q11}, [lr]! + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vld1.u8 {q12}, [lr]! + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + + vmull.u8 q3, d22, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d23, d0 + vmull.u8 q5, d24, d0 + vmull.u8 q6, d25, d0 + + vmlsl.u8 q3, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d24, d1 + vmlsl.u8 q5, d25, d1 + vmlsl.u8 q6, d26, d1 + + vmlsl.u8 q3, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d27, d4 + vmlsl.u8 q5, d28, d4 + vmlsl.u8 q6, d29, d4 + + vmlal.u8 q3, d24, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d25, d2 + vmlal.u8 q5, d26, d2 + vmlal.u8 q6, d27, d2 + + vmlal.u8 q3, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d28, d5 + vmlal.u8 q5, d29, d5 + vmlal.u8 q6, d30, d5 + + vmull.u8 q7, d25, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d26, d3 + vmull.u8 q9, d27, d3 + vmull.u8 q10, d28, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vst1.u8 {d7}, [r4], r5 + vst1.u8 {d8}, [r4], r5 + vst1.u8 {d9}, [r4], r5 + + add sp, sp, #32 + pop {r4-r5,pc} + +;-------------------- +firstpass_filter8x4_only + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + vld1.u8 {q3}, [r0], r1 ;load src data + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vld1.u8 {q4}, [r0], r1 + vdup.8 d1, d24[4] + vld1.u8 {q5}, [r0], r1 + vdup.8 d2, d25[0] + vld1.u8 {q6}, [r0], r1 + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First pass: output_height lines x output_width columns (4x8) + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vst1.u8 {d22}, [r4], r5 ;store result + vst1.u8 {d23}, [r4], r5 + vst1.u8 {d24}, [r4], r5 + vst1.u8 {d25}, [r4], r5 + + pop {r4-r5,pc} + +;--------------------- +secondpass_filter8x4_only +;Second pass: 8x4 + add r3, r12, r3, lsl #5 + sub r0, r0, r1, lsl #1 + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vld1.u8 {d22}, [r0], r1 + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vld1.u8 {d25}, [r0], r1 + vdup.8 d1, d14[4] + vld1.u8 {d26}, [r0], r1 + vdup.8 d2, d15[0] + vld1.u8 {d27}, [r0], r1 + vdup.8 d3, d15[4] + vld1.u8 {d28}, [r0], r1 + vdup.8 d4, d16[0] + vld1.u8 {d29}, [r0], r1 + vdup.8 d5, d16[4] + vld1.u8 {d30}, [r0], r1 + + vmull.u8 q3, d22, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d23, d0 + vmull.u8 q5, d24, d0 + vmull.u8 q6, d25, d0 + + vmlsl.u8 q3, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d24, d1 + vmlsl.u8 q5, d25, d1 + vmlsl.u8 q6, d26, d1 + + vmlsl.u8 q3, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d27, d4 + vmlsl.u8 q5, d28, d4 + vmlsl.u8 q6, d29, d4 + + vmlal.u8 q3, d24, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d25, d2 + vmlal.u8 q5, d26, d2 + vmlal.u8 q6, d27, d2 + + vmlal.u8 q3, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d28, d5 + vmlal.u8 q5, d29, d5 + vmlal.u8 q6, d30, d5 + + vmull.u8 q7, d25, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d26, d3 + vmull.u8 q9, d27, d3 + vmull.u8 q10, d28, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vst1.u8 {d7}, [r4], r5 + vst1.u8 {d8}, [r4], r5 + vst1.u8 {d9}, [r4], r5 + + pop {r4-r5,pc} + + ENDP + +;----------------- + + END diff --git a/vp8/common/arm/neon/sixtappredict8x8_neon.asm b/vp8/common/arm/neon/sixtappredict8x8_neon.asm new file mode 100644 index 0000000..00ed5ae --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict8x8_neon.asm @@ -0,0 +1,524 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict8x8_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +filter8_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +|vp8_sixtap_predict8x8_neon| PROC + push {r4-r5, lr} + + adr r12, filter8_coeff + + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter8x8_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter8x8_only + + sub sp, sp, #64 ;reserve space on stack for temporary storage + mov lr, sp + + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #2 ;loop counter + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + sub r0, r0, r1, lsl #1 + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + +;First pass: output_height lines x output_width columns (13x8) + vld1.u8 {q3}, [r0], r1 ;load src data + vdup.8 d3, d25[4] + vld1.u8 {q4}, [r0], r1 + vdup.8 d4, d26[0] + vld1.u8 {q5}, [r0], r1 + vdup.8 d5, d26[4] + vld1.u8 {q6}, [r0], r1 + +filt_blk2d_fp8x8_loop_neon + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + + subs r2, r2, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vld1.u8 {q3}, [r0], r1 ;load src data + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vst1.u8 {d22}, [lr]! ;store result + vld1.u8 {q4}, [r0], r1 + vst1.u8 {d23}, [lr]! + vld1.u8 {q5}, [r0], r1 + vst1.u8 {d24}, [lr]! + vld1.u8 {q6}, [r0], r1 + vst1.u8 {d25}, [lr]! + + bne filt_blk2d_fp8x8_loop_neon + + ;first_pass filtering on the rest 5-line data + ;vld1.u8 {q3}, [r0], r1 ;load src data + ;vld1.u8 {q4}, [r0], r1 + ;vld1.u8 {q5}, [r0], r1 + ;vld1.u8 {q6}, [r0], r1 + vld1.u8 {q7}, [r0], r1 + + vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + vmull.u8 q11, d12, d0 + vmull.u8 q12, d14, d0 + + vext.8 d27, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d28, d8, d9, #1 + vext.8 d29, d10, d11, #1 + vext.8 d30, d12, d13, #1 + vext.8 d31, d14, d15, #1 + + vmlsl.u8 q8, d27, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q9, d28, d1 + vmlsl.u8 q10, d29, d1 + vmlsl.u8 q11, d30, d1 + vmlsl.u8 q12, d31, d1 + + vext.8 d27, d6, d7, #4 ;construct src_ptr[2] + vext.8 d28, d8, d9, #4 + vext.8 d29, d10, d11, #4 + vext.8 d30, d12, d13, #4 + vext.8 d31, d14, d15, #4 + + vmlsl.u8 q8, d27, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q9, d28, d4 + vmlsl.u8 q10, d29, d4 + vmlsl.u8 q11, d30, d4 + vmlsl.u8 q12, d31, d4 + + vext.8 d27, d6, d7, #2 ;construct src_ptr[0] + vext.8 d28, d8, d9, #2 + vext.8 d29, d10, d11, #2 + vext.8 d30, d12, d13, #2 + vext.8 d31, d14, d15, #2 + + vmlal.u8 q8, d27, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q9, d28, d2 + vmlal.u8 q10, d29, d2 + vmlal.u8 q11, d30, d2 + vmlal.u8 q12, d31, d2 + + vext.8 d27, d6, d7, #5 ;construct src_ptr[3] + vext.8 d28, d8, d9, #5 + vext.8 d29, d10, d11, #5 + vext.8 d30, d12, d13, #5 + vext.8 d31, d14, d15, #5 + + vmlal.u8 q8, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q9, d28, d5 + vmlal.u8 q10, d29, d5 + vmlal.u8 q11, d30, d5 + vmlal.u8 q12, d31, d5 + + vext.8 d27, d6, d7, #3 ;construct src_ptr[1] + vext.8 d28, d8, d9, #3 + vext.8 d29, d10, d11, #3 + vext.8 d30, d12, d13, #3 + vext.8 d31, d14, d15, #3 + + vmull.u8 q3, d27, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d28, d3 + vmull.u8 q5, d29, d3 + vmull.u8 q6, d30, d3 + vmull.u8 q7, d31, d3 + + vqadd.s16 q8, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q9, q4 + vqadd.s16 q10, q5 + vqadd.s16 q11, q6 + vqadd.s16 q12, q7 + + add r3, r12, r3, lsl #5 + + vqrshrun.s16 d26, q8, #7 ;shift/round/saturate to u8 + sub lr, lr, #64 + vqrshrun.s16 d27, q9, #7 + vld1.u8 {q9}, [lr]! ;load intermediate data from stack + vqrshrun.s16 d28, q10, #7 + vld1.u8 {q10}, [lr]! + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + + vqrshrun.s16 d29, q11, #7 + vld1.u8 {q11}, [lr]! + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vqrshrun.s16 d30, q12, #7 + vld1.u8 {q12}, [lr]! + +;Second pass: 8x8 + mov r3, #2 ;loop counter + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + +filt_blk2d_sp8x8_loop_neon + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r3, r3, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vmov q9, q11 + vst1.u8 {d6}, [r4], r5 ;store result + vmov q10, q12 + vst1.u8 {d7}, [r4], r5 + vmov q11, q13 + vst1.u8 {d8}, [r4], r5 + vmov q12, q14 + vst1.u8 {d9}, [r4], r5 + vmov d26, d30 + + bne filt_blk2d_sp8x8_loop_neon + + add sp, sp, #64 + pop {r4-r5,pc} + +;--------------------- +firstpass_filter8x8_only + ;add r2, r12, r2, lsl #5 ;calculate filter location + ;vld1.s32 {q14, q15}, [r2] ;load first_pass filter + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #2 ;loop counter + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First pass: output_height lines x output_width columns (8x8) +filt_blk2d_fpo8x8_loop_neon + vld1.u8 {q3}, [r0], r1 ;load src data + vld1.u8 {q4}, [r0], r1 + vld1.u8 {q5}, [r0], r1 + vld1.u8 {q6}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + ; + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + subs r2, r2, #1 + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vst1.u8 {d22}, [r4], r5 ;store result + vst1.u8 {d23}, [r4], r5 + vst1.u8 {d24}, [r4], r5 + vst1.u8 {d25}, [r4], r5 + + bne filt_blk2d_fpo8x8_loop_neon + + pop {r4-r5,pc} + +;--------------------- +secondpass_filter8x8_only + sub r0, r0, r1, lsl #1 + add r3, r12, r3, lsl #5 + + vld1.u8 {d18}, [r0], r1 ;load src data + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vld1.u8 {d19}, [r0], r1 + vabs.s32 q7, q5 + vld1.u8 {d20}, [r0], r1 + vabs.s32 q8, q6 + vld1.u8 {d21}, [r0], r1 + mov r3, #2 ;loop counter + vld1.u8 {d22}, [r0], r1 + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vld1.u8 {d23}, [r0], r1 + vdup.8 d1, d14[4] + vld1.u8 {d24}, [r0], r1 + vdup.8 d2, d15[0] + vld1.u8 {d25}, [r0], r1 + vdup.8 d3, d15[4] + vld1.u8 {d26}, [r0], r1 + vdup.8 d4, d16[0] + vld1.u8 {d27}, [r0], r1 + vdup.8 d5, d16[4] + vld1.u8 {d28}, [r0], r1 + vld1.u8 {d29}, [r0], r1 + vld1.u8 {d30}, [r0], r1 + +;Second pass: 8x8 +filt_blk2d_spo8x8_loop_neon + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r3, r3, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vmov q9, q11 + vst1.u8 {d6}, [r4], r5 ;store result + vmov q10, q12 + vst1.u8 {d7}, [r4], r5 + vmov q11, q13 + vst1.u8 {d8}, [r4], r5 + vmov q12, q14 + vst1.u8 {d9}, [r4], r5 + vmov d26, d30 + + bne filt_blk2d_spo8x8_loop_neon + + pop {r4-r5,pc} + + ENDP + +;----------------- + + END diff --git a/vp8/common/arm/neon/variance_neon.asm b/vp8/common/arm/neon/variance_neon.asm new file mode 100644 index 0000000..e3b4832 --- /dev/null +++ b/vp8/common/arm/neon/variance_neon.asm @@ -0,0 +1,276 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance16x16_neon| + EXPORT |vp8_variance16x8_neon| + EXPORT |vp8_variance8x16_neon| + EXPORT |vp8_variance8x8_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance16x16_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #8 + +variance16x16_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + ;VPADAL adds adjacent pairs of elements of a vector, and accumulates + ;the results into the elements of the destination vector. The explanation + ;in ARM guide is wrong. + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne variance16x16_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + ;vmov.32 r0, d0[0] ;this instruction costs a lot + ;vmov.32 r1, d1[0] + ;mul r0, r0, r0 + ;str r1, [r12] + ;sub r0, r1, r0, lsr #8 + + ; while sum is signed, sum * sum is always positive and must be treated as + ; unsigned to avoid propagating the sign bit. + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.u32 d10, d10, #8 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + +;================================ +;unsigned int vp8_variance16x8_c( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *sse) +|vp8_variance16x8_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #4 + +variance16x8_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne variance16x8_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.u32 d10, d10, #7 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + +;================================= +;unsigned int vp8_variance8x16_c( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *sse) + +|vp8_variance8x16_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #8 + +variance8x16_neon_loop + vld1.8 {d0}, [r0], r1 ;Load up source and reference + vld1.8 {d4}, [r2], r3 + vld1.8 {d2}, [r0], r1 + vld1.8 {d6}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d2, d6 + + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + + bne variance8x16_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.u32 d10, d10, #7 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + +;================================== +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance8x8_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #2 + +variance8x8_neon_loop + vld1.8 {d0}, [r0], r1 ;Load up source and reference + vld1.8 {d4}, [r2], r3 + vld1.8 {d1}, [r0], r1 + vld1.8 {d5}, [r2], r3 + vld1.8 {d2}, [r0], r1 + vld1.8 {d6}, [r2], r3 + vld1.8 {d3}, [r0], r1 + vld1.8 {d7}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne variance8x8_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.u32 d10, d10, #6 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + + END diff --git a/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm b/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm new file mode 100644 index 0000000..e7a3ed1 --- /dev/null +++ b/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm @@ -0,0 +1,423 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +bilinear_taps_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + +;----------------- + + EXPORT |vp8_sub_pixel_variance16x16_neon_func| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(r5) int dst_pixels_per_line, +; stack(r6) unsigned int *sse +;note: most of the code is copied from bilinear_predict16x16_neon and vp8_variance16x16_neon. + +|vp8_sub_pixel_variance16x16_neon_func| PROC + push {r4-r6, lr} + + adr r12, bilinear_taps_coeff + ldr r4, [sp, #16] ;load *dst_ptr from stack + ldr r5, [sp, #20] ;load dst_pixels_per_line from stack + ldr r6, [sp, #24] ;load *sse from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_bfilter16x16_only + + add r2, r12, r2, lsl #3 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {d31}, [r2] ;load first_pass filter + + beq firstpass_bfilter16x16_only + + sub sp, sp, #272 ;reserve space on stack for temporary storage + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + mov lr, sp + vld1.u8 {d5, d6, d7}, [r0], r1 + + mov r2, #3 ;loop counter + vld1.u8 {d8, d9, d10}, [r0], r1 + + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {d11, d12, d13}, [r0], r1 + + vdup.8 d1, d31[4] + +;First Pass: output_height lines x output_width columns (17x16) +vp8e_filt_blk2d_fp16x16_loop_neon + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vqrshrn.u16 d21, q14, #7 + vld1.u8 {d5, d6, d7}, [r0], r1 + + vst1.u8 {d14, d15, d16, d17}, [lr]! ;store result + vld1.u8 {d8, d9, d10}, [r0], r1 + vst1.u8 {d18, d19, d20, d21}, [lr]! + vld1.u8 {d11, d12, d13}, [r0], r1 + + bne vp8e_filt_blk2d_fp16x16_loop_neon + +;First-pass filtering for rest 5 lines + vld1.u8 {d14, d15, d16}, [r0], r1 + + vmull.u8 q9, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q10, d3, d0 + vmull.u8 q11, d5, d0 + vmull.u8 q12, d6, d0 + vmull.u8 q13, d8, d0 + vmull.u8 q14, d9, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + + vmlal.u8 q9, d2, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q11, d5, d1 + vmlal.u8 q13, d8, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + + vmlal.u8 q10, d3, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q12, d6, d1 + vmlal.u8 q14, d9, d1 + + vmull.u8 q1, d11, d0 + vmull.u8 q2, d12, d0 + vmull.u8 q3, d14, d0 + vmull.u8 q4, d15, d0 + + vext.8 d11, d11, d12, #1 ;construct src_ptr[1] + vext.8 d14, d14, d15, #1 + + vmlal.u8 q1, d11, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q3, d14, d1 + + vext.8 d12, d12, d13, #1 + vext.8 d15, d15, d16, #1 + + vmlal.u8 q2, d12, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q4, d15, d1 + + vqrshrn.u16 d10, q9, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d11, q10, #7 + vqrshrn.u16 d12, q11, #7 + vqrshrn.u16 d13, q12, #7 + vqrshrn.u16 d14, q13, #7 + vqrshrn.u16 d15, q14, #7 + vqrshrn.u16 d16, q1, #7 + vqrshrn.u16 d17, q2, #7 + vqrshrn.u16 d18, q3, #7 + vqrshrn.u16 d19, q4, #7 + + vst1.u8 {d10, d11, d12, d13}, [lr]! ;store result + vst1.u8 {d14, d15, d16, d17}, [lr]! + vst1.u8 {d18, d19}, [lr]! + +;Second pass: 16x16 +;secondpass_filter + add r3, r12, r3, lsl #3 + sub lr, lr, #272 + + vld1.u32 {d31}, [r3] ;load second_pass filter + + sub sp, sp, #256 + mov r3, sp + + vld1.u8 {d22, d23}, [lr]! ;load src data + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + mov r12, #4 ;loop counter + +vp8e_filt_blk2d_sp16x16_loop_neon + vld1.u8 {d24, d25}, [lr]! + vmull.u8 q1, d22, d0 ;(src_ptr[0] * Filter[0]) + vld1.u8 {d26, d27}, [lr]! + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [lr]! + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [lr]! + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * Filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + subs r12, r12, #1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r3]! ;store result + vst1.u8 {d4, d5}, [r3]! + vst1.u8 {d6, d7}, [r3]! + vmov q11, q15 + vst1.u8 {d8, d9}, [r3]! + + bne vp8e_filt_blk2d_sp16x16_loop_neon + + b sub_pixel_variance16x16_neon + +;-------------------- +firstpass_bfilter16x16_only + mov r2, #4 ;loop counter + sub sp, sp, #528 ;reserve space on stack for temporary storage + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vdup.8 d1, d31[4] + mov r3, sp + +;First Pass: output_height lines x output_width columns (16x16) +vp8e_filt_blk2d_fpo16x16_loop_neon + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vld1.u8 {d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10}, [r0], r1 + vld1.u8 {d11, d12, d13}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + vst1.u8 {d14, d15}, [r3]! ;store result + vqrshrn.u16 d21, q14, #7 + + vst1.u8 {d16, d17}, [r3]! + vst1.u8 {d18, d19}, [r3]! + vst1.u8 {d20, d21}, [r3]! + + bne vp8e_filt_blk2d_fpo16x16_loop_neon + + b sub_pixel_variance16x16_neon + +;--------------------- +secondpass_bfilter16x16_only +;Second pass: 16x16 +;secondpass_filter + sub sp, sp, #528 ;reserve space on stack for temporary storage + add r3, r12, r3, lsl #3 + mov r12, #4 ;loop counter + vld1.u32 {d31}, [r3] ;load second_pass filter + vld1.u8 {d22, d23}, [r0], r1 ;load src data + mov r3, sp + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + +vp8e_filt_blk2d_spo16x16_loop_neon + vld1.u8 {d24, d25}, [r0], r1 + vmull.u8 q1, d22, d0 ;(src_ptr[0] * Filter[0]) + vld1.u8 {d26, d27}, [r0], r1 + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [r0], r1 + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [r0], r1 + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * Filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r3]! ;store result + subs r12, r12, #1 + vst1.u8 {d4, d5}, [r3]! + vmov q11, q15 + vst1.u8 {d6, d7}, [r3]! + vst1.u8 {d8, d9}, [r3]! + + bne vp8e_filt_blk2d_spo16x16_loop_neon + + b sub_pixel_variance16x16_neon + +;---------------------------- +;variance16x16 +sub_pixel_variance16x16_neon + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + sub r3, r3, #256 + mov r12, #8 + +sub_pixel_variance16x16_neon_loop + vld1.8 {q0}, [r3]! ;Load up source and reference + vld1.8 {q2}, [r4], r5 + vld1.8 {q1}, [r3]! + vld1.8 {q3}, [r4], r5 + + vsubl.u8 q11, d0, d4 ;diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 ;sum + vmlal.s16 q9, d22, d22 ;sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne sub_pixel_variance16x16_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r6] ;store sse + vshr.u32 d10, d10, #8 + vsub.u32 d0, d1, d10 + + add sp, sp, #528 + vmov.32 r0, d0[0] ;return + + pop {r4-r6,pc} + + ENDP + + END diff --git a/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm b/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm new file mode 100644 index 0000000..155be4f --- /dev/null +++ b/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm @@ -0,0 +1,572 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_variance_halfpixvar16x16_h_neon| + EXPORT |vp8_variance_halfpixvar16x16_v_neon| + EXPORT |vp8_variance_halfpixvar16x16_hv_neon| + EXPORT |vp8_sub_pixel_variance16x16s_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;================================================ +;unsigned int vp8_variance_halfpixvar16x16_h_neon +;( +; unsigned char *src_ptr, r0 +; int src_pixels_per_line, r1 +; unsigned char *dst_ptr, r2 +; int dst_pixels_per_line, r3 +; unsigned int *sse +;); +;================================================ +|vp8_variance_halfpixvar16x16_h_neon| PROC + push {lr} + + mov r12, #4 ;loop counter + ldr lr, [sp, #4] ;load *sse from stack + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + +;First Pass: output_height lines x output_width columns (16x16) +vp8_filt_fpo16x16s_4_0_loop_neon + vld1.u8 {d0, d1, d2, d3}, [r0], r1 ;load src data + vld1.8 {q11}, [r2], r3 + vld1.u8 {d4, d5, d6, d7}, [r0], r1 + vld1.8 {q12}, [r2], r3 + vld1.u8 {d8, d9, d10, d11}, [r0], r1 + vld1.8 {q13}, [r2], r3 + vld1.u8 {d12, d13, d14, d15}, [r0], r1 + + ;pld [r0] + ;pld [r0, r1] + ;pld [r0, r1, lsl #1] + + vext.8 q1, q0, q1, #1 ;construct src_ptr[1] + vext.8 q3, q2, q3, #1 + vext.8 q5, q4, q5, #1 + vext.8 q7, q6, q7, #1 + + vrhadd.u8 q0, q0, q1 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + vld1.8 {q14}, [r2], r3 + vrhadd.u8 q1, q2, q3 + vrhadd.u8 q2, q4, q5 + vrhadd.u8 q3, q6, q7 + + vsubl.u8 q4, d0, d22 ;diff + vsubl.u8 q5, d1, d23 + vsubl.u8 q6, d2, d24 + vsubl.u8 q7, d3, d25 + vsubl.u8 q0, d4, d26 + vsubl.u8 q1, d5, d27 + vsubl.u8 q2, d6, d28 + vsubl.u8 q3, d7, d29 + + vpadal.s16 q8, q4 ;sum + vmlal.s16 q9, d8, d8 ;sse + vmlal.s16 q10, d9, d9 + + subs r12, r12, #1 + + vpadal.s16 q8, q5 + vmlal.s16 q9, d10, d10 + vmlal.s16 q10, d11, d11 + vpadal.s16 q8, q6 + vmlal.s16 q9, d12, d12 + vmlal.s16 q10, d13, d13 + vpadal.s16 q8, q7 + vmlal.s16 q9, d14, d14 + vmlal.s16 q10, d15, d15 + + vpadal.s16 q8, q0 ;sum + vmlal.s16 q9, d0, d0 ;sse + vmlal.s16 q10, d1, d1 + vpadal.s16 q8, q1 + vmlal.s16 q9, d2, d2 + vmlal.s16 q10, d3, d3 + vpadal.s16 q8, q2 + vmlal.s16 q9, d4, d4 + vmlal.s16 q10, d5, d5 + vpadal.s16 q8, q3 + vmlal.s16 q9, d6, d6 + vmlal.s16 q10, d7, d7 + + bne vp8_filt_fpo16x16s_4_0_loop_neon + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.u32 d10, d10, #8 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {pc} + ENDP + +;================================================ +;unsigned int vp8_variance_halfpixvar16x16_v_neon +;( +; unsigned char *src_ptr, r0 +; int src_pixels_per_line, r1 +; unsigned char *dst_ptr, r2 +; int dst_pixels_per_line, r3 +; unsigned int *sse +;); +;================================================ +|vp8_variance_halfpixvar16x16_v_neon| PROC + push {lr} + + mov r12, #4 ;loop counter + + vld1.u8 {q0}, [r0], r1 ;load src data + ldr lr, [sp, #4] ;load *sse from stack + + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + +vp8_filt_spo16x16s_0_4_loop_neon + vld1.u8 {q2}, [r0], r1 + vld1.8 {q1}, [r2], r3 + vld1.u8 {q4}, [r0], r1 + vld1.8 {q3}, [r2], r3 + vld1.u8 {q6}, [r0], r1 + vld1.8 {q5}, [r2], r3 + vld1.u8 {q15}, [r0], r1 + + vrhadd.u8 q0, q0, q2 + vld1.8 {q7}, [r2], r3 + vrhadd.u8 q2, q2, q4 + vrhadd.u8 q4, q4, q6 + vrhadd.u8 q6, q6, q15 + + vsubl.u8 q11, d0, d2 ;diff + vsubl.u8 q12, d1, d3 + vsubl.u8 q13, d4, d6 + vsubl.u8 q14, d5, d7 + vsubl.u8 q0, d8, d10 + vsubl.u8 q1, d9, d11 + vsubl.u8 q2, d12, d14 + vsubl.u8 q3, d13, d15 + + vpadal.s16 q8, q11 ;sum + vmlal.s16 q9, d22, d22 ;sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + vpadal.s16 q8, q0 ;sum + vmlal.s16 q9, d0, d0 ;sse + vmlal.s16 q10, d1, d1 + vpadal.s16 q8, q1 + vmlal.s16 q9, d2, d2 + vmlal.s16 q10, d3, d3 + vpadal.s16 q8, q2 + vmlal.s16 q9, d4, d4 + vmlal.s16 q10, d5, d5 + + vmov q0, q15 + + vpadal.s16 q8, q3 + vmlal.s16 q9, d6, d6 + vmlal.s16 q10, d7, d7 + + bne vp8_filt_spo16x16s_0_4_loop_neon + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.u32 d10, d10, #8 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {pc} + ENDP + +;================================================ +;unsigned int vp8_variance_halfpixvar16x16_hv_neon +;( +; unsigned char *src_ptr, r0 +; int src_pixels_per_line, r1 +; unsigned char *dst_ptr, r2 +; int dst_pixels_per_line, r3 +; unsigned int *sse +;); +;================================================ +|vp8_variance_halfpixvar16x16_hv_neon| PROC + push {lr} + + vld1.u8 {d0, d1, d2, d3}, [r0], r1 ;load src data + + ldr lr, [sp, #4] ;load *sse from stack + vmov.i8 q13, #0 ;q8 - sum + vext.8 q1, q0, q1, #1 ;construct src_ptr[1] + + vmov.i8 q14, #0 ;q9, q10 - sse + vmov.i8 q15, #0 + + mov r12, #4 ;loop counter + vrhadd.u8 q0, q0, q1 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + +;First Pass: output_height lines x output_width columns (17x16) +vp8_filt16x16s_4_4_loop_neon + vld1.u8 {d4, d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10, d11}, [r0], r1 + vld1.u8 {d12, d13, d14, d15}, [r0], r1 + vld1.u8 {d16, d17, d18, d19}, [r0], r1 + + ;pld [r0] + ;pld [r0, r1] + ;pld [r0, r1, lsl #1] + + vext.8 q3, q2, q3, #1 ;construct src_ptr[1] + vext.8 q5, q4, q5, #1 + vext.8 q7, q6, q7, #1 + vext.8 q9, q8, q9, #1 + + vrhadd.u8 q1, q2, q3 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + vrhadd.u8 q2, q4, q5 + vrhadd.u8 q3, q6, q7 + vrhadd.u8 q4, q8, q9 + + vld1.8 {q5}, [r2], r3 + vrhadd.u8 q0, q0, q1 + vld1.8 {q6}, [r2], r3 + vrhadd.u8 q1, q1, q2 + vld1.8 {q7}, [r2], r3 + vrhadd.u8 q2, q2, q3 + vld1.8 {q8}, [r2], r3 + vrhadd.u8 q3, q3, q4 + + vsubl.u8 q9, d0, d10 ;diff + vsubl.u8 q10, d1, d11 + vsubl.u8 q11, d2, d12 + vsubl.u8 q12, d3, d13 + + vsubl.u8 q0, d4, d14 ;diff + vsubl.u8 q1, d5, d15 + vsubl.u8 q5, d6, d16 + vsubl.u8 q6, d7, d17 + + vpadal.s16 q13, q9 ;sum + vmlal.s16 q14, d18, d18 ;sse + vmlal.s16 q15, d19, d19 + + vpadal.s16 q13, q10 ;sum + vmlal.s16 q14, d20, d20 ;sse + vmlal.s16 q15, d21, d21 + + vpadal.s16 q13, q11 ;sum + vmlal.s16 q14, d22, d22 ;sse + vmlal.s16 q15, d23, d23 + + vpadal.s16 q13, q12 ;sum + vmlal.s16 q14, d24, d24 ;sse + vmlal.s16 q15, d25, d25 + + subs r12, r12, #1 + + vpadal.s16 q13, q0 ;sum + vmlal.s16 q14, d0, d0 ;sse + vmlal.s16 q15, d1, d1 + + vpadal.s16 q13, q1 ;sum + vmlal.s16 q14, d2, d2 ;sse + vmlal.s16 q15, d3, d3 + + vpadal.s16 q13, q5 ;sum + vmlal.s16 q14, d10, d10 ;sse + vmlal.s16 q15, d11, d11 + + vmov q0, q4 + + vpadal.s16 q13, q6 ;sum + vmlal.s16 q14, d12, d12 ;sse + vmlal.s16 q15, d13, d13 + + bne vp8_filt16x16s_4_4_loop_neon + + vadd.u32 q15, q14, q15 ;accumulate sse + vpaddl.s32 q0, q13 ;accumulate sum + + vpaddl.u32 q1, q15 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.u32 d10, d10, #8 + vsub.u32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {pc} + ENDP + +;============================== +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack unsigned char *dst_ptr, +; stack int dst_pixels_per_line, +; stack unsigned int *sse +;note: in vp8_find_best_half_pixel_step()(called when 8dst.y_buffer; + unsigned char *ypred_ptr = x->predictor; + int y_stride = x->dst.y_stride; + int mode = x->mode_info_context->mbmi.mode; + int Up = x->up_available; + int Left = x->left_available; + + vp8_build_intra_predictors_mby_neon_func(y_buffer, ypred_ptr, y_stride, mode, Up, Left); +} + +extern void vp8_build_intra_predictors_mby_s_neon_func( + unsigned char *y_buffer, + unsigned char *ypred_ptr, + int y_stride, + int mode, + int Up, + int Left); + +void vp8_build_intra_predictors_mby_s_neon(MACROBLOCKD *x) +{ + unsigned char *y_buffer = x->dst.y_buffer; + unsigned char *ypred_ptr = x->predictor; + int y_stride = x->dst.y_stride; + int mode = x->mode_info_context->mbmi.mode; + int Up = x->up_available; + int Left = x->left_available; + + vp8_build_intra_predictors_mby_s_neon_func(y_buffer, ypred_ptr, y_stride, mode, Up, Left); +} + +#endif diff --git a/vp8/common/arm/variance_arm.c b/vp8/common/arm/variance_arm.c new file mode 100644 index 0000000..891d767 --- /dev/null +++ b/vp8/common/arm/variance_arm.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vp8/common/variance.h" +#include "vp8/common/filter.h" + +#if HAVE_MEDIA +#include "vp8/common/arm/bilinearfilter_arm.h" + +unsigned int vp8_sub_pixel_variance8x8_armv6 +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short first_pass[10*8]; + unsigned char second_pass[8*8]; + const short *HFilter, *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_first_pass_armv6(src_ptr, first_pass, + src_pixels_per_line, + 9, 8, HFilter); + vp8_filter_block2d_bil_second_pass_armv6(first_pass, second_pass, + 8, 8, 8, VFilter); + + return vp8_variance8x8_armv6(second_pass, 8, dst_ptr, + dst_pixels_per_line, sse); +} + +unsigned int vp8_sub_pixel_variance16x16_armv6 +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short first_pass[36*16]; + unsigned char second_pass[20*16]; + const short *HFilter, *VFilter; + unsigned int var; + + if (xoffset == 4 && yoffset == 0) + { + var = vp8_variance_halfpixvar16x16_h_armv6(src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, sse); + } + else if (xoffset == 0 && yoffset == 4) + { + var = vp8_variance_halfpixvar16x16_v_armv6(src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, sse); + } + else if (xoffset == 4 && yoffset == 4) + { + var = vp8_variance_halfpixvar16x16_hv_armv6(src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, sse); + } + else + { + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_first_pass_armv6(src_ptr, first_pass, + src_pixels_per_line, + 17, 16, HFilter); + vp8_filter_block2d_bil_second_pass_armv6(first_pass, second_pass, + 16, 16, 16, VFilter); + + var = vp8_variance16x16_armv6(second_pass, 16, dst_ptr, + dst_pixels_per_line, sse); + } + return var; +} + +#endif /* HAVE_MEDIA */ + + +#if HAVE_NEON + +extern unsigned int vp8_sub_pixel_variance16x16_neon_func +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +); + +unsigned int vp8_sub_pixel_variance16x16_neon +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + if (xoffset == 4 && yoffset == 0) + return vp8_variance_halfpixvar16x16_h_neon(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); + else if (xoffset == 0 && yoffset == 4) + return vp8_variance_halfpixvar16x16_v_neon(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); + else if (xoffset == 4 && yoffset == 4) + return vp8_variance_halfpixvar16x16_hv_neon(src_ptr, src_pixels_per_line, dst_ptr, dst_pixels_per_line, sse); + else + return vp8_sub_pixel_variance16x16_neon_func(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); +} + +#endif diff --git a/vp8/common/asm_com_offsets.c b/vp8/common/asm_com_offsets.c new file mode 100644 index 0000000..ae22b5f --- /dev/null +++ b/vp8/common/asm_com_offsets.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx/vpx_codec.h" +#include "vpx_ports/asm_offsets.h" +#include "vpx_scale/yv12config.h" +#include "vp8/common/blockd.h" + +#if CONFIG_POSTPROC +#include "postproc.h" +#endif /* CONFIG_POSTPROC */ + +BEGIN + +/* vpx_scale */ +DEFINE(yv12_buffer_config_y_width, offsetof(YV12_BUFFER_CONFIG, y_width)); +DEFINE(yv12_buffer_config_y_height, offsetof(YV12_BUFFER_CONFIG, y_height)); +DEFINE(yv12_buffer_config_y_stride, offsetof(YV12_BUFFER_CONFIG, y_stride)); +DEFINE(yv12_buffer_config_uv_width, offsetof(YV12_BUFFER_CONFIG, uv_width)); +DEFINE(yv12_buffer_config_uv_height, offsetof(YV12_BUFFER_CONFIG, uv_height)); +DEFINE(yv12_buffer_config_uv_stride, offsetof(YV12_BUFFER_CONFIG, uv_stride)); +DEFINE(yv12_buffer_config_y_buffer, offsetof(YV12_BUFFER_CONFIG, y_buffer)); +DEFINE(yv12_buffer_config_u_buffer, offsetof(YV12_BUFFER_CONFIG, u_buffer)); +DEFINE(yv12_buffer_config_v_buffer, offsetof(YV12_BUFFER_CONFIG, v_buffer)); +DEFINE(yv12_buffer_config_border, offsetof(YV12_BUFFER_CONFIG, border)); +DEFINE(VP8BORDERINPIXELS_VAL, VP8BORDERINPIXELS); + +#if CONFIG_POSTPROC +/* mfqe.c / filter_by_weight */ +DEFINE(MFQE_PRECISION_VAL, MFQE_PRECISION); +#endif /* CONFIG_POSTPROC */ + +END + +/* add asserts for any offset that is not supported by assembly code */ +/* add asserts for any size that is not supported by assembly code */ + +#if HAVE_MEDIA +/* switch case in vp8_intra4x4_predict_armv6 is based on these enumerated values */ +ct_assert(B_DC_PRED, B_DC_PRED == 0); +ct_assert(B_TM_PRED, B_TM_PRED == 1); +ct_assert(B_VE_PRED, B_VE_PRED == 2); +ct_assert(B_HE_PRED, B_HE_PRED == 3); +ct_assert(B_LD_PRED, B_LD_PRED == 4); +ct_assert(B_RD_PRED, B_RD_PRED == 5); +ct_assert(B_VR_PRED, B_VR_PRED == 6); +ct_assert(B_VL_PRED, B_VL_PRED == 7); +ct_assert(B_HD_PRED, B_HD_PRED == 8); +ct_assert(B_HU_PRED, B_HU_PRED == 9); +#endif + +#if HAVE_NEON +/* vp8_yv12_extend_frame_borders_neon makes several assumptions based on this */ +ct_assert(VP8BORDERINPIXELS_VAL, VP8BORDERINPIXELS == 32) +#endif + +#if HAVE_SSE2 +#if CONFIG_POSTPROC +/* vp8_filter_by_weight16x16 and 8x8 */ +ct_assert(MFQE_PRECISION_VAL, MFQE_PRECISION == 4) +#endif /* CONFIG_POSTPROC */ +#endif /* HAVE_SSE2 */ diff --git a/vp8/common/blockd.c b/vp8/common/blockd.c new file mode 100644 index 0000000..1fc3cd0 --- /dev/null +++ b/vp8/common/blockd.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "blockd.h" +#include "vpx_mem/vpx_mem.h" + +const unsigned char vp8_block2left[25] = +{ + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 +}; +const unsigned char vp8_block2above[25] = +{ + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8 +}; diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h new file mode 100644 index 0000000..a4c1d92 --- /dev/null +++ b/vp8/common/blockd.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_BLOCKD_H +#define __INC_BLOCKD_H + +void vpx_log(const char *format, ...); + +#include "vpx_config.h" +#include "vpx_scale/yv12config.h" +#include "mv.h" +#include "treecoder.h" +#include "vpx_ports/mem.h" + +/*#define DCPRED 1*/ +#define DCPREDSIMTHRESH 0 +#define DCPREDCNTTHRESH 3 + +#define MB_FEATURE_TREE_PROBS 3 +#define MAX_MB_SEGMENTS 4 + +#define MAX_REF_LF_DELTAS 4 +#define MAX_MODE_LF_DELTAS 4 + +/* Segment Feature Masks */ +#define SEGMENT_DELTADATA 0 +#define SEGMENT_ABSDATA 1 + +typedef struct +{ + int r, c; +} POS; + +#define PLANE_TYPE_Y_NO_DC 0 +#define PLANE_TYPE_Y2 1 +#define PLANE_TYPE_UV 2 +#define PLANE_TYPE_Y_WITH_DC 3 + + +typedef char ENTROPY_CONTEXT; +typedef struct +{ + ENTROPY_CONTEXT y1[4]; + ENTROPY_CONTEXT u[2]; + ENTROPY_CONTEXT v[2]; + ENTROPY_CONTEXT y2; +} ENTROPY_CONTEXT_PLANES; + +extern const unsigned char vp8_block2left[25]; +extern const unsigned char vp8_block2above[25]; + +#define VP8_COMBINEENTROPYCONTEXTS( Dest, A, B) \ + Dest = (A)+(B); + + +typedef enum +{ + KEY_FRAME = 0, + INTER_FRAME = 1 +} FRAME_TYPE; + +typedef enum +{ + DC_PRED, /* average of above and left pixels */ + V_PRED, /* vertical prediction */ + H_PRED, /* horizontal prediction */ + TM_PRED, /* Truemotion prediction */ + B_PRED, /* block based prediction, each block has its own prediction mode */ + + NEARESTMV, + NEARMV, + ZEROMV, + NEWMV, + SPLITMV, + + MB_MODE_COUNT +} MB_PREDICTION_MODE; + +/* Macroblock level features */ +typedef enum +{ + MB_LVL_ALT_Q = 0, /* Use alternate Quantizer .... */ + MB_LVL_ALT_LF = 1, /* Use alternate loop filter value... */ + MB_LVL_MAX = 2 /* Number of MB level features supported */ + +} MB_LVL_FEATURES; + +/* Segment Feature Masks */ +#define SEGMENT_ALTQ 0x01 +#define SEGMENT_ALT_LF 0x02 + +#define VP8_YMODES (B_PRED + 1) +#define VP8_UV_MODES (TM_PRED + 1) + +#define VP8_MVREFS (1 + SPLITMV - NEARESTMV) + +typedef enum +{ + B_DC_PRED, /* average of above and left pixels */ + B_TM_PRED, + + B_VE_PRED, /* vertical prediction */ + B_HE_PRED, /* horizontal prediction */ + + B_LD_PRED, + B_RD_PRED, + + B_VR_PRED, + B_VL_PRED, + B_HD_PRED, + B_HU_PRED, + + LEFT4X4, + ABOVE4X4, + ZERO4X4, + NEW4X4, + + B_MODE_COUNT +} B_PREDICTION_MODE; + +#define VP8_BINTRAMODES (B_HU_PRED + 1) /* 10 */ +#define VP8_SUBMVREFS (1 + NEW4X4 - LEFT4X4) + +/* For keyframes, intra block modes are predicted by the (already decoded) + modes for the Y blocks to the left and above us; for interframes, there + is a single probability table. */ + +union b_mode_info +{ + B_PREDICTION_MODE as_mode; + int_mv mv; +}; + +typedef enum +{ + INTRA_FRAME = 0, + LAST_FRAME = 1, + GOLDEN_FRAME = 2, + ALTREF_FRAME = 3, + MAX_REF_FRAMES = 4 +} MV_REFERENCE_FRAME; + +typedef struct +{ + uint8_t mode, uv_mode; + uint8_t ref_frame; + uint8_t is_4x4; + int_mv mv; + + uint8_t partitioning; + uint8_t mb_skip_coeff; /* does this mb has coefficients at all, 1=no coefficients, 0=need decode tokens */ + uint8_t need_to_clamp_mvs; + uint8_t segment_id; /* Which set of segmentation parameters should be used for this MB */ +} MB_MODE_INFO; + +typedef struct +{ + MB_MODE_INFO mbmi; + union b_mode_info bmi[16]; +} MODE_INFO; + +#if CONFIG_MULTI_RES_ENCODING +/* The information needed to be stored for higher-resolution encoder */ +typedef struct +{ + MB_PREDICTION_MODE mode; + MV_REFERENCE_FRAME ref_frame; + int_mv mv; + //union b_mode_info bmi[16]; + int dissim; // dissimilarity level of the macroblock +} LOWER_RES_INFO; +#endif + +typedef struct blockd +{ + short *qcoeff; + short *dqcoeff; + unsigned char *predictor; + short *dequant; + + int offset; + char *eob; + + union b_mode_info bmi; +} BLOCKD; + +typedef void (*vp8_subpix_fn_t)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); + +typedef struct macroblockd +{ + DECLARE_ALIGNED(16, unsigned char, predictor[384]); + DECLARE_ALIGNED(16, short, qcoeff[400]); + DECLARE_ALIGNED(16, short, dqcoeff[400]); + DECLARE_ALIGNED(16, char, eobs[25]); + + DECLARE_ALIGNED(16, short, dequant_y1[16]); + DECLARE_ALIGNED(16, short, dequant_y1_dc[16]); + DECLARE_ALIGNED(16, short, dequant_y2[16]); + DECLARE_ALIGNED(16, short, dequant_uv[16]); + + /* 16 Y blocks, 4 U, 4 V, 1 DC 2nd order block, each with 16 entries. */ + BLOCKD block[25]; + int fullpixel_mask; + + YV12_BUFFER_CONFIG pre; /* Filtered copy of previous frame reconstruction */ + YV12_BUFFER_CONFIG dst; + + MODE_INFO *mode_info_context; + int mode_info_stride; + +#if CONFIG_TEMPORAL_DENOISING + MB_PREDICTION_MODE best_sse_inter_mode; + int_mv best_sse_mv; + unsigned char need_to_clamp_best_mvs; +#endif + + FRAME_TYPE frame_type; + + int up_available; + int left_available; + + unsigned char *recon_above[3]; + unsigned char *recon_left[3]; + int recon_left_stride[2]; + + /* Y,U,V,Y2 */ + ENTROPY_CONTEXT_PLANES *above_context; + ENTROPY_CONTEXT_PLANES *left_context; + + /* 0 indicates segmentation at MB level is not enabled. Otherwise the individual bits indicate which features are active. */ + unsigned char segmentation_enabled; + + /* 0 (do not update) 1 (update) the macroblock segmentation map. */ + unsigned char update_mb_segmentation_map; + + /* 0 (do not update) 1 (update) the macroblock segmentation feature data. */ + unsigned char update_mb_segmentation_data; + + /* 0 (do not update) 1 (update) the macroblock segmentation feature data. */ + unsigned char mb_segement_abs_delta; + + /* Per frame flags that define which MB level features (such as quantizer or loop filter level) */ + /* are enabled and when enabled the proabilities used to decode the per MB flags in MB_MODE_INFO */ + vp8_prob mb_segment_tree_probs[MB_FEATURE_TREE_PROBS]; /* Probability Tree used to code Segment number */ + + signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; /* Segment parameters */ + + /* mode_based Loop filter adjustment */ + unsigned char mode_ref_lf_delta_enabled; + unsigned char mode_ref_lf_delta_update; + + /* Delta values have the range +/- MAX_LOOP_FILTER */ + signed char last_ref_lf_deltas[MAX_REF_LF_DELTAS]; /* 0 = Intra, Last, GF, ARF */ + signed char ref_lf_deltas[MAX_REF_LF_DELTAS]; /* 0 = Intra, Last, GF, ARF */ + signed char last_mode_lf_deltas[MAX_MODE_LF_DELTAS]; /* 0 = BPRED, ZERO_MV, MV, SPLIT */ + signed char mode_lf_deltas[MAX_MODE_LF_DELTAS]; /* 0 = BPRED, ZERO_MV, MV, SPLIT */ + + /* Distance of MB away from frame edges */ + int mb_to_left_edge; + int mb_to_right_edge; + int mb_to_top_edge; + int mb_to_bottom_edge; + + + + vp8_subpix_fn_t subpixel_predict; + vp8_subpix_fn_t subpixel_predict8x4; + vp8_subpix_fn_t subpixel_predict8x8; + vp8_subpix_fn_t subpixel_predict16x16; + + void *current_bc; + + int corrupted; + +#if ARCH_X86 || ARCH_X86_64 + /* This is an intermediate buffer currently used in sub-pixel motion search + * to keep a copy of the reference area. This buffer can be used for other + * purpose. + */ + DECLARE_ALIGNED(32, unsigned char, y_buf[22*32]); +#endif +} MACROBLOCKD; + + +extern void vp8_build_block_doffsets(MACROBLOCKD *x); +extern void vp8_setup_block_dptrs(MACROBLOCKD *x); + +#endif /* __INC_BLOCKD_H */ diff --git a/vp8/common/coefupdateprobs.h b/vp8/common/coefupdateprobs.h new file mode 100644 index 0000000..9e194dc --- /dev/null +++ b/vp8/common/coefupdateprobs.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* Update probabilities for the nodes in the token entropy tree. + Generated file included by entropy.c */ + +const vp8_prob vp8_coef_update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] = +{ + { + { + {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, }, + }, + { + {176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255, }, + {250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255, }, + {254, 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, }, + }, + }, + { + { + {217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255, }, + {234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 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, }, + }, + }, + { + { + {186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255, }, + {251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 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, }, + }, + }, + { + { + {248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 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, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, +}; diff --git a/vp8/common/common.h b/vp8/common/common.h new file mode 100644 index 0000000..2cc1c54 --- /dev/null +++ b/vp8/common/common.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef common_h +#define common_h 1 + +#include + +/* Interface header for common constant data structures and lookup tables */ + +#include "vpx_mem/vpx_mem.h" + +/* Only need this for fixed-size arrays, for structs just assign. */ + +#define vp8_copy( Dest, Src) { \ + assert( sizeof( Dest) == sizeof( Src)); \ + vpx_memcpy( Dest, Src, sizeof( Src)); \ + } + +/* Use this for variably-sized arrays. */ + +#define vp8_copy_array( Dest, Src, N) { \ + assert( sizeof( *Dest) == sizeof( *Src)); \ + vpx_memcpy( Dest, Src, N * sizeof( *Src)); \ + } + +#define vp8_zero( Dest) vpx_memset( &Dest, 0, sizeof( Dest)); + +#define vp8_zero_array( Dest, N) vpx_memset( Dest, 0, N * sizeof( *Dest)); + + +#endif /* common_h */ diff --git a/vp8/common/context.c b/vp8/common/context.c new file mode 100644 index 0000000..99e95d3 --- /dev/null +++ b/vp8/common/context.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "entropy.h" + +/* *** GENERATED FILE: DO NOT EDIT *** */ + +#if 0 +int Contexts[vp8_coef_counter_dimen]; + +const int default_contexts[vp8_coef_counter_dimen] = +{ + { + // Block Type ( 0 ) + { + // Coeff Band ( 0 ) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + { + // Coeff Band ( 1 ) + {30190, 26544, 225, 24, 4, 0, 0, 0, 0, 0, 0, 4171593,}, + {26846, 25157, 1241, 130, 26, 6, 1, 0, 0, 0, 0, 149987,}, + {10484, 9538, 1006, 160, 36, 18, 0, 0, 0, 0, 0, 15104,}, + }, + { + // Coeff Band ( 2 ) + {25842, 40456, 1126, 83, 11, 2, 0, 0, 0, 0, 0, 0,}, + {9338, 8010, 512, 73, 7, 3, 2, 0, 0, 0, 0, 43294,}, + {1047, 751, 149, 31, 13, 6, 1, 0, 0, 0, 0, 879,}, + }, + { + // Coeff Band ( 3 ) + {26136, 9826, 252, 13, 0, 0, 0, 0, 0, 0, 0, 0,}, + {8134, 5574, 191, 14, 2, 0, 0, 0, 0, 0, 0, 35302,}, + { 605, 677, 116, 9, 1, 0, 0, 0, 0, 0, 0, 611,}, + }, + { + // Coeff Band ( 4 ) + {10263, 15463, 283, 17, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2773, 2191, 128, 9, 2, 2, 0, 0, 0, 0, 0, 10073,}, + { 134, 125, 32, 4, 0, 2, 0, 0, 0, 0, 0, 50,}, + }, + { + // Coeff Band ( 5 ) + {10483, 2663, 23, 1, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2137, 1251, 27, 1, 1, 0, 0, 0, 0, 0, 0, 14362,}, + { 116, 156, 14, 2, 1, 0, 0, 0, 0, 0, 0, 190,}, + }, + { + // Coeff Band ( 6 ) + {40977, 27614, 412, 28, 0, 0, 0, 0, 0, 0, 0, 0,}, + {6113, 5213, 261, 22, 3, 0, 0, 0, 0, 0, 0, 26164,}, + { 382, 312, 50, 14, 2, 0, 0, 0, 0, 0, 0, 345,}, + }, + { + // Coeff Band ( 7 ) + { 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,}, + }, + }, + { + // Block Type ( 1 ) + { + // Coeff Band ( 0 ) + {3268, 19382, 1043, 250, 93, 82, 49, 26, 17, 8, 25, 82289,}, + {8758, 32110, 5436, 1832, 827, 668, 420, 153, 24, 0, 3, 52914,}, + {9337, 23725, 8487, 3954, 2107, 1836, 1069, 399, 59, 0, 0, 18620,}, + }, + { + // Coeff Band ( 1 ) + {12419, 8420, 452, 62, 9, 1, 0, 0, 0, 0, 0, 0,}, + {11715, 8705, 693, 92, 15, 7, 2, 0, 0, 0, 0, 53988,}, + {7603, 8585, 2306, 778, 270, 145, 39, 5, 0, 0, 0, 9136,}, + }, + { + // Coeff Band ( 2 ) + {15938, 14335, 1207, 184, 55, 13, 4, 1, 0, 0, 0, 0,}, + {7415, 6829, 1138, 244, 71, 26, 7, 0, 0, 0, 0, 9980,}, + {1580, 1824, 655, 241, 89, 46, 10, 2, 0, 0, 0, 429,}, + }, + { + // Coeff Band ( 3 ) + {19453, 5260, 201, 19, 0, 0, 0, 0, 0, 0, 0, 0,}, + {9173, 3758, 213, 22, 1, 1, 0, 0, 0, 0, 0, 9820,}, + {1689, 1277, 276, 51, 17, 4, 0, 0, 0, 0, 0, 679,}, + }, + { + // Coeff Band ( 4 ) + {12076, 10667, 620, 85, 19, 9, 5, 0, 0, 0, 0, 0,}, + {4665, 3625, 423, 55, 19, 9, 0, 0, 0, 0, 0, 5127,}, + { 415, 440, 143, 34, 20, 7, 2, 0, 0, 0, 0, 101,}, + }, + { + // Coeff Band ( 5 ) + {12183, 4846, 115, 11, 1, 0, 0, 0, 0, 0, 0, 0,}, + {4226, 3149, 177, 21, 2, 0, 0, 0, 0, 0, 0, 7157,}, + { 375, 621, 189, 51, 11, 4, 1, 0, 0, 0, 0, 198,}, + }, + { + // Coeff Band ( 6 ) + {61658, 37743, 1203, 94, 10, 3, 0, 0, 0, 0, 0, 0,}, + {15514, 11563, 903, 111, 14, 5, 0, 0, 0, 0, 0, 25195,}, + { 929, 1077, 291, 78, 14, 7, 1, 0, 0, 0, 0, 507,}, + }, + { + // Coeff Band ( 7 ) + { 0, 990, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 412, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1641,}, + { 0, 18, 7, 1, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + }, + { + // Block Type ( 2 ) + { + // Coeff Band ( 0 ) + { 953, 24519, 628, 120, 28, 12, 4, 0, 0, 0, 0, 2248798,}, + {1525, 25654, 2647, 617, 239, 143, 42, 5, 0, 0, 0, 66837,}, + {1180, 11011, 3001, 1237, 532, 448, 239, 54, 5, 0, 0, 7122,}, + }, + { + // Coeff Band ( 1 ) + {1356, 2220, 67, 10, 4, 1, 0, 0, 0, 0, 0, 0,}, + {1450, 2544, 102, 18, 4, 3, 0, 0, 0, 0, 0, 57063,}, + {1182, 2110, 470, 130, 41, 21, 0, 0, 0, 0, 0, 6047,}, + }, + { + // Coeff Band ( 2 ) + { 370, 3378, 200, 30, 5, 4, 1, 0, 0, 0, 0, 0,}, + { 293, 1006, 131, 29, 11, 0, 0, 0, 0, 0, 0, 5404,}, + { 114, 387, 98, 23, 4, 8, 1, 0, 0, 0, 0, 236,}, + }, + { + // Coeff Band ( 3 ) + { 579, 194, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 395, 213, 5, 1, 0, 0, 0, 0, 0, 0, 0, 4157,}, + { 119, 122, 4, 0, 0, 0, 0, 0, 0, 0, 0, 300,}, + }, + { + // Coeff Band ( 4 ) + { 38, 557, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 21, 114, 12, 1, 0, 0, 0, 0, 0, 0, 0, 427,}, + { 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,}, + }, + { + // Coeff Band ( 5 ) + { 52, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 652,}, + { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + { + // Coeff Band ( 6 ) + { 640, 569, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 25, 77, 2, 0, 0, 0, 0, 0, 0, 0, 0, 517,}, + { 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,}, + }, + { + // Coeff Band ( 7 ) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + }, + { + // Block Type ( 3 ) + { + // Coeff Band ( 0 ) + {2506, 20161, 2707, 767, 261, 178, 107, 30, 14, 3, 0, 100694,}, + {8806, 36478, 8817, 3268, 1280, 850, 401, 114, 42, 0, 0, 58572,}, + {11003, 27214, 11798, 5716, 2482, 2072, 1048, 175, 32, 0, 0, 19284,}, + }, + { + // Coeff Band ( 1 ) + {9738, 11313, 959, 205, 70, 18, 11, 1, 0, 0, 0, 0,}, + {12628, 15085, 1507, 273, 52, 19, 9, 0, 0, 0, 0, 54280,}, + {10701, 15846, 5561, 1926, 813, 570, 249, 36, 0, 0, 0, 6460,}, + }, + { + // Coeff Band ( 2 ) + {6781, 22539, 2784, 634, 182, 123, 20, 4, 0, 0, 0, 0,}, + {6263, 11544, 2649, 790, 259, 168, 27, 5, 0, 0, 0, 20539,}, + {3109, 4075, 2031, 896, 457, 386, 158, 29, 0, 0, 0, 1138,}, + }, + { + // Coeff Band ( 3 ) + {11515, 4079, 465, 73, 5, 14, 2, 0, 0, 0, 0, 0,}, + {9361, 5834, 650, 96, 24, 8, 4, 0, 0, 0, 0, 22181,}, + {4343, 3974, 1360, 415, 132, 96, 14, 1, 0, 0, 0, 1267,}, + }, + { + // Coeff Band ( 4 ) + {4787, 9297, 823, 168, 44, 12, 4, 0, 0, 0, 0, 0,}, + {3619, 4472, 719, 198, 60, 31, 3, 0, 0, 0, 0, 8401,}, + {1157, 1175, 483, 182, 88, 31, 8, 0, 0, 0, 0, 268,}, + }, + { + // Coeff Band ( 5 ) + {8299, 1226, 32, 5, 1, 0, 0, 0, 0, 0, 0, 0,}, + {3502, 1568, 57, 4, 1, 1, 0, 0, 0, 0, 0, 9811,}, + {1055, 1070, 166, 29, 6, 1, 0, 0, 0, 0, 0, 527,}, + }, + { + // Coeff Band ( 6 ) + {27414, 27927, 1989, 347, 69, 26, 0, 0, 0, 0, 0, 0,}, + {5876, 10074, 1574, 341, 91, 24, 4, 0, 0, 0, 0, 21954,}, + {1571, 2171, 778, 324, 124, 65, 16, 0, 0, 0, 0, 979,}, + }, + { + // Coeff Band ( 7 ) + { 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459,}, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,}, + }, + }, +}; + +//Update probabilities for the nodes in the token entropy tree. +const vp8_prob tree_update_probs[vp8_coef_tree_dimen] = +{ + { + { + {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, }, + }, + { + {176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255, }, + {250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255, }, + {254, 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, }, + }, + }, + { + { + {217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255, }, + {234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 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, }, + }, + }, + { + { + {186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255, }, + {251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 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, }, + }, + }, + { + { + {248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 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, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, +}; +#endif diff --git a/vp8/common/debugmodes.c b/vp8/common/debugmodes.c new file mode 100644 index 0000000..46064e6 --- /dev/null +++ b/vp8/common/debugmodes.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "blockd.h" + + +void vp8_print_modes_and_motion_vectors(MODE_INFO *mi, int rows, int cols, int frame) +{ + + int mb_row; + int mb_col; + int mb_index = 0; + FILE *mvs = fopen("mvs.stt", "a"); + + /* print out the macroblock Y modes */ + mb_index = 0; + fprintf(mvs, "Mb Modes for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + + fprintf(mvs, "%2d ", mi[mb_index].mbmi.mode); + + mb_index++; + } + + fprintf(mvs, "\n"); + mb_index++; + } + + fprintf(mvs, "\n"); + + mb_index = 0; + fprintf(mvs, "Mb mv ref for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + + fprintf(mvs, "%2d ", mi[mb_index].mbmi.ref_frame); + + mb_index++; + } + + fprintf(mvs, "\n"); + mb_index++; + } + + fprintf(mvs, "\n"); + + /* print out the macroblock UV modes */ + mb_index = 0; + fprintf(mvs, "UV Modes for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + + fprintf(mvs, "%2d ", mi[mb_index].mbmi.uv_mode); + + mb_index++; + } + + mb_index++; + fprintf(mvs, "\n"); + } + + fprintf(mvs, "\n"); + + /* print out the block modes */ + mb_index = 0; + fprintf(mvs, "Mbs for Frame %d\n", frame); + { + int b_row; + + for (b_row = 0; b_row < 4 * rows; b_row++) + { + int b_col; + int bindex; + + for (b_col = 0; b_col < 4 * cols; b_col++) + { + mb_index = (b_row >> 2) * (cols + 1) + (b_col >> 2); + bindex = (b_row & 3) * 4 + (b_col & 3); + + if (mi[mb_index].mbmi.mode == B_PRED) + fprintf(mvs, "%2d ", mi[mb_index].bmi[bindex].as_mode); + else + fprintf(mvs, "xx "); + + } + + fprintf(mvs, "\n"); + } + } + fprintf(mvs, "\n"); + + /* print out the macroblock mvs */ + mb_index = 0; + fprintf(mvs, "MVs for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + fprintf(mvs, "%5d:%-5d", mi[mb_index].mbmi.mv.as_mv.row / 2, mi[mb_index].mbmi.mv.as_mv.col / 2); + + mb_index++; + } + + mb_index++; + fprintf(mvs, "\n"); + } + + fprintf(mvs, "\n"); + + + /* print out the block modes */ + mb_index = 0; + fprintf(mvs, "MVs for Frame %d\n", frame); + { + int b_row; + + for (b_row = 0; b_row < 4 * rows; b_row++) + { + int b_col; + int bindex; + + for (b_col = 0; b_col < 4 * cols; b_col++) + { + mb_index = (b_row >> 2) * (cols + 1) + (b_col >> 2); + bindex = (b_row & 3) * 4 + (b_col & 3); + fprintf(mvs, "%3d:%-3d ", mi[mb_index].bmi[bindex].mv.as_mv.row, mi[mb_index].bmi[bindex].mv.as_mv.col); + + } + + fprintf(mvs, "\n"); + } + } + fprintf(mvs, "\n"); + + + fclose(mvs); +} diff --git a/vp8/common/default_coef_probs.h b/vp8/common/default_coef_probs.h new file mode 100644 index 0000000..0d19563 --- /dev/null +++ b/vp8/common/default_coef_probs.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. +*/ + + +/*Generated file, included by entropy.c*/ + + +static const vp8_prob default_coef_probs [BLOCK_TYPES] + [COEF_BANDS] + [PREV_COEF_CONTEXTS] + [ENTROPY_NODES] = +{ + { /* Block Type ( 0 ) */ + { /* Coeff Band ( 0 )*/ + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 1 )*/ + { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 }, + { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 }, + { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 } + }, + { /* Coeff Band ( 2 )*/ + { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 }, + { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 }, + { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 } + }, + { /* Coeff Band ( 3 )*/ + { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 }, + { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 }, + { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 4 )*/ + { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 }, + { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 }, + { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 } + }, + { /* Coeff Band ( 5 )*/ + { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 }, + { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 }, + { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 6 )*/ + { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 }, + { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 }, + { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 7 )*/ + { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { /* Block Type ( 1 ) */ + { /* Coeff Band ( 0 )*/ + { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 }, + { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 }, + { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 } + }, + { /* Coeff Band ( 1 )*/ + { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 }, + { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 }, + { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 } + }, + { /* Coeff Band ( 2 )*/ + { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 }, + { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 }, + { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 } + }, + { /* Coeff Band ( 3 )*/ + { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 }, + { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 }, + { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 } + }, + { /* Coeff Band ( 4 )*/ + { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 }, + { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 }, + { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 } + }, + { /* Coeff Band ( 5 )*/ + { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 }, + { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 }, + { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 } + }, + { /* Coeff Band ( 6 )*/ + { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 }, + { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 }, + { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 } + }, + { /* Coeff Band ( 7 )*/ + { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 } + } + }, + { /* Block Type ( 2 ) */ + { /* Coeff Band ( 0 )*/ + { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 }, + { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 }, + { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 } + }, + { /* Coeff Band ( 1 )*/ + { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 }, + { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 }, + { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 } + }, + { /* Coeff Band ( 2 )*/ + { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 }, + { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 }, + { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 } + }, + { /* Coeff Band ( 3 )*/ + { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 4 )*/ + { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 }, + { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 5 )*/ + { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 6 )*/ + { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { /* Coeff Band ( 7 )*/ + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { /* Block Type ( 3 ) */ + { /* Coeff Band ( 0 )*/ + { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 }, + { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 }, + { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 } + }, + { /* Coeff Band ( 1 )*/ + { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 }, + { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 }, + { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 } + }, + { /* Coeff Band ( 2 )*/ + { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 }, + { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 }, + { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 } + }, + { /* Coeff Band ( 3 )*/ + { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 }, + { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 }, + { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 } + }, + { /* Coeff Band ( 4 )*/ + { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 }, + { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 }, + { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 } + }, + { /* Coeff Band ( 5 )*/ + { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 }, + { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 }, + { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 } + }, + { /* Coeff Band ( 6 )*/ + { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 }, + { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 }, + { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 } + }, + { /* Coeff Band ( 7 )*/ + { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + } + } +}; diff --git a/vp8/common/dequantize.c b/vp8/common/dequantize.c new file mode 100644 index 0000000..8eda486 --- /dev/null +++ b/vp8/common/dequantize.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vp8/common/blockd.h" +#include "vpx_mem/vpx_mem.h" + +void vp8_dequantize_b_c(BLOCKD *d, short *DQC) +{ + int i; + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + + for (i = 0; i < 16; i++) + { + DQ[i] = Q[i] * DQC[i]; + } +} + +void vp8_dequant_idct_add_c(short *input, short *dq, + unsigned char *dest, int stride) +{ + int i; + + for (i = 0; i < 16; i++) + { + input[i] = dq[i] * input[i]; + } + + vp8_short_idct4x4llm_c(input, dest, stride, dest, stride); + + vpx_memset(input, 0, 32); + +} diff --git a/vp8/common/entropy.c b/vp8/common/entropy.c new file mode 100644 index 0000000..a95a923 --- /dev/null +++ b/vp8/common/entropy.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "entropy.h" +#include "blockd.h" +#include "onyxc_int.h" +#include "vpx_mem/vpx_mem.h" + +#include "coefupdateprobs.h" + +DECLARE_ALIGNED(16, const unsigned char, vp8_norm[256]) = +{ + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +DECLARE_ALIGNED(16, const unsigned char, vp8_coef_bands[16]) = +{ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7}; + +DECLARE_ALIGNED(16, const unsigned char, + vp8_prev_token_class[MAX_ENTROPY_TOKENS]) = +{ 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0}; + +DECLARE_ALIGNED(16, const int, vp8_default_zig_zag1d[16]) = +{ + 0, 1, 4, 8, + 5, 2, 3, 6, + 9, 12, 13, 10, + 7, 11, 14, 15, +}; + +DECLARE_ALIGNED(16, const short, vp8_default_inv_zig_zag[16]) = +{ + 1, 2, 6, 7, + 3, 5, 8, 13, + 4, 9, 12, 14, + 10, 11, 15, 16 +}; + +/* vp8_default_zig_zag_mask generated with: + + void vp8_init_scan_order_mask() + { + int i; + + for (i = 0; i < 16; i++) + { + vp8_default_zig_zag_mask[vp8_default_zig_zag1d[i]] = 1 << i; + } + + } +*/ +DECLARE_ALIGNED(16, const short, vp8_default_zig_zag_mask[16]) = +{ + 1, 2, 32, 64, + 4, 16, 128, 4096, + 8, 256, 2048, 8192, + 512, 1024, 16384, -32768 +}; + +const int vp8_mb_feature_data_bits[MB_LVL_MAX] = {7, 6}; + +/* Array indices are identical to previously-existing CONTEXT_NODE indices */ + +const vp8_tree_index vp8_coef_tree[ 22] = /* corresponding _CONTEXT_NODEs */ +{ + -DCT_EOB_TOKEN, 2, /* 0 = EOB */ + -ZERO_TOKEN, 4, /* 1 = ZERO */ + -ONE_TOKEN, 6, /* 2 = ONE */ + 8, 12, /* 3 = LOW_VAL */ + -TWO_TOKEN, 10, /* 4 = TWO */ + -THREE_TOKEN, -FOUR_TOKEN, /* 5 = THREE */ + 14, 16, /* 6 = HIGH_LOW */ + -DCT_VAL_CATEGORY1, -DCT_VAL_CATEGORY2, /* 7 = CAT_ONE */ + 18, 20, /* 8 = CAT_THREEFOUR */ + -DCT_VAL_CATEGORY3, -DCT_VAL_CATEGORY4, /* 9 = CAT_THREE */ + -DCT_VAL_CATEGORY5, -DCT_VAL_CATEGORY6 /* 10 = CAT_FIVE */ +}; + +/* vp8_coef_encodings generated with: + vp8_tokens_from_tree(vp8_coef_encodings, vp8_coef_tree); +*/ +const vp8_token vp8_coef_encodings[MAX_ENTROPY_TOKENS] = +{ + {2, 2}, + {6, 3}, + {28, 5}, + {58, 6}, + {59, 6}, + {60, 6}, + {61, 6}, + {124, 7}, + {125, 7}, + {126, 7}, + {127, 7}, + {0, 1} +}; + +/* Trees for extra bits. Probabilities are constant and + do not depend on previously encoded bits */ + +static const vp8_prob Pcat1[] = { 159}; +static const vp8_prob Pcat2[] = { 165, 145}; +static const vp8_prob Pcat3[] = { 173, 148, 140}; +static const vp8_prob Pcat4[] = { 176, 155, 140, 135}; +static const vp8_prob Pcat5[] = { 180, 157, 141, 134, 130}; +static const vp8_prob Pcat6[] = +{ 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129}; + + +/* tree index tables generated with: + + void init_bit_tree(vp8_tree_index *p, int n) + { + int i = 0; + + while (++i < n) + { + p[0] = p[1] = i << 1; + p += 2; + } + + p[0] = p[1] = 0; + } + + void init_bit_trees() + { + init_bit_tree(cat1, 1); + init_bit_tree(cat2, 2); + init_bit_tree(cat3, 3); + init_bit_tree(cat4, 4); + init_bit_tree(cat5, 5); + init_bit_tree(cat6, 11); + } +*/ + +static const vp8_tree_index cat1[2] = { 0, 0 }; +static const vp8_tree_index cat2[4] = { 2, 2, 0, 0 }; +static const vp8_tree_index cat3[6] = { 2, 2, 4, 4, 0, 0 }; +static const vp8_tree_index cat4[8] = { 2, 2, 4, 4, 6, 6, 0, 0 }; +static const vp8_tree_index cat5[10] = { 2, 2, 4, 4, 6, 6, 8, 8, 0, 0 }; +static const vp8_tree_index cat6[22] = { 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, + 14, 14, 16, 16, 18, 18, 20, 20, 0, 0 }; + +const vp8_extra_bit_struct vp8_extra_bits[12] = +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 1}, + { 0, 0, 0, 2}, + { 0, 0, 0, 3}, + { 0, 0, 0, 4}, + { cat1, Pcat1, 1, 5}, + { cat2, Pcat2, 2, 7}, + { cat3, Pcat3, 3, 11}, + { cat4, Pcat4, 4, 19}, + { cat5, Pcat5, 5, 35}, + { cat6, Pcat6, 11, 67}, + { 0, 0, 0, 0} +}; + +#include "default_coef_probs.h" + +void vp8_default_coef_probs(VP8_COMMON *pc) +{ + vpx_memcpy(pc->fc.coef_probs, default_coef_probs, + sizeof(default_coef_probs)); +} + diff --git a/vp8/common/entropy.h b/vp8/common/entropy.h new file mode 100644 index 0000000..5389bc1 --- /dev/null +++ b/vp8/common/entropy.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_ENTROPY_H +#define __INC_ENTROPY_H + +#include "treecoder.h" +#include "blockd.h" + +/* Coefficient token alphabet */ + +#define ZERO_TOKEN 0 /* 0 Extra Bits 0+0 */ +#define ONE_TOKEN 1 /* 1 Extra Bits 0+1 */ +#define TWO_TOKEN 2 /* 2 Extra Bits 0+1 */ +#define THREE_TOKEN 3 /* 3 Extra Bits 0+1 */ +#define FOUR_TOKEN 4 /* 4 Extra Bits 0+1 */ +#define DCT_VAL_CATEGORY1 5 /* 5-6 Extra Bits 1+1 */ +#define DCT_VAL_CATEGORY2 6 /* 7-10 Extra Bits 2+1 */ +#define DCT_VAL_CATEGORY3 7 /* 11-18 Extra Bits 3+1 */ +#define DCT_VAL_CATEGORY4 8 /* 19-34 Extra Bits 4+1 */ +#define DCT_VAL_CATEGORY5 9 /* 35-66 Extra Bits 5+1 */ +#define DCT_VAL_CATEGORY6 10 /* 67+ Extra Bits 11+1 */ +#define DCT_EOB_TOKEN 11 /* EOB Extra Bits 0+0 */ + +#define MAX_ENTROPY_TOKENS 12 +#define ENTROPY_NODES 11 + +extern const vp8_tree_index vp8_coef_tree[]; + +extern const struct vp8_token_struct vp8_coef_encodings[MAX_ENTROPY_TOKENS]; + +typedef struct +{ + vp8_tree_p tree; + const vp8_prob *prob; + int Len; + int base_val; +} vp8_extra_bit_struct; + +extern const vp8_extra_bit_struct vp8_extra_bits[12]; /* indexed by token value */ + +#define PROB_UPDATE_BASELINE_COST 7 + +#define MAX_PROB 255 +#define DCT_MAX_VALUE 2048 + + +/* Coefficients are predicted via a 3-dimensional probability table. */ + +/* Outside dimension. 0 = Y no DC, 1 = Y2, 2 = UV, 3 = Y with DC */ + +#define BLOCK_TYPES 4 + +/* Middle dimension is a coarsening of the coefficient's + position within the 4x4 DCT. */ + +#define COEF_BANDS 8 +extern DECLARE_ALIGNED(16, const unsigned char, vp8_coef_bands[16]); + +/* Inside dimension is 3-valued measure of nearby complexity, that is, + the extent to which nearby coefficients are nonzero. For the first + coefficient (DC, unless block type is 0), we look at the (already encoded) + blocks above and to the left of the current block. The context index is + then the number (0,1,or 2) of these blocks having nonzero coefficients. + After decoding a coefficient, the measure is roughly the size of the + most recently decoded coefficient (0 for 0, 1 for 1, 2 for >1). + Note that the intuitive meaning of this measure changes as coefficients + are decoded, e.g., prior to the first token, a zero means that my neighbors + are empty while, after the first token, because of the use of end-of-block, + a zero means we just decoded a zero and hence guarantees that a non-zero + coefficient will appear later in this block. However, this shift + in meaning is perfectly OK because our context depends also on the + coefficient band (and since zigzag positions 0, 1, and 2 are in + distinct bands). */ + +/*# define DC_TOKEN_CONTEXTS 3*/ /* 00, 0!0, !0!0 */ +# define PREV_COEF_CONTEXTS 3 + +extern DECLARE_ALIGNED(16, const unsigned char, vp8_prev_token_class[MAX_ENTROPY_TOKENS]); + +extern const vp8_prob vp8_coef_update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; + + +struct VP8Common; +void vp8_default_coef_probs(struct VP8Common *); + +extern DECLARE_ALIGNED(16, const int, vp8_default_zig_zag1d[16]); +extern DECLARE_ALIGNED(16, const short, vp8_default_inv_zig_zag[16]); +extern DECLARE_ALIGNED(16, const short, vp8_default_zig_zag_mask[16]); +extern const int vp8_mb_feature_data_bits[MB_LVL_MAX]; + +void vp8_coef_tree_initialize(void); +#endif diff --git a/vp8/common/entropymode.c b/vp8/common/entropymode.c new file mode 100644 index 0000000..de7e828 --- /dev/null +++ b/vp8/common/entropymode.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#define USE_PREBUILT_TABLES + +#include "entropymode.h" +#include "entropy.h" +#include "vpx_mem/vpx_mem.h" + +#include "vp8_entropymodedata.h" + +int vp8_mv_cont(const int_mv *l, const int_mv *a) +{ + int lez = (l->as_int == 0); + int aez = (a->as_int == 0); + int lea = (l->as_int == a->as_int); + + if (lea && lez) + return SUBMVREF_LEFT_ABOVE_ZED; + + if (lea) + return SUBMVREF_LEFT_ABOVE_SAME; + + if (aez) + return SUBMVREF_ABOVE_ZED; + + if (lez) + return SUBMVREF_LEFT_ZED; + + return SUBMVREF_NORMAL; +} + +static const vp8_prob sub_mv_ref_prob [VP8_SUBMVREFS-1] = { 180, 162, 25}; + +const vp8_prob vp8_sub_mv_ref_prob2 [SUBMVREF_COUNT][VP8_SUBMVREFS-1] = +{ + { 147, 136, 18 }, + { 106, 145, 1 }, + { 179, 121, 1 }, + { 223, 1 , 34 }, + { 208, 1 , 1 } +}; + + + +const vp8_mbsplit vp8_mbsplits [VP8_NUMMBSPLITS] = +{ + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + { + 0, 0, 1, 1, + 0, 0, 1, 1, + 0, 0, 1, 1, + 0, 0, 1, 1, + }, + { + 0, 0, 1, 1, + 0, 0, 1, 1, + 2, 2, 3, 3, + 2, 2, 3, 3, + }, + { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + } +}; + +const int vp8_mbsplit_count [VP8_NUMMBSPLITS] = { 2, 2, 4, 16}; + +const vp8_prob vp8_mbsplit_probs [VP8_NUMMBSPLITS-1] = { 110, 111, 150}; + + +/* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */ + +const vp8_tree_index vp8_bmode_tree[18] = /* INTRAMODECONTEXTNODE value */ +{ + -B_DC_PRED, 2, /* 0 = DC_NODE */ + -B_TM_PRED, 4, /* 1 = TM_NODE */ + -B_VE_PRED, 6, /* 2 = VE_NODE */ + 8, 12, /* 3 = COM_NODE */ + -B_HE_PRED, 10, /* 4 = HE_NODE */ + -B_RD_PRED, -B_VR_PRED, /* 5 = RD_NODE */ + -B_LD_PRED, 14, /* 6 = LD_NODE */ + -B_VL_PRED, 16, /* 7 = VL_NODE */ + -B_HD_PRED, -B_HU_PRED /* 8 = HD_NODE */ +}; + +/* Again, these trees use the same probability indices as their + explicitly-programmed predecessors. */ + +const vp8_tree_index vp8_ymode_tree[8] = +{ + -DC_PRED, 2, + 4, 6, + -V_PRED, -H_PRED, + -TM_PRED, -B_PRED +}; + +const vp8_tree_index vp8_kf_ymode_tree[8] = +{ + -B_PRED, 2, + 4, 6, + -DC_PRED, -V_PRED, + -H_PRED, -TM_PRED +}; + +const vp8_tree_index vp8_uv_mode_tree[6] = +{ + -DC_PRED, 2, + -V_PRED, 4, + -H_PRED, -TM_PRED +}; + +const vp8_tree_index vp8_mbsplit_tree[6] = +{ + -3, 2, + -2, 4, + -0, -1 +}; + +const vp8_tree_index vp8_mv_ref_tree[8] = +{ + -ZEROMV, 2, + -NEARESTMV, 4, + -NEARMV, 6, + -NEWMV, -SPLITMV +}; + +const vp8_tree_index vp8_sub_mv_ref_tree[6] = +{ + -LEFT4X4, 2, + -ABOVE4X4, 4, + -ZERO4X4, -NEW4X4 +}; + +const vp8_tree_index vp8_small_mvtree [14] = +{ + 2, 8, + 4, 6, + -0, -1, + -2, -3, + 10, 12, + -4, -5, + -6, -7 +}; + +void vp8_init_mbmode_probs(VP8_COMMON *x) +{ + vpx_memcpy(x->fc.ymode_prob, vp8_ymode_prob, sizeof(vp8_ymode_prob)); + vpx_memcpy(x->kf_ymode_prob, vp8_kf_ymode_prob, sizeof(vp8_kf_ymode_prob)); + vpx_memcpy(x->fc.uv_mode_prob, vp8_uv_mode_prob, sizeof(vp8_uv_mode_prob)); + vpx_memcpy(x->kf_uv_mode_prob, vp8_kf_uv_mode_prob, sizeof(vp8_kf_uv_mode_prob)); + vpx_memcpy(x->fc.sub_mv_ref_prob, sub_mv_ref_prob, sizeof(sub_mv_ref_prob)); +} + +void vp8_default_bmode_probs(vp8_prob p [VP8_BINTRAMODES-1]) +{ + vpx_memcpy(p, vp8_bmode_prob, sizeof(vp8_bmode_prob)); +} + +void vp8_kf_default_bmode_probs(vp8_prob p [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]) +{ + vpx_memcpy(p, vp8_kf_bmode_prob, sizeof(vp8_kf_bmode_prob)); +} diff --git a/vp8/common/entropymode.h b/vp8/common/entropymode.h new file mode 100644 index 0000000..70200cb --- /dev/null +++ b/vp8/common/entropymode.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_ENTROPYMODE_H +#define __INC_ENTROPYMODE_H + +#include "onyxc_int.h" +#include "treecoder.h" + +typedef enum +{ + SUBMVREF_NORMAL, + SUBMVREF_LEFT_ZED, + SUBMVREF_ABOVE_ZED, + SUBMVREF_LEFT_ABOVE_SAME, + SUBMVREF_LEFT_ABOVE_ZED +} sumvfref_t; + +typedef const int vp8_mbsplit[16]; + +#define VP8_NUMMBSPLITS 4 + +extern vp8_mbsplit vp8_mbsplits [VP8_NUMMBSPLITS]; + +extern const int vp8_mbsplit_count [VP8_NUMMBSPLITS]; /* # of subsets */ + +extern const vp8_prob vp8_mbsplit_probs [VP8_NUMMBSPLITS-1]; + +extern int vp8_mv_cont(const int_mv *l, const int_mv *a); +#define SUBMVREF_COUNT 5 +extern const vp8_prob vp8_sub_mv_ref_prob2 [SUBMVREF_COUNT][VP8_SUBMVREFS-1]; + + +extern const unsigned int vp8_kf_default_bmode_counts [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES]; + + +extern const vp8_tree_index vp8_bmode_tree[]; + +extern const vp8_tree_index vp8_ymode_tree[]; +extern const vp8_tree_index vp8_kf_ymode_tree[]; +extern const vp8_tree_index vp8_uv_mode_tree[]; + +extern const vp8_tree_index vp8_mbsplit_tree[]; +extern const vp8_tree_index vp8_mv_ref_tree[]; +extern const vp8_tree_index vp8_sub_mv_ref_tree[]; + +extern const struct vp8_token_struct vp8_bmode_encodings[VP8_BINTRAMODES]; +extern const struct vp8_token_struct vp8_ymode_encodings[VP8_YMODES]; +extern const struct vp8_token_struct vp8_kf_ymode_encodings[VP8_YMODES]; +extern const struct vp8_token_struct vp8_uv_mode_encodings[VP8_UV_MODES]; +extern const struct vp8_token_struct vp8_mbsplit_encodings[VP8_NUMMBSPLITS]; + +/* Inter mode values do not start at zero */ + +extern const struct vp8_token_struct vp8_mv_ref_encoding_array[VP8_MVREFS]; +extern const struct vp8_token_struct vp8_sub_mv_ref_encoding_array[VP8_SUBMVREFS]; + +extern const vp8_tree_index vp8_small_mvtree[]; + +extern const struct vp8_token_struct vp8_small_mvencodings[8]; + +void vp8_init_mbmode_probs(VP8_COMMON *x); + +void vp8_default_bmode_probs(vp8_prob dest [VP8_BINTRAMODES-1]); +void vp8_kf_default_bmode_probs(vp8_prob dest [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]); + +#endif diff --git a/vp8/common/entropymv.c b/vp8/common/entropymv.c new file mode 100644 index 0000000..e5df1f0 --- /dev/null +++ b/vp8/common/entropymv.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "entropymv.h" + +const MV_CONTEXT vp8_mv_update_probs[2] = +{ + {{ + 237, + 246, + 253, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 + }}, + {{ + 231, + 243, + 245, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 + }} +}; +const MV_CONTEXT vp8_default_mv_context[2] = +{ + {{ + /* row */ + 162, /* is short */ + 128, /* sign */ + 225, 146, 172, 147, 214, 39, 156, /* short tree */ + 128, 129, 132, 75, 145, 178, 206, 239, 254, 254 /* long bits */ + }}, + + + + {{ + /* same for column */ + 164, /* is short */ + 128, + 204, 170, 119, 235, 140, 230, 228, + 128, 130, 130, 74, 148, 180, 203, 236, 254, 254 /* long bits */ + + }} +}; diff --git a/vp8/common/entropymv.h b/vp8/common/entropymv.h new file mode 100644 index 0000000..2db1e38 --- /dev/null +++ b/vp8/common/entropymv.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_ENTROPYMV_H +#define __INC_ENTROPYMV_H + +#include "treecoder.h" + +enum +{ + mv_max = 1023, /* max absolute value of a MV component */ + MVvals = (2 * mv_max) + 1, /* # possible values "" */ + mvfp_max = 255, /* max absolute value of a full pixel MV component */ + MVfpvals = (2 * mvfp_max) +1, /* # possible full pixel MV values */ + + mvlong_width = 10, /* Large MVs have 9 bit magnitudes */ + mvnum_short = 8, /* magnitudes 0 through 7 */ + + /* probability offsets for coding each MV component */ + + mvpis_short = 0, /* short (<= 7) vs long (>= 8) */ + MVPsign, /* sign for non-zero */ + MVPshort, /* 8 short values = 7-position tree */ + + MVPbits = MVPshort + mvnum_short - 1, /* mvlong_width long value bits */ + MVPcount = MVPbits + mvlong_width /* (with independent probabilities) */ +}; + +typedef struct mv_context +{ + vp8_prob prob[MVPcount]; /* often come in row, col pairs */ +} MV_CONTEXT; + +extern const MV_CONTEXT vp8_mv_update_probs[2], vp8_default_mv_context[2]; + +#endif diff --git a/vp8/common/extend.c b/vp8/common/extend.c new file mode 100644 index 0000000..9089e16 --- /dev/null +++ b/vp8/common/extend.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "extend.h" +#include "vpx_mem/vpx_mem.h" + + +static void copy_and_extend_plane +( + unsigned char *s, /* source */ + int sp, /* source pitch */ + unsigned char *d, /* destination */ + int dp, /* destination pitch */ + int h, /* height */ + int w, /* width */ + int et, /* extend top border */ + int el, /* extend left border */ + int eb, /* extend bottom border */ + int er /* extend right border */ +) +{ + int i; + unsigned char *src_ptr1, *src_ptr2; + unsigned char *dest_ptr1, *dest_ptr2; + int linesize; + + /* copy the left and right most columns out */ + src_ptr1 = s; + src_ptr2 = s + w - 1; + dest_ptr1 = d - el; + dest_ptr2 = d + w; + + for (i = 0; i < h; i++) + { + vpx_memset(dest_ptr1, src_ptr1[0], el); + vpx_memcpy(dest_ptr1 + el, src_ptr1, w); + vpx_memset(dest_ptr2, src_ptr2[0], er); + src_ptr1 += sp; + src_ptr2 += sp; + dest_ptr1 += dp; + dest_ptr2 += dp; + } + + /* Now copy the top and bottom lines into each line of the respective + * borders + */ + src_ptr1 = d - el; + src_ptr2 = d + dp * (h - 1) - el; + dest_ptr1 = d + dp * (-et) - el; + dest_ptr2 = d + dp * (h) - el; + linesize = el + er + w; + + for (i = 0; i < et; i++) + { + vpx_memcpy(dest_ptr1, src_ptr1, linesize); + dest_ptr1 += dp; + } + + for (i = 0; i < eb; i++) + { + vpx_memcpy(dest_ptr2, src_ptr2, linesize); + dest_ptr2 += dp; + } +} + + +void vp8_copy_and_extend_frame(YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst) +{ + int et = dst->border; + int el = dst->border; + int eb = dst->border + dst->y_height - src->y_height; + int er = dst->border + dst->y_width - src->y_width; + + copy_and_extend_plane(src->y_buffer, src->y_stride, + dst->y_buffer, dst->y_stride, + src->y_height, src->y_width, + et, el, eb, er); + + et = dst->border >> 1; + el = dst->border >> 1; + eb = (dst->border >> 1) + dst->uv_height - src->uv_height; + er = (dst->border >> 1) + dst->uv_width - src->uv_width; + + copy_and_extend_plane(src->u_buffer, src->uv_stride, + dst->u_buffer, dst->uv_stride, + src->uv_height, src->uv_width, + et, el, eb, er); + + copy_and_extend_plane(src->v_buffer, src->uv_stride, + dst->v_buffer, dst->uv_stride, + src->uv_height, src->uv_width, + et, el, eb, er); +} + + +void vp8_copy_and_extend_frame_with_rect(YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst, + int srcy, int srcx, + int srch, int srcw) +{ + int et = dst->border; + int el = dst->border; + int eb = dst->border + dst->y_height - src->y_height; + int er = dst->border + dst->y_width - src->y_width; + int src_y_offset = srcy * src->y_stride + srcx; + int dst_y_offset = srcy * dst->y_stride + srcx; + int src_uv_offset = ((srcy * src->uv_stride) >> 1) + (srcx >> 1); + int dst_uv_offset = ((srcy * dst->uv_stride) >> 1) + (srcx >> 1); + + // If the side is not touching the bounder then don't extend. + if (srcy) + et = 0; + if (srcx) + el = 0; + if (srcy + srch != src->y_height) + eb = 0; + if (srcx + srcw != src->y_width) + er = 0; + + copy_and_extend_plane(src->y_buffer + src_y_offset, + src->y_stride, + dst->y_buffer + dst_y_offset, + dst->y_stride, + srch, srcw, + et, el, eb, er); + + et = (et + 1) >> 1; + el = (el + 1) >> 1; + eb = (eb + 1) >> 1; + er = (er + 1) >> 1; + srch = (srch + 1) >> 1; + srcw = (srcw + 1) >> 1; + + copy_and_extend_plane(src->u_buffer + src_uv_offset, + src->uv_stride, + dst->u_buffer + dst_uv_offset, + dst->uv_stride, + srch, srcw, + et, el, eb, er); + + copy_and_extend_plane(src->v_buffer + src_uv_offset, + src->uv_stride, + dst->v_buffer + dst_uv_offset, + dst->uv_stride, + srch, srcw, + et, el, eb, er); +} + + +/* note the extension is only for the last row, for intra prediction purpose */ +void vp8_extend_mb_row(YV12_BUFFER_CONFIG *ybf, unsigned char *YPtr, unsigned char *UPtr, unsigned char *VPtr) +{ + int i; + + YPtr += ybf->y_stride * 14; + UPtr += ybf->uv_stride * 6; + VPtr += ybf->uv_stride * 6; + + for (i = 0; i < 4; i++) + { + YPtr[i] = YPtr[-1]; + UPtr[i] = UPtr[-1]; + VPtr[i] = VPtr[-1]; + } + + YPtr += ybf->y_stride; + UPtr += ybf->uv_stride; + VPtr += ybf->uv_stride; + + for (i = 0; i < 4; i++) + { + YPtr[i] = YPtr[-1]; + UPtr[i] = UPtr[-1]; + VPtr[i] = VPtr[-1]; + } +} diff --git a/vp8/common/extend.h b/vp8/common/extend.h new file mode 100644 index 0000000..74a0b17 --- /dev/null +++ b/vp8/common/extend.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_EXTEND_H +#define __INC_EXTEND_H + +#include "vpx_scale/yv12config.h" + +void vp8_extend_mb_row(YV12_BUFFER_CONFIG *ybf, unsigned char *YPtr, unsigned char *UPtr, unsigned char *VPtr); +void vp8_copy_and_extend_frame(YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst); +void vp8_copy_and_extend_frame_with_rect(YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst, + int srcy, int srcx, + int srch, int srcw); + +#endif diff --git a/vp8/common/filter.c b/vp8/common/filter.c new file mode 100644 index 0000000..1901ea3 --- /dev/null +++ b/vp8/common/filter.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "filter.h" +#include "vpx_ports/mem.h" + +DECLARE_ALIGNED(16, const short, vp8_bilinear_filters[8][2]) = +{ + { 128, 0 }, + { 112, 16 }, + { 96, 32 }, + { 80, 48 }, + { 64, 64 }, + { 48, 80 }, + { 32, 96 }, + { 16, 112 } +}; + +DECLARE_ALIGNED(16, const short, vp8_sub_pel_filters[8][6]) = +{ + + { 0, 0, 128, 0, 0, 0 }, /* note that 1/8 pel positions are just as per alpha -0.5 bicubic */ + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, /* New 1/4 pel 6 tap filter */ + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, /* New 1/2 pel 6 tap filter */ + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, /* New 1/4 pel 6 tap filter */ + { 0, -1, 12, 123, -6, 0 }, +}; + +static void filter_block2d_first_pass +( + unsigned char *src_ptr, + int *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ + + /* Normalize back to 0-255 */ + Temp = Temp >> VP8_FILTER_SHIFT; + + if (Temp < 0) + Temp = 0; + else if (Temp > 255) + Temp = 255; + + output_ptr[j] = Temp; + src_ptr++; + } + + /* Next row... */ + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + +static void filter_block2d_second_pass +( + int *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + /* Apply filter */ + Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + (VP8_FILTER_WEIGHT >> 1); /* Rounding */ + + /* Normalize back to 0-255 */ + Temp = Temp >> VP8_FILTER_SHIFT; + + if (Temp < 0) + Temp = 0; + else if (Temp > 255) + Temp = 255; + + output_ptr[j] = (unsigned char)Temp; + src_ptr++; + } + + /* Start next row */ + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_pitch; + } +} + + +static void filter_block2d +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + int output_pitch, + const short *HFilter, + const short *VFilter +) +{ + int FData[9*4]; /* Temp data buffer used in filtering */ + + /* First filter 1-D horizontally... */ + filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 9, 4, HFilter); + + /* then filter verticaly... */ + filter_block2d_second_pass(FData + 8, output_ptr, output_pitch, 4, 4, 4, 4, VFilter); +} + + +void vp8_sixtap_predict4x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + filter_block2d(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter); +} +void vp8_sixtap_predict8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + int FData[13*16]; /* Temp data buffer used in filtering */ + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + /* First filter 1-D horizontally... */ + filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 13, 8, HFilter); + + + /* then filter verticaly... */ + filter_block2d_second_pass(FData + 16, dst_ptr, dst_pitch, 8, 8, 8, 8, VFilter); + +} + +void vp8_sixtap_predict8x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + int FData[13*16]; /* Temp data buffer used in filtering */ + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + /* First filter 1-D horizontally... */ + filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 9, 8, HFilter); + + + /* then filter verticaly... */ + filter_block2d_second_pass(FData + 16, dst_ptr, dst_pitch, 8, 8, 4, 8, VFilter); + +} + +void vp8_sixtap_predict16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + int FData[21*24]; /* Temp data buffer used in filtering */ + + + HFilter = vp8_sub_pel_filters[xoffset]; /* 6 tap */ + VFilter = vp8_sub_pel_filters[yoffset]; /* 6 tap */ + + /* First filter 1-D horizontally... */ + filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 21, 16, HFilter); + + /* then filter verticaly... */ + filter_block2d_second_pass(FData + 32, dst_ptr, dst_pitch, 16, 16, 16, 16, VFilter); + +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_first_pass + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_stride : Stride of source block. + * UINT32 height : Block height. + * UINT32 width : Block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : INT32 *dst_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block + * in the horizontal direction to produce the filtered output + * block. Used to implement first-pass of 2-D separable filter. + * + * SPECIAL NOTES : Produces INT32 output to retain precision for next pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * + ****************************************************************************/ +static void filter_block2d_bil_first_pass +( + unsigned char *src_ptr, + unsigned short *dst_ptr, + unsigned int src_stride, + unsigned int height, + unsigned int width, + const short *vp8_filter +) +{ + unsigned int i, j; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + /* Apply bilinear filter */ + dst_ptr[j] = (((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[1] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2)) >> VP8_FILTER_SHIFT; + src_ptr++; + } + + /* Next row... */ + src_ptr += src_stride - width; + dst_ptr += width; + } +} + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_second_pass + * + * INPUTS : INT32 *src_ptr : Pointer to source block. + * UINT32 dst_pitch : Destination block pitch. + * UINT32 height : Block height. + * UINT32 width : Block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : UINT16 *dst_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block + * in the vertical direction to produce the filtered output + * block. Used to implement second-pass of 2-D separable filter. + * + * SPECIAL NOTES : Requires 32-bit input as produced by filter_block2d_bil_first_pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * + ****************************************************************************/ +static void filter_block2d_bil_second_pass +( + unsigned short *src_ptr, + unsigned char *dst_ptr, + int dst_pitch, + unsigned int height, + unsigned int width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + /* Apply filter */ + Temp = ((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[width] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2); + dst_ptr[j] = (unsigned int)(Temp >> VP8_FILTER_SHIFT); + src_ptr++; + } + + /* Next row... */ + dst_ptr += dst_pitch; + } +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_pitch : Stride of source block. + * UINT32 dst_pitch : Stride of destination block. + * INT32 *HFilter : Array of 2 horizontal filter taps. + * INT32 *VFilter : Array of 2 vertical filter taps. + * INT32 Width : Block width + * INT32 Height : Block height + * + * OUTPUTS : UINT16 *dst_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : 2-D filters an input block by applying a 2-tap + * bi-linear filter horizontally followed by a 2-tap + * bi-linear filter vertically on the result. + * + * SPECIAL NOTES : The largest block size can be handled here is 16x16 + * + ****************************************************************************/ +static void filter_block2d_bil +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + unsigned int src_pitch, + unsigned int dst_pitch, + const short *HFilter, + const short *VFilter, + int Width, + int Height +) +{ + + unsigned short FData[17*16]; /* Temp data buffer used in filtering */ + + /* First filter 1-D horizontally... */ + filter_block2d_bil_first_pass(src_ptr, FData, src_pitch, Height + 1, Width, HFilter); + + /* then 1-D vertically... */ + filter_block2d_bil_second_pass(FData, dst_ptr, dst_pitch, Height, Width, VFilter); +} + + +void vp8_bilinear_predict4x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; +#if 0 + { + int i; + unsigned char temp1[16]; + unsigned char temp2[16]; + + bilinear_predict4x4_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, temp1, 4); + filter_block2d_bil(src_ptr, temp2, src_pixels_per_line, 4, HFilter, VFilter, 4, 4); + + for (i = 0; i < 16; i++) + { + if (temp1[i] != temp2[i]) + { + bilinear_predict4x4_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, temp1, 4); + filter_block2d_bil(src_ptr, temp2, src_pixels_per_line, 4, HFilter, VFilter, 4, 4); + } + } + } +#endif + filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 4, 4); + +} + +void vp8_bilinear_predict8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 8); + +} + +void vp8_bilinear_predict8x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 4); + +} + +void vp8_bilinear_predict16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 16, 16); +} diff --git a/vp8/common/filter.h b/vp8/common/filter.h new file mode 100644 index 0000000..0f225c2 --- /dev/null +++ b/vp8/common/filter.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef FILTER_H +#define FILTER_H + +#define BLOCK_HEIGHT_WIDTH 4 +#define VP8_FILTER_WEIGHT 128 +#define VP8_FILTER_SHIFT 7 + +extern const short vp8_bilinear_filters[8][2]; +extern const short vp8_sub_pel_filters[8][6]; + +#endif //FILTER_H diff --git a/vp8/common/findnearmv.c b/vp8/common/findnearmv.c new file mode 100644 index 0000000..e8ee40f --- /dev/null +++ b/vp8/common/findnearmv.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "findnearmv.h" + +const unsigned char vp8_mbsplit_offset[4][16] = { + { 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 2, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} +}; + +/* Predict motion vectors using those from already-decoded nearby blocks. + Note that we only consider one 4x4 subblock from each candidate 16x16 + macroblock. */ +void vp8_find_near_mvs +( + MACROBLOCKD *xd, + const MODE_INFO *here, + int_mv *nearest, + int_mv *nearby, + int_mv *best_mv, + int cnt[4], + int refframe, + int *ref_frame_sign_bias +) +{ + const MODE_INFO *above = here - xd->mode_info_stride; + const MODE_INFO *left = here - 1; + const MODE_INFO *aboveleft = above - 1; + int_mv near_mvs[4]; + int_mv *mv = near_mvs; + int *cntx = cnt; + enum {CNT_INTRA, CNT_NEAREST, CNT_NEAR, CNT_SPLITMV}; + + /* Zero accumulators */ + mv[0].as_int = mv[1].as_int = mv[2].as_int = 0; + cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0; + + /* Process above */ + if (above->mbmi.ref_frame != INTRA_FRAME) + { + if (above->mbmi.mv.as_int) + { + (++mv)->as_int = above->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[above->mbmi.ref_frame], refframe, mv, ref_frame_sign_bias); + ++cntx; + } + + *cntx += 2; + } + + /* Process left */ + if (left->mbmi.ref_frame != INTRA_FRAME) + { + if (left->mbmi.mv.as_int) + { + int_mv this_mv; + + this_mv.as_int = left->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[left->mbmi.ref_frame], refframe, &this_mv, ref_frame_sign_bias); + + if (this_mv.as_int != mv->as_int) + { + (++mv)->as_int = this_mv.as_int; + ++cntx; + } + + *cntx += 2; + } + else + cnt[CNT_INTRA] += 2; + } + + /* Process above left */ + if (aboveleft->mbmi.ref_frame != INTRA_FRAME) + { + if (aboveleft->mbmi.mv.as_int) + { + int_mv this_mv; + + this_mv.as_int = aboveleft->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[aboveleft->mbmi.ref_frame], refframe, &this_mv, ref_frame_sign_bias); + + if (this_mv.as_int != mv->as_int) + { + (++mv)->as_int = this_mv.as_int; + ++cntx; + } + + *cntx += 1; + } + else + cnt[CNT_INTRA] += 1; + } + + /* If we have three distinct MV's ... */ + if (cnt[CNT_SPLITMV]) + { + /* See if above-left MV can be merged with NEAREST */ + if (mv->as_int == near_mvs[CNT_NEAREST].as_int) + cnt[CNT_NEAREST] += 1; + } + + cnt[CNT_SPLITMV] = ((above->mbmi.mode == SPLITMV) + + (left->mbmi.mode == SPLITMV)) * 2 + + (aboveleft->mbmi.mode == SPLITMV); + + /* Swap near and nearest if necessary */ + if (cnt[CNT_NEAR] > cnt[CNT_NEAREST]) + { + int tmp; + tmp = cnt[CNT_NEAREST]; + cnt[CNT_NEAREST] = cnt[CNT_NEAR]; + cnt[CNT_NEAR] = tmp; + tmp = near_mvs[CNT_NEAREST].as_int; + near_mvs[CNT_NEAREST].as_int = near_mvs[CNT_NEAR].as_int; + near_mvs[CNT_NEAR].as_int = tmp; + } + + /* Use near_mvs[0] to store the "best" MV */ + if (cnt[CNT_NEAREST] >= cnt[CNT_INTRA]) + near_mvs[CNT_INTRA] = near_mvs[CNT_NEAREST]; + + /* Set up return values */ + best_mv->as_int = near_mvs[0].as_int; + nearest->as_int = near_mvs[CNT_NEAREST].as_int; + nearby->as_int = near_mvs[CNT_NEAR].as_int; +} + + +static void invert_and_clamp_mvs(int_mv *inv, int_mv *src, MACROBLOCKD *xd) +{ + inv->as_mv.row = src->as_mv.row * -1; + inv->as_mv.col = src->as_mv.col * -1; + vp8_clamp_mv2(inv, xd); + vp8_clamp_mv2(src, xd); +} + + +int vp8_find_near_mvs_bias +( + MACROBLOCKD *xd, + const MODE_INFO *here, + int_mv mode_mv_sb[2][MB_MODE_COUNT], + int_mv best_mv_sb[2], + int cnt[4], + int refframe, + int *ref_frame_sign_bias +) +{ + int sign_bias = ref_frame_sign_bias[refframe]; + + vp8_find_near_mvs(xd, + here, + &mode_mv_sb[sign_bias][NEARESTMV], + &mode_mv_sb[sign_bias][NEARMV], + &best_mv_sb[sign_bias], + cnt, + refframe, + ref_frame_sign_bias); + + invert_and_clamp_mvs(&mode_mv_sb[!sign_bias][NEARESTMV], + &mode_mv_sb[sign_bias][NEARESTMV], xd); + invert_and_clamp_mvs(&mode_mv_sb[!sign_bias][NEARMV], + &mode_mv_sb[sign_bias][NEARMV], xd); + invert_and_clamp_mvs(&best_mv_sb[!sign_bias], + &best_mv_sb[sign_bias], xd); + + return sign_bias; +} + + +vp8_prob *vp8_mv_ref_probs( + vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] +) +{ + p[0] = vp8_mode_contexts [near_mv_ref_ct[0]] [0]; + p[1] = vp8_mode_contexts [near_mv_ref_ct[1]] [1]; + p[2] = vp8_mode_contexts [near_mv_ref_ct[2]] [2]; + p[3] = vp8_mode_contexts [near_mv_ref_ct[3]] [3]; + /*p[3] = vp8_mode_contexts [near_mv_ref_ct[1] + near_mv_ref_ct[2] + near_mv_ref_ct[3]] [3];*/ + return p; +} + diff --git a/vp8/common/findnearmv.h b/vp8/common/findnearmv.h new file mode 100644 index 0000000..06ef060 --- /dev/null +++ b/vp8/common/findnearmv.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_FINDNEARMV_H +#define __INC_FINDNEARMV_H + +#include "mv.h" +#include "blockd.h" +#include "modecont.h" +#include "treecoder.h" + + +static void mv_bias(int refmb_ref_frame_sign_bias, int refframe, int_mv *mvp, + const int *ref_frame_sign_bias) +{ + if (refmb_ref_frame_sign_bias != ref_frame_sign_bias[refframe]) + { + mvp->as_mv.row *= -1; + mvp->as_mv.col *= -1; + } +} + +#define LEFT_TOP_MARGIN (16 << 3) +#define RIGHT_BOTTOM_MARGIN (16 << 3) +static void vp8_clamp_mv2(int_mv *mv, const MACROBLOCKD *xd) +{ + if (mv->as_mv.col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN)) + mv->as_mv.col = xd->mb_to_left_edge - LEFT_TOP_MARGIN; + else if (mv->as_mv.col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN) + mv->as_mv.col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN; + + if (mv->as_mv.row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN)) + mv->as_mv.row = xd->mb_to_top_edge - LEFT_TOP_MARGIN; + else if (mv->as_mv.row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN) + mv->as_mv.row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN; +} + +static void vp8_clamp_mv(int_mv *mv, int mb_to_left_edge, int mb_to_right_edge, + int mb_to_top_edge, int mb_to_bottom_edge) +{ + mv->as_mv.col = (mv->as_mv.col < mb_to_left_edge) ? + mb_to_left_edge : mv->as_mv.col; + mv->as_mv.col = (mv->as_mv.col > mb_to_right_edge) ? + mb_to_right_edge : mv->as_mv.col; + mv->as_mv.row = (mv->as_mv.row < mb_to_top_edge) ? + mb_to_top_edge : mv->as_mv.row; + mv->as_mv.row = (mv->as_mv.row > mb_to_bottom_edge) ? + mb_to_bottom_edge : mv->as_mv.row; +} +static unsigned int vp8_check_mv_bounds(int_mv *mv, int mb_to_left_edge, + int mb_to_right_edge, int mb_to_top_edge, + int mb_to_bottom_edge) +{ + unsigned int need_to_clamp; + need_to_clamp = (mv->as_mv.col < mb_to_left_edge); + need_to_clamp |= (mv->as_mv.col > mb_to_right_edge); + need_to_clamp |= (mv->as_mv.row < mb_to_top_edge); + need_to_clamp |= (mv->as_mv.row > mb_to_bottom_edge); + return need_to_clamp; +} + +void vp8_find_near_mvs +( + MACROBLOCKD *xd, + const MODE_INFO *here, + int_mv *nearest, int_mv *nearby, int_mv *best, + int near_mv_ref_cts[4], + int refframe, + int *ref_frame_sign_bias +); + + +int vp8_find_near_mvs_bias +( + MACROBLOCKD *xd, + const MODE_INFO *here, + int_mv mode_mv_sb[2][MB_MODE_COUNT], + int_mv best_mv_sb[2], + int cnt[4], + int refframe, + int *ref_frame_sign_bias +); + + +vp8_prob *vp8_mv_ref_probs( + vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] +); + +extern const unsigned char vp8_mbsplit_offset[4][16]; + + +static int left_block_mv(const MODE_INFO *cur_mb, int b) +{ + if (!(b & 3)) + { + /* On L edge, get from MB to left of us */ + --cur_mb; + + if(cur_mb->mbmi.mode != SPLITMV) + return cur_mb->mbmi.mv.as_int; + b += 4; + } + + return (cur_mb->bmi + b - 1)->mv.as_int; +} + +static int above_block_mv(const MODE_INFO *cur_mb, int b, int mi_stride) +{ + if (!(b >> 2)) + { + /* On top edge, get from MB above us */ + cur_mb -= mi_stride; + + if(cur_mb->mbmi.mode != SPLITMV) + return cur_mb->mbmi.mv.as_int; + b += 16; + } + + return (cur_mb->bmi + b - 4)->mv.as_int; +} +static B_PREDICTION_MODE left_block_mode(const MODE_INFO *cur_mb, int b) +{ + if (!(b & 3)) + { + /* On L edge, get from MB to left of us */ + --cur_mb; + switch (cur_mb->mbmi.mode) + { + case B_PRED: + return (cur_mb->bmi + b + 3)->as_mode; + case DC_PRED: + return B_DC_PRED; + case V_PRED: + return B_VE_PRED; + case H_PRED: + return B_HE_PRED; + case TM_PRED: + return B_TM_PRED; + default: + return B_DC_PRED; + } + } + + return (cur_mb->bmi + b - 1)->as_mode; +} + +static B_PREDICTION_MODE above_block_mode(const MODE_INFO *cur_mb, int b, int mi_stride) +{ + if (!(b >> 2)) + { + /* On top edge, get from MB above us */ + cur_mb -= mi_stride; + + switch (cur_mb->mbmi.mode) + { + case B_PRED: + return (cur_mb->bmi + b + 12)->as_mode; + case DC_PRED: + return B_DC_PRED; + case V_PRED: + return B_VE_PRED; + case H_PRED: + return B_HE_PRED; + case TM_PRED: + return B_TM_PRED; + default: + return B_DC_PRED; + } + } + + return (cur_mb->bmi + b - 4)->as_mode; +} + +#endif diff --git a/vp8/common/generic/systemdependent.c b/vp8/common/generic/systemdependent.c new file mode 100644 index 0000000..2a30166 --- /dev/null +++ b/vp8/common/generic/systemdependent.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#if ARCH_ARM +#include "vpx_ports/arm.h" +#elif ARCH_X86 || ARCH_X86_64 +#include "vpx_ports/x86.h" +#endif +#include "vp8/common/onyxc_int.h" + +#if CONFIG_MULTITHREAD +#if HAVE_UNISTD_H && !defined(__OS2__) +#include +#elif defined(_WIN32) +#include +typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); +#elif defined(__OS2__) +#define INCL_DOS +#define INCL_DOSSPINLOCK +#include +#endif +#endif + +#if CONFIG_MULTITHREAD +static int get_cpu_count() +{ + int core_count = 16; + +#if HAVE_UNISTD_H && !defined(__OS2__) +#if defined(_SC_NPROCESSORS_ONLN) + core_count = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_SC_NPROC_ONLN) + core_count = sysconf(_SC_NPROC_ONLN); +#endif +#elif defined(_WIN32) + { + PGNSI pGNSI; + SYSTEM_INFO sysinfo; + + /* Call GetNativeSystemInfo if supported or + * GetSystemInfo otherwise. */ + + pGNSI = (PGNSI) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); + if (pGNSI != NULL) + pGNSI(&sysinfo); + else + GetSystemInfo(&sysinfo); + + core_count = sysinfo.dwNumberOfProcessors; + } +#elif defined(__OS2__) + { + ULONG proc_id; + ULONG status; + + core_count = 0; + for (proc_id = 1; ; proc_id++) + { + if (DosGetProcessorStatus(proc_id, &status)) + break; + + if (status == PROC_ONLINE) + core_count++; + } + } +#else + /* other platforms */ +#endif + + return core_count > 0 ? core_count : 1; +} +#endif + + +#if HAVE_PTHREAD_H +#include +static void once(void (*func)(void)) +{ + static pthread_once_t lock = PTHREAD_ONCE_INIT; + pthread_once(&lock, func); +} + + +#elif defined(_WIN32) +static void once(void (*func)(void)) +{ + /* Using a static initializer here rather than InitializeCriticalSection() + * since there's no race-free context in which to execute it. Protecting + * it with an atomic op like InterlockedCompareExchangePointer introduces + * an x86 dependency, and InitOnceExecuteOnce requires Vista. + */ + static CRITICAL_SECTION lock = {(void *)-1, -1, 0, 0, 0, 0}; + static int done; + + EnterCriticalSection(&lock); + + if (!done) + { + func(); + done = 1; + } + + LeaveCriticalSection(&lock); +} + + +#else +/* No-op version that performs no synchronization. vpx_rtcd() is idempotent, + * so as long as your platform provides atomic loads/stores of pointers + * no synchronization is strictly necessary. + */ + +static void once(void (*func)(void)) +{ + static int done; + + if(!done) + { + func(); + done = 1; + } +} +#endif + + +void vp8_machine_specific_config(VP8_COMMON *ctx) +{ +#if CONFIG_MULTITHREAD + ctx->processor_core_count = get_cpu_count(); +#endif /* CONFIG_MULTITHREAD */ + +#if ARCH_ARM + ctx->cpu_caps = arm_cpu_caps(); +#elif ARCH_X86 || ARCH_X86_64 + ctx->cpu_caps = x86_simd_caps(); +#endif + + once(vpx_rtcd); +} diff --git a/vp8/common/header.h b/vp8/common/header.h new file mode 100644 index 0000000..3e98eeb --- /dev/null +++ b/vp8/common/header.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_HEADER_H +#define __INC_HEADER_H + +/* 24 bits total */ +typedef struct +{ + unsigned int type: 1; + unsigned int version: 3; + unsigned int show_frame: 1; + + /* Allow 2^20 bytes = 8 megabits for first partition */ + + unsigned int first_partition_length_in_bytes: 19; + +#ifdef PACKET_TESTING + unsigned int frame_number; + unsigned int update_gold: 1; + unsigned int uses_gold: 1; + unsigned int update_last: 1; + unsigned int uses_last: 1; +#endif + +} VP8_HEADER; + +#ifdef PACKET_TESTING +#define VP8_HEADER_SIZE 8 +#else +#define VP8_HEADER_SIZE 3 +#endif + + +#endif diff --git a/vp8/common/idct_blk.c b/vp8/common/idct_blk.c new file mode 100644 index 0000000..0b058c7 --- /dev/null +++ b/vp8/common/idct_blk.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" + +void vp8_dequant_idct_add_c(short *input, short *dq, + unsigned char *dest, int stride); +void vp8_dc_only_idct_add_c(short input_dc, unsigned char * pred, + int pred_stride, unsigned char *dst_ptr, + int dst_stride); + +void vp8_dequant_idct_add_y_block_c + (short *q, short *dq, + unsigned char *dst, int stride, char *eobs) +{ + int i, j; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + if (*eobs++ > 1) + vp8_dequant_idct_add_c (q, dq, dst, stride); + else + { + vp8_dc_only_idct_add_c (q[0]*dq[0], dst, stride, dst, stride); + ((int *)q)[0] = 0; + } + + q += 16; + dst += 4; + } + + dst += 4*stride - 16; + } +} + +void vp8_dequant_idct_add_uv_block_c + (short *q, short *dq, + unsigned char *dstu, unsigned char *dstv, int stride, char *eobs) +{ + int i, j; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (*eobs++ > 1) + vp8_dequant_idct_add_c (q, dq, dstu, stride); + else + { + vp8_dc_only_idct_add_c (q[0]*dq[0], dstu, stride, dstu, stride); + ((int *)q)[0] = 0; + } + + q += 16; + dstu += 4; + } + + dstu += 4*stride - 8; + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (*eobs++ > 1) + vp8_dequant_idct_add_c (q, dq, dstv, stride); + else + { + vp8_dc_only_idct_add_c (q[0]*dq[0], dstv, stride, dstv, stride); + ((int *)q)[0] = 0; + } + + q += 16; + dstv += 4; + } + + dstv += 4*stride - 8; + } +} diff --git a/vp8/common/idctllm.c b/vp8/common/idctllm.c new file mode 100644 index 0000000..47af52f --- /dev/null +++ b/vp8/common/idctllm.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** + * Notes: + * + * This implementation makes use of 16 bit fixed point verio of two multiply + * constants: + * 1. sqrt(2) * cos (pi/8) + * 2. sqrt(2) * sin (pi/8) + * Becuase the first constant is bigger than 1, to maintain the same 16 bit + * fixed point precision as the second one, we use a trick of + * x * a = x + x*(a-1) + * so + * x * sqrt(2) * cos (pi/8) = x + x * (sqrt(2) *cos(pi/8)-1). + **************************************************************************/ +static const int cospi8sqrt2minus1 = 20091; +static const int sinpi8sqrt2 = 35468; + +void vp8_short_idct4x4llm_c(short *input, unsigned char *pred_ptr, + int pred_stride, unsigned char *dst_ptr, + int dst_stride) +{ + int i; + int r, c; + int a1, b1, c1, d1; + short output[16]; + short *ip = input; + short *op = output; + int temp1, temp2; + int shortpitch = 4; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[8]; + b1 = ip[0] - ip[8]; + + temp1 = (ip[4] * sinpi8sqrt2) >> 16; + temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16); + c1 = temp1 - temp2; + + temp1 = ip[4] + ((ip[4] * cospi8sqrt2minus1) >> 16); + temp2 = (ip[12] * sinpi8sqrt2) >> 16; + d1 = temp1 + temp2; + + op[shortpitch*0] = a1 + d1; + op[shortpitch*3] = a1 - d1; + + op[shortpitch*1] = b1 + c1; + op[shortpitch*2] = b1 - c1; + + ip++; + op++; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[2]; + b1 = ip[0] - ip[2]; + + temp1 = (ip[1] * sinpi8sqrt2) >> 16; + temp2 = ip[3] + ((ip[3] * cospi8sqrt2minus1) >> 16); + c1 = temp1 - temp2; + + temp1 = ip[1] + ((ip[1] * cospi8sqrt2minus1) >> 16); + temp2 = (ip[3] * sinpi8sqrt2) >> 16; + d1 = temp1 + temp2; + + + op[0] = (a1 + d1 + 4) >> 3; + op[3] = (a1 - d1 + 4) >> 3; + + op[1] = (b1 + c1 + 4) >> 3; + op[2] = (b1 - c1 + 4) >> 3; + + ip += shortpitch; + op += shortpitch; + } + + ip = output; + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = ip[c] + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + ip += 4; + dst_ptr += dst_stride; + pred_ptr += pred_stride; + } +} + +void vp8_dc_only_idct_add_c(short input_dc, unsigned char *pred_ptr, + int pred_stride, unsigned char *dst_ptr, + int dst_stride) +{ + int a1 = ((input_dc + 4) >> 3); + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = a1 + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += dst_stride; + pred_ptr += pred_stride; + } + +} + +void vp8_short_inv_walsh4x4_c(short *input, short *mb_dqcoeff) +{ + short output[16]; + int i; + int a1, b1, c1, d1; + int a2, b2, c2, d2; + short *ip = input; + short *op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[12]; + b1 = ip[4] + ip[8]; + c1 = ip[4] - ip[8]; + d1 = ip[0] - ip[12]; + + op[0] = a1 + b1; + op[4] = c1 + d1; + op[8] = a1 - b1; + op[12] = d1 - c1; + ip++; + op++; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[3]; + b1 = ip[1] + ip[2]; + c1 = ip[1] - ip[2]; + d1 = ip[0] - ip[3]; + + a2 = a1 + b1; + b2 = c1 + d1; + c2 = a1 - b1; + d2 = d1 - c1; + + op[0] = (a2 + 3) >> 3; + op[1] = (b2 + 3) >> 3; + op[2] = (c2 + 3) >> 3; + op[3] = (d2 + 3) >> 3; + + ip += 4; + op += 4; + } + + for(i = 0; i < 16; i++) + { + mb_dqcoeff[i * 16] = output[i]; + } +} + +void vp8_short_inv_walsh4x4_1_c(short *input, short *mb_dqcoeff) +{ + int i; + int a1; + + a1 = ((input[0] + 3) >> 3); + for(i = 0; i < 16; i++) + { + mb_dqcoeff[i * 16] = a1; + } +} diff --git a/vp8/common/idctllm_test.cc b/vp8/common/idctllm_test.cc new file mode 100755 index 0000000..0f6ebe7 --- /dev/null +++ b/vp8/common/idctllm_test.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + + extern "C" { + void vp8_short_idct4x4llm_c(short *input, unsigned char *pred_ptr, + int pred_stride, unsigned char *dst_ptr, + int dst_stride); +} + +#include "vpx_config.h" +#include "idctllm_test.h" +namespace +{ + +INSTANTIATE_TEST_CASE_P(C, IDCTTest, + ::testing::Values(vp8_short_idct4x4llm_c)); + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/vp8/common/idctllm_test.h b/vp8/common/idctllm_test.h new file mode 100755 index 0000000..a6a694b --- /dev/null +++ b/vp8/common/idctllm_test.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + + #include "third_party/googletest/src/include/gtest/gtest.h" +typedef void (*idct_fn_t)(short *input, unsigned char *pred_ptr, + int pred_stride, unsigned char *dst_ptr, + int dst_stride); +namespace { +class IDCTTest : public ::testing::TestWithParam +{ + protected: + virtual void SetUp() + { + int i; + + UUT = GetParam(); + memset(input, 0, sizeof(input)); + /* Set up guard blocks */ + for(i=0; i<256; i++) + output[i] = ((i&0xF)<4&&(i<64))?0:-1; + } + + idct_fn_t UUT; + short input[16]; + unsigned char output[256]; + unsigned char predict[256]; +}; + +TEST_P(IDCTTest, TestGuardBlocks) +{ + int i; + + for(i=0; i<256; i++) + if((i&0xF) < 4 && i<64) + EXPECT_EQ(0, output[i]) << i; + else + EXPECT_EQ(255, output[i]); +} + +TEST_P(IDCTTest, TestAllZeros) +{ + int i; + + UUT(input, output, 16, output, 16); + + for(i=0; i<256; i++) + if((i&0xF) < 4 && i<64) + EXPECT_EQ(0, output[i]) << "i==" << i; + else + EXPECT_EQ(255, output[i]) << "i==" << i; +} + +TEST_P(IDCTTest, TestAllOnes) +{ + int i; + + input[0] = 4; + UUT(input, output, 16, output, 16); + + for(i=0; i<256; i++) + if((i&0xF) < 4 && i<64) + EXPECT_EQ(1, output[i]) << "i==" << i; + else + EXPECT_EQ(255, output[i]) << "i==" << i; +} + +TEST_P(IDCTTest, TestAddOne) +{ + int i; + + for(i=0; i<256; i++) + predict[i] = i; + + input[0] = 4; + UUT(input, predict, 16, output, 16); + + for(i=0; i<256; i++) + if((i&0xF) < 4 && i<64) + EXPECT_EQ(i+1, output[i]) << "i==" << i; + else + EXPECT_EQ(255, output[i]) << "i==" << i; +} + +TEST_P(IDCTTest, TestWithData) +{ + int i; + + for(i=0; i<16; i++) + input[i] = i; + + UUT(input, output, 16, output, 16); + + for(i=0; i<256; i++) + if((i&0xF) > 3 || i>63) + EXPECT_EQ(255, output[i]) << "i==" << i; + else if(i == 0) + EXPECT_EQ(11, output[i]) << "i==" << i; + else if(i == 34) + EXPECT_EQ(1, output[i]) << "i==" << i; + else if(i == 2 || i == 17 || i == 32) + EXPECT_EQ(3, output[i]) << "i==" << i; + else + EXPECT_EQ(0, output[i]) << "i==" << i; +} +} diff --git a/vp8/common/invtrans.h b/vp8/common/invtrans.h new file mode 100644 index 0000000..d048665 --- /dev/null +++ b/vp8/common/invtrans.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_INVTRANS_H +#define __INC_INVTRANS_H + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "blockd.h" +#include "onyxc_int.h" + +#if CONFIG_MULTITHREAD +#include "vpx_mem/vpx_mem.h" +#endif + +static void eob_adjust(char *eobs, short *diff) +{ + /* eob adjust.... the idct can only skip if both the dc and eob are zero */ + int js; + for(js = 0; js < 16; js++) + { + if((eobs[js] == 0) && (diff[0] != 0)) + eobs[js]++; + diff+=16; + } +} + +static void vp8_inverse_transform_mby(MACROBLOCKD *xd) +{ + short *DQC = xd->dequant_y1; + + if (xd->mode_info_context->mbmi.mode != SPLITMV) + { + /* do 2nd order transform on the dc block */ + if (xd->eobs[24] > 1) + { + vp8_short_inv_walsh4x4 + (&xd->block[24].dqcoeff[0], xd->qcoeff); + } + else + { + vp8_short_inv_walsh4x4_1 + (&xd->block[24].dqcoeff[0], xd->qcoeff); + } + eob_adjust(xd->eobs, xd->qcoeff); + + DQC = xd->dequant_y1_dc; + } + vp8_dequant_idct_add_y_block + (xd->qcoeff, DQC, + xd->dst.y_buffer, + xd->dst.y_stride, xd->eobs); +} +#endif diff --git a/vp8/common/loopfilter.c b/vp8/common/loopfilter.c new file mode 100644 index 0000000..3f05efe --- /dev/null +++ b/vp8/common/loopfilter.c @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "loopfilter.h" +#include "onyxc_int.h" +#include "vpx_mem/vpx_mem.h" + +typedef unsigned char uc; + +static void lf_init_lut(loop_filter_info_n *lfi) +{ + int filt_lvl; + + for (filt_lvl = 0; filt_lvl <= MAX_LOOP_FILTER; filt_lvl++) + { + if (filt_lvl >= 40) + { + lfi->hev_thr_lut[KEY_FRAME][filt_lvl] = 2; + lfi->hev_thr_lut[INTER_FRAME][filt_lvl] = 3; + } + else if (filt_lvl >= 20) + { + lfi->hev_thr_lut[KEY_FRAME][filt_lvl] = 1; + lfi->hev_thr_lut[INTER_FRAME][filt_lvl] = 2; + } + else if (filt_lvl >= 15) + { + lfi->hev_thr_lut[KEY_FRAME][filt_lvl] = 1; + lfi->hev_thr_lut[INTER_FRAME][filt_lvl] = 1; + } + else + { + lfi->hev_thr_lut[KEY_FRAME][filt_lvl] = 0; + lfi->hev_thr_lut[INTER_FRAME][filt_lvl] = 0; + } + } + + lfi->mode_lf_lut[DC_PRED] = 1; + lfi->mode_lf_lut[V_PRED] = 1; + lfi->mode_lf_lut[H_PRED] = 1; + lfi->mode_lf_lut[TM_PRED] = 1; + lfi->mode_lf_lut[B_PRED] = 0; + + lfi->mode_lf_lut[ZEROMV] = 1; + lfi->mode_lf_lut[NEARESTMV] = 2; + lfi->mode_lf_lut[NEARMV] = 2; + lfi->mode_lf_lut[NEWMV] = 2; + lfi->mode_lf_lut[SPLITMV] = 3; + +} + +void vp8_loop_filter_update_sharpness(loop_filter_info_n *lfi, + int sharpness_lvl) +{ + int i; + + /* For each possible value for the loop filter fill out limits */ + for (i = 0; i <= MAX_LOOP_FILTER; i++) + { + int filt_lvl = i; + int block_inside_limit = 0; + + /* Set loop filter paramaeters that control sharpness. */ + block_inside_limit = filt_lvl >> (sharpness_lvl > 0); + block_inside_limit = block_inside_limit >> (sharpness_lvl > 4); + + if (sharpness_lvl > 0) + { + if (block_inside_limit > (9 - sharpness_lvl)) + block_inside_limit = (9 - sharpness_lvl); + } + + if (block_inside_limit < 1) + block_inside_limit = 1; + + vpx_memset(lfi->lim[i], block_inside_limit, SIMD_WIDTH); + vpx_memset(lfi->blim[i], (2 * filt_lvl + block_inside_limit), + SIMD_WIDTH); + vpx_memset(lfi->mblim[i], (2 * (filt_lvl + 2) + block_inside_limit), + SIMD_WIDTH); + } +} + +void vp8_loop_filter_init(VP8_COMMON *cm) +{ + loop_filter_info_n *lfi = &cm->lf_info; + int i; + + /* init limits for given sharpness*/ + vp8_loop_filter_update_sharpness(lfi, cm->sharpness_level); + cm->last_sharpness_level = cm->sharpness_level; + + /* init LUT for lvl and hev thr picking */ + lf_init_lut(lfi); + + /* init hev threshold const vectors */ + for(i = 0; i < 4 ; i++) + { + vpx_memset(lfi->hev_thr[i], i, SIMD_WIDTH); + } +} + +void vp8_loop_filter_frame_init(VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl) +{ + int seg, /* segment number */ + ref, /* index in ref_lf_deltas */ + mode; /* index in mode_lf_deltas */ + + loop_filter_info_n *lfi = &cm->lf_info; + + /* update limits if sharpness has changed */ + if(cm->last_sharpness_level != cm->sharpness_level) + { + vp8_loop_filter_update_sharpness(lfi, cm->sharpness_level); + cm->last_sharpness_level = cm->sharpness_level; + } + + for(seg = 0; seg < MAX_MB_SEGMENTS; seg++) + { + int lvl_seg = default_filt_lvl; + int lvl_ref, lvl_mode; + + /* Note the baseline filter values for each segment */ + if (mbd->segmentation_enabled) + { + /* Abs value */ + if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + { + lvl_seg = mbd->segment_feature_data[MB_LVL_ALT_LF][seg]; + } + else /* Delta Value */ + { + lvl_seg += mbd->segment_feature_data[MB_LVL_ALT_LF][seg]; + lvl_seg = (lvl_seg > 0) ? ((lvl_seg > 63) ? 63: lvl_seg) : 0; + } + } + + if (!mbd->mode_ref_lf_delta_enabled) + { + /* we could get rid of this if we assume that deltas are set to + * zero when not in use; encoder always uses deltas + */ + vpx_memset(lfi->lvl[seg][0], lvl_seg, 4 * 4 ); + continue; + } + + lvl_ref = lvl_seg; + + /* INTRA_FRAME */ + ref = INTRA_FRAME; + + /* Apply delta for reference frame */ + lvl_ref += mbd->ref_lf_deltas[ref]; + + /* Apply delta for Intra modes */ + mode = 0; /* B_PRED */ + /* Only the split mode BPRED has a further special case */ + lvl_mode = lvl_ref + mbd->mode_lf_deltas[mode]; + lvl_mode = (lvl_mode > 0) ? (lvl_mode > 63 ? 63 : lvl_mode) : 0; /* clamp */ + + lfi->lvl[seg][ref][mode] = lvl_mode; + + mode = 1; /* all the rest of Intra modes */ + lvl_mode = (lvl_ref > 0) ? (lvl_ref > 63 ? 63 : lvl_ref) : 0; /* clamp */ + lfi->lvl[seg][ref][mode] = lvl_mode; + + /* LAST, GOLDEN, ALT */ + for(ref = 1; ref < MAX_REF_FRAMES; ref++) + { + int lvl_ref = lvl_seg; + + /* Apply delta for reference frame */ + lvl_ref += mbd->ref_lf_deltas[ref]; + + /* Apply delta for Inter modes */ + for (mode = 1; mode < 4; mode++) + { + lvl_mode = lvl_ref + mbd->mode_lf_deltas[mode]; + lvl_mode = (lvl_mode > 0) ? (lvl_mode > 63 ? 63 : lvl_mode) : 0; /* clamp */ + + lfi->lvl[seg][ref][mode] = lvl_mode; + } + } + } +} + +void vp8_loop_filter_frame +( + VP8_COMMON *cm, + MACROBLOCKD *mbd +) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + loop_filter_info_n *lfi_n = &cm->lf_info; + loop_filter_info lfi; + + FRAME_TYPE frame_type = cm->frame_type; + + int mb_row; + int mb_col; + int mb_rows = cm->mb_rows; + int mb_cols = cm->mb_cols; + + int filter_level; + + unsigned char *y_ptr, *u_ptr, *v_ptr; + + /* Point at base of Mb MODE_INFO list */ + const MODE_INFO *mode_info_context = cm->mi; + int post_y_stride = post->y_stride; + int post_uv_stride = post->uv_stride; + + /* Initialize the loop filter for this frame. */ + vp8_loop_filter_frame_init(cm, mbd, cm->filter_level); + + /* Set up the buffer pointers */ + y_ptr = post->y_buffer; + u_ptr = post->u_buffer; + v_ptr = post->v_buffer; + + /* vp8_filter each macro block */ + if (cm->filter_type == NORMAL_LOOPFILTER) + { + for (mb_row = 0; mb_row < mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < mb_cols; mb_col++) + { + int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != SPLITMV && + mode_info_context->mbmi.mb_skip_coeff); + + const int mode_index = lfi_n->mode_lf_lut[mode_info_context->mbmi.mode]; + const int seg = mode_info_context->mbmi.segment_id; + const int ref_frame = mode_info_context->mbmi.ref_frame; + + filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; + + if (filter_level) + { + const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level]; + lfi.mblim = lfi_n->mblim[filter_level]; + lfi.blim = lfi_n->blim[filter_level]; + lfi.lim = lfi_n->lim[filter_level]; + lfi.hev_thr = lfi_n->hev_thr[hev_index]; + + if (mb_col > 0) + vp8_loop_filter_mbv + (y_ptr, u_ptr, v_ptr, post_y_stride, post_uv_stride, &lfi); + + if (!skip_lf) + vp8_loop_filter_bv + (y_ptr, u_ptr, v_ptr, post_y_stride, post_uv_stride, &lfi); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_mbh + (y_ptr, u_ptr, v_ptr, post_y_stride, post_uv_stride, &lfi); + + if (!skip_lf) + vp8_loop_filter_bh + (y_ptr, u_ptr, v_ptr, post_y_stride, post_uv_stride, &lfi); + } + + y_ptr += 16; + u_ptr += 8; + v_ptr += 8; + + mode_info_context++; /* step to next MB */ + } + y_ptr += post_y_stride * 16 - post->y_width; + u_ptr += post_uv_stride * 8 - post->uv_width; + v_ptr += post_uv_stride * 8 - post->uv_width; + + mode_info_context++; /* Skip border mb */ + + } + } + else /* SIMPLE_LOOPFILTER */ + { + for (mb_row = 0; mb_row < mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < mb_cols; mb_col++) + { + int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != SPLITMV && + mode_info_context->mbmi.mb_skip_coeff); + + const int mode_index = lfi_n->mode_lf_lut[mode_info_context->mbmi.mode]; + const int seg = mode_info_context->mbmi.segment_id; + const int ref_frame = mode_info_context->mbmi.ref_frame; + + filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; + if (filter_level) + { + const unsigned char * mblim = lfi_n->mblim[filter_level]; + const unsigned char * blim = lfi_n->blim[filter_level]; + + if (mb_col > 0) + vp8_loop_filter_simple_mbv + (y_ptr, post_y_stride, mblim); + + if (!skip_lf) + vp8_loop_filter_simple_bv + (y_ptr, post_y_stride, blim); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_simple_mbh + (y_ptr, post_y_stride, mblim); + + if (!skip_lf) + vp8_loop_filter_simple_bh + (y_ptr, post_y_stride, blim); + } + + y_ptr += 16; + u_ptr += 8; + v_ptr += 8; + + mode_info_context++; /* step to next MB */ + } + y_ptr += post_y_stride * 16 - post->y_width; + u_ptr += post_uv_stride * 8 - post->uv_width; + v_ptr += post_uv_stride * 8 - post->uv_width; + + mode_info_context++; /* Skip border mb */ + + } + } +} + +void vp8_loop_filter_frame_yonly +( + VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl +) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + + unsigned char *y_ptr; + int mb_row; + int mb_col; + + loop_filter_info_n *lfi_n = &cm->lf_info; + loop_filter_info lfi; + + int filter_level; + FRAME_TYPE frame_type = cm->frame_type; + + /* Point at base of Mb MODE_INFO list */ + const MODE_INFO *mode_info_context = cm->mi; + +#if 0 + if(default_filt_lvl == 0) /* no filter applied */ + return; +#endif + + /* Initialize the loop filter for this frame. */ + vp8_loop_filter_frame_init( cm, mbd, default_filt_lvl); + + /* Set up the buffer pointers */ + y_ptr = post->y_buffer; + + /* vp8_filter each macro block */ + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != SPLITMV && + mode_info_context->mbmi.mb_skip_coeff); + + const int mode_index = lfi_n->mode_lf_lut[mode_info_context->mbmi.mode]; + const int seg = mode_info_context->mbmi.segment_id; + const int ref_frame = mode_info_context->mbmi.ref_frame; + + filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; + + if (filter_level) + { + if (cm->filter_type == NORMAL_LOOPFILTER) + { + const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level]; + lfi.mblim = lfi_n->mblim[filter_level]; + lfi.blim = lfi_n->blim[filter_level]; + lfi.lim = lfi_n->lim[filter_level]; + lfi.hev_thr = lfi_n->hev_thr[hev_index]; + + if (mb_col > 0) + vp8_loop_filter_mbv + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + + if (!skip_lf) + vp8_loop_filter_bv + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_mbh + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + + if (!skip_lf) + vp8_loop_filter_bh + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + } + else + { + if (mb_col > 0) + vp8_loop_filter_simple_mbv + (y_ptr, post->y_stride, lfi_n->mblim[filter_level]); + + if (!skip_lf) + vp8_loop_filter_simple_bv + (y_ptr, post->y_stride, lfi_n->blim[filter_level]); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_simple_mbh + (y_ptr, post->y_stride, lfi_n->mblim[filter_level]); + + if (!skip_lf) + vp8_loop_filter_simple_bh + (y_ptr, post->y_stride, lfi_n->blim[filter_level]); + } + } + + y_ptr += 16; + mode_info_context ++; /* step to next MB */ + + } + + y_ptr += post->y_stride * 16 - post->y_width; + mode_info_context ++; /* Skip border mb */ + } + +} + +void vp8_loop_filter_partial_frame +( + VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl +) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + + unsigned char *y_ptr; + int mb_row; + int mb_col; + int mb_cols = post->y_width >> 4; + int mb_rows = post->y_height >> 4; + + int linestocopy, i; + + loop_filter_info_n *lfi_n = &cm->lf_info; + loop_filter_info lfi; + + int filter_level; + int alt_flt_enabled = mbd->segmentation_enabled; + FRAME_TYPE frame_type = cm->frame_type; + + const MODE_INFO *mode_info_context; + + int lvl_seg[MAX_MB_SEGMENTS]; + + /* number of MB rows to use in partial filtering */ + linestocopy = mb_rows / PARTIAL_FRAME_FRACTION; + linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */ + + /* Note the baseline filter values for each segment */ + /* See vp8_loop_filter_frame_init. Rather than call that for each change + * to default_filt_lvl, copy the relevant calculation here. + */ + if (alt_flt_enabled) + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { /* Abs value */ + if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + { + lvl_seg[i] = mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + } + /* Delta Value */ + else + { + lvl_seg[i] = default_filt_lvl + + mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + lvl_seg[i] = (lvl_seg[i] > 0) ? + ((lvl_seg[i] > 63) ? 63: lvl_seg[i]) : 0; + } + } + } + + /* Set up the buffer pointers; partial image starts at ~middle of frame */ + y_ptr = post->y_buffer + ((post->y_height >> 5) * 16) * post->y_stride; + mode_info_context = cm->mi + (post->y_height >> 5) * (mb_cols + 1); + + /* vp8_filter each macro block */ + for (mb_row = 0; mb_row<(linestocopy >> 4); mb_row++) + { + for (mb_col = 0; mb_col < mb_cols; mb_col++) + { + int skip_lf = (mode_info_context->mbmi.mode != B_PRED && + mode_info_context->mbmi.mode != SPLITMV && + mode_info_context->mbmi.mb_skip_coeff); + + if (alt_flt_enabled) + filter_level = lvl_seg[mode_info_context->mbmi.segment_id]; + else + filter_level = default_filt_lvl; + + if (filter_level) + { + if (cm->filter_type == NORMAL_LOOPFILTER) + { + const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level]; + lfi.mblim = lfi_n->mblim[filter_level]; + lfi.blim = lfi_n->blim[filter_level]; + lfi.lim = lfi_n->lim[filter_level]; + lfi.hev_thr = lfi_n->hev_thr[hev_index]; + + if (mb_col > 0) + vp8_loop_filter_mbv + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + + if (!skip_lf) + vp8_loop_filter_bv + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + + vp8_loop_filter_mbh + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + + if (!skip_lf) + vp8_loop_filter_bh + (y_ptr, 0, 0, post->y_stride, 0, &lfi); + } + else + { + if (mb_col > 0) + vp8_loop_filter_simple_mbv + (y_ptr, post->y_stride, lfi_n->mblim[filter_level]); + + if (!skip_lf) + vp8_loop_filter_simple_bv + (y_ptr, post->y_stride, lfi_n->blim[filter_level]); + + vp8_loop_filter_simple_mbh + (y_ptr, post->y_stride, lfi_n->mblim[filter_level]); + + if (!skip_lf) + vp8_loop_filter_simple_bh + (y_ptr, post->y_stride, lfi_n->blim[filter_level]); + } + } + + y_ptr += 16; + mode_info_context += 1; /* step to next MB */ + } + + y_ptr += post->y_stride * 16 - post->y_width; + mode_info_context += 1; /* Skip border mb */ + } +} diff --git a/vp8/common/loopfilter.h b/vp8/common/loopfilter.h new file mode 100644 index 0000000..0fa8375 --- /dev/null +++ b/vp8/common/loopfilter.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef loopfilter_h +#define loopfilter_h + +#include "vpx_ports/mem.h" +#include "vpx_config.h" +#include "vpx_rtcd.h" + +#define MAX_LOOP_FILTER 63 +/* fraction of total macroblock rows to be used in fast filter level picking */ +/* has to be > 2 */ +#define PARTIAL_FRAME_FRACTION 8 + +typedef enum +{ + NORMAL_LOOPFILTER = 0, + SIMPLE_LOOPFILTER = 1 +} LOOPFILTERTYPE; + +#if ARCH_ARM +#define SIMD_WIDTH 1 +#else +#define SIMD_WIDTH 16 +#endif + +/* Need to align this structure so when it is declared and + * passed it can be loaded into vector registers. + */ +typedef struct +{ + DECLARE_ALIGNED(SIMD_WIDTH, unsigned char, mblim[MAX_LOOP_FILTER + 1][SIMD_WIDTH]); + DECLARE_ALIGNED(SIMD_WIDTH, unsigned char, blim[MAX_LOOP_FILTER + 1][SIMD_WIDTH]); + DECLARE_ALIGNED(SIMD_WIDTH, unsigned char, lim[MAX_LOOP_FILTER + 1][SIMD_WIDTH]); + DECLARE_ALIGNED(SIMD_WIDTH, unsigned char, hev_thr[4][SIMD_WIDTH]); + unsigned char lvl[4][4][4]; + unsigned char hev_thr_lut[2][MAX_LOOP_FILTER + 1]; + unsigned char mode_lf_lut[10]; +} loop_filter_info_n; + +typedef struct loop_filter_info +{ + const unsigned char * mblim; + const unsigned char * blim; + const unsigned char * lim; + const unsigned char * hev_thr; +} loop_filter_info; + + +typedef void loop_filter_uvfunction +( + unsigned char *u, /* source pointer */ + int p, /* pitch */ + const unsigned char *blimit, + const unsigned char *limit, + const unsigned char *thresh, + unsigned char *v +); + +/* assorted loopfilter functions which get used elsewhere */ +struct VP8Common; +struct macroblockd; + +void vp8_loop_filter_init(struct VP8Common *cm); + +void vp8_loop_filter_frame_init(struct VP8Common *cm, + struct macroblockd *mbd, + int default_filt_lvl); + +void vp8_loop_filter_frame(struct VP8Common *cm, struct macroblockd *mbd); + +void vp8_loop_filter_partial_frame(struct VP8Common *cm, + struct macroblockd *mbd, + int default_filt_lvl); + +void vp8_loop_filter_frame_yonly(struct VP8Common *cm, + struct macroblockd *mbd, + int default_filt_lvl); + +void vp8_loop_filter_update_sharpness(loop_filter_info_n *lfi, + int sharpness_lvl); + +#endif diff --git a/vp8/common/loopfilter_filters.c b/vp8/common/loopfilter_filters.c new file mode 100644 index 0000000..8235f6e --- /dev/null +++ b/vp8/common/loopfilter_filters.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "loopfilter.h" +#include "onyxc_int.h" + +typedef unsigned char uc; + +static signed char vp8_signed_char_clamp(int t) +{ + t = (t < -128 ? -128 : t); + t = (t > 127 ? 127 : t); + return (signed char) t; +} + + +/* should we apply any filter at all ( 11111111 yes, 00000000 no) */ +static signed char vp8_filter_mask(uc limit, uc blimit, + uc p3, uc p2, uc p1, uc p0, + uc q0, uc q1, uc q2, uc q3) +{ + signed char mask = 0; + mask |= (abs(p3 - p2) > limit); + mask |= (abs(p2 - p1) > limit); + mask |= (abs(p1 - p0) > limit); + mask |= (abs(q1 - q0) > limit); + mask |= (abs(q2 - q1) > limit); + mask |= (abs(q3 - q2) > limit); + mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 > blimit); + return mask - 1; +} + +/* is there high variance internal edge ( 11111111 yes, 00000000 no) */ +static signed char vp8_hevmask(uc thresh, uc p1, uc p0, uc q0, uc q1) +{ + signed char hev = 0; + hev |= (abs(p1 - p0) > thresh) * -1; + hev |= (abs(q1 - q0) > thresh) * -1; + return hev; +} + +static void vp8_filter(signed char mask, uc hev, uc *op1, + uc *op0, uc *oq0, uc *oq1) + +{ + signed char ps0, qs0; + signed char ps1, qs1; + signed char vp8_filter, Filter1, Filter2; + signed char u; + + ps1 = (signed char) * op1 ^ 0x80; + ps0 = (signed char) * op0 ^ 0x80; + qs0 = (signed char) * oq0 ^ 0x80; + qs1 = (signed char) * oq1 ^ 0x80; + + /* add outer taps if we have high edge variance */ + vp8_filter = vp8_signed_char_clamp(ps1 - qs1); + vp8_filter &= hev; + + /* inner taps */ + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); + vp8_filter &= mask; + + /* save bottom 3 bits so that we round one side +4 and the other +3 + * if it equals 4 we'll set to adjust by -1 to account for the fact + * we'd round 3 the other way + */ + Filter1 = vp8_signed_char_clamp(vp8_filter + 4); + Filter2 = vp8_signed_char_clamp(vp8_filter + 3); + Filter1 >>= 3; + Filter2 >>= 3; + u = vp8_signed_char_clamp(qs0 - Filter1); + *oq0 = u ^ 0x80; + u = vp8_signed_char_clamp(ps0 + Filter2); + *op0 = u ^ 0x80; + vp8_filter = Filter1; + + /* outer tap adjustments */ + vp8_filter += 1; + vp8_filter >>= 1; + vp8_filter &= ~hev; + + u = vp8_signed_char_clamp(qs1 - vp8_filter); + *oq1 = u ^ 0x80; + u = vp8_signed_char_clamp(ps1 + vp8_filter); + *op1 = u ^ 0x80; + +} +void vp8_loop_filter_horizontal_edge_c +( + unsigned char *s, + int p, /* pitch */ + const unsigned char *blimit, + const unsigned char *limit, + const unsigned char *thresh, + int count +) +{ + int hev = 0; /* high edge variance */ + signed char mask = 0; + int i = 0; + + /* loop filter designed to work using chars so that we can make maximum use + * of 8 bit simd instructions. + */ + do + { + mask = vp8_filter_mask(limit[0], blimit[0], + s[-4*p], s[-3*p], s[-2*p], s[-1*p], + s[0*p], s[1*p], s[2*p], s[3*p]); + + hev = vp8_hevmask(thresh[0], s[-2*p], s[-1*p], s[0*p], s[1*p]); + + vp8_filter(mask, hev, s - 2 * p, s - 1 * p, s, s + 1 * p); + + ++s; + } + while (++i < count * 8); +} + +void vp8_loop_filter_vertical_edge_c +( + unsigned char *s, + int p, + const unsigned char *blimit, + const unsigned char *limit, + const unsigned char *thresh, + int count +) +{ + int hev = 0; /* high edge variance */ + signed char mask = 0; + int i = 0; + + /* loop filter designed to work using chars so that we can make maximum use + * of 8 bit simd instructions. + */ + do + { + mask = vp8_filter_mask(limit[0], blimit[0], + s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]); + + hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]); + + vp8_filter(mask, hev, s - 2, s - 1, s, s + 1); + + s += p; + } + while (++i < count * 8); +} + +static void vp8_mbfilter(signed char mask, uc hev, + uc *op2, uc *op1, uc *op0, uc *oq0, uc *oq1, uc *oq2) +{ + signed char s, u; + signed char vp8_filter, Filter1, Filter2; + signed char ps2 = (signed char) * op2 ^ 0x80; + signed char ps1 = (signed char) * op1 ^ 0x80; + signed char ps0 = (signed char) * op0 ^ 0x80; + signed char qs0 = (signed char) * oq0 ^ 0x80; + signed char qs1 = (signed char) * oq1 ^ 0x80; + signed char qs2 = (signed char) * oq2 ^ 0x80; + + /* add outer taps if we have high edge variance */ + vp8_filter = vp8_signed_char_clamp(ps1 - qs1); + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); + vp8_filter &= mask; + + Filter2 = vp8_filter; + Filter2 &= hev; + + /* save bottom 3 bits so that we round one side +4 and the other +3 */ + Filter1 = vp8_signed_char_clamp(Filter2 + 4); + Filter2 = vp8_signed_char_clamp(Filter2 + 3); + Filter1 >>= 3; + Filter2 >>= 3; + qs0 = vp8_signed_char_clamp(qs0 - Filter1); + ps0 = vp8_signed_char_clamp(ps0 + Filter2); + + + /* only apply wider filter if not high edge variance */ + vp8_filter &= ~hev; + Filter2 = vp8_filter; + + /* roughly 3/7th difference across boundary */ + u = vp8_signed_char_clamp((63 + Filter2 * 27) >> 7); + s = vp8_signed_char_clamp(qs0 - u); + *oq0 = s ^ 0x80; + s = vp8_signed_char_clamp(ps0 + u); + *op0 = s ^ 0x80; + + /* roughly 2/7th difference across boundary */ + u = vp8_signed_char_clamp((63 + Filter2 * 18) >> 7); + s = vp8_signed_char_clamp(qs1 - u); + *oq1 = s ^ 0x80; + s = vp8_signed_char_clamp(ps1 + u); + *op1 = s ^ 0x80; + + /* roughly 1/7th difference across boundary */ + u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7); + s = vp8_signed_char_clamp(qs2 - u); + *oq2 = s ^ 0x80; + s = vp8_signed_char_clamp(ps2 + u); + *op2 = s ^ 0x80; +} + +void vp8_mbloop_filter_horizontal_edge_c +( + unsigned char *s, + int p, + const unsigned char *blimit, + const unsigned char *limit, + const unsigned char *thresh, + int count +) +{ + signed char hev = 0; /* high edge variance */ + signed char mask = 0; + int i = 0; + + /* loop filter designed to work using chars so that we can make maximum use + * of 8 bit simd instructions. + */ + do + { + + mask = vp8_filter_mask(limit[0], blimit[0], + s[-4*p], s[-3*p], s[-2*p], s[-1*p], + s[0*p], s[1*p], s[2*p], s[3*p]); + + hev = vp8_hevmask(thresh[0], s[-2*p], s[-1*p], s[0*p], s[1*p]); + + vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p); + + ++s; + } + while (++i < count * 8); + +} + + +void vp8_mbloop_filter_vertical_edge_c +( + unsigned char *s, + int p, + const unsigned char *blimit, + const unsigned char *limit, + const unsigned char *thresh, + int count +) +{ + signed char hev = 0; /* high edge variance */ + signed char mask = 0; + int i = 0; + + do + { + + mask = vp8_filter_mask(limit[0], blimit[0], + s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]); + + hev = vp8_hevmask(thresh[0], s[-2], s[-1], s[0], s[1]); + + vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2); + + s += p; + } + while (++i < count * 8); + +} + +/* should we apply any filter at all ( 11111111 yes, 00000000 no) */ +static signed char vp8_simple_filter_mask(uc blimit, uc p1, uc p0, uc q0, uc q1) +{ +/* Why does this cause problems for win32? + * error C2143: syntax error : missing ';' before 'type' + * (void) limit; + */ + signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 <= blimit) * -1; + return mask; +} + +static void vp8_simple_filter(signed char mask, uc *op1, uc *op0, uc *oq0, uc *oq1) +{ + signed char vp8_filter, Filter1, Filter2; + signed char p1 = (signed char) * op1 ^ 0x80; + signed char p0 = (signed char) * op0 ^ 0x80; + signed char q0 = (signed char) * oq0 ^ 0x80; + signed char q1 = (signed char) * oq1 ^ 0x80; + signed char u; + + vp8_filter = vp8_signed_char_clamp(p1 - q1); + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (q0 - p0)); + vp8_filter &= mask; + + /* save bottom 3 bits so that we round one side +4 and the other +3 */ + Filter1 = vp8_signed_char_clamp(vp8_filter + 4); + Filter1 >>= 3; + u = vp8_signed_char_clamp(q0 - Filter1); + *oq0 = u ^ 0x80; + + Filter2 = vp8_signed_char_clamp(vp8_filter + 3); + Filter2 >>= 3; + u = vp8_signed_char_clamp(p0 + Filter2); + *op0 = u ^ 0x80; +} + +void vp8_loop_filter_simple_horizontal_edge_c +( + unsigned char *s, + int p, + const unsigned char *blimit +) +{ + signed char mask = 0; + int i = 0; + + do + { + mask = vp8_simple_filter_mask(blimit[0], s[-2*p], s[-1*p], s[0*p], s[1*p]); + vp8_simple_filter(mask, s - 2 * p, s - 1 * p, s, s + 1 * p); + ++s; + } + while (++i < 16); +} + +void vp8_loop_filter_simple_vertical_edge_c +( + unsigned char *s, + int p, + const unsigned char *blimit +) +{ + signed char mask = 0; + int i = 0; + + do + { + mask = vp8_simple_filter_mask(blimit[0], s[-2], s[-1], s[0], s[1]); + vp8_simple_filter(mask, s - 2, s - 1, s, s + 1); + s += p; + } + while (++i < 16); + +} + +/* Horizontal MB filtering */ +void vp8_loop_filter_mbh_c(unsigned char *y_ptr, unsigned char *u_ptr, + unsigned char *v_ptr, int y_stride, int uv_stride, + loop_filter_info *lfi) +{ + vp8_mbloop_filter_horizontal_edge_c(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_c(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_c(v_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); +} + +/* Vertical MB Filtering */ +void vp8_loop_filter_mbv_c(unsigned char *y_ptr, unsigned char *u_ptr, + unsigned char *v_ptr, int y_stride, int uv_stride, + loop_filter_info *lfi) +{ + vp8_mbloop_filter_vertical_edge_c(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_c(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_c(v_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); +} + +/* Horizontal B Filtering */ +void vp8_loop_filter_bh_c(unsigned char *y_ptr, unsigned char *u_ptr, + unsigned char *v_ptr, int y_stride, int uv_stride, + loop_filter_info *lfi) +{ + vp8_loop_filter_horizontal_edge_c(y_ptr + 4 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_horizontal_edge_c(y_ptr + 8 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_horizontal_edge_c(y_ptr + 12 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_c(u_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_c(v_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); +} + +void vp8_loop_filter_bhs_c(unsigned char *y_ptr, int y_stride, + const unsigned char *blimit) +{ + vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 4 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 8 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 12 * y_stride, y_stride, blimit); +} + +/* Vertical B Filtering */ +void vp8_loop_filter_bv_c(unsigned char *y_ptr, unsigned char *u_ptr, + unsigned char *v_ptr, int y_stride, int uv_stride, + loop_filter_info *lfi) +{ + vp8_loop_filter_vertical_edge_c(y_ptr + 4, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_vertical_edge_c(y_ptr + 8, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_vertical_edge_c(y_ptr + 12, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_c(u_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_c(v_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); +} + +void vp8_loop_filter_bvs_c(unsigned char *y_ptr, int y_stride, + const unsigned char *blimit) +{ + vp8_loop_filter_simple_vertical_edge_c(y_ptr + 4, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_c(y_ptr + 8, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_c(y_ptr + 12, y_stride, blimit); +} diff --git a/vp8/common/mbpitch.c b/vp8/common/mbpitch.c new file mode 100644 index 0000000..32e1b66 --- /dev/null +++ b/vp8/common/mbpitch.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "blockd.h" + +void vp8_setup_block_dptrs(MACROBLOCKD *x) +{ + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + x->block[r*4+c].predictor = x->predictor + r * 4 * 16 + c * 4; + } + } + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[16+r*2+c].predictor = x->predictor + 256 + r * 4 * 8 + c * 4; + + } + } + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[20+r*2+c].predictor = x->predictor + 320 + r * 4 * 8 + c * 4; + + } + } + + for (r = 0; r < 25; r++) + { + x->block[r].qcoeff = x->qcoeff + r * 16; + x->block[r].dqcoeff = x->dqcoeff + r * 16; + x->block[r].eob = x->eobs + r; + } +} + +void vp8_build_block_doffsets(MACROBLOCKD *x) +{ + int block; + + for (block = 0; block < 16; block++) /* y blocks */ + { + x->block[block].offset = + (block >> 2) * 4 * x->dst.y_stride + (block & 3) * 4; + } + + for (block = 16; block < 20; block++) /* U and V blocks */ + { + x->block[block+4].offset = + x->block[block].offset = + ((block - 16) >> 1) * 4 * x->dst.uv_stride + (block & 1) * 4; + } +} diff --git a/vp8/common/mfqe.c b/vp8/common/mfqe.c new file mode 100644 index 0000000..ca67e91 --- /dev/null +++ b/vp8/common/mfqe.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* MFQE: Multiframe Quality Enhancement + * In rate limited situations keyframes may cause significant visual artifacts + * commonly referred to as "popping." This file implements a postproccesing + * algorithm which blends data from the preceeding frame when there is no + * motion and the q from the previous frame is lower which indicates that it is + * higher quality. + */ + +#include "postproc.h" +#include "variance.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_rtcd.h" +#include "vpx_scale/yv12config.h" + +#include +#include + +static void filter_by_weight(unsigned char *src, int src_stride, + unsigned char *dst, int dst_stride, + int block_size, int src_weight) +{ + int dst_weight = (1 << MFQE_PRECISION) - src_weight; + int rounding_bit = 1 << (MFQE_PRECISION - 1); + int r, c; + + for (r = 0; r < block_size; r++) + { + for (c = 0; c < block_size; c++) + { + dst[c] = (src[c] * src_weight + + dst[c] * dst_weight + + rounding_bit) >> MFQE_PRECISION; + } + src += src_stride; + dst += dst_stride; + } +} + +void vp8_filter_by_weight16x16_c(unsigned char *src, int src_stride, + unsigned char *dst, int dst_stride, + int src_weight) +{ + filter_by_weight(src, src_stride, dst, dst_stride, 16, src_weight); +} + +void vp8_filter_by_weight8x8_c(unsigned char *src, int src_stride, + unsigned char *dst, int dst_stride, + int src_weight) +{ + filter_by_weight(src, src_stride, dst, dst_stride, 8, src_weight); +} + +void vp8_filter_by_weight4x4_c(unsigned char *src, int src_stride, + unsigned char *dst, int dst_stride, + int src_weight) +{ + filter_by_weight(src, src_stride, dst, dst_stride, 4, src_weight); +} + +static void apply_ifactor(unsigned char *y_src, + int y_src_stride, + unsigned char *y_dst, + int y_dst_stride, + unsigned char *u_src, + unsigned char *v_src, + int uv_src_stride, + unsigned char *u_dst, + unsigned char *v_dst, + int uv_dst_stride, + int block_size, + int src_weight) +{ + if (block_size == 16) + { + vp8_filter_by_weight16x16(y_src, y_src_stride, y_dst, y_dst_stride, src_weight); + vp8_filter_by_weight8x8(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight); + vp8_filter_by_weight8x8(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight); + } + else /* if (block_size == 8) */ + { + vp8_filter_by_weight8x8(y_src, y_src_stride, y_dst, y_dst_stride, src_weight); + vp8_filter_by_weight4x4(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight); + vp8_filter_by_weight4x4(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight); + } +} + +static unsigned int int_sqrt(unsigned int x) +{ + unsigned int y = x; + unsigned int guess; + int p = 1; + while (y>>=1) p++; + p>>=1; + + guess=0; + while (p>=0) + { + guess |= (1<> 1; + int qdiff = qcurr - qprev; + + int i; + unsigned char *up; + unsigned char *udp; + unsigned char *vp; + unsigned char *vdp; + + unsigned int act, actd, sad, usad, vsad, sse, thr, thrsq, actrisk; + + if (blksize == 16) + { + actd = (vp8_variance16x16(yd, yd_stride, VP8_ZEROS, 0, &sse)+128)>>8; + act = (vp8_variance16x16(y, y_stride, VP8_ZEROS, 0, &sse)+128)>>8; +#ifdef USE_SSD + sad = (vp8_variance16x16(y, y_stride, yd, yd_stride, &sse)); + sad = (sse + 128)>>8; + usad = (vp8_variance8x8(u, uv_stride, ud, uvd_stride, &sse)); + usad = (sse + 32)>>6; + vsad = (vp8_variance8x8(v, uv_stride, vd, uvd_stride, &sse)); + vsad = (sse + 32)>>6; +#else + sad = (vp8_sad16x16(y, y_stride, yd, yd_stride, INT_MAX)+128)>>8; + usad = (vp8_sad8x8(u, uv_stride, ud, uvd_stride, INT_MAX)+32)>>6; + vsad = (vp8_sad8x8(v, uv_stride, vd, uvd_stride, INT_MAX)+32)>>6; +#endif + } + else /* if (blksize == 8) */ + { + actd = (vp8_variance8x8(yd, yd_stride, VP8_ZEROS, 0, &sse)+32)>>6; + act = (vp8_variance8x8(y, y_stride, VP8_ZEROS, 0, &sse)+32)>>6; +#ifdef USE_SSD + sad = (vp8_variance8x8(y, y_stride, yd, yd_stride, &sse)); + sad = (sse + 32)>>6; + usad = (vp8_variance4x4(u, uv_stride, ud, uvd_stride, &sse)); + usad = (sse + 8)>>4; + vsad = (vp8_variance4x4(v, uv_stride, vd, uvd_stride, &sse)); + vsad = (sse + 8)>>4; +#else + sad = (vp8_sad8x8(y, y_stride, yd, yd_stride, INT_MAX)+32)>>6; + usad = (vp8_sad4x4(u, uv_stride, ud, uvd_stride, INT_MAX)+8)>>4; + vsad = (vp8_sad4x4(v, uv_stride, vd, uvd_stride, INT_MAX)+8)>>4; +#endif + } + + actrisk = (actd > act * 5); + + /* thr = qdiff/8 + log2(act) + log4(qprev) */ + thr = (qdiff >> 3); + while (actd >>= 1) thr++; + while (qprev >>= 2) thr++; + +#ifdef USE_SSD + thrsq = thr * thr; + if (sad < thrsq && + /* additional checks for color mismatch and excessive addition of + * high-frequencies */ + 4 * usad < thrsq && 4 * vsad < thrsq && !actrisk) +#else + if (sad < thr && + /* additional checks for color mismatch and excessive addition of + * high-frequencies */ + 2 * usad < thr && 2 * vsad < thr && !actrisk) +#endif + { + int ifactor; +#ifdef USE_SSD + /* TODO: optimize this later to not need sqr root */ + sad = int_sqrt(sad); +#endif + ifactor = (sad << MFQE_PRECISION) / thr; + ifactor >>= (qdiff >> 5); + + if (ifactor) + { + apply_ifactor(y, y_stride, yd, yd_stride, + u, v, uv_stride, + ud, vd, uvd_stride, + blksize, ifactor); + } + } + else /* else implicitly copy from previous frame */ + { + if (blksize == 16) + { + vp8_copy_mem16x16(y, y_stride, yd, yd_stride); + vp8_copy_mem8x8(u, uv_stride, ud, uvd_stride); + vp8_copy_mem8x8(v, uv_stride, vd, uvd_stride); + } + else /* if (blksize == 8) */ + { + vp8_copy_mem8x8(y, y_stride, yd, yd_stride); + for (up = u, udp = ud, i = 0; i < uvblksize; ++i, up += uv_stride, udp += uvd_stride) + vpx_memcpy(udp, up, uvblksize); + for (vp = v, vdp = vd, i = 0; i < uvblksize; ++i, vp += uv_stride, vdp += uvd_stride) + vpx_memcpy(vdp, vp, uvblksize); + } + } +} + +static int qualify_inter_mb(const MODE_INFO *mode_info_context, int *map) +{ + if (mode_info_context->mbmi.mb_skip_coeff) + map[0] = map[1] = map[2] = map[3] = 1; + else if (mode_info_context->mbmi.mode==SPLITMV) + { + static int ndx[4][4] = + { + {0, 1, 4, 5}, + {2, 3, 6, 7}, + {8, 9, 12, 13}, + {10, 11, 14, 15} + }; + int i, j; + for (i=0; i<4; ++i) + { + map[i] = 1; + for (j=0; j<4 && map[j]; ++j) + map[i] &= (mode_info_context->bmi[ndx[i][j]].mv.as_mv.row <= 2 && + mode_info_context->bmi[ndx[i][j]].mv.as_mv.col <= 2); + } + } + else + { + map[0] = map[1] = map[2] = map[3] = + (mode_info_context->mbmi.mode > B_PRED && + abs(mode_info_context->mbmi.mv.as_mv.row) <= 2 && + abs(mode_info_context->mbmi.mv.as_mv.col) <= 2); + } + return (map[0]+map[1]+map[2]+map[3]); +} + +void vp8_multiframe_quality_enhance +( + VP8_COMMON *cm +) +{ + YV12_BUFFER_CONFIG *show = cm->frame_to_show; + YV12_BUFFER_CONFIG *dest = &cm->post_proc_buffer; + + FRAME_TYPE frame_type = cm->frame_type; + /* Point at base of Mb MODE_INFO list has motion vectors etc */ + const MODE_INFO *mode_info_context = cm->mi; + int mb_row; + int mb_col; + int totmap, map[4]; + int qcurr = cm->base_qindex; + int qprev = cm->postproc_state.last_base_qindex; + + unsigned char *y_ptr, *u_ptr, *v_ptr; + unsigned char *yd_ptr, *ud_ptr, *vd_ptr; + + /* Set up the buffer pointers */ + y_ptr = show->y_buffer; + u_ptr = show->u_buffer; + v_ptr = show->v_buffer; + yd_ptr = dest->y_buffer; + ud_ptr = dest->u_buffer; + vd_ptr = dest->v_buffer; + + /* postprocess each macro block */ + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + /* if motion is high there will likely be no benefit */ + if (frame_type == INTER_FRAME) totmap = qualify_inter_mb(mode_info_context, map); + else totmap = (frame_type == KEY_FRAME ? 4 : 0); + if (totmap) + { + if (totmap < 4) + { + int i, j; + for (i=0; i<2; ++i) + for (j=0; j<2; ++j) + { + if (map[i*2+j]) + { + multiframe_quality_enhance_block(8, qcurr, qprev, + y_ptr + 8*(i*show->y_stride+j), + u_ptr + 4*(i*show->uv_stride+j), + v_ptr + 4*(i*show->uv_stride+j), + show->y_stride, + show->uv_stride, + yd_ptr + 8*(i*dest->y_stride+j), + ud_ptr + 4*(i*dest->uv_stride+j), + vd_ptr + 4*(i*dest->uv_stride+j), + dest->y_stride, + dest->uv_stride); + } + else + { + /* copy a 8x8 block */ + int k; + unsigned char *up = u_ptr + 4*(i*show->uv_stride+j); + unsigned char *udp = ud_ptr + 4*(i*dest->uv_stride+j); + unsigned char *vp = v_ptr + 4*(i*show->uv_stride+j); + unsigned char *vdp = vd_ptr + 4*(i*dest->uv_stride+j); + vp8_copy_mem8x8(y_ptr + 8*(i*show->y_stride+j), show->y_stride, + yd_ptr + 8*(i*dest->y_stride+j), dest->y_stride); + for (k = 0; k < 4; ++k, up += show->uv_stride, udp += dest->uv_stride, + vp += show->uv_stride, vdp += dest->uv_stride) + { + vpx_memcpy(udp, up, 4); + vpx_memcpy(vdp, vp, 4); + } + } + } + } + else /* totmap = 4 */ + { + multiframe_quality_enhance_block(16, qcurr, qprev, y_ptr, + u_ptr, v_ptr, + show->y_stride, + show->uv_stride, + yd_ptr, ud_ptr, vd_ptr, + dest->y_stride, + dest->uv_stride); + } + } + else + { + vp8_copy_mem16x16(y_ptr, show->y_stride, yd_ptr, dest->y_stride); + vp8_copy_mem8x8(u_ptr, show->uv_stride, ud_ptr, dest->uv_stride); + vp8_copy_mem8x8(v_ptr, show->uv_stride, vd_ptr, dest->uv_stride); + } + y_ptr += 16; + u_ptr += 8; + v_ptr += 8; + yd_ptr += 16; + ud_ptr += 8; + vd_ptr += 8; + mode_info_context++; /* step to next MB */ + } + + y_ptr += show->y_stride * 16 - 16 * cm->mb_cols; + u_ptr += show->uv_stride * 8 - 8 * cm->mb_cols; + v_ptr += show->uv_stride * 8 - 8 * cm->mb_cols; + yd_ptr += dest->y_stride * 16 - 16 * cm->mb_cols; + ud_ptr += dest->uv_stride * 8 - 8 * cm->mb_cols; + vd_ptr += dest->uv_stride * 8 - 8 * cm->mb_cols; + + mode_info_context++; /* Skip border mb */ + } +} diff --git a/vp8/common/modecont.c b/vp8/common/modecont.c new file mode 100644 index 0000000..86a74bc --- /dev/null +++ b/vp8/common/modecont.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "entropy.h" + +const int vp8_mode_contexts[6][4] = +{ + { + /* 0 */ + 7, 1, 1, 143, + }, + { + /* 1 */ + 14, 18, 14, 107, + }, + { + /* 2 */ + 135, 64, 57, 68, + }, + { + /* 3 */ + 60, 56, 128, 65, + }, + { + /* 4 */ + 159, 134, 128, 34, + }, + { + /* 5 */ + 234, 188, 128, 28, + }, +}; diff --git a/vp8/common/modecont.h b/vp8/common/modecont.h new file mode 100644 index 0000000..24db882 --- /dev/null +++ b/vp8/common/modecont.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_MODECONT_H +#define __INC_MODECONT_H + +extern const int vp8_mode_contexts[6][4]; + +#endif diff --git a/vp8/common/mv.h b/vp8/common/mv.h new file mode 100644 index 0000000..b3f919d --- /dev/null +++ b/vp8/common/mv.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_MV_H +#define __INC_MV_H +#include "vpx/vpx_integer.h" + +typedef struct +{ + short row; + short col; +} MV; + +typedef union int_mv +{ + uint32_t as_int; + MV as_mv; +} int_mv; /* facilitates faster equality tests and copies */ + +#endif diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h new file mode 100644 index 0000000..2e282f6 --- /dev/null +++ b/vp8/common/onyx.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_VP8_H +#define __INC_VP8_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "vpx_config.h" +#include "vpx/internal/vpx_codec_internal.h" +#include "vpx/vp8cx.h" +#include "vpx/vpx_encoder.h" +#include "vpx_scale/yv12config.h" +#include "ppflags.h" + + struct VP8_COMP; + + /* Create/destroy static data structures. */ + + typedef enum + { + NORMAL = 0, + FOURFIVE = 1, + THREEFIVE = 2, + ONETWO = 3 + + } VPX_SCALING; + + typedef enum + { + VP8_LAST_FLAG = 1, + VP8_GOLD_FLAG = 2, + VP8_ALT_FLAG = 4 + } VP8_REFFRAME; + + + typedef enum + { + USAGE_STREAM_FROM_SERVER = 0x0, + USAGE_LOCAL_FILE_PLAYBACK = 0x1, + USAGE_CONSTRAINED_QUALITY = 0x2 + } END_USAGE; + + + typedef enum + { + MODE_REALTIME = 0x0, + MODE_GOODQUALITY = 0x1, + MODE_BESTQUALITY = 0x2, + MODE_FIRSTPASS = 0x3, + MODE_SECONDPASS = 0x4, + MODE_SECONDPASS_BEST = 0x5 + } MODE; + + typedef enum + { + FRAMEFLAGS_KEY = 1, + FRAMEFLAGS_GOLDEN = 2, + FRAMEFLAGS_ALTREF = 4 + } FRAMETYPE_FLAGS; + + +#include + static void Scale2Ratio(int mode, int *hr, int *hs) + { + switch (mode) + { + case NORMAL: + *hr = 1; + *hs = 1; + break; + case FOURFIVE: + *hr = 4; + *hs = 5; + break; + case THREEFIVE: + *hr = 3; + *hs = 5; + break; + case ONETWO: + *hr = 1; + *hs = 2; + break; + default: + *hr = 1; + *hs = 1; + assert(0); + break; + } + } + + typedef struct + { + int Version; // 4 versions of bitstream defined 0 best quality/slowest decode, 3 lowest quality/fastest decode + int Width; // width of data passed to the compressor + int Height; // height of data passed to the compressor + struct vpx_rational timebase; + int target_bandwidth; // bandwidth to be used in kilobits per second + + int noise_sensitivity; // parameter used for applying pre processing blur: recommendation 0 + int Sharpness; // parameter used for sharpening output: recommendation 0: + int cpu_used; + unsigned int rc_max_intra_bitrate_pct; + + // mode -> + //(0)=Realtime/Live Encoding. This mode is optimized for realtim encoding (for example, capturing + // a television signal or feed from a live camera). ( speed setting controls how fast ) + //(1)=Good Quality Fast Encoding. The encoder balances quality with the amount of time it takes to + // encode the output. ( speed setting controls how fast ) + //(2)=One Pass - Best Quality. The encoder places priority on the quality of the output over encoding + // speed. The output is compressed at the highest possible quality. This option takes the longest + // amount of time to encode. ( speed setting ignored ) + //(3)=Two Pass - First Pass. The encoder generates a file of statistics for use in the second encoding + // pass. ( speed setting controls how fast ) + //(4)=Two Pass - Second Pass. The encoder uses the statistics that were generated in the first encoding + // pass to create the compressed output. ( speed setting controls how fast ) + //(5)=Two Pass - Second Pass Best. The encoder uses the statistics that were generated in the first + // encoding pass to create the compressed output using the highest possible quality, and taking a + // longer amount of time to encode.. ( speed setting ignored ) + int Mode; // + + // Key Framing Operations + int auto_key; // automatically detect cut scenes and set the keyframes + int key_freq; // maximum distance to key frame. + + int allow_lag; // allow lagged compression (if 0 lagin frames is ignored) + int lag_in_frames; // how many frames lag before we start encoding + + //---------------------------------------------------------------- + // DATARATE CONTROL OPTIONS + + int end_usage; // vbr or cbr + + // buffer targeting aggressiveness + int under_shoot_pct; + int over_shoot_pct; + + // buffering parameters + int64_t starting_buffer_level; // in bytes + int64_t optimal_buffer_level; + int64_t maximum_buffer_size; + + int64_t starting_buffer_level_in_ms; // in milli-seconds + int64_t optimal_buffer_level_in_ms; + int64_t maximum_buffer_size_in_ms; + + // controlling quality + int fixed_q; + int worst_allowed_q; + int best_allowed_q; + int cq_level; + + // allow internal resizing ( currently disabled in the build !!!!!) + int allow_spatial_resampling; + int resample_down_water_mark; + int resample_up_water_mark; + + // allow internal frame rate alterations + int allow_df; + int drop_frames_water_mark; + + // two pass datarate control + int two_pass_vbrbias; // two pass datarate control tweaks + int two_pass_vbrmin_section; + int two_pass_vbrmax_section; + // END DATARATE CONTROL OPTIONS + //---------------------------------------------------------------- + + + // these parameters aren't to be used in final build don't use!!! + int play_alternate; + int alt_freq; + int alt_q; + int key_q; + int gold_q; + + + int multi_threaded; // how many threads to run the encoder on + int token_partitions; // how many token partitions to create for multi core decoding + int encode_breakout; // early breakout encode threshold : for video conf recommend 800 + + unsigned int error_resilient_mode; // Bitfield defining the error + // resiliency features to enable. Can provide + // decodable frames after losses in previous + // frames and decodable partitions after + // losses in the same frame. + + int arnr_max_frames; + int arnr_strength ; + int arnr_type ; + + struct vpx_fixed_buf two_pass_stats_in; + struct vpx_codec_pkt_list *output_pkt_list; + + vp8e_tuning tuning; + + // Temporal scaling parameters + unsigned int number_of_layers; + unsigned int target_bitrate[VPX_TS_MAX_PERIODICITY]; + unsigned int rate_decimator[VPX_TS_MAX_PERIODICITY]; + unsigned int periodicity; + unsigned int layer_id[VPX_TS_MAX_PERIODICITY]; + +#if CONFIG_MULTI_RES_ENCODING + /* Number of total resolutions encoded */ + unsigned int mr_total_resolutions; + + /* Current encoder ID */ + unsigned int mr_encoder_id; + + /* Down-sampling factor */ + vpx_rational_t mr_down_sampling_factor; + + /* Memory location to store low-resolution encoder's mode info */ + void* mr_low_res_mode_info; +#endif + } VP8_CONFIG; + + + void vp8_initialize(); + + struct VP8_COMP* vp8_create_compressor(VP8_CONFIG *oxcf); + void vp8_remove_compressor(struct VP8_COMP* *comp); + + void vp8_init_config(struct VP8_COMP* onyx, VP8_CONFIG *oxcf); + void vp8_change_config(struct VP8_COMP* onyx, VP8_CONFIG *oxcf); + +// receive a frames worth of data caller can assume that a copy of this frame is made +// and not just a copy of the pointer.. + int vp8_receive_raw_frame(struct VP8_COMP* comp, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time_stamp); + int vp8_get_compressed_data(struct VP8_COMP* comp, unsigned int *frame_flags, unsigned long *size, unsigned char *dest, unsigned char *dest_end, int64_t *time_stamp, int64_t *time_end, int flush); + int vp8_get_preview_raw_frame(struct VP8_COMP* comp, YV12_BUFFER_CONFIG *dest, vp8_ppflags_t *flags); + + int vp8_use_as_reference(struct VP8_COMP* comp, int ref_frame_flags); + int vp8_update_reference(struct VP8_COMP* comp, int ref_frame_flags); + int vp8_get_reference(struct VP8_COMP* comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + int vp8_set_reference(struct VP8_COMP* comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + int vp8_update_entropy(struct VP8_COMP* comp, int update); + int vp8_set_roimap(struct VP8_COMP* comp, unsigned char *map, unsigned int rows, unsigned int cols, int delta_q[4], int delta_lf[4], unsigned int threshold[4]); + int vp8_set_active_map(struct VP8_COMP* comp, unsigned char *map, unsigned int rows, unsigned int cols); + int vp8_set_internal_size(struct VP8_COMP* comp, VPX_SCALING horiz_mode, VPX_SCALING vert_mode); + int vp8_get_quantizer(struct VP8_COMP* c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h new file mode 100644 index 0000000..c3215c0 --- /dev/null +++ b/vp8/common/onyxc_int.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_VP8C_INT_H +#define __INC_VP8C_INT_H + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx/internal/vpx_codec_internal.h" +#include "loopfilter.h" +#include "entropymv.h" +#include "entropy.h" +#if CONFIG_POSTPROC +#include "postproc.h" +#endif + +/*#ifdef PACKET_TESTING*/ +#include "header.h" +/*#endif*/ + +#define MINQ 0 +#define MAXQ 127 +#define QINDEX_RANGE (MAXQ + 1) + +#define NUM_YV12_BUFFERS 4 + +#define MAX_PARTITIONS 9 + +typedef struct frame_contexts +{ + vp8_prob bmode_prob [VP8_BINTRAMODES-1]; + vp8_prob ymode_prob [VP8_YMODES-1]; /* interframe intra mode probs */ + vp8_prob uv_mode_prob [VP8_UV_MODES-1]; + vp8_prob sub_mv_ref_prob [VP8_SUBMVREFS-1]; + vp8_prob coef_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; + MV_CONTEXT mvc[2]; + MV_CONTEXT pre_mvc[2]; /* not to caculate the mvcost for the frame if mvc doesn't change. */ +} FRAME_CONTEXT; + +typedef enum +{ + ONE_PARTITION = 0, + TWO_PARTITION = 1, + FOUR_PARTITION = 2, + EIGHT_PARTITION = 3 +} TOKEN_PARTITION; + +typedef enum +{ + RECON_CLAMP_REQUIRED = 0, + RECON_CLAMP_NOTREQUIRED = 1 +} CLAMP_TYPE; + +typedef enum +{ + SIXTAP = 0, + BILINEAR = 1 +} INTERPOLATIONFILTERTYPE; + +typedef struct VP8Common + +{ + struct vpx_internal_error_info error; + + DECLARE_ALIGNED(16, short, Y1dequant[QINDEX_RANGE][2]); + DECLARE_ALIGNED(16, short, Y2dequant[QINDEX_RANGE][2]); + DECLARE_ALIGNED(16, short, UVdequant[QINDEX_RANGE][2]); + + int Width; + int Height; + int horiz_scale; + int vert_scale; + + YUV_TYPE clr_type; + CLAMP_TYPE clamp_type; + + YV12_BUFFER_CONFIG *frame_to_show; + + YV12_BUFFER_CONFIG yv12_fb[NUM_YV12_BUFFERS]; + int fb_idx_ref_cnt[NUM_YV12_BUFFERS]; + int new_fb_idx, lst_fb_idx, gld_fb_idx, alt_fb_idx; + + YV12_BUFFER_CONFIG temp_scale_frame; + +#if CONFIG_POSTPROC + YV12_BUFFER_CONFIG post_proc_buffer; + YV12_BUFFER_CONFIG post_proc_buffer_int; + int post_proc_buffer_int_used; +#endif + + FRAME_TYPE last_frame_type; /* Save last frame's frame type for motion search. */ + FRAME_TYPE frame_type; + + int show_frame; + + int frame_flags; + int MBs; + int mb_rows; + int mb_cols; + int mode_info_stride; + + /* profile settings */ + int mb_no_coeff_skip; + int no_lpf; + int use_bilinear_mc_filter; + int full_pixel; + + int base_qindex; + int last_kf_gf_q; /* Q used on the last GF or KF */ + + int y1dc_delta_q; + int y2dc_delta_q; + int y2ac_delta_q; + int uvdc_delta_q; + int uvac_delta_q; + + unsigned int frames_since_golden; + unsigned int frames_till_alt_ref_frame; + + /* We allocate a MODE_INFO struct for each macroblock, together with + an extra row on top and column on the left to simplify prediction. */ + + MODE_INFO *mip; /* Base of allocated array */ + MODE_INFO *mi; /* Corresponds to upper left visible macroblock */ + MODE_INFO *prev_mip; /* MODE_INFO array 'mip' from last decoded frame */ + MODE_INFO *prev_mi; /* 'mi' from last frame (points into prev_mip) */ + + + INTERPOLATIONFILTERTYPE mcomp_filter_type; + LOOPFILTERTYPE filter_type; + + loop_filter_info_n lf_info; + + int filter_level; + int last_sharpness_level; + int sharpness_level; + + int refresh_last_frame; /* Two state 0 = NO, 1 = YES */ + int refresh_golden_frame; /* Two state 0 = NO, 1 = YES */ + int refresh_alt_ref_frame; /* Two state 0 = NO, 1 = YES */ + + int copy_buffer_to_gf; /* 0 none, 1 Last to GF, 2 ARF to GF */ + int copy_buffer_to_arf; /* 0 none, 1 Last to ARF, 2 GF to ARF */ + + int refresh_entropy_probs; /* Two state 0 = NO, 1 = YES */ + + int ref_frame_sign_bias[MAX_REF_FRAMES]; /* Two state 0, 1 */ + + /* Y,U,V,Y2 */ + ENTROPY_CONTEXT_PLANES *above_context; /* row of context for each plane */ + ENTROPY_CONTEXT_PLANES left_context; /* (up to) 4 contexts "" */ + + + /* keyframe block modes are predicted by their above, left neighbors */ + + vp8_prob kf_bmode_prob [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]; + vp8_prob kf_ymode_prob [VP8_YMODES-1]; /* keyframe "" */ + vp8_prob kf_uv_mode_prob [VP8_UV_MODES-1]; + + + FRAME_CONTEXT lfc; /* last frame entropy */ + FRAME_CONTEXT fc; /* this frame entropy */ + + unsigned int current_video_frame; + + int near_boffset[3]; + int version; + + TOKEN_PARTITION multi_token_partition; + +#ifdef PACKET_TESTING + VP8_HEADER oh; +#endif + double bitrate; + double framerate; + +#if CONFIG_MULTITHREAD + int processor_core_count; +#endif +#if CONFIG_POSTPROC + struct postproc_state postproc_state; +#endif + int cpu_caps; +} VP8_COMMON; + +#endif diff --git a/vp8/common/onyxd.h b/vp8/common/onyxd.h new file mode 100644 index 0000000..35a8b6e --- /dev/null +++ b/vp8/common/onyxd.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_VP8D_H +#define __INC_VP8D_H + + +/* Create/destroy static data structures. */ +#ifdef __cplusplus +extern "C" +{ +#endif +#include "vpx_scale/yv12config.h" +#include "ppflags.h" +#include "vpx_ports/mem.h" +#include "vpx/vpx_codec.h" + + struct VP8D_COMP; + + typedef struct + { + int Width; + int Height; + int Version; + int postprocess; + int max_threads; + int error_concealment; + int input_fragments; + } VP8D_CONFIG; + typedef enum + { + VP8_LAST_FLAG = 1, + VP8_GOLD_FLAG = 2, + VP8_ALT_FLAG = 4 + } VP8_REFFRAME; + + typedef enum + { + VP8D_OK = 0 + } VP8D_SETTING; + + void vp8dx_initialize(void); + + void vp8dx_set_setting(struct VP8D_COMP* comp, VP8D_SETTING oxst, int x); + + int vp8dx_get_setting(struct VP8D_COMP* comp, VP8D_SETTING oxst); + + int vp8dx_receive_compressed_data(struct VP8D_COMP* comp, unsigned long size, const unsigned char *dest, int64_t time_stamp); + int vp8dx_get_raw_frame(struct VP8D_COMP* comp, YV12_BUFFER_CONFIG *sd, int64_t *time_stamp, int64_t *time_end_stamp, vp8_ppflags_t *flags); + + vpx_codec_err_t vp8dx_get_reference(struct VP8D_COMP* comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + vpx_codec_err_t vp8dx_set_reference(struct VP8D_COMP* comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + + struct VP8D_COMP* vp8dx_create_decompressor(VP8D_CONFIG *oxcf); + + void vp8dx_remove_decompressor(struct VP8D_COMP* comp); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/vp8/common/postproc.c b/vp8/common/postproc.c new file mode 100644 index 0000000..ccf6ad7 --- /dev/null +++ b/vp8/common/postproc.c @@ -0,0 +1,1173 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx_scale/yv12config.h" +#include "postproc.h" +#include "common.h" +#include "vpx_scale/vpxscale.h" +#include "systemdependent.h" + +#include +#include +#include +#include + +#define RGB_TO_YUV(t) \ + ( (0.257*(float)(t>>16)) + (0.504*(float)(t>>8&0xff)) + (0.098*(float)(t&0xff)) + 16), \ + (-(0.148*(float)(t>>16)) - (0.291*(float)(t>>8&0xff)) + (0.439*(float)(t&0xff)) + 128), \ + ( (0.439*(float)(t>>16)) - (0.368*(float)(t>>8&0xff)) - (0.071*(float)(t&0xff)) + 128) + +/* global constants */ +#if CONFIG_POSTPROC_VISUALIZER +static const unsigned char MB_PREDICTION_MODE_colors[MB_MODE_COUNT][3] = +{ + { RGB_TO_YUV(0x98FB98) }, /* PaleGreen */ + { RGB_TO_YUV(0x00FF00) }, /* Green */ + { RGB_TO_YUV(0xADFF2F) }, /* GreenYellow */ + { RGB_TO_YUV(0x228B22) }, /* ForestGreen */ + { RGB_TO_YUV(0x006400) }, /* DarkGreen */ + { RGB_TO_YUV(0x98F5FF) }, /* Cadet Blue */ + { RGB_TO_YUV(0x6CA6CD) }, /* Sky Blue */ + { RGB_TO_YUV(0x00008B) }, /* Dark blue */ + { RGB_TO_YUV(0x551A8B) }, /* Purple */ + { RGB_TO_YUV(0xFF0000) } /* Red */ +}; + +static const unsigned char B_PREDICTION_MODE_colors[B_MODE_COUNT][3] = +{ + { RGB_TO_YUV(0x6633ff) }, /* Purple */ + { RGB_TO_YUV(0xcc33ff) }, /* Magenta */ + { RGB_TO_YUV(0xff33cc) }, /* Pink */ + { RGB_TO_YUV(0xff3366) }, /* Coral */ + { RGB_TO_YUV(0x3366ff) }, /* Blue */ + { RGB_TO_YUV(0xed00f5) }, /* Dark Blue */ + { RGB_TO_YUV(0x2e00b8) }, /* Dark Purple */ + { RGB_TO_YUV(0xff6633) }, /* Orange */ + { RGB_TO_YUV(0x33ccff) }, /* Light Blue */ + { RGB_TO_YUV(0x8ab800) }, /* Green */ + { RGB_TO_YUV(0xffcc33) }, /* Light Orange */ + { RGB_TO_YUV(0x33ffcc) }, /* Aqua */ + { RGB_TO_YUV(0x66ff33) }, /* Light Green */ + { RGB_TO_YUV(0xccff33) }, /* Yellow */ +}; + +static const unsigned char MV_REFERENCE_FRAME_colors[MAX_REF_FRAMES][3] = +{ + { RGB_TO_YUV(0x00ff00) }, /* Blue */ + { RGB_TO_YUV(0x0000ff) }, /* Green */ + { RGB_TO_YUV(0xffff00) }, /* Yellow */ + { RGB_TO_YUV(0xff0000) }, /* Red */ +}; +#endif + +static const short kernel5[] = +{ + 1, 1, 4, 1, 1 +}; + +const short vp8_rv[] = +{ + 8, 5, 2, 2, 8, 12, 4, 9, 8, 3, + 0, 3, 9, 0, 0, 0, 8, 3, 14, 4, + 10, 1, 11, 14, 1, 14, 9, 6, 12, 11, + 8, 6, 10, 0, 0, 8, 9, 0, 3, 14, + 8, 11, 13, 4, 2, 9, 0, 3, 9, 6, + 1, 2, 3, 14, 13, 1, 8, 2, 9, 7, + 3, 3, 1, 13, 13, 6, 6, 5, 2, 7, + 11, 9, 11, 8, 7, 3, 2, 0, 13, 13, + 14, 4, 12, 5, 12, 10, 8, 10, 13, 10, + 4, 14, 4, 10, 0, 8, 11, 1, 13, 7, + 7, 14, 6, 14, 13, 2, 13, 5, 4, 4, + 0, 10, 0, 5, 13, 2, 12, 7, 11, 13, + 8, 0, 4, 10, 7, 2, 7, 2, 2, 5, + 3, 4, 7, 3, 3, 14, 14, 5, 9, 13, + 3, 14, 3, 6, 3, 0, 11, 8, 13, 1, + 13, 1, 12, 0, 10, 9, 7, 6, 2, 8, + 5, 2, 13, 7, 1, 13, 14, 7, 6, 7, + 9, 6, 10, 11, 7, 8, 7, 5, 14, 8, + 4, 4, 0, 8, 7, 10, 0, 8, 14, 11, + 3, 12, 5, 7, 14, 3, 14, 5, 2, 6, + 11, 12, 12, 8, 0, 11, 13, 1, 2, 0, + 5, 10, 14, 7, 8, 0, 4, 11, 0, 8, + 0, 3, 10, 5, 8, 0, 11, 6, 7, 8, + 10, 7, 13, 9, 2, 5, 1, 5, 10, 2, + 4, 3, 5, 6, 10, 8, 9, 4, 11, 14, + 0, 10, 0, 5, 13, 2, 12, 7, 11, 13, + 8, 0, 4, 10, 7, 2, 7, 2, 2, 5, + 3, 4, 7, 3, 3, 14, 14, 5, 9, 13, + 3, 14, 3, 6, 3, 0, 11, 8, 13, 1, + 13, 1, 12, 0, 10, 9, 7, 6, 2, 8, + 5, 2, 13, 7, 1, 13, 14, 7, 6, 7, + 9, 6, 10, 11, 7, 8, 7, 5, 14, 8, + 4, 4, 0, 8, 7, 10, 0, 8, 14, 11, + 3, 12, 5, 7, 14, 3, 14, 5, 2, 6, + 11, 12, 12, 8, 0, 11, 13, 1, 2, 0, + 5, 10, 14, 7, 8, 0, 4, 11, 0, 8, + 0, 3, 10, 5, 8, 0, 11, 6, 7, 8, + 10, 7, 13, 9, 2, 5, 1, 5, 10, 2, + 4, 3, 5, 6, 10, 8, 9, 4, 11, 14, + 3, 8, 3, 7, 8, 5, 11, 4, 12, 3, + 11, 9, 14, 8, 14, 13, 4, 3, 1, 2, + 14, 6, 5, 4, 4, 11, 4, 6, 2, 1, + 5, 8, 8, 12, 13, 5, 14, 10, 12, 13, + 0, 9, 5, 5, 11, 10, 13, 9, 10, 13, +}; + +extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch); +extern void vp8_blit_line(int x0, int x1, int y0, int y1, unsigned char *image, const int pitch); +/*********************************************************************************************************** + */ +void vp8_post_proc_down_and_across_c +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +) +{ + unsigned char *p_src, *p_dst; + int row; + int col; + int i; + int v; + int pitch = src_pixels_per_line; + unsigned char d[8]; + (void)dst_pixels_per_line; + + for (row = 0; row < rows; row++) + { + /* post_proc_down for one row */ + p_src = src_ptr; + p_dst = dst_ptr; + + for (col = 0; col < cols; col++) + { + + int kernel = 4; + int v = p_src[col]; + + for (i = -2; i <= 2; i++) + { + if (abs(v - p_src[col+i*pitch]) > flimit) + goto down_skip_convolve; + + kernel += kernel5[2+i] * p_src[col+i*pitch]; + } + + v = (kernel >> 3); + down_skip_convolve: + p_dst[col] = v; + } + + /* now post_proc_across */ + p_src = dst_ptr; + p_dst = dst_ptr; + + for (i = -8; i<0; i++) + p_src[i]=p_src[0]; + + for (i = cols; i flimit) + goto across_skip_convolve; + + kernel += kernel5[2+i] * p_src[col+i]; + } + + d[col&7] = (kernel >> 3); + across_skip_convolve: + + if (col >= 2) + p_dst[col-2] = d[(col-2)&7]; + } + + /* handle the last two pixels */ + p_dst[col-2] = d[(col-2)&7]; + p_dst[col-1] = d[(col-1)&7]; + + + /* next row */ + src_ptr += pitch; + dst_ptr += pitch; + } +} + +static int q2mbl(int x) +{ + if (x < 20) x = 20; + + x = 50 + (x - 50) * 10 / 8; + return x * x / 3; +} +void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit) +{ + int r, c, i; + + unsigned char *s = src; + unsigned char d[16]; + + for (r = 0; r < rows; r++) + { + int sumsq = 0; + int sum = 0; + + for (i = -8; i<0; i++) + s[i]=s[0]; + + // 17 avoids valgrind warning - we buffer values in c in d + // and only write them when we've read 8 ahead... + for (i = cols; i> 4; + } + + s[c-8] = d[(c-8)&15]; + } + + s += pitch; + } +} + + + + + +void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit) +{ + int r, c, i; + const short *rv3 = &vp8_rv[63&rand()]; + + for (c = 0; c < cols; c++ ) + { + unsigned char *s = &dst[c]; + int sumsq = 0; + int sum = 0; + unsigned char d[16]; + const short *rv2 = rv3 + ((c * 17) & 127); + + for (i = -8; i < 0; i++) + s[i*pitch]=s[0]; + + // 17 avoids valgrind warning - we buffer values in c in d + // and only write them when we've read 8 ahead... + for (i = rows; i < rows+17; i++) + s[i*pitch]=s[(rows-1)*pitch]; + + for (i = -8; i <= 6; i++) + { + sumsq += s[i*pitch] * s[i*pitch]; + sum += s[i*pitch]; + } + + for (r = 0; r < rows + 8; r++) + { + sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch]; + sum += s[7*pitch] - s[-8*pitch]; + d[r&15] = s[0]; + + if (sumsq * 15 - sum * sum < flimit) + { + d[r&15] = (rv2[r&127] + sum + s[0]) >> 4; + } + + s[-8*pitch] = d[(r-8)&15]; + s += pitch; + } + } +} + + +static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag) +{ + double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065; + int ppl = (int)(level + .5); + (void) low_var_thresh; + (void) flag; + + vp8_post_proc_down_and_across(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl); + vp8_mbpost_proc_across_ip(post->y_buffer, post->y_stride, post->y_height, post->y_width, q2mbl(q)); + vp8_mbpost_proc_down(post->y_buffer, post->y_stride, post->y_height, post->y_width, q2mbl(q)); + + vp8_post_proc_down_and_across(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); + vp8_post_proc_down_and_across(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); + +} + +void vp8_deblock(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag) +{ + double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065; + int ppl = (int)(level + .5); + (void) low_var_thresh; + (void) flag; + + vp8_post_proc_down_and_across(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl); + vp8_post_proc_down_and_across(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); + vp8_post_proc_down_and_across(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); +} + +#if !(CONFIG_TEMPORAL_DENOISING) +void vp8_de_noise(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag) +{ + double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065; + int ppl = (int)(level + .5); + (void) post; + (void) low_var_thresh; + (void) flag; + + vp8_post_proc_down_and_across( + source->y_buffer + 2 * source->y_stride + 2, + source->y_buffer + 2 * source->y_stride + 2, + source->y_stride, + source->y_stride, + source->y_height - 4, + source->y_width - 4, + ppl); + vp8_post_proc_down_and_across( + source->u_buffer + 2 * source->uv_stride + 2, + source->u_buffer + 2 * source->uv_stride + 2, + source->uv_stride, + source->uv_stride, + source->uv_height - 4, + source->uv_width - 4, ppl); + vp8_post_proc_down_and_across( + source->v_buffer + 2 * source->uv_stride + 2, + source->v_buffer + 2 * source->uv_stride + 2, + source->uv_stride, + source->uv_stride, + source->uv_height - 4, + source->uv_width - 4, ppl); + +} +#endif + +double vp8_gaussian(double sigma, double mu, double x) +{ + return 1 / (sigma * sqrt(2.0 * 3.14159265)) * + (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma))); +} + +static void fillrd(struct postproc_state *state, int q, int a) +{ + char char_dist[300]; + + double sigma; + int ai = a, qi = q, i; + + vp8_clear_system_state(); + + + sigma = ai + .5 + .6 * (63 - qi) / 63.0; + + /* set up a lookup table of 256 entries that matches + * a gaussian distribution with sigma determined by q. + */ + { + double i; + int next, j; + + next = 0; + + for (i = -32; i < 32; i++) + { + int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i)); + + if (a) + { + for (j = 0; j < a; j++) + { + char_dist[next+j] = (char) i; + } + + next = next + j; + } + + } + + for (next = next; next < 256; next++) + char_dist[next] = 0; + + } + + for (i = 0; i < 3072; i++) + { + state->noise[i] = char_dist[rand() & 0xff]; + } + + for (i = 0; i < 16; i++) + { + state->blackclamp[i] = -char_dist[0]; + state->whiteclamp[i] = -char_dist[0]; + state->bothclamp[i] = -2 * char_dist[0]; + } + + state->last_q = q; + state->last_noise = a; +} + +/**************************************************************************** + * + * ROUTINE : plane_add_noise_c + * + * INPUTS : unsigned char *Start starting address of buffer to add gaussian + * noise to + * unsigned int Width width of plane + * unsigned int Height height of plane + * int Pitch distance between subsequent lines of frame + * int q quantizer used to determine amount of noise + * to add + * + * OUTPUTS : None. + * + * RETURNS : void. + * + * FUNCTION : adds gaussian noise to a plane of pixels + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_plane_add_noise_c(unsigned char *Start, char *noise, + char blackclamp[16], + char whiteclamp[16], + char bothclamp[16], + unsigned int Width, unsigned int Height, int Pitch) +{ + unsigned int i, j; + + for (i = 0; i < Height; i++) + { + unsigned char *Pos = Start + i * Pitch; + char *Ref = (char *)(noise + (rand() & 0xff)); + + for (j = 0; j < Width; j++) + { + if (Pos[j] < blackclamp[0]) + Pos[j] = blackclamp[0]; + + if (Pos[j] > 255 + whiteclamp[0]) + Pos[j] = 255 + whiteclamp[0]; + + Pos[j] += Ref[j]; + } + } +} + +/* Blend the macro block with a solid colored square. Leave the + * edges unblended to give distinction to macro blocks in areas + * filled with the same color block. + */ +void vp8_blend_mb_inner_c (unsigned char *y, unsigned char *u, unsigned char *v, + int y1, int u1, int v1, int alpha, int stride) +{ + int i, j; + int y1_const = y1*((1<<16)-alpha); + int u1_const = u1*((1<<16)-alpha); + int v1_const = v1*((1<<16)-alpha); + + y += 2*stride + 2; + for (i = 0; i < 12; i++) + { + for (j = 0; j < 12; j++) + { + y[j] = (y[j]*alpha + y1_const)>>16; + } + y += stride; + } + + stride >>= 1; + + u += stride + 1; + v += stride + 1; + + for (i = 0; i < 6; i++) + { + for (j = 0; j < 6; j++) + { + u[j] = (u[j]*alpha + u1_const)>>16; + v[j] = (v[j]*alpha + v1_const)>>16; + } + u += stride; + v += stride; + } +} + +/* Blend only the edge of the macro block. Leave center + * unblended to allow for other visualizations to be layered. + */ +void vp8_blend_mb_outer_c (unsigned char *y, unsigned char *u, unsigned char *v, + int y1, int u1, int v1, int alpha, int stride) +{ + int i, j; + int y1_const = y1*((1<<16)-alpha); + int u1_const = u1*((1<<16)-alpha); + int v1_const = v1*((1<<16)-alpha); + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 16; j++) + { + y[j] = (y[j]*alpha + y1_const)>>16; + } + y += stride; + } + + for (i = 0; i < 12; i++) + { + y[0] = (y[0]*alpha + y1_const)>>16; + y[1] = (y[1]*alpha + y1_const)>>16; + y[14] = (y[14]*alpha + y1_const)>>16; + y[15] = (y[15]*alpha + y1_const)>>16; + y += stride; + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 16; j++) + { + y[j] = (y[j]*alpha + y1_const)>>16; + } + y += stride; + } + + stride >>= 1; + + for (j = 0; j < 8; j++) + { + u[j] = (u[j]*alpha + u1_const)>>16; + v[j] = (v[j]*alpha + v1_const)>>16; + } + u += stride; + v += stride; + + for (i = 0; i < 6; i++) + { + u[0] = (u[0]*alpha + u1_const)>>16; + v[0] = (v[0]*alpha + v1_const)>>16; + + u[7] = (u[7]*alpha + u1_const)>>16; + v[7] = (v[7]*alpha + v1_const)>>16; + + u += stride; + v += stride; + } + + for (j = 0; j < 8; j++) + { + u[j] = (u[j]*alpha + u1_const)>>16; + v[j] = (v[j]*alpha + v1_const)>>16; + } +} + +void vp8_blend_b_c (unsigned char *y, unsigned char *u, unsigned char *v, + int y1, int u1, int v1, int alpha, int stride) +{ + int i, j; + int y1_const = y1*((1<<16)-alpha); + int u1_const = u1*((1<<16)-alpha); + int v1_const = v1*((1<<16)-alpha); + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + y[j] = (y[j]*alpha + y1_const)>>16; + } + y += stride; + } + + stride >>= 1; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + u[j] = (u[j]*alpha + u1_const)>>16; + v[j] = (v[j]*alpha + v1_const)>>16; + } + u += stride; + v += stride; + } +} + +static void constrain_line (int x0, int *x1, int y0, int *y1, int width, int height) +{ + int dx; + int dy; + + if (*x1 > width) + { + dx = *x1 - x0; + dy = *y1 - y0; + + *x1 = width; + if (dx) + *y1 = ((width-x0)*dy)/dx + y0; + } + if (*x1 < 0) + { + dx = *x1 - x0; + dy = *y1 - y0; + + *x1 = 0; + if (dx) + *y1 = ((0-x0)*dy)/dx + y0; + } + if (*y1 > height) + { + dx = *x1 - x0; + dy = *y1 - y0; + + *y1 = height; + if (dy) + *x1 = ((height-y0)*dx)/dy + x0; + } + if (*y1 < 0) + { + dx = *x1 - x0; + dy = *y1 - y0; + + *y1 = 0; + if (dy) + *x1 = ((0-y0)*dx)/dy + x0; + } +} + +#if CONFIG_POSTPROC +int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, vp8_ppflags_t *ppflags) +{ + int q = oci->filter_level * 10 / 6; + int flags = ppflags->post_proc_flag; + int deblock_level = ppflags->deblocking_level; + int noise_level = ppflags->noise_level; + + if (!oci->frame_to_show) + return -1; + + if (q > 63) + q = 63; + + if (!flags) + { + *dest = *oci->frame_to_show; + + /* handle problem with extending borders */ + dest->y_width = oci->Width; + dest->y_height = oci->Height; + dest->uv_height = dest->y_height / 2; + oci->postproc_state.last_base_qindex = oci->base_qindex; + oci->postproc_state.last_frame_valid = 1; + return 0; + } + + /* Allocate post_proc_buffer_int if needed */ + if ((flags & VP8D_MFQE) && !oci->post_proc_buffer_int_used) + { + if ((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) + { + int width = (oci->Width + 15) & ~15; + int height = (oci->Height + 15) & ~15; + + if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer_int, + width, height, VP8BORDERINPIXELS)) + vpx_internal_error(&oci->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate MFQE framebuffer"); + + oci->post_proc_buffer_int_used = 1; + + // insure that postproc is set to all 0's so that post proc + // doesn't pull random data in from edge + vpx_memset((&oci->post_proc_buffer_int)->buffer_alloc,128,(&oci->post_proc_buffer)->frame_size); + + } + } + +#if ARCH_X86||ARCH_X86_64 + vpx_reset_mmx_state(); +#endif + + if ((flags & VP8D_MFQE) && + oci->postproc_state.last_frame_valid && + oci->current_video_frame >= 2 && + oci->base_qindex - oci->postproc_state.last_base_qindex >= 10) + { + vp8_multiframe_quality_enhance(oci); + if (((flags & VP8D_DEBLOCK) || (flags & VP8D_DEMACROBLOCK)) && + oci->post_proc_buffer_int_used) + { + vp8_yv12_copy_frame(&oci->post_proc_buffer, &oci->post_proc_buffer_int); + if (flags & VP8D_DEMACROBLOCK) + { + vp8_deblock_and_de_macro_block(&oci->post_proc_buffer_int, &oci->post_proc_buffer, + q + (deblock_level - 5) * 10, 1, 0); + } + else if (flags & VP8D_DEBLOCK) + { + vp8_deblock(&oci->post_proc_buffer_int, &oci->post_proc_buffer, + q, 1, 0); + } + } + /* Move partially towards the base q of the previous frame */ + oci->postproc_state.last_base_qindex = (3*oci->postproc_state.last_base_qindex + oci->base_qindex)>>2; + } + else if (flags & VP8D_DEMACROBLOCK) + { + vp8_deblock_and_de_macro_block(oci->frame_to_show, &oci->post_proc_buffer, + q + (deblock_level - 5) * 10, 1, 0); + oci->postproc_state.last_base_qindex = oci->base_qindex; + } + else if (flags & VP8D_DEBLOCK) + { + vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer, + q, 1, 0); + oci->postproc_state.last_base_qindex = oci->base_qindex; + } + else + { + vp8_yv12_copy_frame(oci->frame_to_show, &oci->post_proc_buffer); + oci->postproc_state.last_base_qindex = oci->base_qindex; + } + oci->postproc_state.last_frame_valid = 1; + + if (flags & VP8D_ADDNOISE) + { + if (oci->postproc_state.last_q != q + || oci->postproc_state.last_noise != noise_level) + { + fillrd(&oci->postproc_state, 63 - q, noise_level); + } + + vp8_plane_add_noise + (oci->post_proc_buffer.y_buffer, + oci->postproc_state.noise, + oci->postproc_state.blackclamp, + oci->postproc_state.whiteclamp, + oci->postproc_state.bothclamp, + oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height, + oci->post_proc_buffer.y_stride); + } + +#if CONFIG_POSTPROC_VISUALIZER + if (flags & VP8D_DEBUG_TXT_FRAME_INFO) + { + char message[512]; + sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d", + (oci->frame_type == KEY_FRAME), + oci->refresh_golden_frame, + oci->base_qindex, + oci->filter_level, + flags, + oci->mb_cols, oci->mb_rows); + vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride); + } + + if (flags & VP8D_DEBUG_TXT_MBLK_MODES) + { + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = oci->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + /* vp8_filter each macro block */ + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + + sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a'); + + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + mb_index ++; /* border */ + y_ptr += post->y_stride * 16 - post->y_width; + + } + } + + if (flags & VP8D_DEBUG_TXT_DC_DIFF) + { + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = oci->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + /* vp8_filter each macro block */ + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + int dc_diff = !(mi[mb_index].mbmi.mode != B_PRED && + mi[mb_index].mbmi.mode != SPLITMV && + mi[mb_index].mbmi.mb_skip_coeff); + + if (oci->frame_type == KEY_FRAME) + sprintf(zz, "a"); + else + sprintf(zz, "%c", dc_diff + '0'); + + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + mb_index ++; /* border */ + y_ptr += post->y_stride * 16 - post->y_width; + + } + } + + if (flags & VP8D_DEBUG_TXT_RATE_INFO) + { + char message[512]; + sprintf(message, "Bitrate: %10.2f frame_rate: %10.2f ", oci->bitrate, oci->framerate); + vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride); + } + + /* Draw motion vectors */ + if ((flags & VP8D_DEBUG_DRAW_MV) && ppflags->display_mv_flag) + { + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int width = post->y_width; + int height = post->y_height; + unsigned char *y_buffer = oci->post_proc_buffer.y_buffer; + int y_stride = oci->post_proc_buffer.y_stride; + MODE_INFO *mi = oci->mi; + int x0, y0; + + for (y0 = 0; y0 < height; y0 += 16) + { + for (x0 = 0; x0 < width; x0 += 16) + { + int x1, y1; + + if (!(ppflags->display_mv_flag & (1<mbmi.mode))) + { + mi++; + continue; + } + + if (mi->mbmi.mode == SPLITMV) + { + switch (mi->mbmi.partitioning) + { + case 0 : /* mv_top_bottom */ + { + union b_mode_info *bmi = &mi->bmi[0]; + MV *mv = &bmi->mv.as_mv; + + x1 = x0 + 8 + (mv->col >> 3); + y1 = y0 + 4 + (mv->row >> 3); + + constrain_line (x0+8, &x1, y0+4, &y1, width, height); + vp8_blit_line (x0+8, x1, y0+4, y1, y_buffer, y_stride); + + bmi = &mi->bmi[8]; + + x1 = x0 + 8 + (mv->col >> 3); + y1 = y0 +12 + (mv->row >> 3); + + constrain_line (x0+8, &x1, y0+12, &y1, width, height); + vp8_blit_line (x0+8, x1, y0+12, y1, y_buffer, y_stride); + + break; + } + case 1 : /* mv_left_right */ + { + union b_mode_info *bmi = &mi->bmi[0]; + MV *mv = &bmi->mv.as_mv; + + x1 = x0 + 4 + (mv->col >> 3); + y1 = y0 + 8 + (mv->row >> 3); + + constrain_line (x0+4, &x1, y0+8, &y1, width, height); + vp8_blit_line (x0+4, x1, y0+8, y1, y_buffer, y_stride); + + bmi = &mi->bmi[2]; + + x1 = x0 +12 + (mv->col >> 3); + y1 = y0 + 8 + (mv->row >> 3); + + constrain_line (x0+12, &x1, y0+8, &y1, width, height); + vp8_blit_line (x0+12, x1, y0+8, y1, y_buffer, y_stride); + + break; + } + case 2 : /* mv_quarters */ + { + union b_mode_info *bmi = &mi->bmi[0]; + MV *mv = &bmi->mv.as_mv; + + x1 = x0 + 4 + (mv->col >> 3); + y1 = y0 + 4 + (mv->row >> 3); + + constrain_line (x0+4, &x1, y0+4, &y1, width, height); + vp8_blit_line (x0+4, x1, y0+4, y1, y_buffer, y_stride); + + bmi = &mi->bmi[2]; + + x1 = x0 +12 + (mv->col >> 3); + y1 = y0 + 4 + (mv->row >> 3); + + constrain_line (x0+12, &x1, y0+4, &y1, width, height); + vp8_blit_line (x0+12, x1, y0+4, y1, y_buffer, y_stride); + + bmi = &mi->bmi[8]; + + x1 = x0 + 4 + (mv->col >> 3); + y1 = y0 +12 + (mv->row >> 3); + + constrain_line (x0+4, &x1, y0+12, &y1, width, height); + vp8_blit_line (x0+4, x1, y0+12, y1, y_buffer, y_stride); + + bmi = &mi->bmi[10]; + + x1 = x0 +12 + (mv->col >> 3); + y1 = y0 +12 + (mv->row >> 3); + + constrain_line (x0+12, &x1, y0+12, &y1, width, height); + vp8_blit_line (x0+12, x1, y0+12, y1, y_buffer, y_stride); + break; + } + default : + { + union b_mode_info *bmi = mi->bmi; + int bx0, by0; + + for (by0 = y0; by0 < (y0+16); by0 += 4) + { + for (bx0 = x0; bx0 < (x0+16); bx0 += 4) + { + MV *mv = &bmi->mv.as_mv; + + x1 = bx0 + 2 + (mv->col >> 3); + y1 = by0 + 2 + (mv->row >> 3); + + constrain_line (bx0+2, &x1, by0+2, &y1, width, height); + vp8_blit_line (bx0+2, x1, by0+2, y1, y_buffer, y_stride); + + bmi++; + } + } + } + } + } + else if (mi->mbmi.mode >= NEARESTMV) + { + MV *mv = &mi->mbmi.mv.as_mv; + const int lx0 = x0 + 8; + const int ly0 = y0 + 8; + + x1 = lx0 + (mv->col >> 3); + y1 = ly0 + (mv->row >> 3); + + if (x1 != lx0 && y1 != ly0) + { + constrain_line (lx0, &x1, ly0-1, &y1, width, height); + vp8_blit_line (lx0, x1, ly0-1, y1, y_buffer, y_stride); + + constrain_line (lx0, &x1, ly0+1, &y1, width, height); + vp8_blit_line (lx0, x1, ly0+1, y1, y_buffer, y_stride); + } + else + vp8_blit_line (lx0, x1, ly0, y1, y_buffer, y_stride); + } + + mi++; + } + mi++; + } + } + + /* Color in block modes */ + if ((flags & VP8D_DEBUG_CLR_BLK_MODES) + && (ppflags->display_mb_modes_flag || ppflags->display_b_modes_flag)) + { + int y, x; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int width = post->y_width; + int height = post->y_height; + unsigned char *y_ptr = oci->post_proc_buffer.y_buffer; + unsigned char *u_ptr = oci->post_proc_buffer.u_buffer; + unsigned char *v_ptr = oci->post_proc_buffer.v_buffer; + int y_stride = oci->post_proc_buffer.y_stride; + MODE_INFO *mi = oci->mi; + + for (y = 0; y < height; y += 16) + { + for (x = 0; x < width; x += 16) + { + int Y = 0, U = 0, V = 0; + + if (mi->mbmi.mode == B_PRED && + ((ppflags->display_mb_modes_flag & B_PRED) || ppflags->display_b_modes_flag)) + { + int by, bx; + unsigned char *yl, *ul, *vl; + union b_mode_info *bmi = mi->bmi; + + yl = y_ptr + x; + ul = u_ptr + (x>>1); + vl = v_ptr + (x>>1); + + for (by = 0; by < 16; by += 4) + { + for (bx = 0; bx < 16; bx += 4) + { + if ((ppflags->display_b_modes_flag & (1<mbmi.mode)) + || (ppflags->display_mb_modes_flag & B_PRED)) + { + Y = B_PREDICTION_MODE_colors[bmi->as_mode][0]; + U = B_PREDICTION_MODE_colors[bmi->as_mode][1]; + V = B_PREDICTION_MODE_colors[bmi->as_mode][2]; + + vp8_blend_b + (yl+bx, ul+(bx>>1), vl+(bx>>1), Y, U, V, 0xc000, y_stride); + } + bmi++; + } + + yl += y_stride*4; + ul += y_stride*1; + vl += y_stride*1; + } + } + else if (ppflags->display_mb_modes_flag & (1<mbmi.mode)) + { + Y = MB_PREDICTION_MODE_colors[mi->mbmi.mode][0]; + U = MB_PREDICTION_MODE_colors[mi->mbmi.mode][1]; + V = MB_PREDICTION_MODE_colors[mi->mbmi.mode][2]; + + vp8_blend_mb_inner + (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride); + } + + mi++; + } + y_ptr += y_stride*16; + u_ptr += y_stride*4; + v_ptr += y_stride*4; + + mi++; + } + } + + /* Color in frame reference blocks */ + if ((flags & VP8D_DEBUG_CLR_FRM_REF_BLKS) && ppflags->display_ref_frame_flag) + { + int y, x; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int width = post->y_width; + int height = post->y_height; + unsigned char *y_ptr = oci->post_proc_buffer.y_buffer; + unsigned char *u_ptr = oci->post_proc_buffer.u_buffer; + unsigned char *v_ptr = oci->post_proc_buffer.v_buffer; + int y_stride = oci->post_proc_buffer.y_stride; + MODE_INFO *mi = oci->mi; + + for (y = 0; y < height; y += 16) + { + for (x = 0; x < width; x +=16) + { + int Y = 0, U = 0, V = 0; + + if (ppflags->display_ref_frame_flag & (1<mbmi.ref_frame)) + { + Y = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][0]; + U = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][1]; + V = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][2]; + + vp8_blend_mb_outer + (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride); + } + + mi++; + } + y_ptr += y_stride*16; + u_ptr += y_stride*4; + v_ptr += y_stride*4; + + mi++; + } + } +#endif + + *dest = oci->post_proc_buffer; + + /* handle problem with extending borders */ + dest->y_width = oci->Width; + dest->y_height = oci->Height; + dest->uv_height = dest->y_height / 2; + return 0; +} +#endif diff --git a/vp8/common/postproc.h b/vp8/common/postproc.h new file mode 100644 index 0000000..6ac788c --- /dev/null +++ b/vp8/common/postproc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef POSTPROC_H +#define POSTPROC_H + +#include "vpx_ports/mem.h" +struct postproc_state +{ + int last_q; + int last_noise; + char noise[3072]; + int last_base_qindex; + int last_frame_valid; + DECLARE_ALIGNED(16, char, blackclamp[16]); + DECLARE_ALIGNED(16, char, whiteclamp[16]); + DECLARE_ALIGNED(16, char, bothclamp[16]); +}; +#include "onyxc_int.h" +#include "ppflags.h" +int vp8_post_proc_frame(struct VP8Common *oci, YV12_BUFFER_CONFIG *dest, + vp8_ppflags_t *flags); + + +void vp8_de_noise(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag); + +void vp8_deblock(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag); + +#define MFQE_PRECISION 4 + +void vp8_multiframe_quality_enhance(struct VP8Common *cm); +#endif diff --git a/vp8/common/ppc/copy_altivec.asm b/vp8/common/ppc/copy_altivec.asm new file mode 100644 index 0000000..a4ce915 --- /dev/null +++ b/vp8/common/ppc/copy_altivec.asm @@ -0,0 +1,47 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl copy_mem16x16_ppc + +;# r3 unsigned char *src +;# r4 int src_stride +;# r5 unsigned char *dst +;# r6 int dst_stride + +;# Make the assumption that input will not be aligned, +;# but the output will be. So two reads and a perm +;# for the input, but only one store for the output. +copy_mem16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xe000 + mtspr 256, r12 ;# set VRSAVE + + li r10, 16 + mtctr r10 + +cp_16x16_loop: + lvsl v0, 0, r3 ;# permutate value for alignment + + lvx v1, 0, r3 + lvx v2, r10, r3 + + vperm v1, v1, v2, v0 + + stvx v1, 0, r5 + + add r3, r3, r4 ;# increment source pointer + add r5, r5, r6 ;# increment destination pointer + + bdnz cp_16x16_loop + + mtspr 256, r11 ;# reset old VRSAVE + + blr diff --git a/vp8/common/ppc/filter_altivec.asm b/vp8/common/ppc/filter_altivec.asm new file mode 100644 index 0000000..4da2e94 --- /dev/null +++ b/vp8/common/ppc/filter_altivec.asm @@ -0,0 +1,1013 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl sixtap_predict_ppc + .globl sixtap_predict8x4_ppc + .globl sixtap_predict8x8_ppc + .globl sixtap_predict16x16_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +.macro load_hfilter V0, V1 + load_c \V0, HFilter, r5, r9, r10 + + addi r5, r5, 16 + lvx \V1, r5, r10 +.endm + +;# Vertical filtering +.macro Vprolog + load_c v0, VFilter, r6, r3, r10 + + vspltish v5, 8 + vspltish v6, 3 + vslh v6, v5, v6 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v1, v0, 1 + vspltb v2, v0, 2 + vspltb v3, v0, 3 + vspltb v4, v0, 4 + vspltb v5, v0, 5 + vspltb v0, v0, 0 +.endm + +.macro vpre_load + Vprolog + li r10, 16 + lvx v10, 0, r9 ;# v10..v14 = first 5 rows + lvx v11, r10, r9 + addi r9, r9, 32 + lvx v12, 0, r9 + lvx v13, r10, r9 + addi r9, r9, 32 + lvx v14, 0, r9 +.endm + +.macro Msum Re, Ro, V, T, TMP + ;# (Re,Ro) += (V*T) + vmuleub \TMP, \V, \T ;# trashes v8 + vadduhm \Re, \Re, \TMP ;# Re = evens, saturation unnecessary + vmuloub \TMP, \V, \T + vadduhm \Ro, \Ro, \TMP ;# Ro = odds +.endm + +.macro vinterp_no_store P0 P1 P2 P3 P4 P5 + vmuleub v8, \P0, v0 ;# 64 + 4 positive taps + vadduhm v16, v6, v8 + vmuloub v8, \P0, v0 + vadduhm v17, v6, v8 + Msum v16, v17, \P2, v2, v8 + Msum v16, v17, \P3, v3, v8 + Msum v16, v17, \P5, v5, v8 + + vmuleub v18, \P1, v1 ;# 2 negative taps + vmuloub v19, \P1, v1 + Msum v18, v19, \P4, v4, v8 + + vsubuhs v16, v16, v18 ;# subtract neg from pos + vsubuhs v17, v17, v19 + vsrh v16, v16, v7 ;# divide by 128 + vsrh v17, v17, v7 ;# v16 v17 = evens, odds + vmrghh v18, v16, v17 ;# v18 v19 = 16-bit result in order + vmrglh v19, v16, v17 + vpkuhus \P0, v18, v19 ;# P0 = 8-bit result +.endm + +.macro vinterp_no_store_8x8 P0 P1 P2 P3 P4 P5 + vmuleub v24, \P0, v13 ;# 64 + 4 positive taps + vadduhm v21, v20, v24 + vmuloub v24, \P0, v13 + vadduhm v22, v20, v24 + Msum v21, v22, \P2, v15, v25 + Msum v21, v22, \P3, v16, v25 + Msum v21, v22, \P5, v18, v25 + + vmuleub v23, \P1, v14 ;# 2 negative taps + vmuloub v24, \P1, v14 + Msum v23, v24, \P4, v17, v25 + + vsubuhs v21, v21, v23 ;# subtract neg from pos + vsubuhs v22, v22, v24 + vsrh v21, v21, v19 ;# divide by 128 + vsrh v22, v22, v19 ;# v16 v17 = evens, odds + vmrghh v23, v21, v22 ;# v18 v19 = 16-bit result in order + vmrglh v24, v21, v22 + vpkuhus \P0, v23, v24 ;# P0 = 8-bit result +.endm + + +.macro Vinterp P0 P1 P2 P3 P4 P5 + vinterp_no_store \P0, \P1, \P2, \P3, \P4, \P5 + stvx \P0, 0, r7 + add r7, r7, r8 ;# 33 ops per 16 pels +.endm + + +.macro luma_v P0, P1, P2, P3, P4, P5 + addi r9, r9, 16 ;# P5 = newest input row + lvx \P5, 0, r9 + Vinterp \P0, \P1, \P2, \P3, \P4, \P5 +.endm + +.macro luma_vtwo + luma_v v10, v11, v12, v13, v14, v15 + luma_v v11, v12, v13, v14, v15, v10 +.endm + +.macro luma_vfour + luma_vtwo + luma_v v12, v13, v14, v15, v10, v11 + luma_v v13, v14, v15, v10, v11, v12 +.endm + +.macro luma_vsix + luma_vfour + luma_v v14, v15, v10, v11, v12, v13 + luma_v v15, v10, v11, v12, v13, v14 +.endm + +.macro Interp4 R I I4 + vmsummbm \R, v13, \I, v15 + vmsummbm \R, v14, \I4, \R +.endm + +.macro Read8x8 VD, RS, RP, increment_counter + lvsl v21, 0, \RS ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx \VD, 0, \RS + lvx v20, r10, \RS + +.if \increment_counter + add \RS, \RS, \RP +.endif + + vperm \VD, \VD, v20, v21 +.endm + +.macro interp_8x8 R + vperm v20, \R, \R, v16 ;# v20 = 0123 1234 2345 3456 + vperm v21, \R, \R, v17 ;# v21 = 4567 5678 6789 789A + Interp4 v20, v20, v21 ;# v20 = result 0 1 2 3 + vperm \R, \R, \R, v18 ;# R = 89AB 9ABC ABCx BCxx + Interp4 v21, v21, \R ;# v21 = result 4 5 6 7 + + vpkswus \R, v20, v21 ;# R = 0 1 2 3 4 5 6 7 + vsrh \R, \R, v19 + + vpkuhus \R, \R, \R ;# saturate and pack + +.endm + +.macro Read4x4 VD, RS, RP, increment_counter + lvsl v21, 0, \RS ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v20, 0, \RS + +.if \increment_counter + add \RS, \RS, \RP +.endif + + vperm \VD, v20, v20, v21 +.endm + .text + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +sixtap_predict_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xff87 + ori r12, r12, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + slwi. r5, r5, 5 ;# index into horizontal filter array + + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq- vertical_only_4x4 + + ;# load up horizontal filter + load_hfilter v13, v14 + + ;# rounding added in on the multiply + vspltisw v16, 8 + vspltisw v15, 3 + vslw v15, v16, v15 ;# 0x00000040000000400000004000000040 + + ;# Load up permutation constants + load_c v16, B_0123, 0, r9, r10 + load_c v17, B_4567, 0, r9, r10 + load_c v18, B_89AB, 0, r9, r10 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + addi r9, r3, 0 + li r10, 16 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# filter a line + interp_8x8 v2 + interp_8x8 v3 + interp_8x8 v4 + interp_8x8 v5 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional 5 lines that are needed + ;# for the vertical filter. + beq- store_4x4 + + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r9, r9, r4 + sub r9, r9, r4 + + Read8x8 v0, r9, r4, 1 + Read8x8 v1, r9, r4, 0 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 0 + + interp_8x8 v0 + interp_8x8 v1 + interp_8x8 v6 + interp_8x8 v7 + interp_8x8 v8 + + b second_pass_4x4 + +vertical_only_4x4: + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + li r10, 16 + + Read8x8 v0, r3, r4, 1 + Read8x8 v1, r3, r4, 1 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 0 + + slwi r6, r6, 4 ;# index into vertical filter array + +second_pass_4x4: + load_c v20, b_hilo_4x4, 0, r9, r10 + load_c v21, b_hilo, 0, r9, r10 + + ;# reposition input so that it can go through the + ;# filtering phase with one pass. + vperm v0, v0, v1, v20 ;# 0 1 x x + vperm v2, v2, v3, v20 ;# 2 3 x x + vperm v4, v4, v5, v20 ;# 4 5 x x + vperm v6, v6, v7, v20 ;# 6 7 x x + + vperm v0, v0, v2, v21 ;# 0 1 2 3 + vperm v4, v4, v6, v21 ;# 4 5 6 7 + + vsldoi v1, v0, v4, 4 + vsldoi v2, v0, v4, 8 + vsldoi v3, v0, v4, 12 + + vsldoi v5, v4, v8, 4 + + load_c v13, VFilter, r6, r9, r10 + + vspltish v15, 8 + vspltish v20, 3 + vslh v20, v15, v20 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v14, v13, 1 + vspltb v15, v13, 2 + vspltb v16, v13, 3 + vspltb v17, v13, 4 + vspltb v18, v13, 5 + vspltb v13, v13, 0 + + vinterp_no_store_8x8 v0, v1, v2, v3, v4, v5 + + stvx v0, 0, r1 + + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + lwz r0, 4(r1) + stw r0, 0(r7) + add r7, r7, r8 + + lwz r0, 8(r1) + stw r0, 0(r7) + add r7, r7, r8 + + lwz r0, 12(r1) + stw r0, 0(r7) + + b exit_4x4 + +store_4x4: + + stvx v2, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v3, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v4, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v5, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + +exit_4x4: + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro w_8x8 V, D, R, P + stvx \V, 0, r1 + lwz \R, 0(r1) + stw \R, 0(r7) + lwz \R, 4(r1) + stw \R, 4(r7) + add \D, \D, \P +.endm + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch + +sixtap_predict8x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + slwi. r5, r5, 5 ;# index into horizontal filter array + + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq- second_pass_pre_copy_8x4 + + load_hfilter v13, v14 + + ;# rounding added in on the multiply + vspltisw v16, 8 + vspltisw v15, 3 + vslw v15, v16, v15 ;# 0x00000040000000400000004000000040 + + ;# Load up permutation constants + load_c v16, B_0123, 0, r9, r10 + load_c v17, B_4567, 0, r9, r10 + load_c v18, B_89AB, 0, r9, r10 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + addi r9, r3, 0 + li r10, 16 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# filter a line + interp_8x8 v2 + interp_8x8 v3 + interp_8x8 v4 + interp_8x8 v5 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional 5 lines that are needed + ;# for the vertical filter. + beq- store_8x4 + + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r9, r9, r4 + sub r9, r9, r4 + + Read8x8 v0, r9, r4, 1 + Read8x8 v1, r9, r4, 0 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 0 + + interp_8x8 v0 + interp_8x8 v1 + interp_8x8 v6 + interp_8x8 v7 + interp_8x8 v8 + + b second_pass_8x4 + +second_pass_pre_copy_8x4: + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + li r10, 16 + + Read8x8 v0, r3, r4, 1 + Read8x8 v1, r3, r4, 1 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 1 + + slwi r6, r6, 4 ;# index into vertical filter array + +second_pass_8x4: + load_c v13, VFilter, r6, r9, r10 + + vspltish v15, 8 + vspltish v20, 3 + vslh v20, v15, v20 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v14, v13, 1 + vspltb v15, v13, 2 + vspltb v16, v13, 3 + vspltb v17, v13, 4 + vspltb v18, v13, 5 + vspltb v13, v13, 0 + + vinterp_no_store_8x8 v0, v1, v2, v3, v4, v5 + vinterp_no_store_8x8 v1, v2, v3, v4, v5, v6 + vinterp_no_store_8x8 v2, v3, v4, v5, v6, v7 + vinterp_no_store_8x8 v3, v4, v5, v6, v7, v8 + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x4 + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + + b exit_8x4 + +store_aligned_8x4: + + load_c v10, b_hilo, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + + b exit_8x4 + +store_8x4: + cmpi cr0, r8, 8 + beq cr0, store_aligned2_8x4 + + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + + b exit_8x4 + +store_aligned2_8x4: + load_c v10, b_hilo, 0, r9, r10 + + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + +exit_8x4: + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch + +;# Because the width that needs to be filtered will fit in a single altivec +;# register there is no need to loop. Everything can stay in registers. +sixtap_predict8x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + slwi. r5, r5, 5 ;# index into horizontal filter array + + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq- second_pass_pre_copy_8x8 + + load_hfilter v13, v14 + + ;# rounding added in on the multiply + vspltisw v16, 8 + vspltisw v15, 3 + vslw v15, v16, v15 ;# 0x00000040000000400000004000000040 + + ;# Load up permutation constants + load_c v16, B_0123, 0, r9, r10 + load_c v17, B_4567, 0, r9, r10 + load_c v18, B_89AB, 0, r9, r10 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + addi r9, r3, 0 + li r10, 16 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 1 + Read8x8 v9, r3, r4, 1 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# filter a line + interp_8x8 v2 + interp_8x8 v3 + interp_8x8 v4 + interp_8x8 v5 + interp_8x8 v6 + interp_8x8 v7 + interp_8x8 v8 + interp_8x8 v9 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional 5 lines that are needed + ;# for the vertical filter. + beq- store_8x8 + + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r9, r9, r4 + sub r9, r9, r4 + + Read8x8 v0, r9, r4, 1 + Read8x8 v1, r9, r4, 0 + Read8x8 v10, r3, r4, 1 + Read8x8 v11, r3, r4, 1 + Read8x8 v12, r3, r4, 0 + + interp_8x8 v0 + interp_8x8 v1 + interp_8x8 v10 + interp_8x8 v11 + interp_8x8 v12 + + b second_pass_8x8 + +second_pass_pre_copy_8x8: + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + li r10, 16 + + Read8x8 v0, r3, r4, 1 + Read8x8 v1, r3, r4, 1 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 1 + Read8x8 v9, r3, r4, 1 + Read8x8 v10, r3, r4, 1 + Read8x8 v11, r3, r4, 1 + Read8x8 v12, r3, r4, 0 + + slwi r6, r6, 4 ;# index into vertical filter array + +second_pass_8x8: + load_c v13, VFilter, r6, r9, r10 + + vspltish v15, 8 + vspltish v20, 3 + vslh v20, v15, v20 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v14, v13, 1 + vspltb v15, v13, 2 + vspltb v16, v13, 3 + vspltb v17, v13, 4 + vspltb v18, v13, 5 + vspltb v13, v13, 0 + + vinterp_no_store_8x8 v0, v1, v2, v3, v4, v5 + vinterp_no_store_8x8 v1, v2, v3, v4, v5, v6 + vinterp_no_store_8x8 v2, v3, v4, v5, v6, v7 + vinterp_no_store_8x8 v3, v4, v5, v6, v7, v8 + vinterp_no_store_8x8 v4, v5, v6, v7, v8, v9 + vinterp_no_store_8x8 v5, v6, v7, v8, v9, v10 + vinterp_no_store_8x8 v6, v7, v8, v9, v10, v11 + vinterp_no_store_8x8 v7, v8, v9, v10, v11, v12 + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x8 + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + w_8x8 v6, r7, r0, r8 + w_8x8 v7, r7, r0, r8 + + b exit_8x8 + +store_aligned_8x8: + + load_c v10, b_hilo, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + vperm v6, v6, v7, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + addi r7, r7, 16 + stvx v6, 0, r7 + + b exit_8x8 + +store_8x8: + cmpi cr0, r8, 8 + beq cr0, store_aligned2_8x8 + + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + w_8x8 v6, r7, r0, r8 + w_8x8 v7, r7, r0, r8 + w_8x8 v8, r7, r0, r8 + w_8x8 v9, r7, r0, r8 + + b exit_8x8 + +store_aligned2_8x8: + load_c v10, b_hilo, 0, r9, r10 + + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + vperm v6, v6, v7, v10 + vperm v8, v8, v9, v10 + + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + addi r7, r7, 16 + stvx v6, 0, r7 + addi r7, r7, 16 + stvx v8, 0, r7 + +exit_8x8: + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch + +;# Two pass filtering. First pass is Horizontal edges, second pass is vertical +;# edges. One of the filters can be null, but both won't be. Needs to use a +;# temporary buffer because the source buffer can't be modified and the buffer +;# for the destination is not large enough to hold the temporary data. +sixtap_predict16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xf000 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-416(r1) ;# create space on the stack + + ;# Three possiblities + ;# 1. First filter is null. Don't use a temp buffer. + ;# 2. Second filter is null. Don't use a temp buffer. + ;# 3. Neither are null, use temp buffer. + + ;# First Pass (horizontal edge) + ;# setup pointers for src + ;# if possiblity (1) then setup the src pointer to be the orginal and jump + ;# to second pass. this is based on if x_offset is 0. + + ;# load up horizontal filter + slwi. r5, r5, 5 ;# index into horizontal filter array + + load_hfilter v4, v5 + + beq- copy_horizontal_16x21 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# setup constants + ;# v14 permutation value for alignment + load_c v14, b_hperm, 0, r9, r10 + + ;# These statements are guessing that there won't be a second pass, + ;# but if there is then inside the bypass they need to be set + li r0, 16 ;# prepare for no vertical filter + + ;# Change the output pointer and pitch to be the actual + ;# desination instead of a temporary buffer. + addi r9, r7, 0 + addi r5, r8, 0 + + ;# no vertical filter, so write the output from the first pass + ;# directly into the output buffer. + beq- no_vertical_filter_bypass + + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + + ;# setup counter for the number of lines that are going to be filtered + li r0, 21 + + ;# use the stack as temporary storage + la r9, 48(r1) + li r5, 16 + +no_vertical_filter_bypass: + + mtctr r0 + + ;# rounding added in on the multiply + vspltisw v10, 8 + vspltisw v12, 3 + vslw v12, v10, v12 ;# 0x00000040000000400000004000000040 + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v13, 7 + + ;# index to the next set of vectors in the row. + li r10, 16 + li r12, 32 + +horizontal_loop_16x16: + + lvsl v15, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v1, 0, r3 + lvx v2, r10, r3 + lvx v3, r12, r3 + + vperm v8, v1, v2, v15 + vperm v9, v2, v3, v15 ;# v8 v9 = 21 input pixels left-justified + + vsldoi v11, v8, v9, 4 + + ;# set 0 + vmsummbm v6, v4, v8, v12 ;# taps times elements + vmsummbm v0, v5, v11, v6 + + ;# set 1 + vsldoi v10, v8, v9, 1 + vsldoi v11, v8, v9, 5 + + vmsummbm v6, v4, v10, v12 + vmsummbm v1, v5, v11, v6 + + ;# set 2 + vsldoi v10, v8, v9, 2 + vsldoi v11, v8, v9, 6 + + vmsummbm v6, v4, v10, v12 + vmsummbm v2, v5, v11, v6 + + ;# set 3 + vsldoi v10, v8, v9, 3 + vsldoi v11, v8, v9, 7 + + vmsummbm v6, v4, v10, v12 + vmsummbm v3, v5, v11, v6 + + vpkswus v0, v0, v1 ;# v0 = 0 4 8 C 1 5 9 D (16-bit) + vpkswus v1, v2, v3 ;# v1 = 2 6 A E 3 7 B F + + vsrh v0, v0, v13 ;# divide v0, v1 by 128 + vsrh v1, v1, v13 + + vpkuhus v0, v0, v1 ;# v0 = scrambled 8-bit result + vperm v0, v0, v0, v14 ;# v0 = correctly-ordered result + + stvx v0, 0, r9 + add r9, r9, r5 + + add r3, r3, r4 + + bdnz horizontal_loop_16x16 + + ;# check again to see if vertical filter needs to be done. + cmpi cr0, r6, 0 + beq cr0, end_16x16 + + ;# yes there is, so go to the second pass + b second_pass_16x16 + +copy_horizontal_16x21: + li r10, 21 + mtctr r10 + + li r10, 16 + + sub r3, r3, r4 + sub r3, r3, r4 + + ;# this is done above if there is a horizontal filter, + ;# if not it needs to be done down here. + slwi r6, r6, 4 ;# index into vertical filter array + + ;# always write to the stack when doing a horizontal copy + la r9, 48(r1) + +copy_horizontal_loop_16x21: + lvsl v15, 0, r3 ;# permutate value for alignment + + lvx v1, 0, r3 + lvx v2, r10, r3 + + vperm v8, v1, v2, v15 + + stvx v8, 0, r9 + addi r9, r9, 16 + + add r3, r3, r4 + + bdnz copy_horizontal_loop_16x21 + +second_pass_16x16: + + ;# always read from the stack when doing a vertical filter + la r9, 48(r1) + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v7, 7 + + vpre_load + + luma_vsix + luma_vsix + luma_vfour + +end_16x16: + + addi r1, r1, 416 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + + .align 4 +HFilter: + .byte 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, -6,123, 12, 0, -6,123, 12, 0, -6,123, 12, 0, -6,123, 12 + .byte -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0 + .byte 2,-11,108, 36, 2,-11,108, 36, 2,-11,108, 36, 2,-11,108, 36 + .byte -8, 1, 0, 0, -8, 1, 0, 0, -8, 1, 0, 0, -8, 1, 0, 0 + .byte 0, -9, 93, 50, 0, -9, 93, 50, 0, -9, 93, 50, 0, -9, 93, 50 + .byte -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0 + .byte 3,-16, 77, 77, 3,-16, 77, 77, 3,-16, 77, 77, 3,-16, 77, 77 + .byte -16, 3, 0, 0,-16, 3, 0, 0,-16, 3, 0, 0,-16, 3, 0, 0 + .byte 0, -6, 50, 93, 0, -6, 50, 93, 0, -6, 50, 93, 0, -6, 50, 93 + .byte -9, 0, 0, 0, -9, 0, 0, 0, -9, 0, 0, 0, -9, 0, 0, 0 + .byte 1, -8, 36,108, 1, -8, 36,108, 1, -8, 36,108, 1, -8, 36,108 + .byte -11, 2, 0, 0,-11, 2, 0, 0,-11, 2, 0, 0,-11, 2, 0, 0 + .byte 0, -1, 12,123, 0, -1, 12,123, 0, -1, 12,123, 0, -1, 12,123 + .byte -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0 + + .align 4 +VFilter: + .byte 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 6,123, 12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 2, 11,108, 36, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 9, 93, 50, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 3, 16, 77, 77, 16, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 6, 50, 93, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 1, 8, 36,108, 11, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 1, 12,123, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + .align 4 +b_hperm: + .byte 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 + + .align 4 +B_0123: + .byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + + .align 4 +B_4567: + .byte 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + + .align 4 +B_89AB: + .byte 8, 9, 10, 11, 9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14 + + .align 4 +b_hilo: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 + + .align 4 +b_hilo_4x4: + .byte 0, 1, 2, 3, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/vp8/common/ppc/filter_bilinear_altivec.asm b/vp8/common/ppc/filter_bilinear_altivec.asm new file mode 100644 index 0000000..fd8aa66 --- /dev/null +++ b/vp8/common/ppc/filter_bilinear_altivec.asm @@ -0,0 +1,677 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl bilinear_predict4x4_ppc + .globl bilinear_predict8x4_ppc + .globl bilinear_predict8x8_ppc + .globl bilinear_predict16x16_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +.macro load_vfilter V0, V1 + load_c \V0, vfilter_b, r6, r9, r10 + + addi r6, r6, 16 + lvx \V1, r6, r10 +.endm + +.macro HProlog jump_label + ;# load up horizontal filter + slwi. r5, r5, 4 ;# index into horizontal filter array + + ;# index to the next set of vectors in the row. + li r10, 16 + li r12, 32 + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq \jump_label + + load_c v20, hfilter_b, r5, r9, r0 + + ;# setup constants + ;# v14 permutation value for alignment + load_c v28, b_hperm_b, 0, r9, r0 + + ;# rounding added in on the multiply + vspltisw v21, 8 + vspltisw v18, 3 + vslw v18, v21, v18 ;# 0x00000040000000400000004000000040 + + slwi. r6, r6, 5 ;# index into vertical filter array +.endm + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# +.macro HFilter V + vperm v24, v21, v21, v10 ;# v20 = 0123 1234 2345 3456 + vperm v25, v21, v21, v11 ;# v21 = 4567 5678 6789 789A + + vmsummbm v24, v20, v24, v18 + vmsummbm v25, v20, v25, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + + vpkuhus \V, v24, v24 ;# \V = scrambled 8-bit result +.endm + +.macro hfilter_8 V, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 9 bytes wide, output is 8 bytes. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + + HFilter \V +.endm + + +.macro load_and_align_8 V, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + + vperm \V, v21, v22, v17 +.endm + +.macro write_aligned_8 V, increment_counter + stvx \V, 0, r7 + +.if \increment_counter + add r7, r7, r8 +.endif +.endm + +.macro vfilter_16 P0 P1 + vmuleub v22, \P0, v20 ;# 64 + 4 positive taps + vadduhm v22, v18, v22 + vmuloub v23, \P0, v20 + vadduhm v23, v18, v23 + + vmuleub v24, \P1, v21 + vadduhm v22, v22, v24 ;# Re = evens, saturation unnecessary + vmuloub v25, \P1, v21 + vadduhm v23, v23, v25 ;# Ro = odds + + vsrh v22, v22, v19 ;# divide by 128 + vsrh v23, v23, v19 ;# v16 v17 = evens, odds + vmrghh \P0, v22, v23 ;# v18 v19 = 16-bit result in order + vmrglh v23, v22, v23 + vpkuhus \P0, \P0, v23 ;# P0 = 8-bit result +.endm + + +.macro w_8x8 V, D, R, P + stvx \V, 0, r1 + lwz \R, 0(r1) + stw \R, 0(r7) + lwz \R, 4(r1) + stw \R, 4(r7) + add \D, \D, \P +.endm + + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict4x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf830 + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_4x4_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r9, r12 + load_c v11, b_4567_b, 0, r9, r12 + + hfilter_8 v0, 1 + hfilter_8 v1, 1 + hfilter_8 v2, 1 + hfilter_8 v3, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_4x4_b + + hfilter_8 v4, 0 + + b second_pass_4x4_b + +second_pass_4x4_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_8 v0, 1 + load_and_align_8 v1, 1 + load_and_align_8 v2, 1 + load_and_align_8 v3, 1 + load_and_align_8 v4, 1 + +second_pass_4x4_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + +store_out_4x4_b: + + stvx v0, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v1, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v2, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v3, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + +exit_4x4: + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict8x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf830 + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x4_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r9, r12 + load_c v11, b_4567_b, 0, r9, r12 + + hfilter_8 v0, 1 + hfilter_8 v1, 1 + hfilter_8 v2, 1 + hfilter_8 v3, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_8x4_b + + hfilter_8 v4, 0 + + b second_pass_8x4_b + +second_pass_8x4_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_8 v0, 1 + load_and_align_8 v1, 1 + load_and_align_8 v2, 1 + load_and_align_8 v3, 1 + load_and_align_8 v4, 1 + +second_pass_8x4_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + +store_out_8x4_b: + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x4_b + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + + b exit_8x4 + +store_aligned_8x4_b: + load_c v10, b_hilo_b, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + +exit_8x4: + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict8x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfff0 + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x8_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r9, r12 + load_c v11, b_4567_b, 0, r9, r12 + + hfilter_8 v0, 1 + hfilter_8 v1, 1 + hfilter_8 v2, 1 + hfilter_8 v3, 1 + hfilter_8 v4, 1 + hfilter_8 v5, 1 + hfilter_8 v6, 1 + hfilter_8 v7, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_8x8_b + + hfilter_8 v8, 0 + + b second_pass_8x8_b + +second_pass_8x8_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_8 v0, 1 + load_and_align_8 v1, 1 + load_and_align_8 v2, 1 + load_and_align_8 v3, 1 + load_and_align_8 v4, 1 + load_and_align_8 v5, 1 + load_and_align_8 v6, 1 + load_and_align_8 v7, 1 + load_and_align_8 v8, 0 + +second_pass_8x8_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + +store_out_8x8_b: + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x8_b + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + w_8x8 v6, r7, r0, r8 + w_8x8 v7, r7, r0, r8 + + b exit_8x8 + +store_aligned_8x8_b: + load_c v10, b_hilo_b, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + vperm v6, v6, v7, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + addi r7, r7, 16 + stvx v6, 0, r7 + +exit_8x8: + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# +.macro hfilter_16 V, increment_counter + + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + lvx v23, r12, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + vperm v22, v22, v23, v17 ;# v8 v9 = 21 input pixels left-justified + + ;# set 0 + vmsummbm v24, v20, v21, v18 ;# taps times elements + + ;# set 1 + vsldoi v23, v21, v22, 1 + vmsummbm v25, v20, v23, v18 + + ;# set 2 + vsldoi v23, v21, v22, 2 + vmsummbm v26, v20, v23, v18 + + ;# set 3 + vsldoi v23, v21, v22, 3 + vmsummbm v27, v20, v23, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + vpkswus v25, v26, v27 ;# v25 = 2 6 A E 3 7 B F + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + vsrh v25, v25, v19 + + vpkuhus \V, v24, v25 ;# \V = scrambled 8-bit result + vperm \V, \V, v0, v28 ;# \V = correctly-ordered result +.endm + +.macro load_and_align_16 V, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + + vperm \V, v21, v22, v17 +.endm + +.macro write_16 V, increment_counter + stvx \V, 0, r7 + +.if \increment_counter + add r7, r7, r8 +.endif +.endm + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + HProlog second_pass_16x16_pre_copy_b + + hfilter_16 v0, 1 + hfilter_16 v1, 1 + hfilter_16 v2, 1 + hfilter_16 v3, 1 + hfilter_16 v4, 1 + hfilter_16 v5, 1 + hfilter_16 v6, 1 + hfilter_16 v7, 1 + hfilter_16 v8, 1 + hfilter_16 v9, 1 + hfilter_16 v10, 1 + hfilter_16 v11, 1 + hfilter_16 v12, 1 + hfilter_16 v13, 1 + hfilter_16 v14, 1 + hfilter_16 v15, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_16x16_b + + hfilter_16 v16, 0 + + b second_pass_16x16_b + +second_pass_16x16_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, 1 + load_and_align_16 v1, 1 + load_and_align_16 v2, 1 + load_and_align_16 v3, 1 + load_and_align_16 v4, 1 + load_and_align_16 v5, 1 + load_and_align_16 v6, 1 + load_and_align_16 v7, 1 + load_and_align_16 v8, 1 + load_and_align_16 v9, 1 + load_and_align_16 v10, 1 + load_and_align_16 v11, 1 + load_and_align_16 v12, 1 + load_and_align_16 v13, 1 + load_and_align_16 v14, 1 + load_and_align_16 v15, 1 + load_and_align_16 v16, 0 + +second_pass_16x16_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + vfilter_16 v8, v9 + vfilter_16 v9, v10 + vfilter_16 v10, v11 + vfilter_16 v11, v12 + vfilter_16 v12, v13 + vfilter_16 v13, v14 + vfilter_16 v14, v15 + vfilter_16 v15, v16 + +store_out_16x16_b: + + write_16 v0, 1 + write_16 v1, 1 + write_16 v2, 1 + write_16 v3, 1 + write_16 v4, 1 + write_16 v5, 1 + write_16 v6, 1 + write_16 v7, 1 + write_16 v8, 1 + write_16 v9, 1 + write_16 v10, 1 + write_16 v11, 1 + write_16 v12, 1 + write_16 v13, 1 + write_16 v14, 1 + write_16 v15, 0 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + + .align 4 +hfilter_b: + .byte 128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0 + .byte 112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0 + .byte 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0 + .byte 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0 + .byte 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0 + .byte 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0 + .byte 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0 + .byte 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0 + + .align 4 +vfilter_b: + .byte 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + + .align 4 +b_hperm_b: + .byte 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 + + .align 4 +b_0123_b: + .byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + + .align 4 +b_4567_b: + .byte 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + +b_hilo_b: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 diff --git a/vp8/common/ppc/idctllm_altivec.asm b/vp8/common/ppc/idctllm_altivec.asm new file mode 100644 index 0000000..117d9cf --- /dev/null +++ b/vp8/common/ppc/idctllm_altivec.asm @@ -0,0 +1,189 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl short_idct4x4llm_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +;# r3 short *input +;# r4 short *output +;# r5 int pitch + .align 2 +short_idct4x4llm_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + load_c v8, sinpi8sqrt2, 0, r9, r10 + load_c v9, cospi8sqrt2minus1, 0, r9, r10 + load_c v10, hi_hi, 0, r9, r10 + load_c v11, lo_lo, 0, r9, r10 + load_c v12, shift_16, 0, r9, r10 + + li r10, 16 + lvx v0, 0, r3 ;# input ip[0], ip[ 4] + lvx v1, r10, r3 ;# input ip[8], ip[12] + + ;# first pass + vupkhsh v2, v0 + vupkhsh v3, v1 + vaddsws v6, v2, v3 ;# a1 = ip[0]+ip[8] + vsubsws v7, v2, v3 ;# b1 = ip[0]-ip[8] + + vupklsh v0, v0 + vmulosh v4, v0, v8 + vsraw v4, v4, v12 + vaddsws v4, v4, v0 ;# ip[ 4] * sin(pi/8) * sqrt(2) + + vupklsh v1, v1 + vmulosh v5, v1, v9 + vsraw v5, v5, v12 ;# ip[12] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v1 + + vsubsws v4, v4, v5 ;# c1 + + vmulosh v3, v1, v8 + vsraw v3, v3, v12 + vaddsws v3, v3, v1 ;# ip[12] * sin(pi/8) * sqrt(2) + + vmulosh v5, v0, v9 + vsraw v5, v5, v12 ;# ip[ 4] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v0 + + vaddsws v3, v3, v5 ;# d1 + + vaddsws v0, v6, v3 ;# a1 + d1 + vsubsws v3, v6, v3 ;# a1 - d1 + + vaddsws v1, v7, v4 ;# b1 + c1 + vsubsws v2, v7, v4 ;# b1 - c1 + + ;# transpose input + vmrghw v4, v0, v1 ;# a0 b0 a1 b1 + vmrghw v5, v2, v3 ;# c0 d0 c1 d1 + + vmrglw v6, v0, v1 ;# a2 b2 a3 b3 + vmrglw v7, v2, v3 ;# c2 d2 c3 d3 + + vperm v0, v4, v5, v10 ;# a0 b0 c0 d0 + vperm v1, v4, v5, v11 ;# a1 b1 c1 d1 + + vperm v2, v6, v7, v10 ;# a2 b2 c2 d2 + vperm v3, v6, v7, v11 ;# a3 b3 c3 d3 + + ;# second pass + vaddsws v6, v0, v2 ;# a1 = ip[0]+ip[8] + vsubsws v7, v0, v2 ;# b1 = ip[0]-ip[8] + + vmulosh v4, v1, v8 + vsraw v4, v4, v12 + vaddsws v4, v4, v1 ;# ip[ 4] * sin(pi/8) * sqrt(2) + + vmulosh v5, v3, v9 + vsraw v5, v5, v12 ;# ip[12] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v3 + + vsubsws v4, v4, v5 ;# c1 + + vmulosh v2, v3, v8 + vsraw v2, v2, v12 + vaddsws v2, v2, v3 ;# ip[12] * sin(pi/8) * sqrt(2) + + vmulosh v5, v1, v9 + vsraw v5, v5, v12 ;# ip[ 4] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v1 + + vaddsws v3, v2, v5 ;# d1 + + vaddsws v0, v6, v3 ;# a1 + d1 + vsubsws v3, v6, v3 ;# a1 - d1 + + vaddsws v1, v7, v4 ;# b1 + c1 + vsubsws v2, v7, v4 ;# b1 - c1 + + vspltish v6, 4 + vspltish v7, 3 + + vpkswss v0, v0, v1 + vpkswss v1, v2, v3 + + vaddshs v0, v0, v6 + vaddshs v1, v1, v6 + + vsrah v0, v0, v7 + vsrah v1, v1, v7 + + ;# transpose output + vmrghh v2, v0, v1 ;# a0 c0 a1 c1 a2 c2 a3 c3 + vmrglh v3, v0, v1 ;# b0 d0 b1 d1 b2 d2 b3 d3 + + vmrghh v0, v2, v3 ;# a0 b0 c0 d0 a1 b1 c1 d1 + vmrglh v1, v2, v3 ;# a2 b2 c2 d2 a3 b3 c3 d3 + + stwu r1,-416(r1) ;# create space on the stack + + stvx v0, 0, r1 + lwz r6, 0(r1) + stw r6, 0(r4) + lwz r6, 4(r1) + stw r6, 4(r4) + + add r4, r4, r5 + + lwz r6, 8(r1) + stw r6, 0(r4) + lwz r6, 12(r1) + stw r6, 4(r4) + + add r4, r4, r5 + + stvx v1, 0, r1 + lwz r6, 0(r1) + stw r6, 0(r4) + lwz r6, 4(r1) + stw r6, 4(r4) + + add r4, r4, r5 + + lwz r6, 8(r1) + stw r6, 0(r4) + lwz r6, 12(r1) + stw r6, 4(r4) + + addi r1, r1, 416 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 4 +sinpi8sqrt2: + .short 35468, 35468, 35468, 35468, 35468, 35468, 35468, 35468 + + .align 4 +cospi8sqrt2minus1: + .short 20091, 20091, 20091, 20091, 20091, 20091, 20091, 20091 + + .align 4 +shift_16: + .long 16, 16, 16, 16 + + .align 4 +hi_hi: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 + + .align 4 +lo_lo: + .byte 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 diff --git a/vp8/common/ppc/loopfilter_altivec.c b/vp8/common/ppc/loopfilter_altivec.c new file mode 100644 index 0000000..71bf6e2 --- /dev/null +++ b/vp8/common/ppc/loopfilter_altivec.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "loopfilter.h" +#include "onyxc_int.h" + +typedef void loop_filter_function_y_ppc +( + unsigned char *s, // source pointer + int p, // pitch + const signed char *flimit, + const signed char *limit, + const signed char *thresh +); + +typedef void loop_filter_function_uv_ppc +( + unsigned char *u, // source pointer + unsigned char *v, // source pointer + int p, // pitch + const signed char *flimit, + const signed char *limit, + const signed char *thresh +); + +typedef void loop_filter_function_s_ppc +( + unsigned char *s, // source pointer + int p, // pitch + const signed char *flimit +); + +loop_filter_function_y_ppc mbloop_filter_horizontal_edge_y_ppc; +loop_filter_function_y_ppc mbloop_filter_vertical_edge_y_ppc; +loop_filter_function_y_ppc loop_filter_horizontal_edge_y_ppc; +loop_filter_function_y_ppc loop_filter_vertical_edge_y_ppc; + +loop_filter_function_uv_ppc mbloop_filter_horizontal_edge_uv_ppc; +loop_filter_function_uv_ppc mbloop_filter_vertical_edge_uv_ppc; +loop_filter_function_uv_ppc loop_filter_horizontal_edge_uv_ppc; +loop_filter_function_uv_ppc loop_filter_vertical_edge_uv_ppc; + +loop_filter_function_s_ppc loop_filter_simple_horizontal_edge_ppc; +loop_filter_function_s_ppc loop_filter_simple_vertical_edge_ppc; + +// Horizontal MB filtering +void loop_filter_mbh_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + mbloop_filter_horizontal_edge_y_ppc(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->thr); + + if (u_ptr) + mbloop_filter_horizontal_edge_uv_ppc(u_ptr, v_ptr, uv_stride, lfi->mbflim, lfi->lim, lfi->thr); +} + +void loop_filter_mbhs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_horizontal_edge_ppc(y_ptr, y_stride, lfi->mbflim); +} + +// Vertical MB Filtering +void loop_filter_mbv_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + mbloop_filter_vertical_edge_y_ppc(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->thr); + + if (u_ptr) + mbloop_filter_vertical_edge_uv_ppc(u_ptr, v_ptr, uv_stride, lfi->mbflim, lfi->lim, lfi->thr); +} + +void loop_filter_mbvs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_vertical_edge_ppc(y_ptr, y_stride, lfi->mbflim); +} + +// Horizontal B Filtering +void loop_filter_bh_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + // These should all be done at once with one call, instead of 3 + loop_filter_horizontal_edge_y_ppc(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr); + loop_filter_horizontal_edge_y_ppc(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr); + loop_filter_horizontal_edge_y_ppc(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr); + + if (u_ptr) + loop_filter_horizontal_edge_uv_ppc(u_ptr + 4 * uv_stride, v_ptr + 4 * uv_stride, uv_stride, lfi->flim, lfi->lim, lfi->thr); +} + +void loop_filter_bhs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_horizontal_edge_ppc(y_ptr + 4 * y_stride, y_stride, lfi->flim); + loop_filter_simple_horizontal_edge_ppc(y_ptr + 8 * y_stride, y_stride, lfi->flim); + loop_filter_simple_horizontal_edge_ppc(y_ptr + 12 * y_stride, y_stride, lfi->flim); +} + +// Vertical B Filtering +void loop_filter_bv_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + loop_filter_vertical_edge_y_ppc(y_ptr, y_stride, lfi->flim, lfi->lim, lfi->thr); + + if (u_ptr) + loop_filter_vertical_edge_uv_ppc(u_ptr + 4, v_ptr + 4, uv_stride, lfi->flim, lfi->lim, lfi->thr); +} + +void loop_filter_bvs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_vertical_edge_ppc(y_ptr + 4, y_stride, lfi->flim); + loop_filter_simple_vertical_edge_ppc(y_ptr + 8, y_stride, lfi->flim); + loop_filter_simple_vertical_edge_ppc(y_ptr + 12, y_stride, lfi->flim); +} diff --git a/vp8/common/ppc/loopfilter_filters_altivec.asm b/vp8/common/ppc/loopfilter_filters_altivec.asm new file mode 100644 index 0000000..61df4e9 --- /dev/null +++ b/vp8/common/ppc/loopfilter_filters_altivec.asm @@ -0,0 +1,1253 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl mbloop_filter_horizontal_edge_y_ppc + .globl loop_filter_horizontal_edge_y_ppc + .globl mbloop_filter_vertical_edge_y_ppc + .globl loop_filter_vertical_edge_y_ppc + + .globl mbloop_filter_horizontal_edge_uv_ppc + .globl loop_filter_horizontal_edge_uv_ppc + .globl mbloop_filter_vertical_edge_uv_ppc + .globl loop_filter_vertical_edge_uv_ppc + + .globl loop_filter_simple_horizontal_edge_ppc + .globl loop_filter_simple_vertical_edge_ppc + + .text +;# We often need to perform transposes (and other transpose-like operations) +;# on matrices of data. This is simplified by the fact that we usually +;# operate on hunks of data whose dimensions are powers of 2, or at least +;# divisible by highish powers of 2. +;# +;# These operations can be very confusing. They become more straightforward +;# when we think of them as permutations of address bits: Concatenate a +;# group of vector registers and think of it as occupying a block of +;# memory beginning at address zero. The low four bits 0...3 of the +;# address then correspond to position within a register, the higher-order +;# address bits select the register. +;# +;# Although register selection, at the code level, is arbitrary, things +;# are simpler if we use contiguous ranges of register numbers, simpler +;# still if the low-order bits of the register number correspond to +;# conceptual address bits. We do this whenever reasonable. +;# +;# A 16x16 transpose can then be thought of as an operation on +;# a 256-element block of memory. It takes 8 bits 0...7 to address this +;# memory and the effect of a transpose is to interchange address bit +;# 0 with 4, 1 with 5, 2 with 6, and 3 with 7. Bits 0...3 index the +;# column, which is interchanged with the row addressed by bits 4..7. +;# +;# The altivec merge instructions provide a rapid means of effecting +;# many of these transforms. They operate at three widths (8,16,32). +;# Writing V(x) for vector register #x, paired merges permute address +;# indices as follows. +;# +;# 0->1 1->2 2->3 3->(4+d) (4+s)->0: +;# +;# vmrghb V( x), V( y), V( y + (1<2 2->3 3->(4+d) (4+s)->1: +;# +;# vmrghh V( x), V( y), V( y + (1<3 3->(4+d) (4+s)->2: +;# +;# vmrghw V( x), V( y), V( y + (1<(4+d) (4+s)->3 by the sequence: +;# +;# vperm V( x), V( y), V( y + (1<4 1<->5 2<->6 3<->7, which we accomplish by +;# 4 iterations of the cyclic transform 0->1->2->3->4->5->6->7->0. +;# +;# Except for the fact that the destination registers get written +;# before we are done referencing the old contents, the cyclic transform +;# is effected by +;# +;# x = 0; do { +;# vmrghb V(2x), V(x), V(x+8); +;# vmrghb V(2x+1), V(x), V(x+8); +;# } while( ++x < 8); +;# +;# For clarity, and because we can afford it, we do this transpose +;# using all 32 registers, alternating the banks 0..15 and 16 .. 31, +;# leaving the final result in 16 .. 31, as the lower registers are +;# used in the filtering itself. +;# +.macro Tpair A, B, X, Y + vmrghb \A, \X, \Y + vmrglb \B, \X, \Y +.endm + +;# Each step takes 8*2 = 16 instructions + +.macro t16_even + Tpair v16,v17, v0,v8 + Tpair v18,v19, v1,v9 + Tpair v20,v21, v2,v10 + Tpair v22,v23, v3,v11 + Tpair v24,v25, v4,v12 + Tpair v26,v27, v5,v13 + Tpair v28,v29, v6,v14 + Tpair v30,v31, v7,v15 +.endm + +.macro t16_odd + Tpair v0,v1, v16,v24 + Tpair v2,v3, v17,v25 + Tpair v4,v5, v18,v26 + Tpair v6,v7, v19,v27 + Tpair v8,v9, v20,v28 + Tpair v10,v11, v21,v29 + Tpair v12,v13, v22,v30 + Tpair v14,v15, v23,v31 +.endm + +;# Whole transpose takes 4*16 = 64 instructions + +.macro t16_full + t16_odd + t16_even + t16_odd + t16_even +.endm + +;# Vertical edge filtering requires transposes. For the simple filter, +;# we need to convert 16 rows of 4 pels each into 4 registers of 16 pels +;# each. Writing 0 ... 63 for the pixel indices, the desired result is: +;# +;# v0 = 0 1 ... 14 15 +;# v1 = 16 17 ... 30 31 +;# v2 = 32 33 ... 47 48 +;# v3 = 49 50 ... 62 63 +;# +;# In frame-buffer memory, the layout is: +;# +;# 0 16 32 48 +;# 1 17 33 49 +;# ... +;# 15 31 47 63. +;# +;# We begin by reading the data 32 bits at a time (using scalar operations) +;# into a temporary array, reading the rows of the array into vector registers, +;# with the following layout: +;# +;# v0 = 0 16 32 48 4 20 36 52 8 24 40 56 12 28 44 60 +;# v1 = 1 17 33 49 5 21 ... 45 61 +;# v2 = 2 18 ... 46 62 +;# v3 = 3 19 ... 47 63 +;# +;# From the "address-bit" perspective discussed above, we simply need to +;# interchange bits 0 <-> 4 and 1 <-> 5, leaving bits 2 and 3 alone. +;# In other words, we transpose each of the four 4x4 submatrices. +;# +;# This transformation is its own inverse, and we need to perform it +;# again before writing the pixels back into the frame buffer. +;# +;# It acts in place on registers v0...v3, uses v4...v7 as temporaries, +;# and assumes that v14/v15 contain the b_hihi/b_lolo selectors +;# defined above. We think of both groups of 4 registers as having +;# "addresses" {0,1,2,3} * 16. +;# +.macro Transpose4times4x4 Vlo, Vhi + + ;# d=s=0 0->1 1->2 2->3 3->4 4->0 =5= + + vmrghb v4, v0, v1 + vmrglb v5, v0, v1 + vmrghb v6, v2, v3 + vmrglb v7, v2, v3 + + ;# d=0 s=1 =0= 1->2 2->3 3->4 4->5 5->1 + + vmrghh v0, v4, v6 + vmrglh v1, v4, v6 + vmrghh v2, v5, v7 + vmrglh v3, v5, v7 + + ;# d=s=0 =0= =1= 2->3 3->4 4->2 =5= + + vmrghw v4, v0, v1 + vmrglw v5, v0, v1 + vmrghw v6, v2, v3 + vmrglw v7, v2, v3 + + ;# d=0 s=1 =0= =1= =2= 3->4 4->5 5->3 + + vperm v0, v4, v6, \Vlo + vperm v1, v4, v6, \Vhi + vperm v2, v5, v7, \Vlo + vperm v3, v5, v7, \Vhi +.endm +;# end Transpose4times4x4 + + +;# Normal mb vertical edge filter transpose. +;# +;# We read 8 columns of data, initially in the following pattern: +;# +;# (0,0) (1,0) ... (7,0) (0,1) (1,1) ... (7,1) +;# (0,2) (1,2) ... (7,2) (0,3) (1,3) ... (7,3) +;# ... +;# (0,14) (1,14) .. (7,14) (0,15) (1,15) .. (7,15) +;# +;# and wish to convert to: +;# +;# (0,0) ... (0,15) +;# (1,0) ... (1,15) +;# ... +;# (7,0) ... (7,15). +;# +;# In "address bit" language, we wish to map +;# +;# 0->4 1->5 2->6 3->0 4->1 5->2 6->3, i.e., I -> (I+4) mod 7. +;# +;# This can be accomplished by 4 iterations of the cyclic transform +;# +;# I -> (I+1) mod 7; +;# +;# each iteration can be realized by (d=0, s=2): +;# +;# x = 0; do Tpair( V(2x),V(2x+1), V(x),V(x+4)) while( ++x < 4); +;# +;# The input/output is in registers v0...v7. We use v10...v17 as mirrors; +;# preserving v8 = sign converter. +;# +;# Inverse transpose is similar, except here I -> (I+3) mod 7 and the +;# result lands in the "mirror" registers v10...v17 +;# +.macro t8x16_odd + Tpair v10, v11, v0, v4 + Tpair v12, v13, v1, v5 + Tpair v14, v15, v2, v6 + Tpair v16, v17, v3, v7 +.endm + +.macro t8x16_even + Tpair v0, v1, v10, v14 + Tpair v2, v3, v11, v15 + Tpair v4, v5, v12, v16 + Tpair v6, v7, v13, v17 +.endm + +.macro transpose8x16_fwd + t8x16_odd + t8x16_even + t8x16_odd + t8x16_even +.endm + +.macro transpose8x16_inv + t8x16_odd + t8x16_even + t8x16_odd +.endm + +.macro Transpose16x16 + vmrghb v0, v16, v24 + vmrglb v1, v16, v24 + vmrghb v2, v17, v25 + vmrglb v3, v17, v25 + vmrghb v4, v18, v26 + vmrglb v5, v18, v26 + vmrghb v6, v19, v27 + vmrglb v7, v19, v27 + vmrghb v8, v20, v28 + vmrglb v9, v20, v28 + vmrghb v10, v21, v29 + vmrglb v11, v21, v29 + vmrghb v12, v22, v30 + vmrglb v13, v22, v30 + vmrghb v14, v23, v31 + vmrglb v15, v23, v31 + vmrghb v16, v0, v8 + vmrglb v17, v0, v8 + vmrghb v18, v1, v9 + vmrglb v19, v1, v9 + vmrghb v20, v2, v10 + vmrglb v21, v2, v10 + vmrghb v22, v3, v11 + vmrglb v23, v3, v11 + vmrghb v24, v4, v12 + vmrglb v25, v4, v12 + vmrghb v26, v5, v13 + vmrglb v27, v5, v13 + vmrghb v28, v6, v14 + vmrglb v29, v6, v14 + vmrghb v30, v7, v15 + vmrglb v31, v7, v15 + vmrghb v0, v16, v24 + vmrglb v1, v16, v24 + vmrghb v2, v17, v25 + vmrglb v3, v17, v25 + vmrghb v4, v18, v26 + vmrglb v5, v18, v26 + vmrghb v6, v19, v27 + vmrglb v7, v19, v27 + vmrghb v8, v20, v28 + vmrglb v9, v20, v28 + vmrghb v10, v21, v29 + vmrglb v11, v21, v29 + vmrghb v12, v22, v30 + vmrglb v13, v22, v30 + vmrghb v14, v23, v31 + vmrglb v15, v23, v31 + vmrghb v16, v0, v8 + vmrglb v17, v0, v8 + vmrghb v18, v1, v9 + vmrglb v19, v1, v9 + vmrghb v20, v2, v10 + vmrglb v21, v2, v10 + vmrghb v22, v3, v11 + vmrglb v23, v3, v11 + vmrghb v24, v4, v12 + vmrglb v25, v4, v12 + vmrghb v26, v5, v13 + vmrglb v27, v5, v13 + vmrghb v28, v6, v14 + vmrglb v29, v6, v14 + vmrghb v30, v7, v15 + vmrglb v31, v7, v15 +.endm + +;# load_g loads a global vector (whose address is in the local variable Gptr) +;# into vector register Vreg. Trashes r0 +.macro load_g Vreg, Gptr + lwz r0, \Gptr + lvx \Vreg, 0, r0 +.endm + +;# exploit the saturation here. if the answer is negative +;# it will be clamped to 0. orring 0 with a positive +;# number will be the positive number (abs) +;# RES = abs( A-B), trashes TMP +.macro Abs RES, TMP, A, B + vsububs \RES, \A, \B + vsububs \TMP, \B, \A + vor \RES, \RES, \TMP +.endm + +;# RES = Max( RES, abs( A-B)), trashes TMP +.macro max_abs RES, TMP, A, B + vsububs \TMP, \A, \B + vmaxub \RES, \RES, \TMP + vsububs \TMP, \B, \A + vmaxub \RES, \RES, \TMP +.endm + +.macro Masks + ;# build masks + ;# input is all 8 bit unsigned (0-255). need to + ;# do abs(vala-valb) > limit. but no need to compare each + ;# value to the limit. find the max of the absolute differences + ;# and compare that to the limit. + ;# First hev + Abs v14, v13, v2, v3 ;# |P1 - P0| + max_abs v14, v13, v5, v4 ;# |Q1 - Q0| + + vcmpgtub v10, v14, v10 ;# HEV = true if thresh exceeded + + ;# Next limit + max_abs v14, v13, v0, v1 ;# |P3 - P2| + max_abs v14, v13, v1, v2 ;# |P2 - P1| + max_abs v14, v13, v6, v5 ;# |Q2 - Q1| + max_abs v14, v13, v7, v6 ;# |Q3 - Q2| + + vcmpgtub v9, v14, v9 ;# R = true if limit exceeded + + ;# flimit + Abs v14, v13, v3, v4 ;# |P0 - Q0| + + vcmpgtub v8, v14, v8 ;# X = true if flimit exceeded + + vor v8, v8, v9 ;# R = true if flimit or limit exceeded + ;# done building masks +.endm + +.macro build_constants RFL, RLI, RTH, FL, LI, TH + ;# build constants + lvx \FL, 0, \RFL ;# flimit + lvx \LI, 0, \RLI ;# limit + lvx \TH, 0, \RTH ;# thresh + + vspltisb v11, 8 + vspltisb v12, 4 + vslb v11, v11, v12 ;# 0x80808080808080808080808080808080 +.endm + +.macro load_data_y + ;# setup strides/pointers to be able to access + ;# all of the data + add r5, r4, r4 ;# r5 = 2 * stride + sub r6, r3, r5 ;# r6 -> 2 rows back + neg r7, r4 ;# r7 = -stride + + ;# load 16 pixels worth of data to work on + sub r0, r6, r5 ;# r0 -> 4 rows back (temp) + lvx v0, 0, r0 ;# P3 (read only) + lvx v1, r7, r6 ;# P2 + lvx v2, 0, r6 ;# P1 + lvx v3, r7, r3 ;# P0 + lvx v4, 0, r3 ;# Q0 + lvx v5, r4, r3 ;# Q1 + lvx v6, r5, r3 ;# Q2 + add r0, r3, r5 ;# r0 -> 2 rows fwd (temp) + lvx v7, r4, r0 ;# Q3 (read only) +.endm + +;# Expects +;# v10 == HEV +;# v13 == tmp +;# v14 == tmp +.macro common_adjust P0, Q0, P1, Q1, HEV_PRESENT + vxor \P1, \P1, v11 ;# SP1 + vxor \P0, \P0, v11 ;# SP0 + vxor \Q0, \Q0, v11 ;# SQ0 + vxor \Q1, \Q1, v11 ;# SQ1 + + vsubsbs v13, \P1, \Q1 ;# f = c (P1 - Q1) +.if \HEV_PRESENT + vand v13, v13, v10 ;# f &= hev +.endif + vsubsbs v14, \Q0, \P0 ;# -126 <= X = Q0-P0 <= +126 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + + vandc v13, v13, v8 ;# f &= mask + + vspltisb v8, 3 + vspltisb v9, 4 + + vaddsbs v14, v13, v9 ;# f1 = c (f+4) + vaddsbs v15, v13, v8 ;# f2 = c (f+3) + + vsrab v13, v14, v8 ;# f1 >>= 3 + vsrab v15, v15, v8 ;# f2 >>= 3 + + vsubsbs \Q0, \Q0, v13 ;# u1 = c (SQ0 - f1) + vaddsbs \P0, \P0, v15 ;# u2 = c (SP0 + f2) +.endm + +.macro vp8_mbfilter + Masks + + ;# start the fitering here + vxor v1, v1, v11 ;# SP2 + vxor v2, v2, v11 ;# SP1 + vxor v3, v3, v11 ;# SP0 + vxor v4, v4, v11 ;# SQ0 + vxor v5, v5, v11 ;# SQ1 + vxor v6, v6, v11 ;# SQ2 + + ;# add outer taps if we have high edge variance + vsubsbs v13, v2, v5 ;# f = c (SP1-SQ1) + + vsubsbs v14, v4, v3 ;# SQ0-SP0 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 ;# f = c( c(SP1-SQ1) + 3*(SQ0-SP0)) + + vandc v13, v13, v8 ;# f &= mask + vand v15, v13, v10 ;# f2 = f & hev + + ;# save bottom 3 bits so that we round one side +4 and the other +3 + vspltisb v8, 3 + vspltisb v9, 4 + + vaddsbs v14, v15, v9 ;# f1 = c (f+4) + vaddsbs v15, v15, v8 ;# f2 = c (f+3) + + vsrab v14, v14, v8 ;# f1 >>= 3 + vsrab v15, v15, v8 ;# f2 >>= 3 + + vsubsbs v4, v4, v14 ;# u1 = c (SQ0 - f1) + vaddsbs v3, v3, v15 ;# u2 = c (SP0 + f2) + + ;# only apply wider filter if not high edge variance + vandc v13, v13, v10 ;# f &= ~hev + + vspltisb v9, 2 + vnor v8, v8, v8 + vsrb v9, v8, v9 ;# 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f + vupkhsb v9, v9 ;# 0x003f003f003f003f003f003f003f003f + vspltisb v8, 9 + + ;# roughly 1/7th difference across boundary + vspltish v10, 7 + vmulosb v14, v8, v13 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + vmulesb v15, v8, v13 + vaddshs v14, v14, v9 ;# += 63 + vaddshs v15, v15, v9 + vsrah v14, v14, v10 ;# >>= 7 + vsrah v15, v15, v10 + vmrglh v10, v15, v14 + vmrghh v15, v15, v14 + + vpkshss v10, v15, v10 ;# X = saturated down to bytes + + vsubsbs v6, v6, v10 ;# subtract from Q and add to P + vaddsbs v1, v1, v10 + + vxor v6, v6, v11 + vxor v1, v1, v11 + + ;# roughly 2/7th difference across boundary + vspltish v10, 7 + vaddubm v12, v8, v8 + vmulosb v14, v12, v13 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + vmulesb v15, v12, v13 + vaddshs v14, v14, v9 + vaddshs v15, v15, v9 + vsrah v14, v14, v10 ;# >>= 7 + vsrah v15, v15, v10 + vmrglh v10, v15, v14 + vmrghh v15, v15, v14 + + vpkshss v10, v15, v10 ;# X = saturated down to bytes + + vsubsbs v5, v5, v10 ;# subtract from Q and add to P + vaddsbs v2, v2, v10 + + vxor v5, v5, v11 + vxor v2, v2, v11 + + ;# roughly 3/7th difference across boundary + vspltish v10, 7 + vaddubm v12, v12, v8 + vmulosb v14, v12, v13 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + vmulesb v15, v12, v13 + vaddshs v14, v14, v9 + vaddshs v15, v15, v9 + vsrah v14, v14, v10 ;# >>= 7 + vsrah v15, v15, v10 + vmrglh v10, v15, v14 + vmrghh v15, v15, v14 + + vpkshss v10, v15, v10 ;# X = saturated down to bytes + + vsubsbs v4, v4, v10 ;# subtract from Q and add to P + vaddsbs v3, v3, v10 + + vxor v4, v4, v11 + vxor v3, v3, v11 +.endm + +.macro SBFilter + Masks + + common_adjust v3, v4, v2, v5, 1 + + ;# outer tap adjustments + vspltisb v8, 1 + + vaddubm v13, v13, v8 ;# f += 1 + vsrab v13, v13, v8 ;# f >>= 1 + + vandc v13, v13, v10 ;# f &= ~hev + + vsubsbs v5, v5, v13 ;# u1 = c (SQ1 - f) + vaddsbs v2, v2, v13 ;# u2 = c (SP1 + f) + + vxor v2, v2, v11 + vxor v3, v3, v11 + vxor v4, v4, v11 + vxor v5, v5, v11 +.endm + + .align 2 +mbloop_filter_horizontal_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r5, r6, r7, v8, v9, v10 + + load_data_y + + vp8_mbfilter + + stvx v1, r7, r6 ;# P2 + stvx v2, 0, r6 ;# P1 + stvx v3, r7, r3 ;# P0 + stvx v4, 0, r3 ;# Q0 + stvx v5, r4, r3 ;# Q1 + stvx v6, r5, r3 ;# Q2 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +;# r6 const signed char *limit +;# r7 const signed char *thresh +loop_filter_horizontal_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r5, r6, r7, v8, v9, v10 + + load_data_y + + SBFilter + + stvx v2, 0, r6 ;# P1 + stvx v3, r7, r3 ;# P0 + stvx v4, 0, r3 ;# Q0 + stvx v5, r4, r3 ;# Q1 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# Filtering a vertical mb. Each mb is aligned on a 16 byte boundary. +;# So we can read in an entire mb aligned. However if we want to filter the mb +;# edge we run into problems. For the loopfilter we require 4 bytes before the mb +;# and 4 after for a total of 8 bytes. Reading 16 bytes inorder to get 4 is a bit +;# of a waste. So this is an even uglier way to get around that. +;# Using the regular register file words are read in and then saved back out to +;# memory to align and order them up. Then they are read in using the +;# vector register file. +.macro RLVmb V, R + lwzux r0, r3, r4 + stw r0, 4(\R) + lwz r0,-4(r3) + stw r0, 0(\R) + lwzux r0, r3, r4 + stw r0,12(\R) + lwz r0,-4(r3) + stw r0, 8(\R) + lvx \V, 0, \R +.endm + +.macro WLVmb V, R + stvx \V, 0, \R + lwz r0,12(\R) + stwux r0, r3, r4 + lwz r0, 8(\R) + stw r0,-4(r3) + lwz r0, 4(\R) + stwux r0, r3, r4 + lwz r0, 0(\R) + stw r0,-4(r3) +.endm + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +;# r6 const signed char *limit +;# r7 const signed char *thresh +mbloop_filter_vertical_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + la r9, -48(r1) ;# temporary space for reading in vectors + sub r3, r3, r4 + + RLVmb v0, r9 + RLVmb v1, r9 + RLVmb v2, r9 + RLVmb v3, r9 + RLVmb v4, r9 + RLVmb v5, r9 + RLVmb v6, r9 + RLVmb v7, r9 + + transpose8x16_fwd + + build_constants r5, r6, r7, v8, v9, v10 + + vp8_mbfilter + + transpose8x16_inv + + add r3, r3, r4 + neg r4, r4 + + WLVmb v17, r9 + WLVmb v16, r9 + WLVmb v15, r9 + WLVmb v14, r9 + WLVmb v13, r9 + WLVmb v12, r9 + WLVmb v11, r9 + WLVmb v10, r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro RL V, R, P + lvx \V, 0, \R + add \R, \R, \P +.endm + +.macro WL V, R, P + stvx \V, 0, \R + add \R, \R, \P +.endm + +.macro Fil P3, P2, P1, P0, Q0, Q1, Q2, Q3 + ;# K = |P0-P1| already + Abs v14, v13, \Q0, \Q1 ;# M = |Q0-Q1| + vmaxub v14, v14, v4 ;# M = max( |P0-P1|, |Q0-Q1|) + vcmpgtub v10, v14, v0 + + Abs v4, v5, \Q2, \Q3 ;# K = |Q2-Q3| = next |P0-P1] + + max_abs v14, v13, \Q1, \Q2 ;# M = max( M, |Q1-Q2|) + max_abs v14, v13, \P1, \P2 ;# M = max( M, |P1-P2|) + max_abs v14, v13, \P2, \P3 ;# M = max( M, |P2-P3|) + + vmaxub v14, v14, v4 ;# M = max interior abs diff + vcmpgtub v9, v14, v2 ;# M = true if int_l exceeded + + Abs v14, v13, \P0, \Q0 ;# X = Abs( P0-Q0) + vcmpgtub v8, v14, v3 ;# X = true if edge_l exceeded + vor v8, v8, v9 ;# M = true if edge_l or int_l exceeded + + ;# replace P1,Q1 w/signed versions + common_adjust \P0, \Q0, \P1, \Q1, 1 + + vaddubm v13, v13, v1 ;# -16 <= M <= 15, saturation irrelevant + vsrab v13, v13, v1 + vandc v13, v13, v10 ;# adjust P1,Q1 by (M+1)>>1 if ! hev + vsubsbs \Q1, \Q1, v13 + vaddsbs \P1, \P1, v13 + + vxor \P1, \P1, v11 ;# P1 + vxor \P0, \P0, v11 ;# P0 + vxor \Q0, \Q0, v11 ;# Q0 + vxor \Q1, \Q1, v11 ;# Q1 +.endm + + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +;# r6 const signed char *limit +;# r7 const signed char *thresh +loop_filter_vertical_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + addi r9, r3, 0 + RL v16, r9, r4 + RL v17, r9, r4 + RL v18, r9, r4 + RL v19, r9, r4 + RL v20, r9, r4 + RL v21, r9, r4 + RL v22, r9, r4 + RL v23, r9, r4 + RL v24, r9, r4 + RL v25, r9, r4 + RL v26, r9, r4 + RL v27, r9, r4 + RL v28, r9, r4 + RL v29, r9, r4 + RL v30, r9, r4 + lvx v31, 0, r9 + + Transpose16x16 + + vspltisb v1, 1 + + build_constants r5, r6, r7, v3, v2, v0 + + Abs v4, v5, v19, v18 ;# K(v14) = first |P0-P1| + + Fil v16, v17, v18, v19, v20, v21, v22, v23 + Fil v20, v21, v22, v23, v24, v25, v26, v27 + Fil v24, v25, v26, v27, v28, v29, v30, v31 + + Transpose16x16 + + addi r9, r3, 0 + WL v16, r9, r4 + WL v17, r9, r4 + WL v18, r9, r4 + WL v19, r9, r4 + WL v20, r9, r4 + WL v21, r9, r4 + WL v22, r9, r4 + WL v23, r9, r4 + WL v24, r9, r4 + WL v25, r9, r4 + WL v26, r9, r4 + WL v27, r9, r4 + WL v28, r9, r4 + WL v29, r9, r4 + WL v30, r9, r4 + stvx v31, 0, r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- UV FILTERING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +.macro active_chroma_sel V + andi. r7, r3, 8 ;# row origin modulo 16 + add r7, r7, r7 ;# selects selectors + lis r12, _chromaSelectors@ha + la r0, _chromaSelectors@l(r12) + lwzux r0, r7, r0 ;# leave selector addr in r7 + + lvx \V, 0, r0 ;# mask to concatenate active U,V pels +.endm + +.macro hread_uv Dest, U, V, Offs, VMask + lvx \U, \Offs, r3 + lvx \V, \Offs, r4 + vperm \Dest, \U, \V, \VMask ;# Dest = active part of U then V +.endm + +.macro hwrite_uv New, U, V, Offs, Umask, Vmask + vperm \U, \New, \U, \Umask ;# Combine new pels with siblings + vperm \V, \New, \V, \Vmask + stvx \U, \Offs, r3 ;# Write to frame buffer + stvx \V, \Offs, r4 +.endm + +;# Process U,V in parallel. +.macro load_chroma_h + neg r9, r5 ;# r9 = -1 * stride + add r8, r9, r9 ;# r8 = -2 * stride + add r10, r5, r5 ;# r10 = 2 * stride + + active_chroma_sel v12 + + ;# P3, Q3 are read-only; need not save addresses or sibling pels + add r6, r8, r8 ;# r6 = -4 * stride + hread_uv v0, v14, v15, r6, v12 + add r6, r10, r5 ;# r6 = 3 * stride + hread_uv v7, v14, v15, r6, v12 + + ;# Others are read/write; save addresses and sibling pels + + add r6, r8, r9 ;# r6 = -3 * stride + hread_uv v1, v16, v17, r6, v12 + hread_uv v2, v18, v19, r8, v12 + hread_uv v3, v20, v21, r9, v12 + hread_uv v4, v22, v23, 0, v12 + hread_uv v5, v24, v25, r5, v12 + hread_uv v6, v26, v27, r10, v12 +.endm + +.macro uresult_sel V + load_g \V, 4(r7) +.endm + +.macro vresult_sel V + load_g \V, 8(r7) +.endm + +;# always write P1,P0,Q0,Q1 +.macro store_chroma_h + uresult_sel v11 + vresult_sel v12 + hwrite_uv v2, v18, v19, r8, v11, v12 + hwrite_uv v3, v20, v21, r9, v11, v12 + hwrite_uv v4, v22, v23, 0, v11, v12 + hwrite_uv v5, v24, v25, r5, v11, v12 +.endm + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +mbloop_filter_horizontal_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r6, r7, r8, v8, v9, v10 + + load_chroma_h + + vp8_mbfilter + + store_chroma_h + + hwrite_uv v1, v16, v17, r6, v11, v12 ;# v1 == P2 + hwrite_uv v6, v26, v27, r10, v11, v12 ;# v6 == Q2 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +loop_filter_horizontal_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r6, r7, r8, v8, v9, v10 + + load_chroma_h + + SBFilter + + store_chroma_h + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro R V, R + lwzux r0, r3, r5 + stw r0, 4(\R) + lwz r0,-4(r3) + stw r0, 0(\R) + lwzux r0, r4, r5 + stw r0,12(\R) + lwz r0,-4(r4) + stw r0, 8(\R) + lvx \V, 0, \R +.endm + + +.macro W V, R + stvx \V, 0, \R + lwz r0,12(\R) + stwux r0, r4, r5 + lwz r0, 8(\R) + stw r0,-4(r4) + lwz r0, 4(\R) + stwux r0, r3, r5 + lwz r0, 0(\R) + stw r0,-4(r3) +.endm + +.macro chroma_vread R + sub r3, r3, r5 ;# back up one line for simplicity + sub r4, r4, r5 + + R v0, \R + R v1, \R + R v2, \R + R v3, \R + R v4, \R + R v5, \R + R v6, \R + R v7, \R + + transpose8x16_fwd +.endm + +.macro chroma_vwrite R + + transpose8x16_inv + + add r3, r3, r5 + add r4, r4, r5 + neg r5, r5 ;# Write rows back in reverse order + + W v17, \R + W v16, \R + W v15, \R + W v14, \R + W v13, \R + W v12, \R + W v11, \R + W v10, \R +.endm + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +mbloop_filter_vertical_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + la r9, -48(r1) ;# temporary space for reading in vectors + + chroma_vread r9 + + build_constants r6, r7, r8, v8, v9, v10 + + vp8_mbfilter + + chroma_vwrite r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +loop_filter_vertical_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + la r9, -48(r1) ;# temporary space for reading in vectors + + chroma_vread r9 + + build_constants r6, r7, r8, v8, v9, v10 + + SBFilter + + chroma_vwrite r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# -=-=-=-=-=-=-=-=-=-=-=-=-=-= SIMPLE LOOP FILTER =-=-=-=-=-=-=-=-=-=-=-=-=-=- + +.macro vp8_simple_filter + Abs v14, v13, v1, v2 ;# M = abs( P0 - Q0) + vcmpgtub v8, v14, v8 ;# v5 = true if _over_ limit + + ;# preserve unsigned v0 and v3 + common_adjust v1, v2, v0, v3, 0 + + vxor v1, v1, v11 + vxor v2, v2, v11 ;# cvt Q0, P0 back to pels +.endm + +.macro simple_vertical + addi r8, 0, 16 + addi r7, r5, 32 + + lvx v0, 0, r5 + lvx v1, r8, r5 + lvx v2, 0, r7 + lvx v3, r8, r7 + + lis r12, _B_hihi@ha + la r0, _B_hihi@l(r12) + lvx v16, 0, r0 + + lis r12, _B_lolo@ha + la r0, _B_lolo@l(r12) + lvx v17, 0, r0 + + Transpose4times4x4 v16, v17 + vp8_simple_filter + + vxor v0, v0, v11 + vxor v3, v3, v11 ;# cvt Q0, P0 back to pels + + Transpose4times4x4 v16, v17 + + stvx v0, 0, r5 + stvx v1, r8, r5 + stvx v2, 0, r7 + stvx v3, r8, r7 +.endm + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +loop_filter_simple_horizontal_edge_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + mtspr 256, r12 ;# set VRSAVE + + ;# build constants + lvx v8, 0, r5 ;# flimit + + vspltisb v11, 8 + vspltisb v12, 4 + vslb v11, v11, v12 ;# 0x80808080808080808080808080808080 + + neg r5, r4 ;# r5 = -1 * stride + add r6, r5, r5 ;# r6 = -2 * stride + + lvx v0, r6, r3 ;# v0 = P1 = 16 pels two rows above edge + lvx v1, r5, r3 ;# v1 = P0 = 16 pels one row above edge + lvx v2, 0, r3 ;# v2 = Q0 = 16 pels one row below edge + lvx v3, r4, r3 ;# v3 = Q1 = 16 pels two rows below edge + + vp8_simple_filter + + stvx v1, r5, r3 ;# store P0 + stvx v2, 0, r3 ;# store Q0 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro RLV Offs + stw r0, (\Offs*4)(r5) + lwzux r0, r7, r4 +.endm + +.macro WLV Offs + lwz r0, (\Offs*4)(r5) + stwux r0, r7, r4 +.endm + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +loop_filter_simple_vertical_edge_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + ;# build constants + lvx v8, 0, r5 ;# flimit + + vspltisb v11, 8 + vspltisb v12, 4 + vslb v11, v11, v12 ;# 0x80808080808080808080808080808080 + + la r5, -96(r1) ;# temporary space for reading in vectors + + ;# Store 4 pels at word "Offs" in temp array, then advance r7 + ;# to next row and read another 4 pels from the frame buffer. + + subi r7, r3, 2 ;# r7 -> 2 pels before start + lwzx r0, 0, r7 ;# read first 4 pels + + ;# 16 unaligned word accesses + RLV 0 + RLV 4 + RLV 8 + RLV 12 + RLV 1 + RLV 5 + RLV 9 + RLV 13 + RLV 2 + RLV 6 + RLV 10 + RLV 14 + RLV 3 + RLV 7 + RLV 11 + + stw r0, (15*4)(r5) ;# write last 4 pels + + simple_vertical + + ;# Read temp array, write frame buffer. + subi r7, r3, 2 ;# r7 -> 2 pels before start + lwzx r0, 0, r5 ;# read/write first 4 pels + stwx r0, 0, r7 + + WLV 4 + WLV 8 + WLV 12 + WLV 1 + WLV 5 + WLV 9 + WLV 13 + WLV 2 + WLV 6 + WLV 10 + WLV 14 + WLV 3 + WLV 7 + WLV 11 + WLV 15 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + +_chromaSelectors: + .long _B_hihi + .long _B_Ures0 + .long _B_Vres0 + .long 0 + .long _B_lolo + .long _B_Ures8 + .long _B_Vres8 + .long 0 + + .align 4 +_B_Vres8: + .byte 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15 + + .align 4 +_B_Ures8: + .byte 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7 + + .align 4 +_B_lolo: + .byte 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 + + .align 4 +_B_Vres0: + .byte 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 + .align 4 +_B_Ures0: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31 + + .align 4 +_B_hihi: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 diff --git a/vp8/common/ppc/platform_altivec.asm b/vp8/common/ppc/platform_altivec.asm new file mode 100644 index 0000000..f81d86f --- /dev/null +++ b/vp8/common/ppc/platform_altivec.asm @@ -0,0 +1,59 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl save_platform_context + .globl restore_platform_context + +.macro W V P + stvx \V, 0, \P + addi \P, \P, 16 +.endm + +.macro R V P + lvx \V, 0, \P + addi \P, \P, 16 +.endm + +;# r3 context_ptr + .align 2 +save_platform_contex: + W v20, r3 + W v21, r3 + W v22, r3 + W v23, r3 + W v24, r3 + W v25, r3 + W v26, r3 + W v27, r3 + W v28, r3 + W v29, r3 + W v30, r3 + W v31, r3 + + blr + +;# r3 context_ptr + .align 2 +restore_platform_context: + R v20, r3 + R v21, r3 + R v22, r3 + R v23, r3 + R v24, r3 + R v25, r3 + R v26, r3 + R v27, r3 + R v28, r3 + R v29, r3 + R v30, r3 + R v31, r3 + + blr diff --git a/vp8/common/ppc/recon_altivec.asm b/vp8/common/ppc/recon_altivec.asm new file mode 100644 index 0000000..dd39e05 --- /dev/null +++ b/vp8/common/ppc/recon_altivec.asm @@ -0,0 +1,175 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl recon4b_ppc + .globl recon2b_ppc + .globl recon_b_ppc + +.macro row_of16 Diff Pred Dst Stride + lvx v1, 0, \Pred ;# v1 = pred = p0..p15 + addi \Pred, \Pred, 16 ;# next pred + vmrghb v2, v0, v1 ;# v2 = 16-bit p0..p7 + lvx v3, 0, \Diff ;# v3 = d0..d7 + vaddshs v2, v2, v3 ;# v2 = r0..r7 + vmrglb v1, v0, v1 ;# v1 = 16-bit p8..p15 + lvx v3, r8, \Diff ;# v3 = d8..d15 + addi \Diff, \Diff, 32 ;# next diff + vaddshs v3, v3, v1 ;# v3 = r8..r15 + vpkshus v2, v2, v3 ;# v2 = 8-bit r0..r15 + stvx v2, 0, \Dst ;# to dst + add \Dst, \Dst, \Stride ;# next dst +.endm + + .text + .align 2 +;# r3 = short *diff_ptr, +;# r4 = unsigned char *pred_ptr, +;# r5 = unsigned char *dst_ptr, +;# r6 = int stride +recon4b_ppc: + mfspr r0, 256 ;# get old VRSAVE + stw r0, -8(r1) ;# save old VRSAVE to stack + oris r0, r0, 0xf000 + mtspr 256,r0 ;# set VRSAVE + + vxor v0, v0, v0 + li r8, 16 + + row_of16 r3, r4, r5, r6 + row_of16 r3, r4, r5, r6 + row_of16 r3, r4, r5, r6 + row_of16 r3, r4, r5, r6 + + lwz r12, -8(r1) ;# restore old VRSAVE from stack + mtspr 256, r12 ;# reset old VRSAVE + + blr + +.macro two_rows_of8 Diff Pred Dst Stride write_first_four_pels + lvx v1, 0, \Pred ;# v1 = pred = p0..p15 + vmrghb v2, v0, v1 ;# v2 = 16-bit p0..p7 + lvx v3, 0, \Diff ;# v3 = d0..d7 + vaddshs v2, v2, v3 ;# v2 = r0..r7 + vmrglb v1, v0, v1 ;# v1 = 16-bit p8..p15 + lvx v3, r8, \Diff ;# v2 = d8..d15 + vaddshs v3, v3, v1 ;# v3 = r8..r15 + vpkshus v2, v2, v3 ;# v3 = 8-bit r0..r15 + stvx v2, 0, r10 ;# 2 rows to dst from buf + lwz r0, 0(r10) +.if \write_first_four_pels + stw r0, 0(\Dst) + .else + stwux r0, \Dst, \Stride +.endif + lwz r0, 4(r10) + stw r0, 4(\Dst) + lwz r0, 8(r10) + stwux r0, \Dst, \Stride ;# advance dst to next row + lwz r0, 12(r10) + stw r0, 4(\Dst) +.endm + + .align 2 +;# r3 = short *diff_ptr, +;# r4 = unsigned char *pred_ptr, +;# r5 = unsigned char *dst_ptr, +;# r6 = int stride + +recon2b_ppc: + mfspr r0, 256 ;# get old VRSAVE + stw r0, -8(r1) ;# save old VRSAVE to stack + oris r0, r0, 0xf000 + mtspr 256,r0 ;# set VRSAVE + + vxor v0, v0, v0 + li r8, 16 + + la r10, -48(r1) ;# buf + + two_rows_of8 r3, r4, r5, r6, 1 + + addi r4, r4, 16; ;# next pred + addi r3, r3, 32; ;# next diff + + two_rows_of8 r3, r4, r5, r6, 0 + + lwz r12, -8(r1) ;# restore old VRSAVE from stack + mtspr 256, r12 ;# reset old VRSAVE + + blr + +.macro get_two_diff_rows + stw r0, 0(r10) + lwz r0, 4(r3) + stw r0, 4(r10) + lwzu r0, 32(r3) + stw r0, 8(r10) + lwz r0, 4(r3) + stw r0, 12(r10) + lvx v3, 0, r10 +.endm + + .align 2 +;# r3 = short *diff_ptr, +;# r4 = unsigned char *pred_ptr, +;# r5 = unsigned char *dst_ptr, +;# r6 = int stride +recon_b_ppc: + mfspr r0, 256 ;# get old VRSAVE + stw r0, -8(r1) ;# save old VRSAVE to stack + oris r0, r0, 0xf000 + mtspr 256,r0 ;# set VRSAVE + + vxor v0, v0, v0 + + la r10, -48(r1) ;# buf + + lwz r0, 0(r4) + stw r0, 0(r10) + lwz r0, 16(r4) + stw r0, 4(r10) + lwz r0, 32(r4) + stw r0, 8(r10) + lwz r0, 48(r4) + stw r0, 12(r10) + + lvx v1, 0, r10; ;# v1 = pred = p0..p15 + + lwz r0, 0(r3) ;# v3 = d0..d7 + + get_two_diff_rows + + vmrghb v2, v0, v1; ;# v2 = 16-bit p0..p7 + vaddshs v2, v2, v3; ;# v2 = r0..r7 + + lwzu r0, 32(r3) ;# v3 = d8..d15 + + get_two_diff_rows + + vmrglb v1, v0, v1; ;# v1 = 16-bit p8..p15 + vaddshs v3, v3, v1; ;# v3 = r8..r15 + + vpkshus v2, v2, v3; ;# v2 = 8-bit r0..r15 + stvx v2, 0, r10; ;# 16 pels to dst from buf + + lwz r0, 0(r10) + stw r0, 0(r5) + lwz r0, 4(r10) + stwux r0, r5, r6 + lwz r0, 8(r10) + stwux r0, r5, r6 + lwz r0, 12(r10) + stwx r0, r5, r6 + + lwz r12, -8(r1) ;# restore old VRSAVE from stack + mtspr 256, r12 ;# reset old VRSAVE + + blr diff --git a/vp8/common/ppc/sad_altivec.asm b/vp8/common/ppc/sad_altivec.asm new file mode 100644 index 0000000..e5f2638 --- /dev/null +++ b/vp8/common/ppc/sad_altivec.asm @@ -0,0 +1,277 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl vp8_sad16x16_ppc + .globl vp8_sad16x8_ppc + .globl vp8_sad8x16_ppc + .globl vp8_sad8x8_ppc + .globl vp8_sad4x4_ppc + +.macro load_aligned_16 V R O + lvsl v3, 0, \R ;# permutate value for alignment + + lvx v1, 0, \R + lvx v2, \O, \R + + vperm \V, v1, v2, v3 +.endm + +.macro prologue + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + li r10, 16 ;# load offset and loop counter + + vspltisw v8, 0 ;# zero out total to start +.endm + +.macro epilogue + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE +.endm + +.macro SAD_16 + ;# v6 = abs (v4 - v5) + vsububs v6, v4, v5 + vsububs v7, v5, v4 + vor v6, v6, v7 + + ;# v8 += abs (v4 - v5) + vsum4ubs v8, v6, v8 +.endm + +.macro sad_16_loop loop_label + lvsl v3, 0, r5 ;# only needs to be done once per block + + ;# preload a line of data before getting into the loop + lvx v4, 0, r3 + lvx v1, 0, r5 + lvx v2, r10, r5 + + add r5, r5, r6 + add r3, r3, r4 + + vperm v5, v1, v2, v3 + + .align 4 +\loop_label: + ;# compute difference on first row + vsububs v6, v4, v5 + vsububs v7, v5, v4 + + ;# load up next set of data + lvx v9, 0, r3 + lvx v1, 0, r5 + lvx v2, r10, r5 + + ;# perform abs() of difference + vor v6, v6, v7 + add r3, r3, r4 + + ;# add to the running tally + vsum4ubs v8, v6, v8 + + ;# now onto the next line + vperm v5, v1, v2, v3 + add r5, r5, r6 + lvx v4, 0, r3 + + ;# compute difference on second row + vsububs v6, v9, v5 + lvx v1, 0, r5 + vsububs v7, v5, v9 + lvx v2, r10, r5 + vor v6, v6, v7 + add r3, r3, r4 + vsum4ubs v8, v6, v8 + vperm v5, v1, v2, v3 + add r5, r5, r6 + + bdnz \loop_label + + vspltisw v7, 0 + + vsumsws v8, v8, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) +.endm + +.macro sad_8_loop loop_label + .align 4 +\loop_label: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + ;# only one of the inputs should need to be aligned. + load_aligned_16 v6, r3, r10 + load_aligned_16 v7, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + vmrghb v4, v4, v6 + vmrghb v5, v5, v7 + + SAD_16 + + bdnz \loop_label + + vspltisw v7, 0 + + vsumsws v8, v8, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad16x16_ppc: + + prologue + + li r9, 8 + mtctr r9 + + sad_16_loop sad16x16_loop + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad16x8_ppc: + + prologue + + li r9, 4 + mtctr r9 + + sad_16_loop sad16x8_loop + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad8x16_ppc: + + prologue + + li r9, 8 + mtctr r9 + + sad_8_loop sad8x16_loop + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad8x8_ppc: + + prologue + + li r9, 4 + mtctr r9 + + sad_8_loop sad8x8_loop + + epilogue + + blr + +.macro transfer_4x4 I P + lwz r0, 0(\I) + add \I, \I, \P + + lwz r7, 0(\I) + add \I, \I, \P + + lwz r8, 0(\I) + add \I, \I, \P + + lwz r9, 0(\I) + + stw r0, 0(r1) + stw r7, 4(r1) + stw r8, 8(r1) + stw r9, 12(r1) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad4x4_ppc: + + prologue + + transfer_4x4 r3, r4 + lvx v4, 0, r1 + + transfer_4x4 r5, r6 + lvx v5, 0, r1 + + vspltisw v8, 0 ;# zero out total to start + + ;# v6 = abs (v4 - v5) + vsububs v6, v4, v5 + vsububs v7, v5, v4 + vor v6, v6, v7 + + ;# v8 += abs (v4 - v5) + vsum4ubs v7, v6, v8 + vsumsws v7, v7, v8 + + stvx v7, 0, r1 + lwz r3, 12(r1) + + epilogue + + blr diff --git a/vp8/common/ppc/systemdependent.c b/vp8/common/ppc/systemdependent.c new file mode 100644 index 0000000..7046a63 --- /dev/null +++ b/vp8/common/ppc/systemdependent.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "subpixel.h" +#include "loopfilter.h" +#include "recon.h" +#include "idct.h" +#include "onyxc_int.h" + +void (*vp8_short_idct4x4)(short *input, short *output, int pitch); +void (*vp8_short_idct4x4_1)(short *input, short *output, int pitch); +void (*vp8_dc_only_idct)(short input_dc, short *output, int pitch); + +extern void (*vp8_post_proc_down_and_across)( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +); + +extern void (*vp8_mbpost_proc_down)(unsigned char *dst, int pitch, int rows, int cols, int flimit); +extern void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit); +extern void (*vp8_mbpost_proc_across_ip)(unsigned char *src, int pitch, int rows, int cols, int flimit); +extern void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit); + +extern void vp8_post_proc_down_and_across_c +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +); +void vp8_plane_add_noise_c(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int q, int a); + +extern copy_mem_block_function *vp8_copy_mem16x16; +extern copy_mem_block_function *vp8_copy_mem8x8; +extern copy_mem_block_function *vp8_copy_mem8x4; + +// PPC +extern subpixel_predict_function sixtap_predict_ppc; +extern subpixel_predict_function sixtap_predict8x4_ppc; +extern subpixel_predict_function sixtap_predict8x8_ppc; +extern subpixel_predict_function sixtap_predict16x16_ppc; +extern subpixel_predict_function bilinear_predict4x4_ppc; +extern subpixel_predict_function bilinear_predict8x4_ppc; +extern subpixel_predict_function bilinear_predict8x8_ppc; +extern subpixel_predict_function bilinear_predict16x16_ppc; + +extern copy_mem_block_function copy_mem16x16_ppc; + +void recon_b_ppc(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void recon2b_ppc(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void recon4b_ppc(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); + +extern void short_idct4x4llm_ppc(short *input, short *output, int pitch); + +// Generic C +extern subpixel_predict_function vp8_sixtap_predict_c; +extern subpixel_predict_function vp8_sixtap_predict8x4_c; +extern subpixel_predict_function vp8_sixtap_predict8x8_c; +extern subpixel_predict_function vp8_sixtap_predict16x16_c; +extern subpixel_predict_function vp8_bilinear_predict4x4_c; +extern subpixel_predict_function vp8_bilinear_predict8x4_c; +extern subpixel_predict_function vp8_bilinear_predict8x8_c; +extern subpixel_predict_function vp8_bilinear_predict16x16_c; + +extern copy_mem_block_function vp8_copy_mem16x16_c; +extern copy_mem_block_function vp8_copy_mem8x8_c; +extern copy_mem_block_function vp8_copy_mem8x4_c; + +void vp8_recon_b_c(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void vp8_recon2b_c(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void vp8_recon4b_c(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); + +extern void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch); +extern void vp8_short_idct4x4llm_c(short *input, short *output, int pitch); +extern void vp8_dc_only_idct_c(short input_dc, short *output, int pitch); + +// PPC +extern loop_filter_block_function loop_filter_mbv_ppc; +extern loop_filter_block_function loop_filter_bv_ppc; +extern loop_filter_block_function loop_filter_mbh_ppc; +extern loop_filter_block_function loop_filter_bh_ppc; + +extern loop_filter_block_function loop_filter_mbvs_ppc; +extern loop_filter_block_function loop_filter_bvs_ppc; +extern loop_filter_block_function loop_filter_mbhs_ppc; +extern loop_filter_block_function loop_filter_bhs_ppc; + +// Generic C +extern loop_filter_block_function vp8_loop_filter_mbv_c; +extern loop_filter_block_function vp8_loop_filter_bv_c; +extern loop_filter_block_function vp8_loop_filter_mbh_c; +extern loop_filter_block_function vp8_loop_filter_bh_c; + +extern loop_filter_block_function vp8_loop_filter_mbvs_c; +extern loop_filter_block_function vp8_loop_filter_bvs_c; +extern loop_filter_block_function vp8_loop_filter_mbhs_c; +extern loop_filter_block_function vp8_loop_filter_bhs_c; + +extern loop_filter_block_function *vp8_lf_mbvfull; +extern loop_filter_block_function *vp8_lf_mbhfull; +extern loop_filter_block_function *vp8_lf_bvfull; +extern loop_filter_block_function *vp8_lf_bhfull; + +extern loop_filter_block_function *vp8_lf_mbvsimple; +extern loop_filter_block_function *vp8_lf_mbhsimple; +extern loop_filter_block_function *vp8_lf_bvsimple; +extern loop_filter_block_function *vp8_lf_bhsimple; + +void vp8_clear_c(void) +{ +} + +void vp8_machine_specific_config(void) +{ + // Pure C: + vp8_clear_system_state = vp8_clear_c; + vp8_recon_b = vp8_recon_b_c; + vp8_recon4b = vp8_recon4b_c; + vp8_recon2b = vp8_recon2b_c; + + vp8_bilinear_predict16x16 = bilinear_predict16x16_ppc; + vp8_bilinear_predict8x8 = bilinear_predict8x8_ppc; + vp8_bilinear_predict8x4 = bilinear_predict8x4_ppc; + vp8_bilinear_predict = bilinear_predict4x4_ppc; + + vp8_sixtap_predict16x16 = sixtap_predict16x16_ppc; + vp8_sixtap_predict8x8 = sixtap_predict8x8_ppc; + vp8_sixtap_predict8x4 = sixtap_predict8x4_ppc; + vp8_sixtap_predict = sixtap_predict_ppc; + + vp8_short_idct4x4_1 = vp8_short_idct4x4llm_1_c; + vp8_short_idct4x4 = short_idct4x4llm_ppc; + vp8_dc_only_idct = vp8_dc_only_idct_c; + + vp8_lf_mbvfull = loop_filter_mbv_ppc; + vp8_lf_bvfull = loop_filter_bv_ppc; + vp8_lf_mbhfull = loop_filter_mbh_ppc; + vp8_lf_bhfull = loop_filter_bh_ppc; + + vp8_lf_mbvsimple = loop_filter_mbvs_ppc; + vp8_lf_bvsimple = loop_filter_bvs_ppc; + vp8_lf_mbhsimple = loop_filter_mbhs_ppc; + vp8_lf_bhsimple = loop_filter_bhs_ppc; + + vp8_post_proc_down_and_across = vp8_post_proc_down_and_across_c; + vp8_mbpost_proc_down = vp8_mbpost_proc_down_c; + vp8_mbpost_proc_across_ip = vp8_mbpost_proc_across_ip_c; + vp8_plane_add_noise = vp8_plane_add_noise_c; + + vp8_copy_mem16x16 = copy_mem16x16_ppc; + vp8_copy_mem8x8 = vp8_copy_mem8x8_c; + vp8_copy_mem8x4 = vp8_copy_mem8x4_c; + +} diff --git a/vp8/common/ppc/variance_altivec.asm b/vp8/common/ppc/variance_altivec.asm new file mode 100644 index 0000000..fb8d5bb --- /dev/null +++ b/vp8/common/ppc/variance_altivec.asm @@ -0,0 +1,375 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl vp8_get8x8var_ppc + .globl vp8_get16x16var_ppc + .globl vp8_mse16x16_ppc + .globl vp8_variance16x16_ppc + .globl vp8_variance16x8_ppc + .globl vp8_variance8x16_ppc + .globl vp8_variance8x8_ppc + .globl vp8_variance4x4_ppc + +.macro load_aligned_16 V R O + lvsl v3, 0, \R ;# permutate value for alignment + + lvx v1, 0, \R + lvx v2, \O, \R + + vperm \V, v1, v2, v3 +.endm + +.macro prologue + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + li r10, 16 ;# load offset and loop counter + + vspltisw v7, 0 ;# zero for merging + vspltisw v8, 0 ;# zero out total to start + vspltisw v9, 0 ;# zero out total for dif^2 +.endm + +.macro epilogue + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE +.endm + +.macro compute_sum_sse + ;# Compute sum first. Unpack to so signed subract + ;# can be used. Only have a half word signed + ;# subract. Do high, then low. + vmrghb v2, v7, v4 + vmrghb v3, v7, v5 + vsubshs v2, v2, v3 + vsum4shs v8, v2, v8 + + vmrglb v2, v7, v4 + vmrglb v3, v7, v5 + vsubshs v2, v2, v3 + vsum4shs v8, v2, v8 + + ;# Now compute sse. + vsububs v2, v4, v5 + vsububs v3, v5, v4 + vor v2, v2, v3 + + vmsumubm v9, v2, v2, v9 +.endm + +.macro variance_16 DS loop_label store_sum +\loop_label: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + compute_sum_sse + + bdnz \loop_label + + vsumsws v8, v8, v7 + vsumsws v9, v9, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r4, 12(r1) + +.if \store_sum + stw r3, 0(r8) ;# sum +.endif + stw r4, 0(r7) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srlwi r3, r3, \DS ;# (sum*sum) >> DS + subf r3, r3, r4 ;# sse - ((sum*sum) >> DS) +.endm + +.macro variance_8 DS loop_label store_sum +\loop_label: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + ;# only one of the inputs should need to be aligned. + load_aligned_16 v6, r3, r10 + load_aligned_16 v0, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + vmrghb v4, v4, v6 + vmrghb v5, v5, v0 + + compute_sum_sse + + bdnz \loop_label + + vsumsws v8, v8, v7 + vsumsws v9, v9, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r4, 12(r1) + +.if \store_sum + stw r3, 0(r8) ;# sum +.endif + stw r4, 0(r7) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srlwi r3, r3, \DS ;# (sum*sum) >> 8 + subf r3, r3, r4 ;# sse - ((sum*sum) >> 8) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *SSE +;# r8 int *Sum +;# +;# r3 return value +vp8_get8x8var_ppc: + + prologue + + li r9, 4 + mtctr r9 + + variance_8 6, get8x8var_loop, 1 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *SSE +;# r8 int *Sum +;# +;# r3 return value +vp8_get16x16var_ppc: + + prologue + + mtctr r10 + + variance_16 8, get16x16var_loop, 1 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r 3 return value +vp8_mse16x16_ppc: + prologue + + mtctr r10 + +mse16x16_loop: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + ;# Now compute sse. + vsububs v2, v4, v5 + vsububs v3, v5, v4 + vor v2, v2, v3 + + vmsumubm v9, v2, v2, v9 + + bdnz mse16x16_loop + + vsumsws v9, v9, v7 + + stvx v9, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r3, 12(r1) + + stw r3, 0(r7) ;# sse + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance16x16_ppc: + + prologue + + mtctr r10 + + variance_16 8, variance16x16_loop, 0 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance16x8_ppc: + + prologue + + li r9, 8 + mtctr r9 + + variance_16 7, variance16x8_loop, 0 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance8x16_ppc: + + prologue + + li r9, 8 + mtctr r9 + + variance_8 7, variance8x16_loop, 0 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance8x8_ppc: + + prologue + + li r9, 4 + mtctr r9 + + variance_8 6, variance8x8_loop, 0 + + epilogue + + blr + +.macro transfer_4x4 I P + lwz r0, 0(\I) + add \I, \I, \P + + lwz r10,0(\I) + add \I, \I, \P + + lwz r8, 0(\I) + add \I, \I, \P + + lwz r9, 0(\I) + + stw r0, 0(r1) + stw r10, 4(r1) + stw r8, 8(r1) + stw r9, 12(r1) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance4x4_ppc: + + prologue + + transfer_4x4 r3, r4 + lvx v4, 0, r1 + + transfer_4x4 r5, r6 + lvx v5, 0, r1 + + compute_sum_sse + + vsumsws v8, v8, v7 + vsumsws v9, v9, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r4, 12(r1) + + stw r4, 0(r7) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srlwi r3, r3, 4 ;# (sum*sum) >> 4 + subf r3, r3, r4 ;# sse - ((sum*sum) >> 4) + + epilogue + + blr diff --git a/vp8/common/ppc/variance_subpixel_altivec.asm b/vp8/common/ppc/variance_subpixel_altivec.asm new file mode 100644 index 0000000..2308373 --- /dev/null +++ b/vp8/common/ppc/variance_subpixel_altivec.asm @@ -0,0 +1,865 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl vp8_sub_pixel_variance4x4_ppc + .globl vp8_sub_pixel_variance8x8_ppc + .globl vp8_sub_pixel_variance8x16_ppc + .globl vp8_sub_pixel_variance16x8_ppc + .globl vp8_sub_pixel_variance16x16_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +.macro load_vfilter V0, V1 + load_c \V0, vfilter_b, r6, r12, r10 + + addi r6, r6, 16 + lvx \V1, r6, r10 +.endm + +.macro HProlog jump_label + ;# load up horizontal filter + slwi. r5, r5, 4 ;# index into horizontal filter array + + ;# index to the next set of vectors in the row. + li r10, 16 + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq \jump_label + + load_c v20, hfilter_b, r5, r12, r0 + + ;# setup constants + ;# v14 permutation value for alignment + load_c v28, b_hperm_b, 0, r12, r0 + + ;# index to the next set of vectors in the row. + li r12, 32 + + ;# rounding added in on the multiply + vspltisw v21, 8 + vspltisw v18, 3 + vslw v18, v21, v18 ;# 0x00000040000000400000004000000040 + + slwi. r6, r6, 5 ;# index into vertical filter array +.endm + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# + +.macro hfilter_8 V, hp, lp, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 9 bytes wide, output is 8 bytes. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + + vperm v24, v21, v21, \hp ;# v20 = 0123 1234 2345 3456 + vperm v25, v21, v21, \lp ;# v21 = 4567 5678 6789 789A + + vmsummbm v24, v20, v24, v18 + vmsummbm v25, v20, v25, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + + vpkuhus \V, v24, v24 ;# \V = scrambled 8-bit result +.endm + +.macro vfilter_16 P0 P1 + vmuleub v22, \P0, v20 ;# 64 + 4 positive taps + vadduhm v22, v18, v22 + vmuloub v23, \P0, v20 + vadduhm v23, v18, v23 + + vmuleub v24, \P1, v21 + vadduhm v22, v22, v24 ;# Re = evens, saturation unnecessary + vmuloub v25, \P1, v21 + vadduhm v23, v23, v25 ;# Ro = odds + + vsrh v22, v22, v19 ;# divide by 128 + vsrh v23, v23, v19 ;# v16 v17 = evens, odds + vmrghh \P0, v22, v23 ;# v18 v19 = 16-bit result in order + vmrglh v23, v22, v23 + vpkuhus \P0, \P0, v23 ;# P0 = 8-bit result +.endm + +.macro compute_sum_sse src, ref, sum, sse, t1, t2, z0 + ;# Compute sum first. Unpack to so signed subract + ;# can be used. Only have a half word signed + ;# subract. Do high, then low. + vmrghb \t1, \z0, \src + vmrghb \t2, \z0, \ref + vsubshs \t1, \t1, \t2 + vsum4shs \sum, \t1, \sum + + vmrglb \t1, \z0, \src + vmrglb \t2, \z0, \ref + vsubshs \t1, \t1, \t2 + vsum4shs \sum, \t1, \sum + + ;# Now compute sse. + vsububs \t1, \src, \ref + vsububs \t2, \ref, \src + vor \t1, \t1, \t2 + + vmsumubm \sse, \t1, \t1, \sse +.endm + +.macro variance_final sum, sse, z0, DS + vsumsws \sum, \sum, \z0 + vsumsws \sse, \sse, \z0 + + stvx \sum, 0, r1 + lwz r3, 12(r1) + + stvx \sse, 0, r1 + lwz r4, 12(r1) + + stw r4, 0(r9) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srlwi r3, r3, \DS ;# (sum*sum) >> 8 + subf r3, r3, r4 ;# sse - ((sum*sum) >> 8) +.endm + +.macro compute_sum_sse_16 V, increment_counter + load_and_align_16 v16, r7, r8, \increment_counter + compute_sum_sse \V, v16, v18, v19, v20, v21, v23 +.endm + +.macro load_and_align_16 V, R, P, increment_counter + lvsl v17, 0, \R ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, \R + lvx v22, r10, \R + +.if \increment_counter + add \R, \R, \P +.endif + + vperm \V, v21, v22, v17 +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance4x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf830 + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_4x4_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r12, r0 + load_c v11, b_4567_b, 0, r12, r0 + + hfilter_8 v0, v10, v11, 1 + hfilter_8 v1, v10, v11, 1 + hfilter_8 v2, v10, v11, 1 + hfilter_8 v3, v10, v11, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_4x4_b + + hfilter_8 v4, v10, v11, 0 + + b second_pass_4x4_b + +second_pass_4x4_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 0 + +second_pass_4x4_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + +compute_sum_sse_4x4_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + load_and_align_16 v4, r7, r8, 1 + load_and_align_16 v5, r7, r8, 1 + load_and_align_16 v6, r7, r8, 1 + load_and_align_16 v7, r7, r8, 1 + + vmrghb v0, v0, v1 + vmrghb v1, v2, v3 + + vmrghb v2, v4, v5 + vmrghb v3, v6, v7 + + load_c v10, b_hilo_b, 0, r12, r0 + + vperm v0, v0, v1, v10 + vperm v1, v2, v3, v10 + + compute_sum_sse v0, v1, v18, v19, v20, v21, v23 + + variance_final v18, v19, v23, 4 + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance8x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfff0 + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x8_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r12, r0 + load_c v11, b_4567_b, 0, r12, r0 + + hfilter_8 v0, v10, v11, 1 + hfilter_8 v1, v10, v11, 1 + hfilter_8 v2, v10, v11, 1 + hfilter_8 v3, v10, v11, 1 + hfilter_8 v4, v10, v11, 1 + hfilter_8 v5, v10, v11, 1 + hfilter_8 v6, v10, v11, 1 + hfilter_8 v7, v10, v11, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_8x8_b + + hfilter_8 v8, v10, v11, 0 + + b second_pass_8x8_b + +second_pass_8x8_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 0 + + beq compute_sum_sse_8x8_b + +second_pass_8x8_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + +compute_sum_sse_8x8_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + vmrghb v0, v0, v1 + vmrghb v1, v2, v3 + vmrghb v2, v4, v5 + vmrghb v3, v6, v7 + + load_and_align_16 v4, r7, r8, 1 + load_and_align_16 v5, r7, r8, 1 + load_and_align_16 v6, r7, r8, 1 + load_and_align_16 v7, r7, r8, 1 + load_and_align_16 v8, r7, r8, 1 + load_and_align_16 v9, r7, r8, 1 + load_and_align_16 v10, r7, r8, 1 + load_and_align_16 v11, r7, r8, 0 + + vmrghb v4, v4, v5 + vmrghb v5, v6, v7 + vmrghb v6, v8, v9 + vmrghb v7, v10, v11 + + compute_sum_sse v0, v4, v18, v19, v20, v21, v23 + compute_sum_sse v1, v5, v18, v19, v20, v21, v23 + compute_sum_sse v2, v6, v18, v19, v20, v21, v23 + compute_sum_sse v3, v7, v18, v19, v20, v21, v23 + + variance_final v18, v19, v23, 6 + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance8x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfffc + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x16_pre_copy_b + + ;# Load up permutation constants + load_c v29, b_0123_b, 0, r12, r0 + load_c v30, b_4567_b, 0, r12, r0 + + hfilter_8 v0, v29, v30, 1 + hfilter_8 v1, v29, v30, 1 + hfilter_8 v2, v29, v30, 1 + hfilter_8 v3, v29, v30, 1 + hfilter_8 v4, v29, v30, 1 + hfilter_8 v5, v29, v30, 1 + hfilter_8 v6, v29, v30, 1 + hfilter_8 v7, v29, v30, 1 + hfilter_8 v8, v29, v30, 1 + hfilter_8 v9, v29, v30, 1 + hfilter_8 v10, v29, v30, 1 + hfilter_8 v11, v29, v30, 1 + hfilter_8 v12, v29, v30, 1 + hfilter_8 v13, v29, v30, 1 + hfilter_8 v14, v29, v30, 1 + hfilter_8 v15, v29, v30, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_8x16_b + + hfilter_8 v16, v29, v30, 0 + + b second_pass_8x16_b + +second_pass_8x16_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 1 + load_and_align_16 v9, r3, r4, 1 + load_and_align_16 v10, r3, r4, 1 + load_and_align_16 v11, r3, r4, 1 + load_and_align_16 v12, r3, r4, 1 + load_and_align_16 v13, r3, r4, 1 + load_and_align_16 v14, r3, r4, 1 + load_and_align_16 v15, r3, r4, 1 + load_and_align_16 v16, r3, r4, 0 + + beq compute_sum_sse_8x16_b + +second_pass_8x16_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + vfilter_16 v8, v9 + vfilter_16 v9, v10 + vfilter_16 v10, v11 + vfilter_16 v11, v12 + vfilter_16 v12, v13 + vfilter_16 v13, v14 + vfilter_16 v14, v15 + vfilter_16 v15, v16 + +compute_sum_sse_8x16_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + vmrghb v0, v0, v1 + vmrghb v1, v2, v3 + vmrghb v2, v4, v5 + vmrghb v3, v6, v7 + vmrghb v4, v8, v9 + vmrghb v5, v10, v11 + vmrghb v6, v12, v13 + vmrghb v7, v14, v15 + + load_and_align_16 v8, r7, r8, 1 + load_and_align_16 v9, r7, r8, 1 + load_and_align_16 v10, r7, r8, 1 + load_and_align_16 v11, r7, r8, 1 + load_and_align_16 v12, r7, r8, 1 + load_and_align_16 v13, r7, r8, 1 + load_and_align_16 v14, r7, r8, 1 + load_and_align_16 v15, r7, r8, 1 + + vmrghb v8, v8, v9 + vmrghb v9, v10, v11 + vmrghb v10, v12, v13 + vmrghb v11, v14, v15 + + compute_sum_sse v0, v8, v18, v19, v20, v21, v23 + compute_sum_sse v1, v9, v18, v19, v20, v21, v23 + compute_sum_sse v2, v10, v18, v19, v20, v21, v23 + compute_sum_sse v3, v11, v18, v19, v20, v21, v23 + + load_and_align_16 v8, r7, r8, 1 + load_and_align_16 v9, r7, r8, 1 + load_and_align_16 v10, r7, r8, 1 + load_and_align_16 v11, r7, r8, 1 + load_and_align_16 v12, r7, r8, 1 + load_and_align_16 v13, r7, r8, 1 + load_and_align_16 v14, r7, r8, 1 + load_and_align_16 v15, r7, r8, 0 + + vmrghb v8, v8, v9 + vmrghb v9, v10, v11 + vmrghb v10, v12, v13 + vmrghb v11, v14, v15 + + compute_sum_sse v4, v8, v18, v19, v20, v21, v23 + compute_sum_sse v5, v9, v18, v19, v20, v21, v23 + compute_sum_sse v6, v10, v18, v19, v20, v21, v23 + compute_sum_sse v7, v11, v18, v19, v20, v21, v23 + + variance_final v18, v19, v23, 7 + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + blr + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# +.macro hfilter_16 V, increment_counter + + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + lvx v23, r12, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + vperm v22, v22, v23, v17 ;# v8 v9 = 21 input pixels left-justified + + ;# set 0 + vmsummbm v24, v20, v21, v18 ;# taps times elements + + ;# set 1 + vsldoi v23, v21, v22, 1 + vmsummbm v25, v20, v23, v18 + + ;# set 2 + vsldoi v23, v21, v22, 2 + vmsummbm v26, v20, v23, v18 + + ;# set 3 + vsldoi v23, v21, v22, 3 + vmsummbm v27, v20, v23, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + vpkswus v25, v26, v27 ;# v25 = 2 6 A E 3 7 B F + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + vsrh v25, v25, v19 + + vpkuhus \V, v24, v25 ;# \V = scrambled 8-bit result + vperm \V, \V, v0, v28 ;# \V = correctly-ordered result +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance16x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + HProlog second_pass_16x8_pre_copy_b + + hfilter_16 v0, 1 + hfilter_16 v1, 1 + hfilter_16 v2, 1 + hfilter_16 v3, 1 + hfilter_16 v4, 1 + hfilter_16 v5, 1 + hfilter_16 v6, 1 + hfilter_16 v7, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_16x8_b + + hfilter_16 v8, 0 + + b second_pass_16x8_b + +second_pass_16x8_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 1 + + beq compute_sum_sse_16x8_b + +second_pass_16x8_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + +compute_sum_sse_16x8_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + compute_sum_sse_16 v0, 1 + compute_sum_sse_16 v1, 1 + compute_sum_sse_16 v2, 1 + compute_sum_sse_16 v3, 1 + compute_sum_sse_16 v4, 1 + compute_sum_sse_16 v5, 1 + compute_sum_sse_16 v6, 1 + compute_sum_sse_16 v7, 0 + + variance_final v18, v19, v23, 7 + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + HProlog second_pass_16x16_pre_copy_b + + hfilter_16 v0, 1 + hfilter_16 v1, 1 + hfilter_16 v2, 1 + hfilter_16 v3, 1 + hfilter_16 v4, 1 + hfilter_16 v5, 1 + hfilter_16 v6, 1 + hfilter_16 v7, 1 + hfilter_16 v8, 1 + hfilter_16 v9, 1 + hfilter_16 v10, 1 + hfilter_16 v11, 1 + hfilter_16 v12, 1 + hfilter_16 v13, 1 + hfilter_16 v14, 1 + hfilter_16 v15, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_16x16_b + + hfilter_16 v16, 0 + + b second_pass_16x16_b + +second_pass_16x16_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 1 + load_and_align_16 v9, r3, r4, 1 + load_and_align_16 v10, r3, r4, 1 + load_and_align_16 v11, r3, r4, 1 + load_and_align_16 v12, r3, r4, 1 + load_and_align_16 v13, r3, r4, 1 + load_and_align_16 v14, r3, r4, 1 + load_and_align_16 v15, r3, r4, 1 + load_and_align_16 v16, r3, r4, 0 + + beq compute_sum_sse_16x16_b + +second_pass_16x16_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + vfilter_16 v8, v9 + vfilter_16 v9, v10 + vfilter_16 v10, v11 + vfilter_16 v11, v12 + vfilter_16 v12, v13 + vfilter_16 v13, v14 + vfilter_16 v14, v15 + vfilter_16 v15, v16 + +compute_sum_sse_16x16_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + compute_sum_sse_16 v0, 1 + compute_sum_sse_16 v1, 1 + compute_sum_sse_16 v2, 1 + compute_sum_sse_16 v3, 1 + compute_sum_sse_16 v4, 1 + compute_sum_sse_16 v5, 1 + compute_sum_sse_16 v6, 1 + compute_sum_sse_16 v7, 1 + compute_sum_sse_16 v8, 1 + compute_sum_sse_16 v9, 1 + compute_sum_sse_16 v10, 1 + compute_sum_sse_16 v11, 1 + compute_sum_sse_16 v12, 1 + compute_sum_sse_16 v13, 1 + compute_sum_sse_16 v14, 1 + compute_sum_sse_16 v15, 0 + + variance_final v18, v19, v23, 8 + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + + .align 4 +hfilter_b: + .byte 128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0 + .byte 112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0 + .byte 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0 + .byte 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0 + .byte 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0 + .byte 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0 + .byte 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0 + .byte 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0 + + .align 4 +vfilter_b: + .byte 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + + .align 4 +b_hperm_b: + .byte 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 + + .align 4 +b_0123_b: + .byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + + .align 4 +b_4567_b: + .byte 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + +b_hilo_b: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 diff --git a/vp8/common/ppflags.h b/vp8/common/ppflags.h new file mode 100644 index 0000000..665e21f --- /dev/null +++ b/vp8/common/ppflags.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_PPFLAGS_H +#define __INC_PPFLAGS_H +enum +{ + VP8D_NOFILTERING = 0, + VP8D_DEBLOCK = 1<<0, + VP8D_DEMACROBLOCK = 1<<1, + VP8D_ADDNOISE = 1<<2, + VP8D_DEBUG_TXT_FRAME_INFO = 1<<3, + VP8D_DEBUG_TXT_MBLK_MODES = 1<<4, + VP8D_DEBUG_TXT_DC_DIFF = 1<<5, + VP8D_DEBUG_TXT_RATE_INFO = 1<<6, + VP8D_DEBUG_DRAW_MV = 1<<7, + VP8D_DEBUG_CLR_BLK_MODES = 1<<8, + VP8D_DEBUG_CLR_FRM_REF_BLKS = 1<<9, + VP8D_MFQE = 1<<10 +}; + +typedef struct +{ + int post_proc_flag; + int deblocking_level; + int noise_level; + int display_ref_frame_flag; + int display_mb_modes_flag; + int display_b_modes_flag; + int display_mv_flag; +} vp8_ppflags_t; + +#endif diff --git a/vp8/common/pragmas.h b/vp8/common/pragmas.h new file mode 100644 index 0000000..99fee5a --- /dev/null +++ b/vp8/common/pragmas.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + + + +#ifdef __INTEL_COMPILER +#pragma warning(disable:997 1011 170) +#endif +#ifdef _MSC_VER +#pragma warning(disable:4799) +#endif diff --git a/vp8/common/quant_common.c b/vp8/common/quant_common.c new file mode 100644 index 0000000..e9833fe --- /dev/null +++ b/vp8/common/quant_common.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "quant_common.h" + +static const int dc_qlookup[QINDEX_RANGE] = +{ + 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 143, 145, 148, 151, 154, 157, +}; + +static const int ac_qlookup[QINDEX_RANGE] = +{ + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, 249, 254, 259, 264, 269, 274, 279, 284, +}; + + +int vp8_dc_quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = dc_qlookup[ QIndex ]; + return retval; +} + +int vp8_dc2quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = dc_qlookup[ QIndex ] * 2; + return retval; + +} +int vp8_dc_uv_quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = dc_qlookup[ QIndex ]; + + if (retval > 132) + retval = 132; + + return retval; +} + +int vp8_ac_yquant(int QIndex) +{ + int retval; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = ac_qlookup[ QIndex ]; + return retval; +} + +int vp8_ac2quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = (ac_qlookup[ QIndex ] * 155) / 100; + + if (retval < 8) + retval = 8; + + return retval; +} +int vp8_ac_uv_quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = ac_qlookup[ QIndex ]; + return retval; +} diff --git a/vp8/common/quant_common.h b/vp8/common/quant_common.h new file mode 100644 index 0000000..cb64d8e --- /dev/null +++ b/vp8/common/quant_common.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "string.h" +#include "blockd.h" +#include "onyxc_int.h" + +extern int vp8_ac_yquant(int QIndex); +extern int vp8_dc_quant(int QIndex, int Delta); +extern int vp8_dc2quant(int QIndex, int Delta); +extern int vp8_ac2quant(int QIndex, int Delta); +extern int vp8_dc_uv_quant(int QIndex, int Delta); +extern int vp8_ac_uv_quant(int QIndex, int Delta); diff --git a/vp8/common/reconinter.c b/vp8/common/reconinter.c new file mode 100644 index 0000000..3da3bc7 --- /dev/null +++ b/vp8/common/reconinter.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx/vpx_integer.h" +#include "blockd.h" +#include "reconinter.h" +#if CONFIG_RUNTIME_CPU_DETECT +#include "onyxc_int.h" +#endif + +void vp8_copy_mem16x16_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + + int r; + + for (r = 0; r < 16; r++) + { +#if !(CONFIG_FAST_UNALIGNED) + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + dst[8] = src[8]; + dst[9] = src[9]; + dst[10] = src[10]; + dst[11] = src[11]; + dst[12] = src[12]; + dst[13] = src[13]; + dst[14] = src[14]; + dst[15] = src[15]; + +#else + ((uint32_t *)dst)[0] = ((uint32_t *)src)[0] ; + ((uint32_t *)dst)[1] = ((uint32_t *)src)[1] ; + ((uint32_t *)dst)[2] = ((uint32_t *)src)[2] ; + ((uint32_t *)dst)[3] = ((uint32_t *)src)[3] ; + +#endif + src += src_stride; + dst += dst_stride; + + } + +} + +void vp8_copy_mem8x8_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + int r; + + for (r = 0; r < 8; r++) + { +#if !(CONFIG_FAST_UNALIGNED) + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +#else + ((uint32_t *)dst)[0] = ((uint32_t *)src)[0] ; + ((uint32_t *)dst)[1] = ((uint32_t *)src)[1] ; +#endif + src += src_stride; + dst += dst_stride; + + } + +} + +void vp8_copy_mem8x4_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + int r; + + for (r = 0; r < 4; r++) + { +#if !(CONFIG_FAST_UNALIGNED) + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +#else + ((uint32_t *)dst)[0] = ((uint32_t *)src)[0] ; + ((uint32_t *)dst)[1] = ((uint32_t *)src)[1] ; +#endif + src += src_stride; + dst += dst_stride; + + } + +} + + +void vp8_build_inter_predictors_b(BLOCKD *d, int pitch, unsigned char *base_pre, int pre_stride, vp8_subpix_fn_t sppf) +{ + int r; + unsigned char *pred_ptr = d->predictor; + unsigned char *ptr; + ptr = base_pre + d->offset + (d->bmi.mv.as_mv.row >> 3) * pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + sppf(ptr, pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); + } + else + { + for (r = 0; r < 4; r++) + { +#if !(CONFIG_FAST_UNALIGNED) + pred_ptr[0] = ptr[0]; + pred_ptr[1] = ptr[1]; + pred_ptr[2] = ptr[2]; + pred_ptr[3] = ptr[3]; +#else + *(uint32_t *)pred_ptr = *(uint32_t *)ptr ; +#endif + pred_ptr += pitch; + ptr += pre_stride; + } + } +} + +static void build_inter_predictors4b(MACROBLOCKD *x, BLOCKD *d, unsigned char *dst, int dst_stride, unsigned char *base_pre, int pre_stride) +{ + unsigned char *ptr; + ptr = base_pre + d->offset + (d->bmi.mv.as_mv.row >> 3) * pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x8(ptr, pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, dst, dst_stride); + } + else + { + vp8_copy_mem8x8(ptr, pre_stride, dst, dst_stride); + } +} + +static void build_inter_predictors2b(MACROBLOCKD *x, BLOCKD *d, unsigned char *dst, int dst_stride, unsigned char *base_pre, int pre_stride) +{ + unsigned char *ptr; + ptr = base_pre + d->offset + (d->bmi.mv.as_mv.row >> 3) * pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x4(ptr, pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, dst, dst_stride); + } + else + { + vp8_copy_mem8x4(ptr, pre_stride, dst, dst_stride); + } +} + +static void build_inter_predictors_b(BLOCKD *d, unsigned char *dst, int dst_stride, unsigned char *base_pre, int pre_stride, vp8_subpix_fn_t sppf) +{ + int r; + unsigned char *ptr; + ptr = base_pre + d->offset + (d->bmi.mv.as_mv.row >> 3) * pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + sppf(ptr, pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, dst, dst_stride); + } + else + { + for (r = 0; r < 4; r++) + { +#if !(CONFIG_FAST_UNALIGNED) + dst[0] = ptr[0]; + dst[1] = ptr[1]; + dst[2] = ptr[2]; + dst[3] = ptr[3]; +#else + *(uint32_t *)dst = *(uint32_t *)ptr ; +#endif + dst += dst_stride; + ptr += pre_stride; + } + } +} + + +/*encoder only*/ +void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *x) +{ + unsigned char *uptr, *vptr; + unsigned char *upred_ptr = &x->predictor[256]; + unsigned char *vpred_ptr = &x->predictor[320]; + + int mv_row = x->mode_info_context->mbmi.mv.as_mv.row; + int mv_col = x->mode_info_context->mbmi.mv.as_mv.col; + int offset; + int pre_stride = x->pre.uv_stride; + + /* calc uv motion vectors */ + mv_row += 1 | (mv_row >> (sizeof(int) * CHAR_BIT - 1)); + mv_col += 1 | (mv_col >> (sizeof(int) * CHAR_BIT - 1)); + mv_row /= 2; + mv_col /= 2; + mv_row &= x->fullpixel_mask; + mv_col &= x->fullpixel_mask; + + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->pre.u_buffer + offset; + vptr = x->pre.v_buffer + offset; + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, 8); + x->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, 8); + } + else + { + vp8_copy_mem8x8(uptr, pre_stride, upred_ptr, 8); + vp8_copy_mem8x8(vptr, pre_stride, vpred_ptr, 8); + } +} + +/*encoder only*/ +void vp8_build_inter4x4_predictors_mbuv(MACROBLOCKD *x) +{ + int i, j; + int pre_stride = x->pre.uv_stride; + unsigned char *base_pre; + + /* build uv mvs */ + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + int yoffset = i * 8 + j * 2; + int uoffset = 16 + i * 2 + j; + int voffset = 20 + i * 2 + j; + + int temp; + + temp = x->block[yoffset ].bmi.mv.as_mv.row + + x->block[yoffset+1].bmi.mv.as_mv.row + + x->block[yoffset+4].bmi.mv.as_mv.row + + x->block[yoffset+5].bmi.mv.as_mv.row; + + temp += 4 + ((temp >> (sizeof(int) * CHAR_BIT - 1)) << 3); + + x->block[uoffset].bmi.mv.as_mv.row = (temp / 8) & x->fullpixel_mask; + + temp = x->block[yoffset ].bmi.mv.as_mv.col + + x->block[yoffset+1].bmi.mv.as_mv.col + + x->block[yoffset+4].bmi.mv.as_mv.col + + x->block[yoffset+5].bmi.mv.as_mv.col; + + temp += 4 + ((temp >> (sizeof(int) * CHAR_BIT - 1)) << 3); + + x->block[uoffset].bmi.mv.as_mv.col = (temp / 8) & x->fullpixel_mask; + + x->block[voffset].bmi.mv.as_int = x->block[uoffset].bmi.mv.as_int; + } + } + + base_pre = x->pre.u_buffer; + for (i = 16; i < 20; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + build_inter_predictors2b(x, d0, d0->predictor, 8, base_pre, pre_stride); + else + { + vp8_build_inter_predictors_b(d0, 8, base_pre, pre_stride, x->subpixel_predict); + vp8_build_inter_predictors_b(d1, 8, base_pre, pre_stride, x->subpixel_predict); + } + } + + base_pre = x->pre.v_buffer; + for (i = 20; i < 24; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + build_inter_predictors2b(x, d0, d0->predictor, 8, base_pre, pre_stride); + else + { + vp8_build_inter_predictors_b(d0, 8, base_pre, pre_stride, x->subpixel_predict); + vp8_build_inter_predictors_b(d1, 8, base_pre, pre_stride, x->subpixel_predict); + } + } +} + + +/*encoder only*/ +void vp8_build_inter16x16_predictors_mby(MACROBLOCKD *x, + unsigned char *dst_y, + int dst_ystride) +{ + unsigned char *ptr_base; + unsigned char *ptr; + int mv_row = x->mode_info_context->mbmi.mv.as_mv.row; + int mv_col = x->mode_info_context->mbmi.mv.as_mv.col; + int pre_stride = x->pre.y_stride; + + ptr_base = x->pre.y_buffer; + ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3); + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, + dst_y, dst_ystride); + } + else + { + vp8_copy_mem16x16(ptr, pre_stride, dst_y, + dst_ystride); + } +} + +static void clamp_mv_to_umv_border(MV *mv, const MACROBLOCKD *xd) +{ + /* If the MV points so far into the UMV border that no visible pixels + * are used for reconstruction, the subpel part of the MV can be + * discarded and the MV limited to 16 pixels with equivalent results. + * + * This limit kicks in at 19 pixels for the top and left edges, for + * the 16 pixels plus 3 taps right of the central pixel when subpel + * filtering. The bottom and right edges use 16 pixels plus 2 pixels + * left of the central pixel when filtering. + */ + if (mv->col < (xd->mb_to_left_edge - (19 << 3))) + mv->col = xd->mb_to_left_edge - (16 << 3); + else if (mv->col > xd->mb_to_right_edge + (18 << 3)) + mv->col = xd->mb_to_right_edge + (16 << 3); + + if (mv->row < (xd->mb_to_top_edge - (19 << 3))) + mv->row = xd->mb_to_top_edge - (16 << 3); + else if (mv->row > xd->mb_to_bottom_edge + (18 << 3)) + mv->row = xd->mb_to_bottom_edge + (16 << 3); +} + +/* A version of the above function for chroma block MVs.*/ +static void clamp_uvmv_to_umv_border(MV *mv, const MACROBLOCKD *xd) +{ + mv->col = (2*mv->col < (xd->mb_to_left_edge - (19 << 3))) ? + (xd->mb_to_left_edge - (16 << 3)) >> 1 : mv->col; + mv->col = (2*mv->col > xd->mb_to_right_edge + (18 << 3)) ? + (xd->mb_to_right_edge + (16 << 3)) >> 1 : mv->col; + + mv->row = (2*mv->row < (xd->mb_to_top_edge - (19 << 3))) ? + (xd->mb_to_top_edge - (16 << 3)) >> 1 : mv->row; + mv->row = (2*mv->row > xd->mb_to_bottom_edge + (18 << 3)) ? + (xd->mb_to_bottom_edge + (16 << 3)) >> 1 : mv->row; +} + +void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, + unsigned char *dst_y, + unsigned char *dst_u, + unsigned char *dst_v, + int dst_ystride, + int dst_uvstride) +{ + int offset; + unsigned char *ptr; + unsigned char *uptr, *vptr; + + int_mv _16x16mv; + + unsigned char *ptr_base = x->pre.y_buffer; + int pre_stride = x->pre.y_stride; + + _16x16mv.as_int = x->mode_info_context->mbmi.mv.as_int; + + if (x->mode_info_context->mbmi.need_to_clamp_mvs) + { + clamp_mv_to_umv_border(&_16x16mv.as_mv, x); + } + + ptr = ptr_base + ( _16x16mv.as_mv.row >> 3) * pre_stride + (_16x16mv.as_mv.col >> 3); + + if ( _16x16mv.as_int & 0x00070007) + { + x->subpixel_predict16x16(ptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_y, dst_ystride); + } + else + { + vp8_copy_mem16x16(ptr, pre_stride, dst_y, dst_ystride); + } + + /* calc uv motion vectors */ + _16x16mv.as_mv.row += 1 | (_16x16mv.as_mv.row >> (sizeof(int) * CHAR_BIT - 1)); + _16x16mv.as_mv.col += 1 | (_16x16mv.as_mv.col >> (sizeof(int) * CHAR_BIT - 1)); + _16x16mv.as_mv.row /= 2; + _16x16mv.as_mv.col /= 2; + _16x16mv.as_mv.row &= x->fullpixel_mask; + _16x16mv.as_mv.col &= x->fullpixel_mask; + + pre_stride >>= 1; + offset = ( _16x16mv.as_mv.row >> 3) * pre_stride + (_16x16mv.as_mv.col >> 3); + uptr = x->pre.u_buffer + offset; + vptr = x->pre.v_buffer + offset; + + if ( _16x16mv.as_int & 0x00070007) + { + x->subpixel_predict8x8(uptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_u, dst_uvstride); + x->subpixel_predict8x8(vptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_v, dst_uvstride); + } + else + { + vp8_copy_mem8x8(uptr, pre_stride, dst_u, dst_uvstride); + vp8_copy_mem8x8(vptr, pre_stride, dst_v, dst_uvstride); + } +} + +static void build_inter4x4_predictors_mb(MACROBLOCKD *x) +{ + int i; + unsigned char *base_dst = x->dst.y_buffer; + unsigned char *base_pre = x->pre.y_buffer; + + if (x->mode_info_context->mbmi.partitioning < 3) + { + BLOCKD *b; + int dst_stride = x->dst.y_stride; + + x->block[ 0].bmi = x->mode_info_context->bmi[ 0]; + x->block[ 2].bmi = x->mode_info_context->bmi[ 2]; + x->block[ 8].bmi = x->mode_info_context->bmi[ 8]; + x->block[10].bmi = x->mode_info_context->bmi[10]; + if (x->mode_info_context->mbmi.need_to_clamp_mvs) + { + clamp_mv_to_umv_border(&x->block[ 0].bmi.mv.as_mv, x); + clamp_mv_to_umv_border(&x->block[ 2].bmi.mv.as_mv, x); + clamp_mv_to_umv_border(&x->block[ 8].bmi.mv.as_mv, x); + clamp_mv_to_umv_border(&x->block[10].bmi.mv.as_mv, x); + } + + b = &x->block[ 0]; + build_inter_predictors4b(x, b, base_dst + b->offset, dst_stride, base_pre, dst_stride); + b = &x->block[ 2]; + build_inter_predictors4b(x, b, base_dst + b->offset, dst_stride, base_pre, dst_stride); + b = &x->block[ 8]; + build_inter_predictors4b(x, b, base_dst + b->offset, dst_stride, base_pre, dst_stride); + b = &x->block[10]; + build_inter_predictors4b(x, b, base_dst + b->offset, dst_stride, base_pre, dst_stride); + } + else + { + for (i = 0; i < 16; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + int dst_stride = x->dst.y_stride; + + x->block[i+0].bmi = x->mode_info_context->bmi[i+0]; + x->block[i+1].bmi = x->mode_info_context->bmi[i+1]; + if (x->mode_info_context->mbmi.need_to_clamp_mvs) + { + clamp_mv_to_umv_border(&x->block[i+0].bmi.mv.as_mv, x); + clamp_mv_to_umv_border(&x->block[i+1].bmi.mv.as_mv, x); + } + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + build_inter_predictors2b(x, d0, base_dst + d0->offset, dst_stride, base_pre, dst_stride); + else + { + build_inter_predictors_b(d0, base_dst + d0->offset, dst_stride, base_pre, dst_stride, x->subpixel_predict); + build_inter_predictors_b(d1, base_dst + d1->offset, dst_stride, base_pre, dst_stride, x->subpixel_predict); + } + + } + + } + base_dst = x->dst.u_buffer; + base_pre = x->pre.u_buffer; + for (i = 16; i < 20; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + int dst_stride = x->dst.uv_stride; + + /* Note: uv mvs already clamped in build_4x4uvmvs() */ + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + build_inter_predictors2b(x, d0, base_dst + d0->offset, dst_stride, base_pre, dst_stride); + else + { + build_inter_predictors_b(d0, base_dst + d0->offset, dst_stride, base_pre, dst_stride, x->subpixel_predict); + build_inter_predictors_b(d1, base_dst + d1->offset, dst_stride, base_pre, dst_stride, x->subpixel_predict); + } + } + + base_dst = x->dst.v_buffer; + base_pre = x->pre.v_buffer; + for (i = 20; i < 24; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + int dst_stride = x->dst.uv_stride; + + /* Note: uv mvs already clamped in build_4x4uvmvs() */ + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + build_inter_predictors2b(x, d0, base_dst + d0->offset, dst_stride, base_pre, dst_stride); + else + { + build_inter_predictors_b(d0, base_dst + d0->offset, dst_stride, base_pre, dst_stride, x->subpixel_predict); + build_inter_predictors_b(d1, base_dst + d1->offset, dst_stride, base_pre, dst_stride, x->subpixel_predict); + } + } +} + +static +void build_4x4uvmvs(MACROBLOCKD *x) +{ + int i, j; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + int yoffset = i * 8 + j * 2; + int uoffset = 16 + i * 2 + j; + int voffset = 20 + i * 2 + j; + + int temp; + + temp = x->mode_info_context->bmi[yoffset + 0].mv.as_mv.row + + x->mode_info_context->bmi[yoffset + 1].mv.as_mv.row + + x->mode_info_context->bmi[yoffset + 4].mv.as_mv.row + + x->mode_info_context->bmi[yoffset + 5].mv.as_mv.row; + + temp += 4 + ((temp >> (sizeof(int) * CHAR_BIT - 1)) << 3); + + x->block[uoffset].bmi.mv.as_mv.row = (temp / 8) & x->fullpixel_mask; + + temp = x->mode_info_context->bmi[yoffset + 0].mv.as_mv.col + + x->mode_info_context->bmi[yoffset + 1].mv.as_mv.col + + x->mode_info_context->bmi[yoffset + 4].mv.as_mv.col + + x->mode_info_context->bmi[yoffset + 5].mv.as_mv.col; + + temp += 4 + ((temp >> (sizeof(int) * CHAR_BIT - 1)) << 3); + + x->block[uoffset].bmi.mv.as_mv.col = (temp / 8) & x->fullpixel_mask; + + if (x->mode_info_context->mbmi.need_to_clamp_mvs) + clamp_uvmv_to_umv_border(&x->block[uoffset].bmi.mv.as_mv, x); + + x->block[voffset].bmi.mv.as_int = x->block[uoffset].bmi.mv.as_int; + } + } +} + +void vp8_build_inter_predictors_mb(MACROBLOCKD *xd) +{ + if (xd->mode_info_context->mbmi.mode != SPLITMV) + { + vp8_build_inter16x16_predictors_mb(xd, xd->dst.y_buffer, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.y_stride, xd->dst.uv_stride); + } + else + { + build_4x4uvmvs(xd); + build_inter4x4_predictors_mb(xd); + } +} diff --git a/vp8/common/reconinter.h b/vp8/common/reconinter.h new file mode 100644 index 0000000..233c02e --- /dev/null +++ b/vp8/common/reconinter.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_RECONINTER_H +#define __INC_RECONINTER_H + +extern void vp8_build_inter_predictors_mb(MACROBLOCKD *x); +extern void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, + unsigned char *dst_y, + unsigned char *dst_u, + unsigned char *dst_v, + int dst_ystride, + int dst_uvstride); + + +extern void vp8_build_inter16x16_predictors_mby(MACROBLOCKD *x, + unsigned char *dst_y, + int dst_ystride); +extern void vp8_build_inter_predictors_b(BLOCKD *d, int pitch, + unsigned char *base_pre, + int pre_stride, + vp8_subpix_fn_t sppf); + +extern void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *x); +extern void vp8_build_inter4x4_predictors_mbuv(MACROBLOCKD *x); + +#endif diff --git a/vp8/common/reconintra.c b/vp8/common/reconintra.c new file mode 100644 index 0000000..4067a68 --- /dev/null +++ b/vp8/common/reconintra.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx_mem/vpx_mem.h" +#include "blockd.h" + +void vp8_build_intra_predictors_mby_s_c(MACROBLOCKD *x, + unsigned char * yabove_row, + unsigned char * yleft, + int left_stride, + unsigned char * ypred_ptr, + int y_stride) +{ + unsigned char yleft_col[16]; + unsigned char ytop_left = yabove_row[-1]; + int r, c, i; + + for (i = 0; i < 16; i++) + { + yleft_col[i] = yleft[i* left_stride]; + } + + /* for Y */ + switch (x->mode_info_context->mbmi.mode) + { + case DC_PRED: + { + int expected_dc; + int i; + int shift; + int average = 0; + + + if (x->up_available || x->left_available) + { + if (x->up_available) + { + for (i = 0; i < 16; i++) + { + average += yabove_row[i]; + } + } + + if (x->left_available) + { + + for (i = 0; i < 16; i++) + { + average += yleft_col[i]; + } + + } + + + + shift = 3 + x->up_available + x->left_available; + expected_dc = (average + (1 << (shift - 1))) >> shift; + } + else + { + expected_dc = 128; + } + + /*vpx_memset(ypred_ptr, expected_dc, 256);*/ + for (r = 0; r < 16; r++) + { + vpx_memset(ypred_ptr, expected_dc, 16); + ypred_ptr += y_stride; + } + } + break; + case V_PRED: + { + + for (r = 0; r < 16; r++) + { + + ((int *)ypred_ptr)[0] = ((int *)yabove_row)[0]; + ((int *)ypred_ptr)[1] = ((int *)yabove_row)[1]; + ((int *)ypred_ptr)[2] = ((int *)yabove_row)[2]; + ((int *)ypred_ptr)[3] = ((int *)yabove_row)[3]; + ypred_ptr += y_stride; + } + } + break; + case H_PRED: + { + + for (r = 0; r < 16; r++) + { + + vpx_memset(ypred_ptr, yleft_col[r], 16); + ypred_ptr += y_stride; + } + + } + break; + case TM_PRED: + { + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + int pred = yleft_col[r] + yabove_row[ c] - ytop_left; + + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + + ypred_ptr[c] = pred; + } + + ypred_ptr += y_stride; + } + + } + break; + case B_PRED: + case NEARESTMV: + case NEARMV: + case ZEROMV: + case NEWMV: + case SPLITMV: + case MB_MODE_COUNT: + break; + } +} + +void vp8_build_intra_predictors_mbuv_s_c(MACROBLOCKD *x, + unsigned char * uabove_row, + unsigned char * vabove_row, + unsigned char * uleft, + unsigned char * vleft, + int left_stride, + unsigned char * upred_ptr, + unsigned char * vpred_ptr, + int pred_stride) +{ + unsigned char uleft_col[8]; + unsigned char utop_left = uabove_row[-1]; + unsigned char vleft_col[8]; + unsigned char vtop_left = vabove_row[-1]; + + int i, j; + + for (i = 0; i < 8; i++) + { + uleft_col[i] = uleft [i* left_stride]; + vleft_col[i] = vleft [i* left_stride]; + } + + switch (x->mode_info_context->mbmi.uv_mode) + { + case DC_PRED: + { + int expected_udc; + int expected_vdc; + int i; + int shift; + int Uaverage = 0; + int Vaverage = 0; + + if (x->up_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uabove_row[i]; + Vaverage += vabove_row[i]; + } + } + + if (x->left_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uleft_col[i]; + Vaverage += vleft_col[i]; + } + } + + if (!x->up_available && !x->left_available) + { + expected_udc = 128; + expected_vdc = 128; + } + else + { + shift = 2 + x->up_available + x->left_available; + expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; + expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; + } + + + /*vpx_memset(upred_ptr,expected_udc,64);*/ + /*vpx_memset(vpred_ptr,expected_vdc,64);*/ + for (i = 0; i < 8; i++) + { + vpx_memset(upred_ptr, expected_udc, 8); + vpx_memset(vpred_ptr, expected_vdc, 8); + upred_ptr += pred_stride; + vpred_ptr += pred_stride; + } + } + break; + case V_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + vpx_memcpy(upred_ptr, uabove_row, 8); + vpx_memcpy(vpred_ptr, vabove_row, 8); + upred_ptr += pred_stride; + vpred_ptr += pred_stride; + } + + } + break; + case H_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + vpx_memset(upred_ptr, uleft_col[i], 8); + vpx_memset(vpred_ptr, vleft_col[i], 8); + upred_ptr += pred_stride; + vpred_ptr += pred_stride; + } + } + + break; + case TM_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + int predu = uleft_col[i] + uabove_row[j] - utop_left; + int predv = vleft_col[i] + vabove_row[j] - vtop_left; + + if (predu < 0) + predu = 0; + + if (predu > 255) + predu = 255; + + if (predv < 0) + predv = 0; + + if (predv > 255) + predv = 255; + + upred_ptr[j] = predu; + vpred_ptr[j] = predv; + } + + upred_ptr += pred_stride; + vpred_ptr += pred_stride; + } + + } + break; + case B_PRED: + case NEARESTMV: + case NEARMV: + case ZEROMV: + case NEWMV: + case SPLITMV: + case MB_MODE_COUNT: + break; + } +} diff --git a/vp8/common/reconintra4x4.c b/vp8/common/reconintra4x4.c new file mode 100644 index 0000000..dcc35ec --- /dev/null +++ b/vp8/common/reconintra4x4.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "blockd.h" + +void vp8_intra4x4_predict_d_c(unsigned char *Above, + unsigned char *yleft, int left_stride, + int b_mode, + unsigned char *dst, int dst_stride, + unsigned char top_left) +{ + int i, r, c; + + unsigned char Left[4]; + Left[0] = yleft[0]; + Left[1] = yleft[left_stride]; + Left[2] = yleft[2 * left_stride]; + Left[3] = yleft[3 * left_stride]; + + switch (b_mode) + { + case B_DC_PRED: + { + int expected_dc = 0; + + for (i = 0; i < 4; i++) + { + expected_dc += Above[i]; + expected_dc += Left[i]; + } + + expected_dc = (expected_dc + 4) >> 3; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + dst[c] = expected_dc; + } + + dst += dst_stride; + } + } + break; + case B_TM_PRED: + { + /* prediction similar to true_motion prediction */ + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int pred = Above[c] - top_left + Left[r]; + + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + + dst[c] = pred; + } + + dst += dst_stride; + } + } + break; + + case B_VE_PRED: + { + + unsigned int ap[4]; + ap[0] = (top_left + 2 * Above[0] + Above[1] + 2) >> 2; + ap[1] = (Above[0] + 2 * Above[1] + Above[2] + 2) >> 2; + ap[2] = (Above[1] + 2 * Above[2] + Above[3] + 2) >> 2; + ap[3] = (Above[2] + 2 * Above[3] + Above[4] + 2) >> 2; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + + dst[c] = ap[c]; + } + + dst += dst_stride; + } + + } + break; + + + case B_HE_PRED: + { + + unsigned int lp[4]; + lp[0] = (top_left + 2 * Left[0] + Left[1] + 2) >> 2; + lp[1] = (Left[0] + 2 * Left[1] + Left[2] + 2) >> 2; + lp[2] = (Left[1] + 2 * Left[2] + Left[3] + 2) >> 2; + lp[3] = (Left[2] + 2 * Left[3] + Left[3] + 2) >> 2; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + dst[c] = lp[r]; + } + + dst += dst_stride; + } + } + break; + case B_LD_PRED: + { + unsigned char *ptr = Above; + dst[0 * dst_stride + 0] = (ptr[0] + ptr[1] * 2 + ptr[2] + 2) >> 2; + dst[0 * dst_stride + 1] = + dst[1 * dst_stride + 0] = (ptr[1] + ptr[2] * 2 + ptr[3] + 2) >> 2; + dst[0 * dst_stride + 2] = + dst[1 * dst_stride + 1] = + dst[2 * dst_stride + 0] = (ptr[2] + ptr[3] * 2 + ptr[4] + 2) >> 2; + dst[0 * dst_stride + 3] = + dst[1 * dst_stride + 2] = + dst[2 * dst_stride + 1] = + dst[3 * dst_stride + 0] = (ptr[3] + ptr[4] * 2 + ptr[5] + 2) >> 2; + dst[1 * dst_stride + 3] = + dst[2 * dst_stride + 2] = + dst[3 * dst_stride + 1] = (ptr[4] + ptr[5] * 2 + ptr[6] + 2) >> 2; + dst[2 * dst_stride + 3] = + dst[3 * dst_stride + 2] = (ptr[5] + ptr[6] * 2 + ptr[7] + 2) >> 2; + dst[3 * dst_stride + 3] = (ptr[6] + ptr[7] * 2 + ptr[7] + 2) >> 2; + + } + break; + case B_RD_PRED: + { + + unsigned char pp[9]; + + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + dst[3 * dst_stride + 0] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + dst[3 * dst_stride + 1] = + dst[2 * dst_stride + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + dst[3 * dst_stride + 2] = + dst[2 * dst_stride + 1] = + dst[1 * dst_stride + 0] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + dst[3 * dst_stride + 3] = + dst[2 * dst_stride + 2] = + dst[1 * dst_stride + 1] = + dst[0 * dst_stride + 0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + dst[2 * dst_stride + 3] = + dst[1 * dst_stride + 2] = + dst[0 * dst_stride + 1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + dst[1 * dst_stride + 3] = + dst[0 * dst_stride + 2] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + dst[0 * dst_stride + 3] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + + } + break; + case B_VR_PRED: + { + + unsigned char pp[9]; + + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + + dst[3 * dst_stride + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + dst[2 * dst_stride + 0] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + dst[3 * dst_stride + 1] = + dst[1 * dst_stride + 0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + dst[2 * dst_stride + 1] = + dst[0 * dst_stride + 0] = (pp[4] + pp[5] + 1) >> 1; + dst[3 * dst_stride + 2] = + dst[1 * dst_stride + 1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + dst[2 * dst_stride + 2] = + dst[0 * dst_stride + 1] = (pp[5] + pp[6] + 1) >> 1; + dst[3 * dst_stride + 3] = + dst[1 * dst_stride + 2] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + dst[2 * dst_stride + 3] = + dst[0 * dst_stride + 2] = (pp[6] + pp[7] + 1) >> 1; + dst[1 * dst_stride + 3] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + dst[0 * dst_stride + 3] = (pp[7] + pp[8] + 1) >> 1; + + } + break; + case B_VL_PRED: + { + + unsigned char *pp = Above; + + dst[0 * dst_stride + 0] = (pp[0] + pp[1] + 1) >> 1; + dst[1 * dst_stride + 0] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + dst[2 * dst_stride + 0] = + dst[0 * dst_stride + 1] = (pp[1] + pp[2] + 1) >> 1; + dst[1 * dst_stride + 1] = + dst[3 * dst_stride + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + dst[2 * dst_stride + 1] = + dst[0 * dst_stride + 2] = (pp[2] + pp[3] + 1) >> 1; + dst[3 * dst_stride + 1] = + dst[1 * dst_stride + 2] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + dst[0 * dst_stride + 3] = + dst[2 * dst_stride + 2] = (pp[3] + pp[4] + 1) >> 1; + dst[1 * dst_stride + 3] = + dst[3 * dst_stride + 2] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + dst[2 * dst_stride + 3] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + dst[3 * dst_stride + 3] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + } + break; + + case B_HD_PRED: + { + unsigned char pp[9]; + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + + dst[3 * dst_stride + 0] = (pp[0] + pp[1] + 1) >> 1; + dst[3 * dst_stride + 1] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + dst[2 * dst_stride + 0] = + dst[3 * dst_stride + 2] = (pp[1] + pp[2] + 1) >> 1; + dst[2 * dst_stride + 1] = + dst[3 * dst_stride + 3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + dst[2 * dst_stride + 2] = + dst[1 * dst_stride + 0] = (pp[2] + pp[3] + 1) >> 1; + dst[2 * dst_stride + 3] = + dst[1 * dst_stride + 1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + dst[1 * dst_stride + 2] = + dst[0 * dst_stride + 0] = (pp[3] + pp[4] + 1) >> 1; + dst[1 * dst_stride + 3] = + dst[0 * dst_stride + 1] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + dst[0 * dst_stride + 2] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + dst[0 * dst_stride + 3] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + } + break; + + + case B_HU_PRED: + { + unsigned char *pp = Left; + dst[0 * dst_stride + 0] = (pp[0] + pp[1] + 1) >> 1; + dst[0 * dst_stride + 1] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + dst[0 * dst_stride + 2] = + dst[1 * dst_stride + 0] = (pp[1] + pp[2] + 1) >> 1; + dst[0 * dst_stride + 3] = + dst[1 * dst_stride + 1] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + dst[1 * dst_stride + 2] = + dst[2 * dst_stride + 0] = (pp[2] + pp[3] + 1) >> 1; + dst[1 * dst_stride + 3] = + dst[2 * dst_stride + 1] = (pp[2] + pp[3] * 2 + pp[3] + 2) >> 2; + dst[2 * dst_stride + 2] = + dst[2 * dst_stride + 3] = + dst[3 * dst_stride + 0] = + dst[3 * dst_stride + 1] = + dst[3 * dst_stride + 2] = + dst[3 * dst_stride + 3] = pp[3]; + } + break; + + + } +} + +void vp8_intra4x4_predict_c(unsigned char *src, int src_stride, + int b_mode, + unsigned char *dst, int dst_stride) +{ + unsigned char *Above = src - src_stride; + + vp8_intra4x4_predict_d_c(Above, + src - 1, src_stride, + b_mode, + dst, dst_stride, + Above[-1]); +} diff --git a/vp8/common/reconintra4x4.h b/vp8/common/reconintra4x4.h new file mode 100644 index 0000000..d2b0d43 --- /dev/null +++ b/vp8/common/reconintra4x4.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_RECONINTRA4x4_H +#define __INC_RECONINTRA4x4_H +#include "vp8/common/blockd.h" + +static void intra_prediction_down_copy(MACROBLOCKD *xd, + unsigned char *above_right_src) +{ + int dst_stride = xd->dst.y_stride; + unsigned char *above_right_dst = xd->dst.y_buffer - dst_stride + 16; + + unsigned int *src_ptr = (unsigned int *)above_right_src; + unsigned int *dst_ptr0 = (unsigned int *)(above_right_dst + 4 * dst_stride); + unsigned int *dst_ptr1 = (unsigned int *)(above_right_dst + 8 * dst_stride); + unsigned int *dst_ptr2 = (unsigned int *)(above_right_dst + 12 * dst_stride); + + *dst_ptr0 = *src_ptr; + *dst_ptr1 = *src_ptr; + *dst_ptr2 = *src_ptr; +} + +#endif diff --git a/vp8/common/rtcd.c b/vp8/common/rtcd.c new file mode 100644 index 0000000..232640d --- /dev/null +++ b/vp8/common/rtcd.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "vpx_config.h" +#define RTCD_C +#include "vpx_rtcd.h" diff --git a/vp8/common/rtcd_defs.sh b/vp8/common/rtcd_defs.sh new file mode 100644 index 0000000..33bf08b --- /dev/null +++ b/vp8/common/rtcd_defs.sh @@ -0,0 +1,541 @@ +common_forward_decls() { +cat < +#include "vpx_config.h" +#include "vpx/vpx_integer.h" + +static +unsigned int sad_mx_n_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad, + int m, + int n) +{ + + int r, c; + unsigned int sad = 0; + + for (r = 0; r < n; r++) + { + for (c = 0; c < m; c++) + { + sad += abs(src_ptr[c] - ref_ptr[c]); + } + + if (sad > max_sad) + break; + + src_ptr += src_stride; + ref_ptr += ref_stride; + } + + return sad; +} + +/* max_sad is provided as an optional optimization point. Alternative + * implementations of these functions are not required to check it. + */ + +unsigned int vp8_sad16x16_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, max_sad, 16, 16); +} + + +unsigned int vp8_sad8x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, max_sad, 8, 8); +} + + +unsigned int vp8_sad16x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, max_sad, 16, 8); + +} + + +unsigned int vp8_sad8x16_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, max_sad, 8, 16); +} + + +unsigned int vp8_sad4x4_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, max_sad, 4, 4); +} + +void vp8_sad16x16x3_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad16x16x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned short *sad_array +) +{ + sad_array[0] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); + sad_array[3] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 3 , ref_stride, 0x7fffffff); + sad_array[4] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 4, ref_stride, 0x7fffffff); + sad_array[5] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 5, ref_stride, 0x7fffffff); + sad_array[6] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 6 , ref_stride, 0x7fffffff); + sad_array[7] = (unsigned short)vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 7, ref_stride, 0x7fffffff); +} + +void vp8_sad16x8x3_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad16x8x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned short *sad_array +) +{ + sad_array[0] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); + sad_array[3] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 3 , ref_stride, 0x7fffffff); + sad_array[4] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 4, ref_stride, 0x7fffffff); + sad_array[5] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 5, ref_stride, 0x7fffffff); + sad_array[6] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 6 , ref_stride, 0x7fffffff); + sad_array[7] = (unsigned short)vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 7, ref_stride, 0x7fffffff); +} + +void vp8_sad8x8x3_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad8x8x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned short *sad_array +) +{ + sad_array[0] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); + sad_array[3] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 3 , ref_stride, 0x7fffffff); + sad_array[4] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 4, ref_stride, 0x7fffffff); + sad_array[5] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 5, ref_stride, 0x7fffffff); + sad_array[6] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 6 , ref_stride, 0x7fffffff); + sad_array[7] = (unsigned short)vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 7, ref_stride, 0x7fffffff); +} + +void vp8_sad8x16x3_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad8x16x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned short *sad_array +) +{ + sad_array[0] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); + sad_array[3] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 3 , ref_stride, 0x7fffffff); + sad_array[4] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 4, ref_stride, 0x7fffffff); + sad_array[5] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 5, ref_stride, 0x7fffffff); + sad_array[6] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 6 , ref_stride, 0x7fffffff); + sad_array[7] = (unsigned short)vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 7, ref_stride, 0x7fffffff); +} + +void vp8_sad4x4x3_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad4x4x8_c( + const unsigned char *src_ptr, + int src_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned short *sad_array +) +{ + sad_array[0] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); + sad_array[3] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 3 , ref_stride, 0x7fffffff); + sad_array[4] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 4, ref_stride, 0x7fffffff); + sad_array[5] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 5, ref_stride, 0x7fffffff); + sad_array[6] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 6 , ref_stride, 0x7fffffff); + sad_array[7] = (unsigned short)vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 7, ref_stride, 0x7fffffff); +} + +void vp8_sad16x16x4d_c( + const unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad16x8x4d_c( + const unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad8x8x4d_c( + const unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad8x16x4d_c( + const unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad4x4x4d_c( + const unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +/* Copy 2 macroblocks to a buffer */ +void vp8_copy32xn_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *dst_ptr, + int dst_stride, + int height) +{ + int r; + + for (r = 0; r < height; r++) + { +#if !(CONFIG_FAST_UNALIGNED) + dst_ptr[0] = src_ptr[0]; + dst_ptr[1] = src_ptr[1]; + dst_ptr[2] = src_ptr[2]; + dst_ptr[3] = src_ptr[3]; + dst_ptr[4] = src_ptr[4]; + dst_ptr[5] = src_ptr[5]; + dst_ptr[6] = src_ptr[6]; + dst_ptr[7] = src_ptr[7]; + dst_ptr[8] = src_ptr[8]; + dst_ptr[9] = src_ptr[9]; + dst_ptr[10] = src_ptr[10]; + dst_ptr[11] = src_ptr[11]; + dst_ptr[12] = src_ptr[12]; + dst_ptr[13] = src_ptr[13]; + dst_ptr[14] = src_ptr[14]; + dst_ptr[15] = src_ptr[15]; + dst_ptr[16] = src_ptr[16]; + dst_ptr[17] = src_ptr[17]; + dst_ptr[18] = src_ptr[18]; + dst_ptr[19] = src_ptr[19]; + dst_ptr[20] = src_ptr[20]; + dst_ptr[21] = src_ptr[21]; + dst_ptr[22] = src_ptr[22]; + dst_ptr[23] = src_ptr[23]; + dst_ptr[24] = src_ptr[24]; + dst_ptr[25] = src_ptr[25]; + dst_ptr[26] = src_ptr[26]; + dst_ptr[27] = src_ptr[27]; + dst_ptr[28] = src_ptr[28]; + dst_ptr[29] = src_ptr[29]; + dst_ptr[30] = src_ptr[30]; + dst_ptr[31] = src_ptr[31]; +#else + ((uint32_t *)dst_ptr)[0] = ((uint32_t *)src_ptr)[0] ; + ((uint32_t *)dst_ptr)[1] = ((uint32_t *)src_ptr)[1] ; + ((uint32_t *)dst_ptr)[2] = ((uint32_t *)src_ptr)[2] ; + ((uint32_t *)dst_ptr)[3] = ((uint32_t *)src_ptr)[3] ; + ((uint32_t *)dst_ptr)[4] = ((uint32_t *)src_ptr)[4] ; + ((uint32_t *)dst_ptr)[5] = ((uint32_t *)src_ptr)[5] ; + ((uint32_t *)dst_ptr)[6] = ((uint32_t *)src_ptr)[6] ; + ((uint32_t *)dst_ptr)[7] = ((uint32_t *)src_ptr)[7] ; +#endif + src_ptr += src_stride; + dst_ptr += dst_stride; + + } +} diff --git a/vp8/common/setupintrarecon.c b/vp8/common/setupintrarecon.c new file mode 100644 index 0000000..7976e25 --- /dev/null +++ b/vp8/common/setupintrarecon.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "setupintrarecon.h" +#include "vpx_mem/vpx_mem.h" + +void vp8_setup_intra_recon(YV12_BUFFER_CONFIG *ybf) +{ + int i; + + /* set up frame new frame for intra coded blocks */ + vpx_memset(ybf->y_buffer - 1 - ybf->y_stride, 127, ybf->y_width + 5); + for (i = 0; i < ybf->y_height; i++) + ybf->y_buffer[ybf->y_stride *i - 1] = (unsigned char) 129; + + vpx_memset(ybf->u_buffer - 1 - ybf->uv_stride, 127, ybf->uv_width + 5); + for (i = 0; i < ybf->uv_height; i++) + ybf->u_buffer[ybf->uv_stride *i - 1] = (unsigned char) 129; + + vpx_memset(ybf->v_buffer - 1 - ybf->uv_stride, 127, ybf->uv_width + 5); + for (i = 0; i < ybf->uv_height; i++) + ybf->v_buffer[ybf->uv_stride *i - 1] = (unsigned char) 129; + +} diff --git a/vp8/common/setupintrarecon.h b/vp8/common/setupintrarecon.h new file mode 100644 index 0000000..5264fd0 --- /dev/null +++ b/vp8/common/setupintrarecon.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +extern void vp8_setup_intra_recon(YV12_BUFFER_CONFIG *ybf); diff --git a/vp8/common/swapyv12buffer.c b/vp8/common/swapyv12buffer.c new file mode 100644 index 0000000..73656b3 --- /dev/null +++ b/vp8/common/swapyv12buffer.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "swapyv12buffer.h" + +void vp8_swap_yv12_buffer(YV12_BUFFER_CONFIG *new_frame, YV12_BUFFER_CONFIG *last_frame) +{ + unsigned char *temp; + + temp = last_frame->buffer_alloc; + last_frame->buffer_alloc = new_frame->buffer_alloc; + new_frame->buffer_alloc = temp; + + temp = last_frame->y_buffer; + last_frame->y_buffer = new_frame->y_buffer; + new_frame->y_buffer = temp; + + temp = last_frame->u_buffer; + last_frame->u_buffer = new_frame->u_buffer; + new_frame->u_buffer = temp; + + temp = last_frame->v_buffer; + last_frame->v_buffer = new_frame->v_buffer; + new_frame->v_buffer = temp; + +} diff --git a/vp8/common/swapyv12buffer.h b/vp8/common/swapyv12buffer.h new file mode 100644 index 0000000..a6473ed --- /dev/null +++ b/vp8/common/swapyv12buffer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef SWAPYV12_BUFFER_H +#define SWAPYV12_BUFFER_H + +#include "vpx_scale/yv12config.h" + +void vp8_swap_yv12_buffer(YV12_BUFFER_CONFIG *new_frame, YV12_BUFFER_CONFIG *last_frame); + +#endif diff --git a/vp8/common/systemdependent.h b/vp8/common/systemdependent.h new file mode 100644 index 0000000..f99c4bb --- /dev/null +++ b/vp8/common/systemdependent.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#if ARCH_X86 || ARCH_X86_64 +void vpx_reset_mmx_state(void); +#define vp8_clear_system_state() vpx_reset_mmx_state() +#else +#define vp8_clear_system_state() +#endif + +struct VP8Common; +void vp8_machine_specific_config(struct VP8Common *); diff --git a/vp8/common/textblit.c b/vp8/common/textblit.c new file mode 100644 index 0000000..1756100 --- /dev/null +++ b/vp8/common/textblit.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + + +void vp8_blit_text(const char *msg, unsigned char *address, const int pitch) +{ + int letter_bitmap; + unsigned char *output_pos = address; + int colpos; + const int font[] = + { + 0x0, 0x5C00, 0x8020, 0xAFABEA, 0xD7EC0, 0x1111111, 0x1855740, 0x18000, + 0x45C0, 0x74400, 0x51140, 0x23880, 0xC4000, 0x21080, 0x80000, 0x111110, + 0xE9D72E, 0x87E40, 0x12AD732, 0xAAD62A, 0x4F94C4, 0x4D6B7, 0x456AA, + 0x3E8423, 0xAAD6AA, 0xAAD6A2, 0x2800, 0x2A00, 0x8A880, 0x52940, 0x22A20, + 0x15422, 0x6AD62E, 0x1E4A53E, 0xAAD6BF, 0x8C62E, 0xE8C63F, 0x118D6BF, + 0x1094BF, 0xCAC62E, 0x1F2109F, 0x118FE31, 0xF8C628, 0x8A89F, 0x108421F, + 0x1F1105F, 0x1F4105F, 0xE8C62E, 0x2294BF, 0x164C62E, 0x12694BF, 0x8AD6A2, + 0x10FC21, 0x1F8421F, 0x744107, 0xF8220F, 0x1151151, 0x117041, 0x119D731, + 0x47E0, 0x1041041, 0xFC400, 0x10440, 0x1084210, 0x820 + }; + colpos = 0; + + while (msg[colpos] != 0) + { + char letter = msg[colpos]; + int fontcol, fontrow; + + if (letter <= 'Z' && letter >= ' ') + letter_bitmap = font[letter-' ']; + else if (letter <= 'z' && letter >= 'a') + letter_bitmap = font[letter-'a'+'A' - ' ']; + else + letter_bitmap = font[0]; + + for (fontcol = 6; fontcol >= 0 ; fontcol--) + for (fontrow = 0; fontrow < 5; fontrow++) + output_pos[fontrow *pitch + fontcol] = + ((letter_bitmap >> (fontcol * 5)) & (1 << fontrow) ? 255 : 0); + + output_pos += 7; + colpos++; + } +} + +static void plot (const int x, const int y, unsigned char *image, const int pitch) +{ + image [x+y*pitch] ^= 255; +} + +/* Bresenham line algorithm */ +void vp8_blit_line(int x0, int x1, int y0, int y1, unsigned char *image, const int pitch) +{ + int steep = abs(y1 - y0) > abs(x1 - x0); + int deltax, deltay; + int error, ystep, y, x; + + if (steep) + { + int t; + t = x0; + x0 = y0; + y0 = t; + + t = x1; + x1 = y1; + y1 = t; + } + + if (x0 > x1) + { + int t; + t = x0; + x0 = x1; + x1 = t; + + t = y0; + y0 = y1; + y1 = t; + } + + deltax = x1 - x0; + deltay = abs(y1 - y0); + error = deltax / 2; + + y = y0; + + if (y0 < y1) + ystep = 1; + else + ystep = -1; + + if (steep) + { + for (x = x0; x <= x1; x++) + { + plot(y,x, image, pitch); + + error = error - deltay; + if (error < 0) + { + y = y + ystep; + error = error + deltax; + } + } + } + else + { + for (x = x0; x <= x1; x++) + { + plot(x,y, image, pitch); + + error = error - deltay; + if (error < 0) + { + y = y + ystep; + error = error + deltax; + } + } + } +} diff --git a/vp8/common/threading.h b/vp8/common/threading.h new file mode 100644 index 0000000..ed9e3e6 --- /dev/null +++ b/vp8/common/threading.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef _PTHREAD_EMULATION +#define _PTHREAD_EMULATION + +#if CONFIG_OS_SUPPORT && CONFIG_MULTITHREAD + +/* Thread management macros */ +#ifdef _WIN32 +/* Win32 */ +#include +#include +#define THREAD_FUNCTION DWORD WINAPI +#define THREAD_FUNCTION_RETURN DWORD +#define THREAD_SPECIFIC_INDEX DWORD +#define pthread_t HANDLE +#define pthread_attr_t DWORD +#define pthread_create(thhandle,attr,thfunc,tharg) (int)((*thhandle=(HANDLE)_beginthreadex(NULL,0,(unsigned int (__stdcall *)(void *))thfunc,tharg,0,NULL))==NULL) +#define pthread_join(thread, result) ((WaitForSingleObject((thread),INFINITE)!=WAIT_OBJECT_0) || !CloseHandle(thread)) +#define pthread_detach(thread) if(thread!=NULL)CloseHandle(thread) +#define thread_sleep(nms) Sleep(nms) +#define pthread_cancel(thread) terminate_thread(thread,0) +#define ts_key_create(ts_key, destructor) {ts_key = TlsAlloc();}; +#define pthread_getspecific(ts_key) TlsGetValue(ts_key) +#define pthread_setspecific(ts_key, value) TlsSetValue(ts_key, (void *)value) +#define pthread_self() GetCurrentThreadId() + +#elif defined(__OS2__) +/* OS/2 */ +#define INCL_DOS +#include + +#include +#define THREAD_FUNCTION void +#define THREAD_FUNCTION_RETURN void +#define THREAD_SPECIFIC_INDEX PULONG +#define pthread_t TID +#define pthread_attr_t ULONG +#define pthread_create(thhandle,attr,thfunc,tharg) \ + ((int)((*(thhandle)=_beginthread(thfunc,NULL,1024*1024,tharg))==-1)) +#define pthread_join(thread, result) ((int)DosWaitThread(&(thread),0)) +#define pthread_detach(thread) 0 +#define thread_sleep(nms) DosSleep(nms) +#define pthread_cancel(thread) DosKillThread(thread) +#define ts_key_create(ts_key, destructor) \ + DosAllocThreadLocalMemory(1, &(ts_key)); +#define pthread_getspecific(ts_key) ((void *)(*(ts_key))) +#define pthread_setspecific(ts_key, value) (*(ts_key)=(ULONG)(value)) +#define pthread_self() _gettid() +#else +#ifdef __APPLE__ +#include +#include +#include +#include +#include + +#else +#include +#endif + +#include +/* pthreads */ +/* Nearly everything is already defined */ +#define THREAD_FUNCTION void * +#define THREAD_FUNCTION_RETURN void * +#define THREAD_SPECIFIC_INDEX pthread_key_t +#define ts_key_create(ts_key, destructor) pthread_key_create (&(ts_key), destructor); +#endif + +/* Syncrhronization macros: Win32 and Pthreads */ +#ifdef _WIN32 +#define sem_t HANDLE +#define pause(voidpara) __asm PAUSE +#define sem_init(sem, sem_attr1, sem_init_value) (int)((*sem = CreateSemaphore(NULL,0,32768,NULL))==NULL) +#define sem_wait(sem) (int)(WAIT_OBJECT_0 != WaitForSingleObject(*sem,INFINITE)) +#define sem_post(sem) ReleaseSemaphore(*sem,1,NULL) +#define sem_destroy(sem) if(*sem)((int)(CloseHandle(*sem))==TRUE) +#define thread_sleep(nms) Sleep(nms) + +#elif defined(__OS2__) +typedef struct +{ + HEV event; + HMTX wait_mutex; + HMTX count_mutex; + int count; +} sem_t; + +static inline int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + DosCreateEventSem(NULL, &sem->event, pshared ? DC_SEM_SHARED : 0, + value > 0 ? TRUE : FALSE); + DosCreateMutexSem(NULL, &sem->wait_mutex, 0, FALSE); + DosCreateMutexSem(NULL, &sem->count_mutex, 0, FALSE); + + sem->count = value; + + return 0; +} + +static inline int sem_wait(sem_t * sem) +{ + DosRequestMutexSem(sem->wait_mutex, -1); + + DosWaitEventSem(sem->event, -1); + + DosRequestMutexSem(sem->count_mutex, -1); + + sem->count--; + if (sem->count == 0) + { + ULONG post_count; + + DosResetEventSem(sem->event, &post_count); + } + + DosReleaseMutexSem(sem->count_mutex); + + DosReleaseMutexSem(sem->wait_mutex); + + return 0; +} + +static inline int sem_post(sem_t * sem) +{ + DosRequestMutexSem(sem->count_mutex, -1); + + if (sem->count < 32768) + { + sem->count++; + DosPostEventSem(sem->event); + } + + DosReleaseMutexSem(sem->count_mutex); + + return 0; +} + +static inline int sem_destroy(sem_t * sem) +{ + DosCloseEventSem(sem->event); + DosCloseMutexSem(sem->wait_mutex); + DosCloseMutexSem(sem->count_mutex); + + return 0; +} + +#define thread_sleep(nms) DosSleep(nms) + +#else + +#ifdef __APPLE__ +#define sem_t semaphore_t +#define sem_init(X,Y,Z) semaphore_create(mach_task_self(), X, SYNC_POLICY_FIFO, Z) +#define sem_wait(sem) (semaphore_wait(*sem) ) +#define sem_post(sem) semaphore_signal(*sem) +#define sem_destroy(sem) semaphore_destroy(mach_task_self(),*sem) +#define thread_sleep(nms) /* { struct timespec ts;ts.tv_sec=0; ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} */ +#else +#include +#include +#define thread_sleep(nms) sched_yield();/* {struct timespec ts;ts.tv_sec=0; ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} */ +#endif +/* Not Windows. Assume pthreads */ + +#endif + +#if ARCH_X86 || ARCH_X86_64 +#include "vpx_ports/x86.h" +#else +#define x86_pause_hint() +#endif + +#endif /* CONFIG_OS_SUPPORT && CONFIG_MULTITHREAD */ + +#endif diff --git a/vp8/common/treecoder.c b/vp8/common/treecoder.c new file mode 100644 index 0000000..d80c64b --- /dev/null +++ b/vp8/common/treecoder.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#if CONFIG_DEBUG +#include +#endif +#include + +#include "treecoder.h" + +static void tree2tok( + struct vp8_token_struct *const p, + vp8_tree t, + int i, + int v, + int L +) +{ + v += v; + ++L; + + do + { + const vp8_tree_index j = t[i++]; + + if (j <= 0) + { + p[-j].value = v; + p[-j].Len = L; + } + else + tree2tok(p, t, j, v, L); + } + while (++v & 1); +} + +void vp8_tokens_from_tree(struct vp8_token_struct *p, vp8_tree t) +{ + tree2tok(p, t, 0, 0, 0); +} + +void vp8_tokens_from_tree_offset(struct vp8_token_struct *p, vp8_tree t, + int offset) +{ + tree2tok(p - offset, t, 0, 0, 0); +} + +static void branch_counts( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ] +) +{ + const int tree_len = n - 1; + int t = 0; + +#if CONFIG_DEBUG + assert(tree_len); +#endif + + do + { + branch_ct[t][0] = branch_ct[t][1] = 0; + } + while (++t < tree_len); + + t = 0; + + do + { + int L = tok[t].Len; + const int enc = tok[t].value; + const unsigned int ct = num_events[t]; + + vp8_tree_index i = 0; + + do + { + const int b = (enc >> --L) & 1; + const int j = i >> 1; +#if CONFIG_DEBUG + assert(j < tree_len && 0 <= L); +#endif + + branch_ct [j] [b] += ct; + i = tree[ i + b]; + } + while (i > 0); + +#if CONFIG_DEBUG + assert(!L); +#endif + } + while (++t < n); + +} + + +void vp8_tree_probs_from_distribution( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + vp8_prob probs [ /* n-1 */ ], + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ], + unsigned int Pfac, + int rd +) +{ + const int tree_len = n - 1; + int t = 0; + + branch_counts(n, tok, tree, branch_ct, num_events); + + do + { + const unsigned int *const c = branch_ct[t]; + const unsigned int tot = c[0] + c[1]; + +#if CONFIG_DEBUG + assert(tot < (1 << 24)); /* no overflow below */ +#endif + + if (tot) + { + const unsigned int p = ((c[0] * Pfac) + (rd ? tot >> 1 : 0)) / tot; + probs[t] = p < 256 ? (p ? p : 1) : 255; /* agree w/old version for now */ + } + else + probs[t] = vp8_prob_half; + } + while (++t < tree_len); +} diff --git a/vp8/common/treecoder.h b/vp8/common/treecoder.h new file mode 100644 index 0000000..ebf51c5 --- /dev/null +++ b/vp8/common/treecoder.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_TREECODER_H +#define __INC_TREECODER_H + +typedef unsigned char vp8bc_index_t; /* probability index */ + + +typedef unsigned char vp8_prob; + +#define vp8_prob_half ( (vp8_prob) 128) + +typedef signed char vp8_tree_index; +struct bool_coder_spec; + +typedef struct bool_coder_spec bool_coder_spec; +typedef struct bool_writer bool_writer; +typedef struct bool_reader bool_reader; + +typedef const bool_coder_spec c_bool_coder_spec; +typedef const bool_writer c_bool_writer; +typedef const bool_reader c_bool_reader; + + + +# define vp8_complement( x) (255 - x) + + +/* We build coding trees compactly in arrays. + Each node of the tree is a pair of vp8_tree_indices. + Array index often references a corresponding probability table. + Index <= 0 means done encoding/decoding and value = -Index, + Index > 0 means need another bit, specification at index. + Nonnegative indices are always even; processing begins at node 0. */ + +typedef const vp8_tree_index vp8_tree[], *vp8_tree_p; + + +typedef const struct vp8_token_struct +{ + int value; + int Len; +} vp8_token; + +/* Construct encoding array from tree. */ + +void vp8_tokens_from_tree(struct vp8_token_struct *, vp8_tree); +void vp8_tokens_from_tree_offset(struct vp8_token_struct *, vp8_tree, + int offset); + + +/* Convert array of token occurrence counts into a table of probabilities + for the associated binary encoding tree. Also writes count of branches + taken for each node on the tree; this facilitiates decisions as to + probability updates. */ + +void vp8_tree_probs_from_distribution( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + vp8_prob probs [ /* n-1 */ ], + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ], + unsigned int Pfactor, + int Round +); + +/* Variant of above using coder spec rather than hardwired 8-bit probs. */ + +void vp8bc_tree_probs_from_distribution( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + vp8_prob probs [ /* n-1 */ ], + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ], + c_bool_coder_spec *s +); + + +#endif diff --git a/vp8/common/variance.h b/vp8/common/variance.h new file mode 100644 index 0000000..b77aa28 --- /dev/null +++ b/vp8/common/variance.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VARIANCE_H +#define VARIANCE_H + +typedef unsigned int(*vp8_sad_fn_t) + ( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int ref_stride, + int max_sad + ); + +typedef void (*vp8_copy32xn_fn_t)( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int ref_stride, + int n); + +typedef void (*vp8_sad_multi_fn_t)( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array); + +typedef void (*vp8_sad_multi1_fn_t) + ( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned short *sad_array + ); + +typedef void (*vp8_sad_multi_d_fn_t) + ( + const unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr[4], + int ref_stride, + unsigned int *sad_array + ); + +typedef unsigned int (*vp8_variance_fn_t) + ( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int ref_stride, + unsigned int *sse + ); + +typedef unsigned int (*vp8_subpixvariance_fn_t) + ( + const unsigned char *src_ptr, + int source_stride, + int xoffset, + int yoffset, + const unsigned char *ref_ptr, + int Refstride, + unsigned int *sse + ); + +typedef void (*vp8_ssimpf_fn_t) + ( + unsigned char *s, + int sp, + unsigned char *r, + int rp, + unsigned long *sum_s, + unsigned long *sum_r, + unsigned long *sum_sq_s, + unsigned long *sum_sq_r, + unsigned long *sum_sxr + ); + +typedef unsigned int (*vp8_getmbss_fn_t)(const short *); + +typedef unsigned int (*vp8_get16x16prederror_fn_t) + ( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int ref_stride + ); + +typedef struct variance_vtable +{ + vp8_sad_fn_t sdf; + vp8_variance_fn_t vf; + vp8_subpixvariance_fn_t svf; + vp8_variance_fn_t svf_halfpix_h; + vp8_variance_fn_t svf_halfpix_v; + vp8_variance_fn_t svf_halfpix_hv; + vp8_sad_multi_fn_t sdx3f; + vp8_sad_multi1_fn_t sdx8f; + vp8_sad_multi_d_fn_t sdx4df; +#if ARCH_X86 || ARCH_X86_64 + vp8_copy32xn_fn_t copymem; +#endif +} vp8_variance_fn_ptr_t; + +#endif diff --git a/vp8/common/variance_c.c b/vp8/common/variance_c.c new file mode 100644 index 0000000..996404d --- /dev/null +++ b/vp8/common/variance_c.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "variance.h" +#include "filter.h" + + +unsigned int vp8_get_mb_ss_c +( + const short *src_ptr +) +{ + unsigned int i = 0, sum = 0; + + do + { + sum += (src_ptr[i] * src_ptr[i]); + i++; + } + while (i < 256); + + return sum; +} + + +static void variance( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + int w, + int h, + unsigned int *sse, + int *sum) +{ + int i, j; + int diff; + + *sum = 0; + *sse = 0; + + for (i = 0; i < h; i++) + { + for (j = 0; j < w; j++) + { + diff = src_ptr[j] - ref_ptr[j]; + *sum += diff; + *sse += diff * diff; + } + + src_ptr += source_stride; + ref_ptr += recon_stride; + } +} + + +unsigned int vp8_variance16x16_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg); + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 8)); +} + +unsigned int vp8_variance8x16_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 16, &var, &avg); + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 7)); +} + +unsigned int vp8_variance16x8_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 8, &var, &avg); + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 7)); +} + + +unsigned int vp8_variance8x8_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 8, &var, &avg); + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 6)); +} + +unsigned int vp8_variance4x4_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + variance(src_ptr, source_stride, ref_ptr, recon_stride, 4, 4, &var, &avg); + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 4)); +} + + +unsigned int vp8_mse16x16_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg); + *sse = var; + return var; +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_first_pass + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * UINT32 pixel_step : Offset between filter input samples (see notes). + * UINT32 output_height : Input block height. + * UINT32 output_width : Input block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : INT32 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in + * either horizontal or vertical direction to produce the + * filtered output block. Used to implement first-pass + * of 2-D separable filter. + * + * SPECIAL NOTES : Produces INT32 output to retain precision for next pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * pixel_step defines whether the filter is applied + * horizontally (pixel_step=1) or vertically (pixel_step=stride). + * It defines the offset required to move from one input + * to the next. + * + ****************************************************************************/ +static void var_filter_block2d_bil_first_pass +( + const unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply bilinear filter + output_ptr[j] = (((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[pixel_step] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2)) >> VP8_FILTER_SHIFT; + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_second_pass + * + * INPUTS : INT32 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * UINT32 pixel_step : Offset between filter input samples (see notes). + * UINT32 output_height : Input block height. + * UINT32 output_width : Input block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : UINT16 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in + * either horizontal or vertical direction to produce the + * filtered output block. Used to implement second-pass + * of 2-D separable filter. + * + * SPECIAL NOTES : Requires 32-bit input as produced by filter_block2d_bil_first_pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * pixel_step defines whether the filter is applied + * horizontally (pixel_step=1) or vertically (pixel_step=stride). + * It defines the offset required to move from one input + * to the next. + * + ****************************************************************************/ +static void var_filter_block2d_bil_second_pass +( + const unsigned short *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply filter + Temp = ((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[pixel_step] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2); + output_ptr[j] = (unsigned int)(Temp >> VP8_FILTER_SHIFT); + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + + +unsigned int vp8_sub_pixel_variance4x4_c +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned char temp2[20*16]; + const short *HFilter, *VFilter; + unsigned short FData3[5*4]; // Temp data bufffer used in filtering + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + // First filter 1d Horizontal + var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 5, 4, HFilter); + + // Now filter Verticaly + var_filter_block2d_bil_second_pass(FData3, temp2, 4, 4, 4, 4, VFilter); + + return vp8_variance4x4_c(temp2, 4, dst_ptr, dst_pixels_per_line, sse); +} + + +unsigned int vp8_sub_pixel_variance8x8_c +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[9*8]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const short *HFilter, *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 9, 8, HFilter); + var_filter_block2d_bil_second_pass(FData3, temp2, 8, 8, 8, 8, VFilter); + + return vp8_variance8x8_c(temp2, 8, dst_ptr, dst_pixels_per_line, sse); +} + +unsigned int vp8_sub_pixel_variance16x16_c +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[17*16]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const short *HFilter, *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 17, 16, HFilter); + var_filter_block2d_bil_second_pass(FData3, temp2, 16, 16, 16, 16, VFilter); + + return vp8_variance16x16_c(temp2, 16, dst_ptr, dst_pixels_per_line, sse); +} + + +unsigned int vp8_variance_halfpixvar16x16_h_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 4, 0, + ref_ptr, recon_stride, sse); +} + + +unsigned int vp8_variance_halfpixvar16x16_v_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 0, 4, + ref_ptr, recon_stride, sse); +} + + +unsigned int vp8_variance_halfpixvar16x16_hv_c( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 4, 4, + ref_ptr, recon_stride, sse); +} + + +unsigned int vp8_sub_pixel_mse16x16_c +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + vp8_sub_pixel_variance16x16_c(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); + return *sse; +} + +unsigned int vp8_sub_pixel_variance16x8_c +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[16*9]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const short *HFilter, *VFilter; + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 9, 16, HFilter); + var_filter_block2d_bil_second_pass(FData3, temp2, 16, 16, 8, 16, VFilter); + + return vp8_variance16x8_c(temp2, 16, dst_ptr, dst_pixels_per_line, sse); +} + +unsigned int vp8_sub_pixel_variance8x16_c +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[9*16]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const short *HFilter, *VFilter; + + + HFilter = vp8_bilinear_filters[xoffset]; + VFilter = vp8_bilinear_filters[yoffset]; + + + var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 17, 8, HFilter); + var_filter_block2d_bil_second_pass(FData3, temp2, 8, 8, 16, 8, VFilter); + + return vp8_variance8x16_c(temp2, 8, dst_ptr, dst_pixels_per_line, sse); +} diff --git a/vp8/common/vp8_entropymodedata.h b/vp8/common/vp8_entropymodedata.h new file mode 100755 index 0000000..13e9a92 --- /dev/null +++ b/vp8/common/vp8_entropymodedata.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. +*/ + + +/*Generated file, included by entropymode.c*/ + + +const struct vp8_token_struct vp8_bmode_encodings[VP8_BINTRAMODES] = +{ + { 0, 1 }, + { 2, 2 }, + { 6, 3 }, + { 28, 5 }, + { 30, 5 }, + { 58, 6 }, + { 59, 6 }, + { 62, 6 }, + { 126, 7 }, + { 127, 7 } +}; + +const struct vp8_token_struct vp8_ymode_encodings[VP8_YMODES] = +{ + { 0, 1 }, + { 4, 3 }, + { 5, 3 }, + { 6, 3 }, + { 7, 3 } +}; + +const struct vp8_token_struct vp8_kf_ymode_encodings[VP8_YMODES] = +{ + { 4, 3 }, + { 5, 3 }, + { 6, 3 }, + { 7, 3 }, + { 0, 1 } +}; + +const struct vp8_token_struct vp8_uv_mode_encodings[VP8_UV_MODES] = +{ + { 0, 1 }, + { 2, 2 }, + { 6, 3 }, + { 7, 3 } +}; + +const struct vp8_token_struct vp8_mbsplit_encodings[VP8_NUMMBSPLITS] = +{ + { 6, 3 }, + { 7, 3 }, + { 2, 2 }, + { 0, 1 } +}; + +const struct vp8_token_struct vp8_mv_ref_encoding_array[VP8_MVREFS] = +{ + { 2, 2 }, + { 6, 3 }, + { 0, 1 }, + { 14, 4 }, + { 15, 4 } +}; + +const struct vp8_token_struct vp8_sub_mv_ref_encoding_array[VP8_SUBMVREFS] = +{ + { 0, 1 }, + { 2, 2 }, + { 6, 3 }, + { 7, 3 } +}; + +const struct vp8_token_struct vp8_small_mvencodings[8] = +{ + { 0, 3 }, + { 1, 3 }, + { 2, 3 }, + { 3, 3 }, + { 4, 3 }, + { 5, 3 }, + { 6, 3 }, + { 7, 3 } +}; + +const vp8_prob vp8_ymode_prob[VP8_YMODES-1] = +{ + 112, 86, 140, 37 +}; + +const vp8_prob vp8_kf_ymode_prob[VP8_YMODES-1] = +{ + 145, 156, 163, 128 +}; + +const vp8_prob vp8_uv_mode_prob[VP8_UV_MODES-1] = +{ + 162, 101, 204 +}; + +const vp8_prob vp8_kf_uv_mode_prob[VP8_UV_MODES-1] = +{ + 142, 114, 183 +}; + +const vp8_prob vp8_bmode_prob[VP8_BINTRAMODES-1] = +{ + 120, 90, 79, 133, 87, 85, 80, 111, 151 +}; + + + +const vp8_prob vp8_kf_bmode_prob +[VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1] = +{ + { + { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, + { 152, 179, 64, 126, 170, 118, 46, 70, 95 }, + { 175, 69, 143, 80, 85, 82, 72, 155, 103 }, + { 56, 58, 10, 171, 218, 189, 17, 13, 152 }, + { 144, 71, 10, 38, 171, 213, 144, 34, 26 }, + { 114, 26, 17, 163, 44, 195, 21, 10, 173 }, + { 121, 24, 80, 195, 26, 62, 44, 64, 85 }, + { 170, 46, 55, 19, 136, 160, 33, 206, 71 }, + { 63, 20, 8, 114, 114, 208, 12, 9, 226 }, + { 81, 40, 11, 96, 182, 84, 29, 16, 36 } + }, + { + { 134, 183, 89, 137, 98, 101, 106, 165, 148 }, + { 72, 187, 100, 130, 157, 111, 32, 75, 80 }, + { 66, 102, 167, 99, 74, 62, 40, 234, 128 }, + { 41, 53, 9, 178, 241, 141, 26, 8, 107 }, + { 104, 79, 12, 27, 217, 255, 87, 17, 7 }, + { 74, 43, 26, 146, 73, 166, 49, 23, 157 }, + { 65, 38, 105, 160, 51, 52, 31, 115, 128 }, + { 87, 68, 71, 44, 114, 51, 15, 186, 23 }, + { 47, 41, 14, 110, 182, 183, 21, 17, 194 }, + { 66, 45, 25, 102, 197, 189, 23, 18, 22 } + }, + { + { 88, 88, 147, 150, 42, 46, 45, 196, 205 }, + { 43, 97, 183, 117, 85, 38, 35, 179, 61 }, + { 39, 53, 200, 87, 26, 21, 43, 232, 171 }, + { 56, 34, 51, 104, 114, 102, 29, 93, 77 }, + { 107, 54, 32, 26, 51, 1, 81, 43, 31 }, + { 39, 28, 85, 171, 58, 165, 90, 98, 64 }, + { 34, 22, 116, 206, 23, 34, 43, 166, 73 }, + { 68, 25, 106, 22, 64, 171, 36, 225, 114 }, + { 34, 19, 21, 102, 132, 188, 16, 76, 124 }, + { 62, 18, 78, 95, 85, 57, 50, 48, 51 } + }, + { + { 193, 101, 35, 159, 215, 111, 89, 46, 111 }, + { 60, 148, 31, 172, 219, 228, 21, 18, 111 }, + { 112, 113, 77, 85, 179, 255, 38, 120, 114 }, + { 40, 42, 1, 196, 245, 209, 10, 25, 109 }, + { 100, 80, 8, 43, 154, 1, 51, 26, 71 }, + { 88, 43, 29, 140, 166, 213, 37, 43, 154 }, + { 61, 63, 30, 155, 67, 45, 68, 1, 209 }, + { 142, 78, 78, 16, 255, 128, 34, 197, 171 }, + { 41, 40, 5, 102, 211, 183, 4, 1, 221 }, + { 51, 50, 17, 168, 209, 192, 23, 25, 82 } + }, + { + { 125, 98, 42, 88, 104, 85, 117, 175, 82 }, + { 95, 84, 53, 89, 128, 100, 113, 101, 45 }, + { 75, 79, 123, 47, 51, 128, 81, 171, 1 }, + { 57, 17, 5, 71, 102, 57, 53, 41, 49 }, + { 115, 21, 2, 10, 102, 255, 166, 23, 6 }, + { 38, 33, 13, 121, 57, 73, 26, 1, 85 }, + { 41, 10, 67, 138, 77, 110, 90, 47, 114 }, + { 101, 29, 16, 10, 85, 128, 101, 196, 26 }, + { 57, 18, 10, 102, 102, 213, 34, 20, 43 }, + { 117, 20, 15, 36, 163, 128, 68, 1, 26 } + }, + { + { 138, 31, 36, 171, 27, 166, 38, 44, 229 }, + { 67, 87, 58, 169, 82, 115, 26, 59, 179 }, + { 63, 59, 90, 180, 59, 166, 93, 73, 154 }, + { 40, 40, 21, 116, 143, 209, 34, 39, 175 }, + { 57, 46, 22, 24, 128, 1, 54, 17, 37 }, + { 47, 15, 16, 183, 34, 223, 49, 45, 183 }, + { 46, 17, 33, 183, 6, 98, 15, 32, 183 }, + { 65, 32, 73, 115, 28, 128, 23, 128, 205 }, + { 40, 3, 9, 115, 51, 192, 18, 6, 223 }, + { 87, 37, 9, 115, 59, 77, 64, 21, 47 } + }, + { + { 104, 55, 44, 218, 9, 54, 53, 130, 226 }, + { 64, 90, 70, 205, 40, 41, 23, 26, 57 }, + { 54, 57, 112, 184, 5, 41, 38, 166, 213 }, + { 30, 34, 26, 133, 152, 116, 10, 32, 134 }, + { 75, 32, 12, 51, 192, 255, 160, 43, 51 }, + { 39, 19, 53, 221, 26, 114, 32, 73, 255 }, + { 31, 9, 65, 234, 2, 15, 1, 118, 73 }, + { 88, 31, 35, 67, 102, 85, 55, 186, 85 }, + { 56, 21, 23, 111, 59, 205, 45, 37, 192 }, + { 55, 38, 70, 124, 73, 102, 1, 34, 98 } + }, + { + { 102, 61, 71, 37, 34, 53, 31, 243, 192 }, + { 69, 60, 71, 38, 73, 119, 28, 222, 37 }, + { 68, 45, 128, 34, 1, 47, 11, 245, 171 }, + { 62, 17, 19, 70, 146, 85, 55, 62, 70 }, + { 75, 15, 9, 9, 64, 255, 184, 119, 16 }, + { 37, 43, 37, 154, 100, 163, 85, 160, 1 }, + { 63, 9, 92, 136, 28, 64, 32, 201, 85 }, + { 86, 6, 28, 5, 64, 255, 25, 248, 1 }, + { 56, 8, 17, 132, 137, 255, 55, 116, 128 }, + { 58, 15, 20, 82, 135, 57, 26, 121, 40 } + }, + { + { 164, 50, 31, 137, 154, 133, 25, 35, 218 }, + { 51, 103, 44, 131, 131, 123, 31, 6, 158 }, + { 86, 40, 64, 135, 148, 224, 45, 183, 128 }, + { 22, 26, 17, 131, 240, 154, 14, 1, 209 }, + { 83, 12, 13, 54, 192, 255, 68, 47, 28 }, + { 45, 16, 21, 91, 64, 222, 7, 1, 197 }, + { 56, 21, 39, 155, 60, 138, 23, 102, 213 }, + { 85, 26, 85, 85, 128, 128, 32, 146, 171 }, + { 18, 11, 7, 63, 144, 171, 4, 4, 246 }, + { 35, 27, 10, 146, 174, 171, 12, 26, 128 } + }, + { + { 190, 80, 35, 99, 180, 80, 126, 54, 45 }, + { 85, 126, 47, 87, 176, 51, 41, 20, 32 }, + { 101, 75, 128, 139, 118, 146, 116, 128, 85 }, + { 56, 41, 15, 176, 236, 85, 37, 9, 62 }, + { 146, 36, 19, 30, 171, 255, 97, 27, 20 }, + { 71, 30, 17, 119, 118, 255, 17, 18, 138 }, + { 101, 38, 60, 138, 55, 70, 43, 26, 142 }, + { 138, 45, 61, 62, 219, 1, 81, 188, 64 }, + { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, + { 112, 19, 12, 61, 195, 128, 48, 4, 24 } + } +}; diff --git a/vp8/common/x86/dequantize_mmx.asm b/vp8/common/x86/dequantize_mmx.asm new file mode 100644 index 0000000..de9eba8 --- /dev/null +++ b/vp8/common/x86/dequantize_mmx.asm @@ -0,0 +1,258 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;void vp8_dequantize_b_impl_mmx(short *sq, short *dq, short *q) +global sym(vp8_dequantize_b_impl_mmx) +sym(vp8_dequantize_b_impl_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;sq + mov rdi, arg(1) ;dq + mov rax, arg(2) ;q + + movq mm1, [rsi] + pmullw mm1, [rax+0] ; mm4 *= kernel 0 modifiers. + movq [rdi], mm1 + + movq mm1, [rsi+8] + pmullw mm1, [rax+8] ; mm4 *= kernel 0 modifiers. + movq [rdi+8], mm1 + + movq mm1, [rsi+16] + pmullw mm1, [rax+16] ; mm4 *= kernel 0 modifiers. + movq [rdi+16], mm1 + + movq mm1, [rsi+24] + pmullw mm1, [rax+24] ; mm4 *= kernel 0 modifiers. + movq [rdi+24], mm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void dequant_idct_add_mmx( +;short *input, 0 +;short *dq, 1 +;unsigned char *dest, 2 +;int stride) 3 +global sym(vp8_dequant_idct_add_mmx) +sym(vp8_dequant_idct_add_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + GET_GOT rbx + push rdi + ; end prolog + + mov rax, arg(0) ;input + mov rdx, arg(1) ;dq + + + movq mm0, [rax ] + pmullw mm0, [rdx] + + movq mm1, [rax +8] + pmullw mm1, [rdx +8] + + movq mm2, [rax+16] + pmullw mm2, [rdx+16] + + movq mm3, [rax+24] + pmullw mm3, [rdx+24] + + mov rdx, arg(2) ;dest + + pxor mm7, mm7 + + + movq [rax], mm7 + movq [rax+8], mm7 + + movq [rax+16],mm7 + movq [rax+24],mm7 + + + movsxd rdi, dword ptr arg(3) ;stride + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [GLOBAL(x_s1sqr2)]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [GLOBAL(x_c1sqr2less1)]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [GLOBAL(x_c1sqr2less1)] + paddw mm5, mm1 + + pmulhw mm3, [GLOBAL(x_s1sqr2)] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq mm3, mm5 ; 33 23 13 03 + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [GLOBAL(x_s1sqr2)]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [GLOBAL(x_c1sqr2less1)]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [GLOBAL(x_c1sqr2less1)] + paddw mm5, mm1 + + pmulhw mm3, [GLOBAL(x_s1sqr2)] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + paddw mm0, [GLOBAL(fours)] + + paddw mm2, [GLOBAL(fours)] + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + psraw mm2, 3 + + psraw mm0, 3 + psraw mm4, 3 + + psraw mm6, 3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + pxor mm7, mm7 + + movd mm4, [rdx] + punpcklbw mm4, mm7 + paddsw mm0, mm4 + packuswb mm0, mm7 + movd [rdx], mm0 + + movd mm4, [rdx+rdi] + punpcklbw mm4, mm7 + paddsw mm1, mm4 + packuswb mm1, mm7 + movd [rdx+rdi], mm1 + + movd mm4, [rdx+2*rdi] + punpcklbw mm4, mm7 + paddsw mm2, mm4 + packuswb mm2, mm7 + movd [rdx+rdi*2], mm2 + + add rdx, rdi + + movd mm4, [rdx+2*rdi] + punpcklbw mm4, mm7 + paddsw mm5, mm4 + packuswb mm5, mm7 + movd [rdx+rdi*2], mm5 + + ; begin epilog + pop rdi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +x_s1sqr2: + times 4 dw 0x8A8C +align 16 +x_c1sqr2less1: + times 4 dw 0x4E7B +align 16 +fours: + times 4 dw 0x0004 diff --git a/vp8/common/x86/filter_x86.c b/vp8/common/x86/filter_x86.c new file mode 100644 index 0000000..ebab814 --- /dev/null +++ b/vp8/common/x86/filter_x86.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_ports/mem.h" + +DECLARE_ALIGNED(16, const short, vp8_bilinear_filters_x86_4[8][8]) = +{ + { 128, 128, 128, 128, 0, 0, 0, 0 }, + { 112, 112, 112, 112, 16, 16, 16, 16 }, + { 96, 96, 96, 96, 32, 32, 32, 32 }, + { 80, 80, 80, 80, 48, 48, 48, 48 }, + { 64, 64, 64, 64, 64, 64, 64, 64 }, + { 48, 48, 48, 48, 80, 80, 80, 80 }, + { 32, 32, 32, 32, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 112, 112, 112, 112 } +}; + +DECLARE_ALIGNED(16, const short, vp8_bilinear_filters_x86_8[8][16]) = +{ + { 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 112, 112, 112, 112, 112, 112, 112, 112, 16, 16, 16, 16, 16, 16, 16, 16 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32 }, + { 80, 80, 80, 80, 80, 80, 80, 80, 48, 48, 48, 48, 48, 48, 48, 48 }, + { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }, + { 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80 }, + { 32, 32, 32, 32, 32, 32, 32, 32, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 112, 112, 112, 112, 112, 112, 112, 112 } +}; diff --git a/vp8/common/x86/filter_x86.h b/vp8/common/x86/filter_x86.h new file mode 100644 index 0000000..efcc4dc --- /dev/null +++ b/vp8/common/x86/filter_x86.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef FILTER_X86_H +#define FILTER_X86_H + +/* x86 assembly specific copy of vp8/common/filter.c:vp8_bilinear_filters with + * duplicated values */ +extern const short vp8_bilinear_filters_x86_4[8][8]; /* duplicated 4x */ +extern const short vp8_bilinear_filters_x86_8[8][16]; /* duplicated 8x */ + +#endif /* FILTER_X86_H */ diff --git a/vp8/common/x86/idct_blk_mmx.c b/vp8/common/x86/idct_blk_mmx.c new file mode 100644 index 0000000..4adf3f5 --- /dev/null +++ b/vp8/common/x86/idct_blk_mmx.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vp8/common/blockd.h" + +extern void vp8_dequantize_b_impl_mmx(short *sq, short *dq, short *q); + +void vp8_dequantize_b_mmx(BLOCKD *d, short *DQC) +{ + short *sq = (short *) d->qcoeff; + short *dq = (short *) d->dqcoeff; + + vp8_dequantize_b_impl_mmx(sq, dq, DQC); +} + +void vp8_dequant_idct_add_y_block_mmx + (short *q, short *dq, + unsigned char *dst, int stride, char *eobs) +{ + int i; + + for (i = 0; i < 4; i++) + { + if (eobs[0] > 1) + vp8_dequant_idct_add_mmx (q, dq, dst, stride); + else if (eobs[0] == 1) + { + vp8_dc_only_idct_add_mmx (q[0]*dq[0], dst, stride, dst, stride); + ((int *)q)[0] = 0; + } + + if (eobs[1] > 1) + vp8_dequant_idct_add_mmx (q+16, dq, dst+4, stride); + else if (eobs[1] == 1) + { + vp8_dc_only_idct_add_mmx (q[16]*dq[0], dst+4, stride, + dst+4, stride); + ((int *)(q+16))[0] = 0; + } + + if (eobs[2] > 1) + vp8_dequant_idct_add_mmx (q+32, dq, dst+8, stride); + else if (eobs[2] == 1) + { + vp8_dc_only_idct_add_mmx (q[32]*dq[0], dst+8, stride, + dst+8, stride); + ((int *)(q+32))[0] = 0; + } + + if (eobs[3] > 1) + vp8_dequant_idct_add_mmx (q+48, dq, dst+12, stride); + else if (eobs[3] == 1) + { + vp8_dc_only_idct_add_mmx (q[48]*dq[0], dst+12, stride, + dst+12, stride); + ((int *)(q+48))[0] = 0; + } + + q += 64; + dst += 4*stride; + eobs += 4; + } +} + +void vp8_dequant_idct_add_uv_block_mmx + (short *q, short *dq, + unsigned char *dstu, unsigned char *dstv, int stride, char *eobs) +{ + int i; + + for (i = 0; i < 2; i++) + { + if (eobs[0] > 1) + vp8_dequant_idct_add_mmx (q, dq, dstu, stride); + else if (eobs[0] == 1) + { + vp8_dc_only_idct_add_mmx (q[0]*dq[0], dstu, stride, dstu, stride); + ((int *)q)[0] = 0; + } + + if (eobs[1] > 1) + vp8_dequant_idct_add_mmx (q+16, dq, dstu+4, stride); + else if (eobs[1] == 1) + { + vp8_dc_only_idct_add_mmx (q[16]*dq[0], dstu+4, stride, + dstu+4, stride); + ((int *)(q+16))[0] = 0; + } + + q += 32; + dstu += 4*stride; + eobs += 2; + } + + for (i = 0; i < 2; i++) + { + if (eobs[0] > 1) + vp8_dequant_idct_add_mmx (q, dq, dstv, stride); + else if (eobs[0] == 1) + { + vp8_dc_only_idct_add_mmx (q[0]*dq[0], dstv, stride, dstv, stride); + ((int *)q)[0] = 0; + } + + if (eobs[1] > 1) + vp8_dequant_idct_add_mmx (q+16, dq, dstv+4, stride); + else if (eobs[1] == 1) + { + vp8_dc_only_idct_add_mmx (q[16]*dq[0], dstv+4, stride, + dstv+4, stride); + ((int *)(q+16))[0] = 0; + } + + q += 32; + dstv += 4*stride; + eobs += 2; + } +} diff --git a/vp8/common/x86/idct_blk_sse2.c b/vp8/common/x86/idct_blk_sse2.c new file mode 100644 index 0000000..056e052 --- /dev/null +++ b/vp8/common/x86/idct_blk_sse2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" + +void vp8_idct_dequant_0_2x_sse2 + (short *q, short *dq , + unsigned char *dst, int dst_stride); +void vp8_idct_dequant_full_2x_sse2 + (short *q, short *dq , + unsigned char *dst, int dst_stride); + +void vp8_dequant_idct_add_y_block_sse2 + (short *q, short *dq, + unsigned char *dst, int stride, char *eobs) +{ + int i; + + for (i = 0; i < 4; i++) + { + if (((short *)(eobs))[0]) + { + if (((short *)(eobs))[0] & 0xfefe) + vp8_idct_dequant_full_2x_sse2 (q, dq, dst, stride); + else + vp8_idct_dequant_0_2x_sse2 (q, dq, dst, stride); + } + if (((short *)(eobs))[1]) + { + if (((short *)(eobs))[1] & 0xfefe) + vp8_idct_dequant_full_2x_sse2 (q+32, dq, dst+8, stride); + else + vp8_idct_dequant_0_2x_sse2 (q+32, dq, dst+8, stride); + } + q += 64; + dst += stride*4; + eobs += 4; + } +} + +void vp8_dequant_idct_add_uv_block_sse2 + (short *q, short *dq, + unsigned char *dstu, unsigned char *dstv, int stride, char *eobs) +{ + if (((short *)(eobs))[0]) + { + if (((short *)(eobs))[0] & 0xfefe) + vp8_idct_dequant_full_2x_sse2 (q, dq, dstu, stride); + else + vp8_idct_dequant_0_2x_sse2 (q, dq, dstu, stride); + } + q += 32; + dstu += stride*4; + + if (((short *)(eobs))[1]) + { + if (((short *)(eobs))[1] & 0xfefe) + vp8_idct_dequant_full_2x_sse2 (q, dq, dstu, stride); + else + vp8_idct_dequant_0_2x_sse2 (q, dq, dstu, stride); + } + q += 32; + + if (((short *)(eobs))[2]) + { + if (((short *)(eobs))[2] & 0xfefe) + vp8_idct_dequant_full_2x_sse2 (q, dq, dstv, stride); + else + vp8_idct_dequant_0_2x_sse2 (q, dq, dstv, stride); + } + q += 32; + dstv += stride*4; + + if (((short *)(eobs))[3]) + { + if (((short *)(eobs))[3] & 0xfefe) + vp8_idct_dequant_full_2x_sse2 (q, dq, dstv, stride); + else + vp8_idct_dequant_0_2x_sse2 (q, dq, dstv, stride); + } +} diff --git a/vp8/common/x86/idctllm_mmx.asm b/vp8/common/x86/idctllm_mmx.asm new file mode 100644 index 0000000..0c9c205 --- /dev/null +++ b/vp8/common/x86/idctllm_mmx.asm @@ -0,0 +1,295 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +; /**************************************************************************** +; * Notes: +; * +; * This implementation makes use of 16 bit fixed point version of two multiply +; * constants: +; * 1. sqrt(2) * cos (pi/8) +; * 2. sqrt(2) * sin (pi/8) +; * Because the first constant is bigger than 1, to maintain the same 16 bit +; * fixed point precision as the second one, we use a trick of +; * x * a = x + x*(a-1) +; * so +; * x * sqrt(2) * cos (pi/8) = x + x * (sqrt(2) *cos(pi/8)-1). +; * +; * For the second constant, because of the 16bit version is 35468, which +; * is bigger than 32768, in signed 16 bit multiply, it becomes a negative +; * number. +; * (x * (unsigned)35468 >> 16) = x * (signed)35468 >> 16 + x +; * +; **************************************************************************/ + + +;void vp8_short_idct4x4llm_mmx(short *input, unsigned char *pred, +;int pitch, unsigned char *dest,int stride) +global sym(vp8_short_idct4x4llm_mmx) +sym(vp8_short_idct4x4llm_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(0) ;input + mov rsi, arg(1) ;pred + + movq mm0, [rax ] + movq mm1, [rax+ 8] + movq mm2, [rax+16] + movq mm3, [rax+24] + +%if 0 + pxor mm7, mm7 + movq [rax], mm7 + movq [rax+8], mm7 + movq [rax+16],mm7 + movq [rax+24],mm7 +%endif + movsxd rax, dword ptr arg(2) ;pitch + mov rdx, arg(3) ;dest + movsxd rdi, dword ptr arg(4) ;stride + + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [GLOBAL(x_s1sqr2)]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [GLOBAL(x_c1sqr2less1)]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [GLOBAL(x_c1sqr2less1)] + paddw mm5, mm1 + + pmulhw mm3, [GLOBAL(x_s1sqr2)] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq mm3, mm5 ; 33 23 13 03 + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [GLOBAL(x_s1sqr2)]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [GLOBAL(x_c1sqr2less1)]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [GLOBAL(x_c1sqr2less1)] + paddw mm5, mm1 + + pmulhw mm3, [GLOBAL(x_s1sqr2)] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + paddw mm0, [GLOBAL(fours)] + + paddw mm2, [GLOBAL(fours)] + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + psraw mm2, 3 + + psraw mm0, 3 + psraw mm4, 3 + + psraw mm6, 3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + pxor mm7, mm7 + + movd mm4, [rsi] + punpcklbw mm4, mm7 + paddsw mm0, mm4 + packuswb mm0, mm7 + movd [rdx], mm0 + + movd mm4, [rsi+rax] + punpcklbw mm4, mm7 + paddsw mm1, mm4 + packuswb mm1, mm7 + movd [rdx+rdi], mm1 + + movd mm4, [rsi+2*rax] + punpcklbw mm4, mm7 + paddsw mm2, mm4 + packuswb mm2, mm7 + movd [rdx+rdi*2], mm2 + + add rdx, rdi + add rsi, rax + + movd mm4, [rsi+2*rax] + punpcklbw mm4, mm7 + paddsw mm5, mm4 + packuswb mm5, mm7 + movd [rdx+rdi*2], mm5 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_dc_only_idct_add_mmx( +;short input_dc, +;unsigned char *pred_ptr, +;int pred_stride, +;unsigned char *dst_ptr, +;int stride) +global sym(vp8_dc_only_idct_add_mmx) +sym(vp8_dc_only_idct_add_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + ; end prolog + + movd mm5, arg(0) ;input_dc + mov rax, arg(1) ;pred_ptr + movsxd rdx, dword ptr arg(2) ;pred_stride + + pxor mm0, mm0 + + paddw mm5, [GLOBAL(fours)] + lea rcx, [rdx + rdx*2] + + psraw mm5, 3 + + punpcklwd mm5, mm5 + + punpckldq mm5, mm5 + + movd mm1, [rax] + movd mm2, [rax+rdx] + movd mm3, [rax+2*rdx] + movd mm4, [rax+rcx] + + mov rax, arg(3) ;d -- destination + movsxd rdx, dword ptr arg(4) ;dst_stride + + punpcklbw mm1, mm0 + paddsw mm1, mm5 + packuswb mm1, mm0 ; pack and unpack to saturate + lea rcx, [rdx + rdx*2] + + punpcklbw mm2, mm0 + paddsw mm2, mm5 + packuswb mm2, mm0 ; pack and unpack to saturate + + punpcklbw mm3, mm0 + paddsw mm3, mm5 + packuswb mm3, mm0 ; pack and unpack to saturate + + punpcklbw mm4, mm0 + paddsw mm4, mm5 + packuswb mm4, mm0 ; pack and unpack to saturate + + movd [rax], mm1 + movd [rax+rdx], mm2 + movd [rax+2*rdx], mm3 + movd [rax+rcx], mm4 + + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +x_s1sqr2: + times 4 dw 0x8A8C +align 16 +x_c1sqr2less1: + times 4 dw 0x4E7B +align 16 +fours: + times 4 dw 0x0004 diff --git a/vp8/common/x86/idctllm_mmx_test.cc b/vp8/common/x86/idctllm_mmx_test.cc new file mode 100755 index 0000000..8c11533 --- /dev/null +++ b/vp8/common/x86/idctllm_mmx_test.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + + extern "C" { + void vp8_short_idct4x4llm_mmx(short *input, unsigned char *pred_ptr, + int pred_stride, unsigned char *dst_ptr, + int dst_stride); +} + +#include "vp8/common/idctllm_test.h" + +namespace +{ + +INSTANTIATE_TEST_CASE_P(MMX, IDCTTest, + ::testing::Values(vp8_short_idct4x4llm_mmx)); + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/vp8/common/x86/idctllm_sse2.asm b/vp8/common/x86/idctllm_sse2.asm new file mode 100644 index 0000000..abeb0b6 --- /dev/null +++ b/vp8/common/x86/idctllm_sse2.asm @@ -0,0 +1,708 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_idct_dequant_0_2x_sse2 +; ( +; short *qcoeff - 0 +; short *dequant - 1 +; unsigned char *dst - 2 +; int dst_stride - 3 +; ) + +global sym(vp8_idct_dequant_0_2x_sse2) +sym(vp8_idct_dequant_0_2x_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + GET_GOT rbx + ; end prolog + + mov rdx, arg(1) ; dequant + mov rax, arg(0) ; qcoeff + + movd xmm4, [rax] + movd xmm5, [rdx] + + pinsrw xmm4, [rax+32], 4 + pinsrw xmm5, [rdx], 4 + + pmullw xmm4, xmm5 + + ; Zero out xmm5, for use unpacking + pxor xmm5, xmm5 + + ; clear coeffs + movd [rax], xmm5 + movd [rax+32], xmm5 +;pshufb + mov rax, arg(2) ; dst + movsxd rdx, dword ptr arg(3) ; dst_stride + + pshuflw xmm4, xmm4, 00000000b + pshufhw xmm4, xmm4, 00000000b + + lea rcx, [rdx + rdx*2] + paddw xmm4, [GLOBAL(fours)] + + psraw xmm4, 3 + + movq xmm0, [rax] + movq xmm1, [rax+rdx] + movq xmm2, [rax+2*rdx] + movq xmm3, [rax+rcx] + + punpcklbw xmm0, xmm5 + punpcklbw xmm1, xmm5 + punpcklbw xmm2, xmm5 + punpcklbw xmm3, xmm5 + + + ; Add to predict buffer + paddw xmm0, xmm4 + paddw xmm1, xmm4 + paddw xmm2, xmm4 + paddw xmm3, xmm4 + + ; pack up before storing + packuswb xmm0, xmm5 + packuswb xmm1, xmm5 + packuswb xmm2, xmm5 + packuswb xmm3, xmm5 + + ; store blocks back out + movq [rax], xmm0 + movq [rax + rdx], xmm1 + + lea rax, [rax + 2*rdx] + + movq [rax], xmm2 + movq [rax + rdx], xmm3 + + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_idct_dequant_full_2x_sse2 +; ( +; short *qcoeff - 0 +; short *dequant - 1 +; unsigned char *dst - 2 +; int dst_stride - 3 +; ) +global sym(vp8_idct_dequant_full_2x_sse2) +sym(vp8_idct_dequant_full_2x_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ; special case when 2 blocks have 0 or 1 coeffs + ; dc is set as first coeff, so no need to load qcoeff + mov rax, arg(0) ; qcoeff + mov rdx, arg(1) ; dequant + mov rdi, arg(2) ; dst + + + ; Zero out xmm7, for use unpacking + pxor xmm7, xmm7 + + + ; note the transpose of xmm1 and xmm2, necessary for shuffle + ; to spit out sensicle data + movdqa xmm0, [rax] + movdqa xmm2, [rax+16] + movdqa xmm1, [rax+32] + movdqa xmm3, [rax+48] + + ; Clear out coeffs + movdqa [rax], xmm7 + movdqa [rax+16], xmm7 + movdqa [rax+32], xmm7 + movdqa [rax+48], xmm7 + + ; dequantize qcoeff buffer + pmullw xmm0, [rdx] + pmullw xmm2, [rdx+16] + pmullw xmm1, [rdx] + pmullw xmm3, [rdx+16] + movsxd rdx, dword ptr arg(3) ; dst_stride + + ; repack so block 0 row x and block 1 row x are together + movdqa xmm4, xmm0 + punpckldq xmm0, xmm1 + punpckhdq xmm4, xmm1 + + pshufd xmm0, xmm0, 11011000b + pshufd xmm1, xmm4, 11011000b + + movdqa xmm4, xmm2 + punpckldq xmm2, xmm3 + punpckhdq xmm4, xmm3 + + pshufd xmm2, xmm2, 11011000b + pshufd xmm3, xmm4, 11011000b + + ; first pass + psubw xmm0, xmm2 ; b1 = 0-2 + paddw xmm2, xmm2 ; + + movdqa xmm5, xmm1 + paddw xmm2, xmm0 ; a1 = 0+2 + + pmulhw xmm5, [GLOBAL(x_s1sqr2)] + lea rcx, [rdx + rdx*2] ;dst_stride * 3 + paddw xmm5, xmm1 ; ip1 * sin(pi/8) * sqrt(2) + + movdqa xmm7, xmm3 + pmulhw xmm7, [GLOBAL(x_c1sqr2less1)] + + paddw xmm7, xmm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw xmm7, xmm5 ; c1 + + movdqa xmm5, xmm1 + movdqa xmm4, xmm3 + + pmulhw xmm5, [GLOBAL(x_c1sqr2less1)] + paddw xmm5, xmm1 + + pmulhw xmm3, [GLOBAL(x_s1sqr2)] + paddw xmm3, xmm4 + + paddw xmm3, xmm5 ; d1 + movdqa xmm6, xmm2 ; a1 + + movdqa xmm4, xmm0 ; b1 + paddw xmm2, xmm3 ;0 + + paddw xmm4, xmm7 ;1 + psubw xmm0, xmm7 ;2 + + psubw xmm6, xmm3 ;3 + + ; transpose for the second pass + movdqa xmm7, xmm2 ; 103 102 101 100 003 002 001 000 + punpcklwd xmm2, xmm0 ; 007 003 006 002 005 001 004 000 + punpckhwd xmm7, xmm0 ; 107 103 106 102 105 101 104 100 + + movdqa xmm5, xmm4 ; 111 110 109 108 011 010 009 008 + punpcklwd xmm4, xmm6 ; 015 011 014 010 013 009 012 008 + punpckhwd xmm5, xmm6 ; 115 111 114 110 113 109 112 108 + + + movdqa xmm1, xmm2 ; 007 003 006 002 005 001 004 000 + punpckldq xmm2, xmm4 ; 013 009 005 001 012 008 004 000 + punpckhdq xmm1, xmm4 ; 015 011 007 003 014 010 006 002 + + movdqa xmm6, xmm7 ; 107 103 106 102 105 101 104 100 + punpckldq xmm7, xmm5 ; 113 109 105 101 112 108 104 100 + punpckhdq xmm6, xmm5 ; 115 111 107 103 114 110 106 102 + + + movdqa xmm5, xmm2 ; 013 009 005 001 012 008 004 000 + punpckldq xmm2, xmm7 ; 112 108 012 008 104 100 004 000 + punpckhdq xmm5, xmm7 ; 113 109 013 009 105 101 005 001 + + movdqa xmm7, xmm1 ; 015 011 007 003 014 010 006 002 + punpckldq xmm1, xmm6 ; 114 110 014 010 106 102 006 002 + punpckhdq xmm7, xmm6 ; 115 111 015 011 107 103 007 003 + + pshufd xmm0, xmm2, 11011000b + pshufd xmm2, xmm1, 11011000b + + pshufd xmm1, xmm5, 11011000b + pshufd xmm3, xmm7, 11011000b + + ; second pass + psubw xmm0, xmm2 ; b1 = 0-2 + paddw xmm2, xmm2 + + movdqa xmm5, xmm1 + paddw xmm2, xmm0 ; a1 = 0+2 + + pmulhw xmm5, [GLOBAL(x_s1sqr2)] + paddw xmm5, xmm1 ; ip1 * sin(pi/8) * sqrt(2) + + movdqa xmm7, xmm3 + pmulhw xmm7, [GLOBAL(x_c1sqr2less1)] + + paddw xmm7, xmm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw xmm7, xmm5 ; c1 + + movdqa xmm5, xmm1 + movdqa xmm4, xmm3 + + pmulhw xmm5, [GLOBAL(x_c1sqr2less1)] + paddw xmm5, xmm1 + + pmulhw xmm3, [GLOBAL(x_s1sqr2)] + paddw xmm3, xmm4 + + paddw xmm3, xmm5 ; d1 + paddw xmm0, [GLOBAL(fours)] + + paddw xmm2, [GLOBAL(fours)] + movdqa xmm6, xmm2 ; a1 + + movdqa xmm4, xmm0 ; b1 + paddw xmm2, xmm3 ;0 + + paddw xmm4, xmm7 ;1 + psubw xmm0, xmm7 ;2 + + psubw xmm6, xmm3 ;3 + psraw xmm2, 3 + + psraw xmm0, 3 + psraw xmm4, 3 + + psraw xmm6, 3 + + ; transpose to save + movdqa xmm7, xmm2 ; 103 102 101 100 003 002 001 000 + punpcklwd xmm2, xmm0 ; 007 003 006 002 005 001 004 000 + punpckhwd xmm7, xmm0 ; 107 103 106 102 105 101 104 100 + + movdqa xmm5, xmm4 ; 111 110 109 108 011 010 009 008 + punpcklwd xmm4, xmm6 ; 015 011 014 010 013 009 012 008 + punpckhwd xmm5, xmm6 ; 115 111 114 110 113 109 112 108 + + + movdqa xmm1, xmm2 ; 007 003 006 002 005 001 004 000 + punpckldq xmm2, xmm4 ; 013 009 005 001 012 008 004 000 + punpckhdq xmm1, xmm4 ; 015 011 007 003 014 010 006 002 + + movdqa xmm6, xmm7 ; 107 103 106 102 105 101 104 100 + punpckldq xmm7, xmm5 ; 113 109 105 101 112 108 104 100 + punpckhdq xmm6, xmm5 ; 115 111 107 103 114 110 106 102 + + + movdqa xmm5, xmm2 ; 013 009 005 001 012 008 004 000 + punpckldq xmm2, xmm7 ; 112 108 012 008 104 100 004 000 + punpckhdq xmm5, xmm7 ; 113 109 013 009 105 101 005 001 + + movdqa xmm7, xmm1 ; 015 011 007 003 014 010 006 002 + punpckldq xmm1, xmm6 ; 114 110 014 010 106 102 006 002 + punpckhdq xmm7, xmm6 ; 115 111 015 011 107 103 007 003 + + pshufd xmm0, xmm2, 11011000b + pshufd xmm2, xmm1, 11011000b + + pshufd xmm1, xmm5, 11011000b + pshufd xmm3, xmm7, 11011000b + + pxor xmm7, xmm7 + + ; Load up predict blocks + movq xmm4, [rdi] + movq xmm5, [rdi+rdx] + + punpcklbw xmm4, xmm7 + punpcklbw xmm5, xmm7 + + paddw xmm0, xmm4 + paddw xmm1, xmm5 + + movq xmm4, [rdi+2*rdx] + movq xmm5, [rdi+rcx] + + punpcklbw xmm4, xmm7 + punpcklbw xmm5, xmm7 + + paddw xmm2, xmm4 + paddw xmm3, xmm5 + +.finish: + + ; pack up before storing + packuswb xmm0, xmm7 + packuswb xmm1, xmm7 + packuswb xmm2, xmm7 + packuswb xmm3, xmm7 + + ; store blocks back out + movq [rdi], xmm0 + movq [rdi + rdx], xmm1 + movq [rdi + rdx*2], xmm2 + movq [rdi + rcx], xmm3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_idct_dequant_dc_0_2x_sse2 +; ( +; short *qcoeff - 0 +; short *dequant - 1 +; unsigned char *dst - 2 +; int dst_stride - 3 +; short *dc - 4 +; ) +global sym(vp8_idct_dequant_dc_0_2x_sse2) +sym(vp8_idct_dequant_dc_0_2x_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rdi + ; end prolog + + ; special case when 2 blocks have 0 or 1 coeffs + ; dc is set as first coeff, so no need to load qcoeff + mov rax, arg(0) ; qcoeff + + mov rdi, arg(2) ; dst + mov rdx, arg(4) ; dc + + ; Zero out xmm5, for use unpacking + pxor xmm5, xmm5 + + ; load up 2 dc words here == 2*16 = doubleword + movd xmm4, [rdx] + + movsxd rdx, dword ptr arg(3) ; dst_stride + lea rcx, [rdx + rdx*2] + ; Load up predict blocks + movq xmm0, [rdi] + movq xmm1, [rdi+rdx*1] + movq xmm2, [rdi+rdx*2] + movq xmm3, [rdi+rcx] + + ; Duplicate and expand dc across + punpcklwd xmm4, xmm4 + punpckldq xmm4, xmm4 + + ; Rounding to dequant and downshift + paddw xmm4, [GLOBAL(fours)] + psraw xmm4, 3 + + ; Predict buffer needs to be expanded from bytes to words + punpcklbw xmm0, xmm5 + punpcklbw xmm1, xmm5 + punpcklbw xmm2, xmm5 + punpcklbw xmm3, xmm5 + + ; Add to predict buffer + paddw xmm0, xmm4 + paddw xmm1, xmm4 + paddw xmm2, xmm4 + paddw xmm3, xmm4 + + ; pack up before storing + packuswb xmm0, xmm5 + packuswb xmm1, xmm5 + packuswb xmm2, xmm5 + packuswb xmm3, xmm5 + + ; store blocks back out + movq [rdi], xmm0 + movq [rdi + rdx], xmm1 + movq [rdi + rdx*2], xmm2 + movq [rdi + rcx], xmm3 + + ; begin epilog + pop rdi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +;void vp8_idct_dequant_dc_full_2x_sse2 +; ( +; short *qcoeff - 0 +; short *dequant - 1 +; unsigned char *dst - 2 +; int dst_stride - 3 +; short *dc - 4 +; ) +global sym(vp8_idct_dequant_dc_full_2x_sse2) +sym(vp8_idct_dequant_dc_full_2x_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + GET_GOT rbx + push rdi + ; end prolog + + ; special case when 2 blocks have 0 or 1 coeffs + ; dc is set as first coeff, so no need to load qcoeff + mov rax, arg(0) ; qcoeff + mov rdx, arg(1) ; dequant + + mov rdi, arg(2) ; dst + + ; Zero out xmm7, for use unpacking + pxor xmm7, xmm7 + + + ; note the transpose of xmm1 and xmm2, necessary for shuffle + ; to spit out sensicle data + movdqa xmm0, [rax] + movdqa xmm2, [rax+16] + movdqa xmm1, [rax+32] + movdqa xmm3, [rax+48] + + ; Clear out coeffs + movdqa [rax], xmm7 + movdqa [rax+16], xmm7 + movdqa [rax+32], xmm7 + movdqa [rax+48], xmm7 + + ; dequantize qcoeff buffer + pmullw xmm0, [rdx] + pmullw xmm2, [rdx+16] + pmullw xmm1, [rdx] + pmullw xmm3, [rdx+16] + + ; DC component + mov rdx, arg(4) + + ; repack so block 0 row x and block 1 row x are together + movdqa xmm4, xmm0 + punpckldq xmm0, xmm1 + punpckhdq xmm4, xmm1 + + pshufd xmm0, xmm0, 11011000b + pshufd xmm1, xmm4, 11011000b + + movdqa xmm4, xmm2 + punpckldq xmm2, xmm3 + punpckhdq xmm4, xmm3 + + pshufd xmm2, xmm2, 11011000b + pshufd xmm3, xmm4, 11011000b + + ; insert DC component + pinsrw xmm0, [rdx], 0 + pinsrw xmm0, [rdx+2], 4 + + ; first pass + psubw xmm0, xmm2 ; b1 = 0-2 + paddw xmm2, xmm2 ; + + movdqa xmm5, xmm1 + paddw xmm2, xmm0 ; a1 = 0+2 + + pmulhw xmm5, [GLOBAL(x_s1sqr2)] + paddw xmm5, xmm1 ; ip1 * sin(pi/8) * sqrt(2) + + movdqa xmm7, xmm3 + pmulhw xmm7, [GLOBAL(x_c1sqr2less1)] + + paddw xmm7, xmm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw xmm7, xmm5 ; c1 + + movdqa xmm5, xmm1 + movdqa xmm4, xmm3 + + pmulhw xmm5, [GLOBAL(x_c1sqr2less1)] + paddw xmm5, xmm1 + + pmulhw xmm3, [GLOBAL(x_s1sqr2)] + paddw xmm3, xmm4 + + paddw xmm3, xmm5 ; d1 + movdqa xmm6, xmm2 ; a1 + + movdqa xmm4, xmm0 ; b1 + paddw xmm2, xmm3 ;0 + + paddw xmm4, xmm7 ;1 + psubw xmm0, xmm7 ;2 + + psubw xmm6, xmm3 ;3 + + ; transpose for the second pass + movdqa xmm7, xmm2 ; 103 102 101 100 003 002 001 000 + punpcklwd xmm2, xmm0 ; 007 003 006 002 005 001 004 000 + punpckhwd xmm7, xmm0 ; 107 103 106 102 105 101 104 100 + + movdqa xmm5, xmm4 ; 111 110 109 108 011 010 009 008 + punpcklwd xmm4, xmm6 ; 015 011 014 010 013 009 012 008 + punpckhwd xmm5, xmm6 ; 115 111 114 110 113 109 112 108 + + + movdqa xmm1, xmm2 ; 007 003 006 002 005 001 004 000 + punpckldq xmm2, xmm4 ; 013 009 005 001 012 008 004 000 + punpckhdq xmm1, xmm4 ; 015 011 007 003 014 010 006 002 + + movdqa xmm6, xmm7 ; 107 103 106 102 105 101 104 100 + punpckldq xmm7, xmm5 ; 113 109 105 101 112 108 104 100 + punpckhdq xmm6, xmm5 ; 115 111 107 103 114 110 106 102 + + + movdqa xmm5, xmm2 ; 013 009 005 001 012 008 004 000 + punpckldq xmm2, xmm7 ; 112 108 012 008 104 100 004 000 + punpckhdq xmm5, xmm7 ; 113 109 013 009 105 101 005 001 + + movdqa xmm7, xmm1 ; 015 011 007 003 014 010 006 002 + punpckldq xmm1, xmm6 ; 114 110 014 010 106 102 006 002 + punpckhdq xmm7, xmm6 ; 115 111 015 011 107 103 007 003 + + pshufd xmm0, xmm2, 11011000b + pshufd xmm2, xmm1, 11011000b + + pshufd xmm1, xmm5, 11011000b + pshufd xmm3, xmm7, 11011000b + + ; second pass + psubw xmm0, xmm2 ; b1 = 0-2 + paddw xmm2, xmm2 + + movdqa xmm5, xmm1 + paddw xmm2, xmm0 ; a1 = 0+2 + + pmulhw xmm5, [GLOBAL(x_s1sqr2)] + paddw xmm5, xmm1 ; ip1 * sin(pi/8) * sqrt(2) + + movdqa xmm7, xmm3 + pmulhw xmm7, [GLOBAL(x_c1sqr2less1)] + + paddw xmm7, xmm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw xmm7, xmm5 ; c1 + + movdqa xmm5, xmm1 + movdqa xmm4, xmm3 + + pmulhw xmm5, [GLOBAL(x_c1sqr2less1)] + paddw xmm5, xmm1 + + pmulhw xmm3, [GLOBAL(x_s1sqr2)] + paddw xmm3, xmm4 + + paddw xmm3, xmm5 ; d1 + paddw xmm0, [GLOBAL(fours)] + + paddw xmm2, [GLOBAL(fours)] + movdqa xmm6, xmm2 ; a1 + + movdqa xmm4, xmm0 ; b1 + paddw xmm2, xmm3 ;0 + + paddw xmm4, xmm7 ;1 + psubw xmm0, xmm7 ;2 + + psubw xmm6, xmm3 ;3 + psraw xmm2, 3 + + psraw xmm0, 3 + psraw xmm4, 3 + + psraw xmm6, 3 + + ; transpose to save + movdqa xmm7, xmm2 ; 103 102 101 100 003 002 001 000 + punpcklwd xmm2, xmm0 ; 007 003 006 002 005 001 004 000 + punpckhwd xmm7, xmm0 ; 107 103 106 102 105 101 104 100 + + movdqa xmm5, xmm4 ; 111 110 109 108 011 010 009 008 + punpcklwd xmm4, xmm6 ; 015 011 014 010 013 009 012 008 + punpckhwd xmm5, xmm6 ; 115 111 114 110 113 109 112 108 + + + movdqa xmm1, xmm2 ; 007 003 006 002 005 001 004 000 + punpckldq xmm2, xmm4 ; 013 009 005 001 012 008 004 000 + punpckhdq xmm1, xmm4 ; 015 011 007 003 014 010 006 002 + + movdqa xmm6, xmm7 ; 107 103 106 102 105 101 104 100 + punpckldq xmm7, xmm5 ; 113 109 105 101 112 108 104 100 + punpckhdq xmm6, xmm5 ; 115 111 107 103 114 110 106 102 + + + movdqa xmm5, xmm2 ; 013 009 005 001 012 008 004 000 + punpckldq xmm2, xmm7 ; 112 108 012 008 104 100 004 000 + punpckhdq xmm5, xmm7 ; 113 109 013 009 105 101 005 001 + + movdqa xmm7, xmm1 ; 015 011 007 003 014 010 006 002 + punpckldq xmm1, xmm6 ; 114 110 014 010 106 102 006 002 + punpckhdq xmm7, xmm6 ; 115 111 015 011 107 103 007 003 + + pshufd xmm0, xmm2, 11011000b + pshufd xmm2, xmm1, 11011000b + + pshufd xmm1, xmm5, 11011000b + pshufd xmm3, xmm7, 11011000b + + pxor xmm7, xmm7 + + ; Load up predict blocks + movsxd rdx, dword ptr arg(3) ; dst_stride + movq xmm4, [rdi] + movq xmm5, [rdi+rdx] + lea rcx, [rdx + rdx*2] + + punpcklbw xmm4, xmm7 + punpcklbw xmm5, xmm7 + + paddw xmm0, xmm4 + paddw xmm1, xmm5 + + movq xmm4, [rdi+rdx*2] + movq xmm5, [rdi+rcx] + + punpcklbw xmm4, xmm7 + punpcklbw xmm5, xmm7 + + paddw xmm2, xmm4 + paddw xmm3, xmm5 + +.finish: + + ; pack up before storing + packuswb xmm0, xmm7 + packuswb xmm1, xmm7 + packuswb xmm2, xmm7 + packuswb xmm3, xmm7 + + ; Load destination stride before writing out, + ; doesn't need to persist + movsxd rdx, dword ptr arg(3) ; dst_stride + + ; store blocks back out + movq [rdi], xmm0 + movq [rdi + rdx], xmm1 + + lea rdi, [rdi + 2*rdx] + + movq [rdi], xmm2 + movq [rdi + rdx], xmm3 + + + ; begin epilog + pop rdi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +fours: + times 8 dw 0x0004 +align 16 +x_s1sqr2: + times 8 dw 0x8A8C +align 16 +x_c1sqr2less1: + times 8 dw 0x4E7B diff --git a/vp8/common/x86/iwalsh_mmx.asm b/vp8/common/x86/iwalsh_mmx.asm new file mode 100644 index 0000000..6582687 --- /dev/null +++ b/vp8/common/x86/iwalsh_mmx.asm @@ -0,0 +1,140 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_inv_walsh4x4_mmx(short *input, short *output) +global sym(vp8_short_inv_walsh4x4_mmx) +sym(vp8_short_inv_walsh4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + ; end prolog + + mov rdx, arg(0) + mov rax, 30003h + + movq mm0, [rdx + 0] ;ip[0] + movq mm1, [rdx + 8] ;ip[4] + movd mm7, rax + + movq mm2, [rdx + 16] ;ip[8] + movq mm3, [rdx + 24] ;ip[12] + punpcklwd mm7, mm7 ;0003000300030003h + mov rdx, arg(1) + + movq mm4, mm0 + movq mm5, mm1 + + paddw mm4, mm3 ;ip[0] + ip[12] aka al + paddw mm5, mm2 ;ip[4] + ip[8] aka bl + + movq mm6, mm4 ;temp al + paddw mm4, mm5 ;al + bl + psubw mm6, mm5 ;al - bl + + psubw mm0, mm3 ;ip[0] - ip[12] aka d1 + psubw mm1, mm2 ;ip[4] - ip[8] aka c1 + + movq mm5, mm0 ;temp dl + paddw mm0, mm1 ;dl + cl + psubw mm5, mm1 ;dl - cl + + ; 03 02 01 00 + ; 13 12 11 10 + ; 23 22 21 20 + ; 33 32 31 30 + + movq mm3, mm4 ; 03 02 01 00 + punpcklwd mm4, mm0 ; 11 01 10 00 + punpckhwd mm3, mm0 ; 13 03 12 02 + + movq mm1, mm6 ; 23 22 21 20 + punpcklwd mm6, mm5 ; 31 21 30 20 + punpckhwd mm1, mm5 ; 33 23 32 22 + + movq mm0, mm4 ; 11 01 10 00 + movq mm2, mm3 ; 13 03 12 02 + + punpckldq mm0, mm6 ; 30 20 10 00 aka ip[0] + punpckhdq mm4, mm6 ; 31 21 11 01 aka ip[4] + + punpckldq mm2, mm1 ; 32 22 12 02 aka ip[8] + punpckhdq mm3, mm1 ; 33 23 13 03 aka ip[12] +;~~~~~~~~~~~~~~~~~~~~~ + movq mm1, mm0 + movq mm5, mm4 + paddw mm1, mm3 ;ip[0] + ip[12] aka al + paddw mm5, mm2 ;ip[4] + ip[8] aka bl + + movq mm6, mm1 ;temp al + paddw mm1, mm5 ;al + bl + psubw mm6, mm5 ;al - bl + paddw mm1, mm7 + paddw mm6, mm7 + psraw mm1, 3 + psraw mm6, 3 + + psubw mm0, mm3 ;ip[0] - ip[12] aka d1 + psubw mm4, mm2 ;ip[4] - ip[8] aka c1 + + movq mm5, mm0 ;temp dl + paddw mm0, mm4 ;dl + cl + psubw mm5, mm4 ;dl - cl + paddw mm0, mm7 + paddw mm5, mm7 + psraw mm0, 3 + psraw mm5, 3 +;~~~~~~~~~~~~~~~~~~~~~ + + movd eax, mm1 + movd ecx, mm0 + psrlq mm0, 32 + psrlq mm1, 32 + mov word ptr[rdx+32*0], ax + mov word ptr[rdx+32*1], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*4], ax + mov word ptr[rdx+32*5], cx + movd eax, mm1 + movd ecx, mm0 + mov word ptr[rdx+32*8], ax + mov word ptr[rdx+32*9], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*12], ax + mov word ptr[rdx+32*13], cx + + movd eax, mm6 + movd ecx, mm5 + psrlq mm5, 32 + psrlq mm6, 32 + mov word ptr[rdx+32*2], ax + mov word ptr[rdx+32*3], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*6], ax + mov word ptr[rdx+32*7], cx + movd eax, mm6 + movd ecx, mm5 + mov word ptr[rdx+32*10], ax + mov word ptr[rdx+32*11], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*14], ax + mov word ptr[rdx+32*15], cx + + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + diff --git a/vp8/common/x86/iwalsh_sse2.asm b/vp8/common/x86/iwalsh_sse2.asm new file mode 100644 index 0000000..51cb5e2 --- /dev/null +++ b/vp8/common/x86/iwalsh_sse2.asm @@ -0,0 +1,121 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_inv_walsh4x4_sse2(short *input, short *output) +global sym(vp8_short_inv_walsh4x4_sse2) +sym(vp8_short_inv_walsh4x4_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + ; end prolog + + mov rcx, arg(0) + mov rdx, arg(1) + mov rax, 30003h + + movdqa xmm0, [rcx + 0] ;ip[4] ip[0] + movdqa xmm1, [rcx + 16] ;ip[12] ip[8] + + + pshufd xmm2, xmm1, 4eh ;ip[8] ip[12] + movdqa xmm3, xmm0 ;ip[4] ip[0] + + paddw xmm0, xmm2 ;ip[4]+ip[8] ip[0]+ip[12] aka b1 a1 + psubw xmm3, xmm2 ;ip[4]-ip[8] ip[0]-ip[12] aka c1 d1 + + movdqa xmm4, xmm0 + punpcklqdq xmm0, xmm3 ;d1 a1 + punpckhqdq xmm4, xmm3 ;c1 b1 + + movdqa xmm1, xmm4 ;c1 b1 + paddw xmm4, xmm0 ;dl+cl a1+b1 aka op[4] op[0] + psubw xmm0, xmm1 ;d1-c1 a1-b1 aka op[12] op[8] + + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; 13 12 11 10 03 02 01 00 + ; + ; 33 32 31 30 23 22 21 20 + ; + movdqa xmm3, xmm4 ; 13 12 11 10 03 02 01 00 + punpcklwd xmm4, xmm0 ; 23 03 22 02 21 01 20 00 + punpckhwd xmm3, xmm0 ; 33 13 32 12 31 11 30 10 + movdqa xmm1, xmm4 ; 23 03 22 02 21 01 20 00 + punpcklwd xmm4, xmm3 ; 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm3 ; 33 23 13 03 32 22 12 02 + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + movd xmm0, eax + pshufd xmm2, xmm1, 4eh ;ip[8] ip[12] + movdqa xmm3, xmm4 ;ip[4] ip[0] + + pshufd xmm0, xmm0, 0 ;03 03 03 03 03 03 03 03 + + paddw xmm4, xmm2 ;ip[4]+ip[8] ip[0]+ip[12] aka b1 a1 + psubw xmm3, xmm2 ;ip[4]-ip[8] ip[0]-ip[12] aka c1 d1 + + movdqa xmm5, xmm4 + punpcklqdq xmm4, xmm3 ;d1 a1 + punpckhqdq xmm5, xmm3 ;c1 b1 + + movdqa xmm1, xmm5 ;c1 b1 + paddw xmm5, xmm4 ;dl+cl a1+b1 aka op[4] op[0] + psubw xmm4, xmm1 ;d1-c1 a1-b1 aka op[12] op[8] + + paddw xmm5, xmm0 + paddw xmm4, xmm0 + psraw xmm5, 3 + psraw xmm4, 3 + + movd eax, xmm5 + movd ecx, xmm4 + psrldq xmm5, 4 + psrldq xmm4, 4 + mov word ptr[rdx+32*0], ax + mov word ptr[rdx+32*2], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*4], ax + mov word ptr[rdx+32*6], cx + movd eax, xmm5 + movd ecx, xmm4 + psrldq xmm5, 4 + psrldq xmm4, 4 + mov word ptr[rdx+32*8], ax + mov word ptr[rdx+32*10], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*12], ax + mov word ptr[rdx+32*14], cx + + movd eax, xmm5 + movd ecx, xmm4 + psrldq xmm5, 4 + psrldq xmm4, 4 + mov word ptr[rdx+32*1], ax + mov word ptr[rdx+32*3], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*5], ax + mov word ptr[rdx+32*7], cx + movd eax, xmm5 + movd ecx, xmm4 + mov word ptr[rdx+32*9], ax + mov word ptr[rdx+32*11], cx + shr eax, 16 + shr ecx, 16 + mov word ptr[rdx+32*13], ax + mov word ptr[rdx+32*15], cx + + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/common/x86/loopfilter_block_sse2.asm b/vp8/common/x86/loopfilter_block_sse2.asm new file mode 100644 index 0000000..4918eb5 --- /dev/null +++ b/vp8/common/x86/loopfilter_block_sse2.asm @@ -0,0 +1,813 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%macro LF_ABS 2 + ; %1 value not preserved + ; %2 value preserved + ; output in %1 + movdqa scratch1, %2 ; v2 + + psubusb scratch1, %1 ; v2 - v1 + psubusb %1, %2 ; v1 - v2 + por %1, scratch1 ; abs(v2 - v1) +%endmacro + +%macro LF_FILTER_HEV_MASK 8-9 + + LF_ABS %1, %2 ; abs(p3 - p2) + LF_ABS %2, %3 ; abs(p2 - p1) + pmaxub %1, %2 ; accumulate mask +%if %0 == 8 + movdqa scratch2, %3 ; save p1 + LF_ABS scratch2, %4 ; abs(p1 - p0) +%endif + LF_ABS %4, %5 ; abs(p0 - q0) + LF_ABS %5, %6 ; abs(q0 - q1) +%if %0 == 8 + pmaxub %5, scratch2 ; accumulate hev +%else + pmaxub %5, %9 +%endif + pmaxub %1, %5 ; accumulate mask + + LF_ABS %3, %6 ; abs(p1 - q1) + LF_ABS %6, %7 ; abs(q1 - q2) + pmaxub %1, %6 ; accumulate mask + LF_ABS %7, %8 ; abs(q2 - q3) + pmaxub %1, %7 ; accumulate mask + + paddusb %4, %4 ; 2 * abs(p0 - q0) + pand %3, [GLOBAL(tfe)] + psrlw %3, 1 ; abs(p1 - q1) / 2 + paddusb %4, %3 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + + psubusb %1, [limit] + psubusb %4, [blimit] + por %1, %4 + pcmpeqb %1, zero ; mask + + psubusb %5, [thresh] + pcmpeqb %5, zero ; ~hev +%endmacro + +%macro LF_FILTER 6 + ; %1-%4: p1-q1 + ; %5: mask + ; %6: hev + + movdqa scratch2, %6 ; save hev + + pxor %1, [GLOBAL(t80)] ; ps1 + pxor %4, [GLOBAL(t80)] ; qs1 + movdqa scratch1, %1 + psubsb scratch1, %4 ; signed_char_clamp(ps1 - qs1) + pandn scratch2, scratch1 ; vp8_filter &= hev + + pxor %2, [GLOBAL(t80)] ; ps0 + pxor %3, [GLOBAL(t80)] ; qs0 + movdqa scratch1, %3 + psubsb scratch1, %2 ; qs0 - ps0 + paddsb scratch2, scratch1 ; vp8_filter += (qs0 - ps0) + paddsb scratch2, scratch1 ; vp8_filter += (qs0 - ps0) + paddsb scratch2, scratch1 ; vp8_filter += (qs0 - ps0) + pand %5, scratch2 ; &= mask + + movdqa scratch2, %5 + paddsb %5, [GLOBAL(t4)] ; Filter1 + paddsb scratch2, [GLOBAL(t3)] ; Filter2 + + ; Filter1 >> 3 + movdqa scratch1, zero + pcmpgtb scratch1, %5 + psrlw %5, 3 + pand scratch1, [GLOBAL(te0)] + pand %5, [GLOBAL(t1f)] + por %5, scratch1 + + psubsb %3, %5 ; qs0 - Filter1 + pxor %3, [GLOBAL(t80)] + + ; Filter2 >> 3 + movdqa scratch1, zero + pcmpgtb scratch1, scratch2 + psrlw scratch2, 3 + pand scratch1, [GLOBAL(te0)] + pand scratch2, [GLOBAL(t1f)] + por scratch2, scratch1 + + paddsb %2, scratch2 ; ps0 + Filter2 + pxor %2, [GLOBAL(t80)] + + ; outer tap adjustments + paddsb %5, [GLOBAL(t1)] + movdqa scratch1, zero + pcmpgtb scratch1, %5 + psrlw %5, 1 + pand scratch1, [GLOBAL(t80)] + pand %5, [GLOBAL(t7f)] + por %5, scratch1 + pand %5, %6 ; vp8_filter &= ~hev + + psubsb %4, %5 ; qs1 - vp8_filter + pxor %4, [GLOBAL(t80)] + + paddsb %1, %5 ; ps1 + vp8_filter + pxor %1, [GLOBAL(t80)] +%endmacro + +;void vp8_loop_filter_bh_y_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh +;) +global sym(vp8_loop_filter_bh_y_sse2) +sym(vp8_loop_filter_bh_y_sse2): + +%ifidn __OUTPUT_FORMAT__,x64 + %define src rcx ; src_ptr + %define stride rdx ; src_pixel_step + %define blimit r8 + %define limit r9 + %define thresh r10 + + %define spp rax + %define stride3 r11 + %define stride5 r12 + %define stride7 r13 + + push rbp + mov rbp, rsp + push r12 + push r13 + mov thresh, arg(4) +%else + %define src rdi ; src_ptr + %define stride rsi ; src_pixel_step + %define blimit rdx + %define limit rcx + %define thresh r8 + + %define spp rax + %define stride3 r9 + %define stride5 r10 + %define stride7 r11 +%endif + + %define scratch1 xmm5 + %define scratch2 xmm6 + %define zero xmm7 + + %define i0 [src] + %define i1 [spp] + %define i2 [src + 2 * stride] + %define i3 [spp + 2 * stride] + %define i4 [src + 4 * stride] + %define i5 [spp + 4 * stride] + %define i6 [src + 2 * stride3] + %define i7 [spp + 2 * stride3] + %define i8 [src + 8 * stride] + %define i9 [spp + 8 * stride] + %define i10 [src + 2 * stride5] + %define i11 [spp + 2 * stride5] + %define i12 [src + 4 * stride3] + %define i13 [spp + 4 * stride3] + %define i14 [src + 2 * stride7] + %define i15 [spp + 2 * stride7] + + ; prep work + lea spp, [src + stride] + lea stride3, [stride + 2 * stride] + lea stride5, [stride3 + 2 * stride] + lea stride7, [stride3 + 4 * stride] + pxor zero, zero + + ; load the first set into registers + movdqa xmm0, i0 + movdqa xmm1, i1 + movdqa xmm2, i2 + movdqa xmm3, i3 + movdqa xmm4, i4 + movdqa xmm8, i5 + movdqa xmm9, i6 ; q2, will contain abs(p1-p0) + movdqa xmm10, i7 +LF_FILTER_HEV_MASK xmm0, xmm1, xmm2, xmm3, xmm4, xmm8, xmm9, xmm10 + + movdqa xmm1, i2 + movdqa xmm2, i3 + movdqa xmm3, i4 + movdqa xmm8, i5 +LF_FILTER xmm1, xmm2, xmm3, xmm8, xmm0, xmm4 + movdqa i2, xmm1 + movdqa i3, xmm2 + +; second set + movdqa i4, xmm3 + movdqa i5, xmm8 + + movdqa xmm0, i6 + movdqa xmm1, i7 + movdqa xmm2, i8 + movdqa xmm4, i9 + movdqa xmm10, i10 ; q2, will contain abs(p1-p0) + movdqa xmm11, i11 +LF_FILTER_HEV_MASK xmm3, xmm8, xmm0, xmm1, xmm2, xmm4, xmm10, xmm11, xmm9 + + movdqa xmm0, i6 + movdqa xmm1, i7 + movdqa xmm4, i8 + movdqa xmm8, i9 +LF_FILTER xmm0, xmm1, xmm4, xmm8, xmm3, xmm2 + movdqa i6, xmm0 + movdqa i7, xmm1 + +; last set + movdqa i8, xmm4 + movdqa i9, xmm8 + + movdqa xmm0, i10 + movdqa xmm1, i11 + movdqa xmm2, i12 + movdqa xmm3, i13 + movdqa xmm9, i14 ; q2, will contain abs(p1-p0) + movdqa xmm11, i15 +LF_FILTER_HEV_MASK xmm4, xmm8, xmm0, xmm1, xmm2, xmm3, xmm9, xmm11, xmm10 + + movdqa xmm0, i10 + movdqa xmm1, i11 + movdqa xmm3, i12 + movdqa xmm8, i13 +LF_FILTER xmm0, xmm1, xmm3, xmm8, xmm4, xmm2 + movdqa i10, xmm0 + movdqa i11, xmm1 + movdqa i12, xmm3 + movdqa i13, xmm8 + +%ifidn __OUTPUT_FORMAT__,x64 + pop r13 + pop r12 + pop rbp +%endif + + ret + + +;void vp8_loop_filter_bv_y_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh +;) + +global sym(vp8_loop_filter_bv_y_sse2) +sym(vp8_loop_filter_bv_y_sse2): + +%ifidn __OUTPUT_FORMAT__,x64 + %define src rcx ; src_ptr + %define stride rdx ; src_pixel_step + %define blimit r8 + %define limit r9 + %define thresh r10 + + %define spp rax + %define stride3 r11 + %define stride5 r12 + %define stride7 r13 + + push rbp + mov rbp, rsp + SAVE_XMM 15 + push r12 + push r13 + mov thresh, arg(4) +%else + %define src rdi + %define stride rsi + %define blimit rdx + %define limit rcx + %define thresh r8 + + %define spp rax + %define stride3 r9 + %define stride5 r10 + %define stride7 r11 +%endif + + %define scratch1 xmm5 + %define scratch2 xmm6 + %define zero xmm7 + + %define s0 [src] + %define s1 [spp] + %define s2 [src + 2 * stride] + %define s3 [spp + 2 * stride] + %define s4 [src + 4 * stride] + %define s5 [spp + 4 * stride] + %define s6 [src + 2 * stride3] + %define s7 [spp + 2 * stride3] + %define s8 [src + 8 * stride] + %define s9 [spp + 8 * stride] + %define s10 [src + 2 * stride5] + %define s11 [spp + 2 * stride5] + %define s12 [src + 4 * stride3] + %define s13 [spp + 4 * stride3] + %define s14 [src + 2 * stride7] + %define s15 [spp + 2 * stride7] + + %define i0 [rsp] + %define i1 [rsp + 16] + %define i2 [rsp + 32] + %define i3 [rsp + 48] + %define i4 [rsp + 64] + %define i5 [rsp + 80] + %define i6 [rsp + 96] + %define i7 [rsp + 112] + %define i8 [rsp + 128] + %define i9 [rsp + 144] + %define i10 [rsp + 160] + %define i11 [rsp + 176] + %define i12 [rsp + 192] + %define i13 [rsp + 208] + %define i14 [rsp + 224] + %define i15 [rsp + 240] + + ALIGN_STACK 16, rax + + ; reserve stack space + %define temp_storage 0 ; size is 256 (16*16) + %define stack_size 256 + sub rsp, stack_size + + ; prep work + lea spp, [src + stride] + lea stride3, [stride + 2 * stride] + lea stride5, [stride3 + 2 * stride] + lea stride7, [stride3 + 4 * stride] + + ; 8-f + movdqa xmm0, s8 + movdqa xmm1, xmm0 + punpcklbw xmm0, s9 ; 80 90 + punpckhbw xmm1, s9 ; 88 98 + + movdqa xmm2, s10 + movdqa xmm3, xmm2 + punpcklbw xmm2, s11 ; a0 b0 + punpckhbw xmm3, s11 ; a8 b8 + + movdqa xmm4, xmm0 + punpcklwd xmm0, xmm2 ; 80 90 a0 b0 + punpckhwd xmm4, xmm2 ; 84 94 a4 b4 + + movdqa xmm2, xmm1 + punpcklwd xmm1, xmm3 ; 88 98 a8 b8 + punpckhwd xmm2, xmm3 ; 8c 9c ac bc + + ; using xmm[0124] + ; work on next 4 rows + + movdqa xmm3, s12 + movdqa xmm5, xmm3 + punpcklbw xmm3, s13 ; c0 d0 + punpckhbw xmm5, s13 ; c8 d8 + + movdqa xmm6, s14 + movdqa xmm7, xmm6 + punpcklbw xmm6, s15 ; e0 f0 + punpckhbw xmm7, s15 ; e8 f8 + + movdqa xmm8, xmm3 + punpcklwd xmm3, xmm6 ; c0 d0 e0 f0 + punpckhwd xmm8, xmm6 ; c4 d4 e4 f4 + + movdqa xmm6, xmm5 + punpcklwd xmm5, xmm7 ; c8 d8 e8 f8 + punpckhwd xmm6, xmm7 ; cc dc ec fc + + ; pull the third and fourth sets together + + movdqa xmm7, xmm0 + punpckldq xmm0, xmm3 ; 80 90 a0 b0 c0 d0 e0 f0 + punpckhdq xmm7, xmm3 ; 82 92 a2 b2 c2 d2 e2 f2 + + movdqa xmm3, xmm4 + punpckldq xmm4, xmm8 ; 84 94 a4 b4 c4 d4 e4 f4 + punpckhdq xmm3, xmm8 ; 86 96 a6 b6 c6 d6 e6 f6 + + movdqa xmm8, xmm1 + punpckldq xmm1, xmm5 ; 88 88 a8 b8 c8 d8 e8 f8 + punpckhdq xmm8, xmm5 ; 8a 9a aa ba ca da ea fa + + movdqa xmm5, xmm2 + punpckldq xmm2, xmm6 ; 8c 9c ac bc cc dc ec fc + punpckhdq xmm5, xmm6 ; 8e 9e ae be ce de ee fe + + ; save the calculations. we only have 15 registers ... + movdqa i0, xmm0 + movdqa i1, xmm7 + movdqa i2, xmm4 + movdqa i3, xmm3 + movdqa i4, xmm1 + movdqa i5, xmm8 + movdqa i6, xmm2 + movdqa i7, xmm5 + + ; 0-7 + movdqa xmm0, s0 + movdqa xmm1, xmm0 + punpcklbw xmm0, s1 ; 00 10 + punpckhbw xmm1, s1 ; 08 18 + + movdqa xmm2, s2 + movdqa xmm3, xmm2 + punpcklbw xmm2, s3 ; 20 30 + punpckhbw xmm3, s3 ; 28 38 + + movdqa xmm4, xmm0 + punpcklwd xmm0, xmm2 ; 00 10 20 30 + punpckhwd xmm4, xmm2 ; 04 14 24 34 + + movdqa xmm2, xmm1 + punpcklwd xmm1, xmm3 ; 08 18 28 38 + punpckhwd xmm2, xmm3 ; 0c 1c 2c 3c + + ; using xmm[0124] + ; work on next 4 rows + + movdqa xmm3, s4 + movdqa xmm5, xmm3 + punpcklbw xmm3, s5 ; 40 50 + punpckhbw xmm5, s5 ; 48 58 + + movdqa xmm6, s6 + movdqa xmm7, xmm6 + punpcklbw xmm6, s7 ; 60 70 + punpckhbw xmm7, s7 ; 68 78 + + movdqa xmm8, xmm3 + punpcklwd xmm3, xmm6 ; 40 50 60 70 + punpckhwd xmm8, xmm6 ; 44 54 64 74 + + movdqa xmm6, xmm5 + punpcklwd xmm5, xmm7 ; 48 58 68 78 + punpckhwd xmm6, xmm7 ; 4c 5c 6c 7c + + ; pull the first two sets together + + movdqa xmm7, xmm0 + punpckldq xmm0, xmm3 ; 00 10 20 30 40 50 60 70 + punpckhdq xmm7, xmm3 ; 02 12 22 32 42 52 62 72 + + movdqa xmm3, xmm4 + punpckldq xmm4, xmm8 ; 04 14 24 34 44 54 64 74 + punpckhdq xmm3, xmm8 ; 06 16 26 36 46 56 66 76 + + movdqa xmm8, xmm1 + punpckldq xmm1, xmm5 ; 08 18 28 38 48 58 68 78 + punpckhdq xmm8, xmm5 ; 0a 1a 2a 3a 4a 5a 6a 7a + + movdqa xmm5, xmm2 + punpckldq xmm2, xmm6 ; 0c 1c 2c 3c 4c 5c 6c 7c + punpckhdq xmm5, xmm6 ; 0e 1e 2e 3e 4e 5e 6e 7e + ; final combination + + movdqa xmm6, xmm0 + punpcklqdq xmm0, i0 + punpckhqdq xmm6, i0 + + movdqa xmm9, xmm7 + punpcklqdq xmm7, i1 + punpckhqdq xmm9, i1 + + movdqa xmm10, xmm4 + punpcklqdq xmm4, i2 + punpckhqdq xmm10, i2 + + movdqa xmm11, xmm3 + punpcklqdq xmm3, i3 + punpckhqdq xmm11, i3 + + movdqa xmm12, xmm1 + punpcklqdq xmm1, i4 + punpckhqdq xmm12, i4 + + movdqa xmm13, xmm8 + punpcklqdq xmm8, i5 + punpckhqdq xmm13, i5 + + movdqa xmm14, xmm2 + punpcklqdq xmm2, i6 + punpckhqdq xmm14, i6 + + movdqa xmm15, xmm5 + punpcklqdq xmm5, i7 + punpckhqdq xmm15, i7 + + movdqa i0, xmm0 + movdqa i1, xmm6 + movdqa i2, xmm7 + movdqa i3, xmm9 + movdqa i4, xmm4 + movdqa i5, xmm10 + movdqa i6, xmm3 + movdqa i7, xmm11 + movdqa i8, xmm1 + movdqa i9, xmm12 + movdqa i10, xmm8 + movdqa i11, xmm13 + movdqa i12, xmm2 + movdqa i13, xmm14 + movdqa i14, xmm5 + movdqa i15, xmm15 + +; TRANSPOSED DATA AVAILABLE ON THE STACK + + movdqa xmm12, xmm6 + movdqa xmm13, xmm7 + + pxor zero, zero + +LF_FILTER_HEV_MASK xmm0, xmm12, xmm13, xmm9, xmm4, xmm10, xmm3, xmm11 + + movdqa xmm1, i2 + movdqa xmm2, i3 + movdqa xmm8, i4 + movdqa xmm9, i5 +LF_FILTER xmm1, xmm2, xmm8, xmm9, xmm0, xmm4 + movdqa i2, xmm1 + movdqa i3, xmm2 + +; second set + movdqa i4, xmm8 + movdqa i5, xmm9 + + movdqa xmm0, i6 + movdqa xmm1, i7 + movdqa xmm2, i8 + movdqa xmm4, i9 + movdqa xmm10, i10 ; q2, will contain abs(p1-p0) + movdqa xmm11, i11 +LF_FILTER_HEV_MASK xmm8, xmm9, xmm0, xmm1, xmm2, xmm4, xmm10, xmm11, xmm3 + + movdqa xmm0, i6 + movdqa xmm1, i7 + movdqa xmm3, i8 + movdqa xmm4, i9 +LF_FILTER xmm0, xmm1, xmm3, xmm4, xmm8, xmm2 + movdqa i6, xmm0 + movdqa i7, xmm1 + +; last set + movdqa i8, xmm3 + movdqa i9, xmm4 + + movdqa xmm0, i10 + movdqa xmm1, i11 + movdqa xmm2, i12 + movdqa xmm8, i13 + movdqa xmm9, i14 ; q2, will contain abs(p1-p0) + movdqa xmm11, i15 +LF_FILTER_HEV_MASK xmm3, xmm4, xmm0, xmm1, xmm2, xmm8, xmm9, xmm11, xmm10 + + movdqa xmm0, i10 + movdqa xmm1, i11 + movdqa xmm4, i12 + movdqa xmm8, i13 +LF_FILTER xmm0, xmm1, xmm4, xmm8, xmm3, xmm2 + movdqa i10, xmm0 + movdqa i11, xmm1 + movdqa i12, xmm4 + movdqa i13, xmm8 + + +; RESHUFFLE AND WRITE OUT + ; 8-f + movdqa xmm0, i8 + movdqa xmm1, xmm0 + punpcklbw xmm0, i9 ; 80 90 + punpckhbw xmm1, i9 ; 88 98 + + movdqa xmm2, i10 + movdqa xmm3, xmm2 + punpcklbw xmm2, i11 ; a0 b0 + punpckhbw xmm3, i11 ; a8 b8 + + movdqa xmm4, xmm0 + punpcklwd xmm0, xmm2 ; 80 90 a0 b0 + punpckhwd xmm4, xmm2 ; 84 94 a4 b4 + + movdqa xmm2, xmm1 + punpcklwd xmm1, xmm3 ; 88 98 a8 b8 + punpckhwd xmm2, xmm3 ; 8c 9c ac bc + + ; using xmm[0124] + ; work on next 4 rows + + movdqa xmm3, i12 + movdqa xmm5, xmm3 + punpcklbw xmm3, i13 ; c0 d0 + punpckhbw xmm5, i13 ; c8 d8 + + movdqa xmm6, i14 + movdqa xmm7, xmm6 + punpcklbw xmm6, i15 ; e0 f0 + punpckhbw xmm7, i15 ; e8 f8 + + movdqa xmm8, xmm3 + punpcklwd xmm3, xmm6 ; c0 d0 e0 f0 + punpckhwd xmm8, xmm6 ; c4 d4 e4 f4 + + movdqa xmm6, xmm5 + punpcklwd xmm5, xmm7 ; c8 d8 e8 f8 + punpckhwd xmm6, xmm7 ; cc dc ec fc + + ; pull the third and fourth sets together + + movdqa xmm7, xmm0 + punpckldq xmm0, xmm3 ; 80 90 a0 b0 c0 d0 e0 f0 + punpckhdq xmm7, xmm3 ; 82 92 a2 b2 c2 d2 e2 f2 + + movdqa xmm3, xmm4 + punpckldq xmm4, xmm8 ; 84 94 a4 b4 c4 d4 e4 f4 + punpckhdq xmm3, xmm8 ; 86 96 a6 b6 c6 d6 e6 f6 + + movdqa xmm8, xmm1 + punpckldq xmm1, xmm5 ; 88 88 a8 b8 c8 d8 e8 f8 + punpckhdq xmm8, xmm5 ; 8a 9a aa ba ca da ea fa + + movdqa xmm5, xmm2 + punpckldq xmm2, xmm6 ; 8c 9c ac bc cc dc ec fc + punpckhdq xmm5, xmm6 ; 8e 9e ae be ce de ee fe + + ; save the calculations. we only have 15 registers ... + movdqa i8, xmm0 + movdqa i9, xmm7 + movdqa i10, xmm4 + movdqa i11, xmm3 + movdqa i12, xmm1 + movdqa i13, xmm8 + movdqa i14, xmm2 + movdqa i15, xmm5 + + ; 0-7 + movdqa xmm0, i0 + movdqa xmm1, xmm0 + punpcklbw xmm0, i1 ; 00 10 + punpckhbw xmm1, i1 ; 08 18 + + movdqa xmm2, i2 + movdqa xmm3, xmm2 + punpcklbw xmm2, i3 ; 20 30 + punpckhbw xmm3, i3 ; 28 38 + + movdqa xmm4, xmm0 + punpcklwd xmm0, xmm2 ; 00 10 20 30 + punpckhwd xmm4, xmm2 ; 04 14 24 34 + + movdqa xmm2, xmm1 + punpcklwd xmm1, xmm3 ; 08 18 28 38 + punpckhwd xmm2, xmm3 ; 0c 1c 2c 3c + + ; using xmm[0124] + ; work on next 4 rows + + movdqa xmm3, i4 + movdqa xmm5, xmm3 + punpcklbw xmm3, i5 ; 40 50 + punpckhbw xmm5, i5 ; 48 58 + + movdqa xmm6, i6 + movdqa xmm7, xmm6 + punpcklbw xmm6, i7 ; 60 70 + punpckhbw xmm7, i7 ; 68 78 + + movdqa xmm8, xmm3 + punpcklwd xmm3, xmm6 ; 40 50 60 70 + punpckhwd xmm8, xmm6 ; 44 54 64 74 + + movdqa xmm6, xmm5 + punpcklwd xmm5, xmm7 ; 48 58 68 78 + punpckhwd xmm6, xmm7 ; 4c 5c 6c 7c + + ; pull the first two sets together + + movdqa xmm7, xmm0 + punpckldq xmm0, xmm3 ; 00 10 20 30 40 50 60 70 + punpckhdq xmm7, xmm3 ; 02 12 22 32 42 52 62 72 + + movdqa xmm3, xmm4 + punpckldq xmm4, xmm8 ; 04 14 24 34 44 54 64 74 + punpckhdq xmm3, xmm8 ; 06 16 26 36 46 56 66 76 + + movdqa xmm8, xmm1 + punpckldq xmm1, xmm5 ; 08 18 28 38 48 58 68 78 + punpckhdq xmm8, xmm5 ; 0a 1a 2a 3a 4a 5a 6a 7a + + movdqa xmm5, xmm2 + punpckldq xmm2, xmm6 ; 0c 1c 2c 3c 4c 5c 6c 7c + punpckhdq xmm5, xmm6 ; 0e 1e 2e 3e 4e 5e 6e 7e + ; final combination + + movdqa xmm6, xmm0 + punpcklqdq xmm0, i8 + punpckhqdq xmm6, i8 + + movdqa xmm9, xmm7 + punpcklqdq xmm7, i9 + punpckhqdq xmm9, i9 + + movdqa xmm10, xmm4 + punpcklqdq xmm4, i10 + punpckhqdq xmm10, i10 + + movdqa xmm11, xmm3 + punpcklqdq xmm3, i11 + punpckhqdq xmm11, i11 + + movdqa xmm12, xmm1 + punpcklqdq xmm1, i12 + punpckhqdq xmm12, i12 + + movdqa xmm13, xmm8 + punpcklqdq xmm8, i13 + punpckhqdq xmm13, i13 + + movdqa xmm14, xmm2 + punpcklqdq xmm2, i14 + punpckhqdq xmm14, i14 + + movdqa xmm15, xmm5 + punpcklqdq xmm5, i15 + punpckhqdq xmm15, i15 + + movdqa s0, xmm0 + movdqa s1, xmm6 + movdqa s2, xmm7 + movdqa s3, xmm9 + movdqa s4, xmm4 + movdqa s5, xmm10 + movdqa s6, xmm3 + movdqa s7, xmm11 + movdqa s8, xmm1 + movdqa s9, xmm12 + movdqa s10, xmm8 + movdqa s11, xmm13 + movdqa s12, xmm2 + movdqa s13, xmm14 + movdqa s14, xmm5 + movdqa s15, xmm15 + + ; free stack space + add rsp, stack_size + + ; un-ALIGN_STACK + pop rsp + +%ifidn __OUTPUT_FORMAT__,x64 + pop r13 + pop r12 + RESTORE_XMM + pop rbp +%endif + + ret + +SECTION_RODATA +align 16 +te0: + times 16 db 0xe0 +align 16 +t7f: + times 16 db 0x7f +align 16 +tfe: + times 16 db 0xfe +align 16 +t1f: + times 16 db 0x1f +align 16 +t80: + times 16 db 0x80 +align 16 +t1: + times 16 db 0x01 +align 16 +t3: + times 16 db 0x03 +align 16 +t4: + times 16 db 0x04 diff --git a/vp8/common/x86/loopfilter_mmx.asm b/vp8/common/x86/loopfilter_mmx.asm new file mode 100644 index 0000000..697a5de --- /dev/null +++ b/vp8/common/x86/loopfilter_mmx.asm @@ -0,0 +1,1753 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;void vp8_loop_filter_horizontal_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_horizontal_edge_mmx) +sym(vp8_loop_filter_horizontal_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + movsxd rcx, dword ptr arg(5) ;count +.next8_h: + mov rdx, arg(3) ;limit + movq mm7, [rdx] + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + ; calculate breakout conditions + movq mm2, [rdi+2*rax] ; q3 + movq mm1, [rsi+2*rax] ; q2 + movq mm6, mm1 ; q2 + psubusb mm1, mm2 ; q2-=q3 + psubusb mm2, mm6 ; q3-=q2 + por mm1, mm2 ; abs(q3-q2) + psubusb mm1, mm7 ; + + + movq mm4, [rsi+rax] ; q1 + movq mm3, mm4 ; q1 + psubusb mm4, mm6 ; q1-=q2 + psubusb mm6, mm3 ; q2-=q1 + por mm4, mm6 ; abs(q2-q1) + + psubusb mm4, mm7 + por mm1, mm4 + + movq mm4, [rsi] ; q0 + movq mm0, mm4 ; q0 + psubusb mm4, mm3 ; q0-=q1 + psubusb mm3, mm0 ; q1-=q0 + por mm4, mm3 ; abs(q0-q1) + movq t0, mm4 ; save to t0 + psubusb mm4, mm7 + por mm1, mm4 + + + neg rax ; negate pitch to deal with above border + + movq mm2, [rsi+4*rax] ; p3 + movq mm4, [rdi+4*rax] ; p2 + movq mm5, mm4 ; p2 + psubusb mm4, mm2 ; p2-=p3 + psubusb mm2, mm5 ; p3-=p2 + por mm4, mm2 ; abs(p3 - p2) + psubusb mm4, mm7 + por mm1, mm4 + + + movq mm4, [rsi+2*rax] ; p1 + movq mm3, mm4 ; p1 + psubusb mm4, mm5 ; p1-=p2 + psubusb mm5, mm3 ; p2-=p1 + por mm4, mm5 ; abs(p2 - p1) + psubusb mm4, mm7 + por mm1, mm4 + + movq mm2, mm3 ; p1 + + movq mm4, [rsi+rax] ; p0 + movq mm5, mm4 ; p0 + psubusb mm4, mm3 ; p0-=p1 + psubusb mm3, mm5 ; p1-=p0 + por mm4, mm3 ; abs(p1 - p0) + movq t1, mm4 ; save to t1 + psubusb mm4, mm7 + por mm1, mm4 + + movq mm3, [rdi] ; q1 + movq mm4, mm3 ; q1 + psubusb mm3, mm2 ; q1-=p1 + psubusb mm2, mm4 ; p1-=q1 + por mm2, mm3 ; abs(p1-q1) + pand mm2, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw mm2, 1 ; abs(p1-q1)/2 + + movq mm6, mm5 ; p0 + movq mm3, [rsi] ; q0 + psubusb mm5, mm3 ; p0-=q0 + psubusb mm3, mm6 ; q0-=p0 + por mm5, mm3 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;blimit ; get blimit + movq mm7, [rdx] ; blimit + + psubusb mm5, mm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > blimit + por mm1, mm5 + pxor mm5, mm5 + pcmpeqb mm1, mm5 ; mask mm1 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 + paddb mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + + pcmpeqb mm4, mm5 + + pcmpeqb mm5, mm5 + pxor mm4, mm5 + + + ; start work on filters + movq mm2, [rsi+2*rax] ; p1 + movq mm7, [rdi] ; q1 + pxor mm2, [GLOBAL(t80)] ; p1 offset to convert to signed values + pxor mm7, [GLOBAL(t80)] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + pand mm2, mm4 ; high var mask (hvm)(p1 - q1) + pxor mm6, [GLOBAL(t80)] ; offset to convert to signed values + pxor mm0, [GLOBAL(t80)] ; offset to convert to signed values + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + paddsb mm2, mm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + movq mm2, mm1 + paddsb mm1, [GLOBAL(t4)] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + paddsb mm2, [GLOBAL(t3)] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + + pxor mm0, mm0 ; + pxor mm5, mm5 + punpcklbw mm0, mm2 ; + punpckhbw mm5, mm2 ; + psraw mm0, 11 ; + psraw mm5, 11 + packsswb mm0, mm5 + movq mm2, mm0 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + + pxor mm0, mm0 ; 0 + movq mm5, mm1 ; abcdefgh + punpcklbw mm0, mm1 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + pxor mm1, mm1 ; 0 + punpckhbw mm1, mm5 ; a0b0c0d0 + psraw mm1, 11 ; sign extended shift right by 3 + movq mm5, mm0 ; save results + + packsswb mm0, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + paddsw mm5, [GLOBAL(ones)] + paddsw mm1, [GLOBAL(ones)] + psraw mm5, 1 ; partial shifted one more time for 2nd tap + psraw mm1, 1 ; partial shifted one more time for 2nd tap + packsswb mm5, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + pandn mm4, mm5 ; high edge variance additive + + paddsb mm6, mm2 ; p0+= p0 add + pxor mm6, [GLOBAL(t80)] ; unoffset + movq [rsi+rax], mm6 ; write back + + movq mm6, [rsi+2*rax] ; p1 + pxor mm6, [GLOBAL(t80)] ; reoffset + paddsb mm6, mm4 ; p1+= p1 add + pxor mm6, [GLOBAL(t80)] ; unoffset + movq [rsi+2*rax], mm6 ; write back + + psubsb mm3, mm0 ; q0-= q0 add + pxor mm3, [GLOBAL(t80)] ; unoffset + movq [rsi], mm3 ; write back + + psubsb mm7, mm4 ; q1-= q1 add + pxor mm7, [GLOBAL(t80)] ; unoffset + movq [rdi], mm7 ; write back + + add rsi,8 + neg rax + dec rcx + jnz .next8_h + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_vertical_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_vertical_edge_mmx) +sym(vp8_loop_filter_vertical_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 64 ; reserve 64 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + %define srct [rsp + 32] ;__declspec(align(16)) char srct[32]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4 - 4] + + movsxd rcx, dword ptr arg(5) ;count +.next8_v: + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + + ;transpose + movq mm6, [rsi+2*rax] ; 67 66 65 64 63 62 61 60 + movq mm7, mm6 ; 77 76 75 74 73 72 71 70 + + punpckhbw mm7, [rdi+2*rax] ; 77 67 76 66 75 65 74 64 + punpcklbw mm6, [rdi+2*rax] ; 73 63 72 62 71 61 70 60 + + movq mm4, [rsi] ; 47 46 45 44 43 42 41 40 + movq mm5, mm4 ; 47 46 45 44 43 42 41 40 + + punpckhbw mm5, [rsi+rax] ; 57 47 56 46 55 45 54 44 + punpcklbw mm4, [rsi+rax] ; 53 43 52 42 51 41 50 40 + + movq mm3, mm5 ; 57 47 56 46 55 45 54 44 + punpckhwd mm5, mm7 ; 77 67 57 47 76 66 56 46 + + punpcklwd mm3, mm7 ; 75 65 55 45 74 64 54 44 + movq mm2, mm4 ; 53 43 52 42 51 41 50 40 + + punpckhwd mm4, mm6 ; 73 63 53 43 72 62 52 42 + punpcklwd mm2, mm6 ; 71 61 51 41 70 60 50 40 + + neg rax + movq mm6, [rsi+rax*2] ; 27 26 25 24 23 22 21 20 + + movq mm1, mm6 ; 27 26 25 24 23 22 21 20 + punpckhbw mm6, [rsi+rax] ; 37 27 36 36 35 25 34 24 + + punpcklbw mm1, [rsi+rax] ; 33 23 32 22 31 21 30 20 + movq mm7, [rsi+rax*4]; ; 07 06 05 04 03 02 01 00 + + punpckhbw mm7, [rdi+rax*4] ; 17 07 16 06 15 05 14 04 + movq mm0, mm7 ; 17 07 16 06 15 05 14 04 + + punpckhwd mm7, mm6 ; 37 27 17 07 36 26 16 06 + punpcklwd mm0, mm6 ; 35 25 15 05 34 24 14 04 + + movq mm6, mm7 ; 37 27 17 07 36 26 16 06 + punpckhdq mm7, mm5 ; 77 67 57 47 37 27 17 07 = q3 + + punpckldq mm6, mm5 ; 76 66 56 46 36 26 16 06 = q2 + + movq mm5, mm6 ; 76 66 56 46 36 26 16 06 + psubusb mm5, mm7 ; q2-q3 + + psubusb mm7, mm6 ; q3-q2 + por mm7, mm5; ; mm7=abs (q3-q2) + + movq mm5, mm0 ; 35 25 15 05 34 24 14 04 + punpckhdq mm5, mm3 ; 75 65 55 45 35 25 15 05 = q1 + + punpckldq mm0, mm3 ; 74 64 54 44 34 24 15 04 = q0 + movq mm3, mm5 ; 75 65 55 45 35 25 15 05 = q1 + + psubusb mm3, mm6 ; q1-q2 + psubusb mm6, mm5 ; q2-q1 + + por mm6, mm3 ; mm6=abs(q2-q1) + lea rdx, srct + + movq [rdx+24], mm5 ; save q1 + movq [rdx+16], mm0 ; save q0 + + movq mm3, [rsi+rax*4] ; 07 06 05 04 03 02 01 00 + punpcklbw mm3, [rdi+rax*4] ; 13 03 12 02 11 01 10 00 + + movq mm0, mm3 ; 13 03 12 02 11 01 10 00 + punpcklwd mm0, mm1 ; 31 21 11 01 30 20 10 00 + + punpckhwd mm3, mm1 ; 33 23 13 03 32 22 12 02 + movq mm1, mm0 ; 31 21 11 01 30 20 10 00 + + punpckldq mm0, mm2 ; 70 60 50 40 30 20 10 00 =p3 + punpckhdq mm1, mm2 ; 71 61 51 41 31 21 11 01 =p2 + + movq mm2, mm1 ; 71 61 51 41 31 21 11 01 =p2 + psubusb mm2, mm0 ; p2-p3 + + psubusb mm0, mm1 ; p3-p2 + por mm0, mm2 ; mm0=abs(p3-p2) + + movq mm2, mm3 ; 33 23 13 03 32 22 12 02 + punpckldq mm2, mm4 ; 72 62 52 42 32 22 12 02 = p1 + + punpckhdq mm3, mm4 ; 73 63 53 43 33 23 13 03 = p0 + movq [rdx+8], mm3 ; save p0 + + movq [rdx], mm2 ; save p1 + movq mm5, mm2 ; mm5 = p1 + + psubusb mm2, mm1 ; p1-p2 + psubusb mm1, mm5 ; p2-p1 + + por mm1, mm2 ; mm1=abs(p2-p1) + mov rdx, arg(3) ;limit + + movq mm4, [rdx] ; mm4 = limit + psubusb mm7, mm4 + + psubusb mm0, mm4 + psubusb mm1, mm4 + + psubusb mm6, mm4 + por mm7, mm6 + + por mm0, mm1 + por mm0, mm7 ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit + + movq mm1, mm5 ; p1 + + movq mm7, mm3 ; mm3=mm7=p0 + psubusb mm7, mm5 ; p0 - p1 + + psubusb mm5, mm3 ; p1 - p0 + por mm5, mm7 ; abs(p1-p0) + + movq t0, mm5 ; save abs(p1-p0) + lea rdx, srct + + psubusb mm5, mm4 + por mm0, mm5 ; mm0=mask + + movq mm5, [rdx+16] ; mm5=q0 + movq mm7, [rdx+24] ; mm7=q1 + + movq mm6, mm5 ; mm6=q0 + movq mm2, mm7 ; q1 + psubusb mm5, mm7 ; q0-q1 + + psubusb mm7, mm6 ; q1-q0 + por mm7, mm5 ; abs(q1-q0) + + movq t1, mm7 ; save abs(q1-q0) + psubusb mm7, mm4 + + por mm0, mm7 ; mask + + movq mm5, mm2 ; q1 + psubusb mm5, mm1 ; q1-=p1 + psubusb mm1, mm2 ; p1-=q1 + por mm5, mm1 ; abs(p1-q1) + pand mm5, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw mm5, 1 ; abs(p1-q1)/2 + + mov rdx, arg(2) ;blimit ; + + movq mm4, [rdx] ;blimit + movq mm1, mm3 ; mm1=mm3=p0 + + movq mm7, mm6 ; mm7=mm6=q0 + psubusb mm1, mm7 ; p0-q0 + + psubusb mm7, mm3 ; q0-p0 + por mm1, mm7 ; abs(q0-p0) + paddusb mm1, mm1 ; abs(q0-p0)*2 + paddusb mm1, mm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + psubusb mm1, mm4 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > blimit + por mm1, mm0; ; mask + + pxor mm0, mm0 + pcmpeqb mm1, mm0 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] + ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 + + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 + + por mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb mm4, mm0 + + pcmpeqb mm0, mm0 + pxor mm4, mm0 + + + + ; start work on filters + lea rdx, srct + + movq mm2, [rdx] ; p1 + movq mm7, [rdx+24] ; q1 + + movq mm6, [rdx+8] ; p0 + movq mm0, [rdx+16] ; q0 + + pxor mm2, [GLOBAL(t80)] ; p1 offset to convert to signed values + pxor mm7, [GLOBAL(t80)] ; q1 offset to convert to signed values + + psubsb mm2, mm7 ; p1 - q1 + pand mm2, mm4 ; high var mask (hvm)(p1 - q1) + + pxor mm6, [GLOBAL(t80)] ; offset to convert to signed values + pxor mm0, [GLOBAL(t80)] ; offset to convert to signed values + + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + + paddsb mm2, mm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + + paddsb mm2, mm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + + movq mm2, mm1 + paddsb mm1, [GLOBAL(t4)] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + + paddsb mm2, [GLOBAL(t3)] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + pxor mm0, mm0 ; + + pxor mm5, mm5 + punpcklbw mm0, mm2 ; + + punpckhbw mm5, mm2 ; + psraw mm0, 11 ; + + psraw mm5, 11 + packsswb mm0, mm5 + + movq mm2, mm0 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + + pxor mm0, mm0 ; 0 + movq mm5, mm1 ; abcdefgh + + punpcklbw mm0, mm1 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + + pxor mm1, mm1 ; 0 + punpckhbw mm1, mm5 ; a0b0c0d0 + + psraw mm1, 11 ; sign extended shift right by 3 + movq mm5, mm0 ; save results + + packsswb mm0, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + paddsw mm5, [GLOBAL(ones)] + + paddsw mm1, [GLOBAL(ones)] + psraw mm5, 1 ; partial shifted one more time for 2nd tap + + psraw mm1, 1 ; partial shifted one more time for 2nd tap + packsswb mm5, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + + pandn mm4, mm5 ; high edge variance additive + + paddsb mm6, mm2 ; p0+= p0 add + pxor mm6, [GLOBAL(t80)] ; unoffset + + ; mm6=p0 ; + movq mm1, [rdx] ; p1 + pxor mm1, [GLOBAL(t80)] ; reoffset + + paddsb mm1, mm4 ; p1+= p1 add + pxor mm1, [GLOBAL(t80)] ; unoffset + ; mm6 = p0 mm1 = p1 + + psubsb mm3, mm0 ; q0-= q0 add + pxor mm3, [GLOBAL(t80)] ; unoffset + + ; mm3 = q0 + psubsb mm7, mm4 ; q1-= q1 add + pxor mm7, [GLOBAL(t80)] ; unoffset + ; mm7 = q1 + + ; tranpose and write back + ; mm1 = 72 62 52 42 32 22 12 02 + ; mm6 = 73 63 53 43 33 23 13 03 + ; mm3 = 74 64 54 44 34 24 14 04 + ; mm7 = 75 65 55 45 35 25 15 05 + + movq mm2, mm1 ; 72 62 52 42 32 22 12 02 + punpcklbw mm2, mm6 ; 33 32 23 22 13 12 03 02 + + movq mm4, mm3 ; 74 64 54 44 34 24 14 04 + punpckhbw mm1, mm6 ; 73 72 63 62 53 52 43 42 + + punpcklbw mm4, mm7 ; 35 34 25 24 15 14 05 04 + punpckhbw mm3, mm7 ; 75 74 65 64 55 54 45 44 + + movq mm6, mm2 ; 33 32 23 22 13 12 03 02 + punpcklwd mm2, mm4 ; 15 14 13 12 05 04 03 02 + + punpckhwd mm6, mm4 ; 35 34 33 32 25 24 23 22 + movq mm5, mm1 ; 73 72 63 62 53 52 43 42 + + punpcklwd mm1, mm3 ; 55 54 53 52 45 44 43 42 + punpckhwd mm5, mm3 ; 75 74 73 72 65 64 63 62 + + + ; mm2 = 15 14 13 12 05 04 03 02 + ; mm6 = 35 34 33 32 25 24 23 22 + ; mm5 = 55 54 53 52 45 44 43 42 + ; mm1 = 75 74 73 72 65 64 63 62 + + + + movd [rsi+rax*4+2], mm2 + psrlq mm2, 32 + + movd [rdi+rax*4+2], mm2 + movd [rsi+rax*2+2], mm6 + + psrlq mm6, 32 + movd [rsi+rax+2],mm6 + + movd [rsi+2], mm1 + psrlq mm1, 32 + + movd [rdi+2], mm1 + neg rax + + movd [rdi+rax+2],mm5 + psrlq mm5, 32 + + movd [rdi+rax*2+2], mm5 + + lea rsi, [rsi+rax*8] + dec rcx + jnz .next8_v + + add rsp, 64 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_horizontal_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_mbloop_filter_horizontal_edge_mmx) +sym(vp8_mbloop_filter_horizontal_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + movsxd rcx, dword ptr arg(5) ;count +.next8_mbh: + mov rdx, arg(3) ;limit + movq mm7, [rdx] + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + ; calculate breakout conditions + movq mm2, [rdi+2*rax] ; q3 + + movq mm1, [rsi+2*rax] ; q2 + movq mm6, mm1 ; q2 + psubusb mm1, mm2 ; q2-=q3 + psubusb mm2, mm6 ; q3-=q2 + por mm1, mm2 ; abs(q3-q2) + psubusb mm1, mm7 + + + ; mm1 = abs(q3-q2), mm6 =q2, mm7 = limit + movq mm4, [rsi+rax] ; q1 + movq mm3, mm4 ; q1 + psubusb mm4, mm6 ; q1-=q2 + psubusb mm6, mm3 ; q2-=q1 + por mm4, mm6 ; abs(q2-q1) + psubusb mm4, mm7 + por mm1, mm4 + + + ; mm1 = mask, mm3=q1, mm7 = limit + + movq mm4, [rsi] ; q0 + movq mm0, mm4 ; q0 + psubusb mm4, mm3 ; q0-=q1 + psubusb mm3, mm0 ; q1-=q0 + por mm4, mm3 ; abs(q0-q1) + movq t0, mm4 ; save to t0 + psubusb mm4, mm7 + por mm1, mm4 + + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + + neg rax ; negate pitch to deal with above border + + movq mm2, [rsi+4*rax] ; p3 + movq mm4, [rdi+4*rax] ; p2 + movq mm5, mm4 ; p2 + psubusb mm4, mm2 ; p2-=p3 + psubusb mm2, mm5 ; p3-=p2 + por mm4, mm2 ; abs(p3 - p2) + psubusb mm4, mm7 + por mm1, mm4 + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + + movq mm4, [rsi+2*rax] ; p1 + movq mm3, mm4 ; p1 + psubusb mm4, mm5 ; p1-=p2 + psubusb mm5, mm3 ; p2-=p1 + por mm4, mm5 ; abs(p2 - p1) + psubusb mm4, mm7 + por mm1, mm4 + + movq mm2, mm3 ; p1 + + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + + movq mm4, [rsi+rax] ; p0 + movq mm5, mm4 ; p0 + psubusb mm4, mm3 ; p0-=p1 + psubusb mm3, mm5 ; p1-=p0 + por mm4, mm3 ; abs(p1 - p0) + movq t1, mm4 ; save to t1 + psubusb mm4, mm7 + por mm1, mm4 + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm5 = p0 + movq mm3, [rdi] ; q1 + movq mm4, mm3 ; q1 + psubusb mm3, mm2 ; q1-=p1 + psubusb mm2, mm4 ; p1-=q1 + por mm2, mm3 ; abs(p1-q1) + pand mm2, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw mm2, 1 ; abs(p1-q1)/2 + + movq mm6, mm5 ; p0 + movq mm3, mm0 ; q0 + psubusb mm5, mm3 ; p0-=q0 + psubusb mm3, mm6 ; q0-=p0 + por mm5, mm3 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;blimit ; get blimit + movq mm7, [rdx] ; blimit + + psubusb mm5, mm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > blimit + por mm1, mm5 + pxor mm5, mm5 + pcmpeqb mm1, mm5 ; mask mm1 + + ; mm1 = mask, mm0=q0, mm7 = blimit, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm6 = p0, + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 + paddb mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + + pcmpeqb mm4, mm5 + + pcmpeqb mm5, mm5 + pxor mm4, mm5 + + + + ; mm1 = mask, mm0=q0, mm7 = thresh, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm6 = p0, mm4=hev + ; start work on filters + movq mm2, [rsi+2*rax] ; p1 + movq mm7, [rdi] ; q1 + pxor mm2, [GLOBAL(t80)] ; p1 offset to convert to signed values + pxor mm7, [GLOBAL(t80)] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + + pxor mm6, [GLOBAL(t80)] ; offset to convert to signed values + pxor mm0, [GLOBAL(t80)] ; offset to convert to signed values + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; 1 * (q0 - p0) + (p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + paddsb mm2, mm0 ; 3 * (q0 - p0) + (p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + + + ; mm1 = vp8_filter, mm4=hev, mm6=ps0, mm3=qs0 + movq mm2, mm1 ; vp8_filter + pand mm2, mm4; ; Filter2 = vp8_filter & hev + + movq mm5, mm2 ; + paddsb mm5, [GLOBAL(t3)]; + + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm5 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm5 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + movq mm5, mm0 ; Filter2 + + paddsb mm2, [GLOBAL(t4)] ; vp8_signed_char_clamp(Filter2 + 4) + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm2 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm2 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + ; mm0= filter2 mm1 = vp8_filter, mm3 =qs0 mm5=s mm4 =hev mm6=ps0 + psubsb mm3, mm0 ; qs0 =qs0 - filter1 + paddsb mm6, mm5 ; ps0 =ps0 + Fitler2 + + ; mm1=vp8_filter, mm3=qs0, mm4 =hev mm6=ps0 + ; vp8_filter &= ~hev; + ; Filter2 = vp8_filter; + pandn mm4, mm1 ; vp8_filter&=~hev + + + ; mm3=qs0, mm4=filter2, mm6=ps0 + + ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7); + ; s = vp8_signed_char_clamp(qs0 - u); + ; *oq0 = s^0x80; + ; s = vp8_signed_char_clamp(ps0 + u); + ; *op0 = s^0x80; + pxor mm0, mm0 + + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [GLOBAL(s27)] + pmulhw mm2, [GLOBAL(s27)] + paddw mm1, [GLOBAL(s63)] + paddw mm2, [GLOBAL(s63)] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + psubsb mm3, mm1 + paddsb mm6, mm1 + + pxor mm3, [GLOBAL(t80)] + pxor mm6, [GLOBAL(t80)] + movq [rsi+rax], mm6 + movq [rsi], mm3 + + ; roughly 2/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7); + ; s = vp8_signed_char_clamp(qs1 - u); + ; *oq1 = s^0x80; + ; s = vp8_signed_char_clamp(ps1 + u); + ; *op1 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [GLOBAL(s18)] + pmulhw mm2, [GLOBAL(s18)] + paddw mm1, [GLOBAL(s63)] + paddw mm2, [GLOBAL(s63)] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + movq mm3, [rdi] + movq mm6, [rsi+rax*2] ; p1 + + pxor mm3, [GLOBAL(t80)] + pxor mm6, [GLOBAL(t80)] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [GLOBAL(t80)] + pxor mm3, [GLOBAL(t80)] + movq [rdi], mm3 + movq [rsi+rax*2], mm6 + + ; roughly 1/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7); + ; s = vp8_signed_char_clamp(qs2 - u); + ; *oq2 = s^0x80; + ; s = vp8_signed_char_clamp(ps2 + u); + ; *op2 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [GLOBAL(s9)] + pmulhw mm2, [GLOBAL(s9)] + paddw mm1, [GLOBAL(s63)] + paddw mm2, [GLOBAL(s63)] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + + movq mm6, [rdi+rax*4] + neg rax + movq mm3, [rdi+rax ] + + pxor mm6, [GLOBAL(t80)] + pxor mm3, [GLOBAL(t80)] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [GLOBAL(t80)] + pxor mm3, [GLOBAL(t80)] + movq [rdi+rax ], mm3 + neg rax + movq [rdi+rax*4], mm6 + +;EARLY_BREAK_OUT: + neg rax + add rsi,8 + dec rcx + jnz .next8_mbh + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_vertical_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_mbloop_filter_vertical_edge_mmx) +sym(vp8_mbloop_filter_vertical_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 96 ; reserve 96 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + %define srct [rsp + 32] ;__declspec(align(16)) char srct[64]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4 - 4] + + movsxd rcx, dword ptr arg(5) ;count +.next8_mbv: + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + + ;transpose + movq mm0, [rdi+2*rax] ; 77 76 75 74 73 72 71 70 + movq mm6, [rsi+2*rax] ; 67 66 65 64 63 62 61 60 + + movq mm7, mm6 ; 77 76 75 74 73 72 71 70 + punpckhbw mm7, mm0 ; 77 67 76 66 75 65 74 64 + + punpcklbw mm6, mm0 ; 73 63 72 62 71 61 70 60 + movq mm0, [rsi+rax] ; 57 56 55 54 53 52 51 50 + + movq mm4, [rsi] ; 47 46 45 44 43 42 41 40 + movq mm5, mm4 ; 47 46 45 44 43 42 41 40 + + punpckhbw mm5, mm0 ; 57 47 56 46 55 45 54 44 + punpcklbw mm4, mm0 ; 53 43 52 42 51 41 50 40 + + movq mm3, mm5 ; 57 47 56 46 55 45 54 44 + punpckhwd mm5, mm7 ; 77 67 57 47 76 66 56 46 + + punpcklwd mm3, mm7 ; 75 65 55 45 74 64 54 44 + movq mm2, mm4 ; 53 43 52 42 51 41 50 40 + + punpckhwd mm4, mm6 ; 73 63 53 43 72 62 52 42 + punpcklwd mm2, mm6 ; 71 61 51 41 70 60 50 40 + + neg rax + + movq mm7, [rsi+rax] ; 37 36 35 34 33 32 31 30 + movq mm6, [rsi+rax*2] ; 27 26 25 24 23 22 21 20 + + movq mm1, mm6 ; 27 26 25 24 23 22 21 20 + punpckhbw mm6, mm7 ; 37 27 36 36 35 25 34 24 + + punpcklbw mm1, mm7 ; 33 23 32 22 31 21 30 20 + + movq mm7, [rsi+rax*4]; ; 07 06 05 04 03 02 01 00 + punpckhbw mm7, [rdi+rax*4] ; 17 07 16 06 15 05 14 04 + + movq mm0, mm7 ; 17 07 16 06 15 05 14 04 + punpckhwd mm7, mm6 ; 37 27 17 07 36 26 16 06 + + punpcklwd mm0, mm6 ; 35 25 15 05 34 24 14 04 + movq mm6, mm7 ; 37 27 17 07 36 26 16 06 + + punpckhdq mm7, mm5 ; 77 67 57 47 37 27 17 07 = q3 + punpckldq mm6, mm5 ; 76 66 56 46 36 26 16 06 = q2 + + lea rdx, srct + movq mm5, mm6 ; 76 66 56 46 36 26 16 06 + + movq [rdx+56], mm7 + psubusb mm5, mm7 ; q2-q3 + + + movq [rdx+48], mm6 + psubusb mm7, mm6 ; q3-q2 + + por mm7, mm5; ; mm7=abs (q3-q2) + movq mm5, mm0 ; 35 25 15 05 34 24 14 04 + + punpckhdq mm5, mm3 ; 75 65 55 45 35 25 15 05 = q1 + punpckldq mm0, mm3 ; 74 64 54 44 34 24 15 04 = q0 + + movq mm3, mm5 ; 75 65 55 45 35 25 15 05 = q1 + psubusb mm3, mm6 ; q1-q2 + + psubusb mm6, mm5 ; q2-q1 + por mm6, mm3 ; mm6=abs(q2-q1) + + movq [rdx+40], mm5 ; save q1 + movq [rdx+32], mm0 ; save q0 + + movq mm3, [rsi+rax*4] ; 07 06 05 04 03 02 01 00 + punpcklbw mm3, [rdi+rax*4] ; 13 03 12 02 11 01 10 00 + + movq mm0, mm3 ; 13 03 12 02 11 01 10 00 + punpcklwd mm0, mm1 ; 31 21 11 01 30 20 10 00 + + punpckhwd mm3, mm1 ; 33 23 13 03 32 22 12 02 + movq mm1, mm0 ; 31 21 11 01 30 20 10 00 + + punpckldq mm0, mm2 ; 70 60 50 40 30 20 10 00 =p3 + punpckhdq mm1, mm2 ; 71 61 51 41 31 21 11 01 =p2 + + movq [rdx], mm0 ; save p3 + movq [rdx+8], mm1 ; save p2 + + movq mm2, mm1 ; 71 61 51 41 31 21 11 01 =p2 + psubusb mm2, mm0 ; p2-p3 + + psubusb mm0, mm1 ; p3-p2 + por mm0, mm2 ; mm0=abs(p3-p2) + + movq mm2, mm3 ; 33 23 13 03 32 22 12 02 + punpckldq mm2, mm4 ; 72 62 52 42 32 22 12 02 = p1 + + punpckhdq mm3, mm4 ; 73 63 53 43 33 23 13 03 = p0 + movq [rdx+24], mm3 ; save p0 + + movq [rdx+16], mm2 ; save p1 + movq mm5, mm2 ; mm5 = p1 + + psubusb mm2, mm1 ; p1-p2 + psubusb mm1, mm5 ; p2-p1 + + por mm1, mm2 ; mm1=abs(p2-p1) + mov rdx, arg(3) ;limit + + movq mm4, [rdx] ; mm4 = limit + psubusb mm7, mm4 ; abs(q3-q2) > limit + + psubusb mm0, mm4 ; abs(p3-p2) > limit + psubusb mm1, mm4 ; abs(p2-p1) > limit + + psubusb mm6, mm4 ; abs(q2-q1) > limit + por mm7, mm6 ; or + + por mm0, mm1 ; + por mm0, mm7 ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit + + movq mm1, mm5 ; p1 + + movq mm7, mm3 ; mm3=mm7=p0 + psubusb mm7, mm5 ; p0 - p1 + + psubusb mm5, mm3 ; p1 - p0 + por mm5, mm7 ; abs(p1-p0) + + movq t0, mm5 ; save abs(p1-p0) + lea rdx, srct + + psubusb mm5, mm4 ; mm5 = abs(p1-p0) > limit + por mm0, mm5 ; mm0=mask + + movq mm5, [rdx+32] ; mm5=q0 + movq mm7, [rdx+40] ; mm7=q1 + + movq mm6, mm5 ; mm6=q0 + movq mm2, mm7 ; q1 + psubusb mm5, mm7 ; q0-q1 + + psubusb mm7, mm6 ; q1-q0 + por mm7, mm5 ; abs(q1-q0) + + movq t1, mm7 ; save abs(q1-q0) + psubusb mm7, mm4 ; mm7=abs(q1-q0)> limit + + por mm0, mm7 ; mask + + movq mm5, mm2 ; q1 + psubusb mm5, mm1 ; q1-=p1 + psubusb mm1, mm2 ; p1-=q1 + por mm5, mm1 ; abs(p1-q1) + pand mm5, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw mm5, 1 ; abs(p1-q1)/2 + + mov rdx, arg(2) ;blimit ; + + movq mm4, [rdx] ;blimit + movq mm1, mm3 ; mm1=mm3=p0 + + movq mm7, mm6 ; mm7=mm6=q0 + psubusb mm1, mm7 ; p0-q0 + + psubusb mm7, mm3 ; q0-p0 + por mm1, mm7 ; abs(q0-p0) + paddusb mm1, mm1 ; abs(q0-p0)*2 + paddusb mm1, mm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + psubusb mm1, mm4 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > blimit + por mm1, mm0; ; mask + + pxor mm0, mm0 + pcmpeqb mm1, mm0 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] + ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 ; abs(q1 - q0) > thresh + + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 ; abs(p1 - p0)> thresh + + por mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb mm4, mm0 + + pcmpeqb mm0, mm0 + pxor mm4, mm0 + + + + + ; start work on filters + lea rdx, srct + + ; start work on filters + movq mm2, [rdx+16] ; p1 + movq mm7, [rdx+40] ; q1 + pxor mm2, [GLOBAL(t80)] ; p1 offset to convert to signed values + pxor mm7, [GLOBAL(t80)] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + + movq mm6, [rdx+24] ; p0 + movq mm0, [rdx+32] ; q0 + pxor mm6, [GLOBAL(t80)] ; offset to convert to signed values + pxor mm0, [GLOBAL(t80)] ; offset to convert to signed values + + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; 1 * (q0 - p0) + (p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + paddsb mm2, mm0 ; 3 * (q0 - p0) + (p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + + ; mm1 = vp8_filter, mm4=hev, mm6=ps0, mm3=qs0 + movq mm2, mm1 ; vp8_filter + pand mm2, mm4; ; Filter2 = vp8_filter & hev + + movq mm5, mm2 ; + paddsb mm5, [GLOBAL(t3)]; + + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm5 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm5 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + movq mm5, mm0 ; Filter2 + + paddsb mm2, [GLOBAL(t4)] ; vp8_signed_char_clamp(Filter2 + 4) + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm2 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm2 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + ; mm0= filter2 mm1 = vp8_filter, mm3 =qs0 mm5=s mm4 =hev mm6=ps0 + psubsb mm3, mm0 ; qs0 =qs0 - filter1 + paddsb mm6, mm5 ; ps0 =ps0 + Fitler2 + + ; mm1=vp8_filter, mm3=qs0, mm4 =hev mm6=ps0 + ; vp8_filter &= ~hev; + ; Filter2 = vp8_filter; + pandn mm4, mm1 ; vp8_filter&=~hev + + + ; mm3=qs0, mm4=filter2, mm6=ps0 + + ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7); + ; s = vp8_signed_char_clamp(qs0 - u); + ; *oq0 = s^0x80; + ; s = vp8_signed_char_clamp(ps0 + u); + ; *op0 = s^0x80; + pxor mm0, mm0 + + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [GLOBAL(s27)] + pmulhw mm2, [GLOBAL(s27)] + paddw mm1, [GLOBAL(s63)] + paddw mm2, [GLOBAL(s63)] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + psubsb mm3, mm1 + paddsb mm6, mm1 + + pxor mm3, [GLOBAL(t80)] + pxor mm6, [GLOBAL(t80)] + movq [rdx+24], mm6 + movq [rdx+32], mm3 + + ; roughly 2/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7); + ; s = vp8_signed_char_clamp(qs1 - u); + ; *oq1 = s^0x80; + ; s = vp8_signed_char_clamp(ps1 + u); + ; *op1 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [GLOBAL(s18)] + pmulhw mm2, [GLOBAL(s18)] + paddw mm1, [GLOBAL(s63)] + paddw mm2, [GLOBAL(s63)] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + movq mm3, [rdx + 40] + movq mm6, [rdx + 16] ; p1 + pxor mm3, [GLOBAL(t80)] + pxor mm6, [GLOBAL(t80)] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [GLOBAL(t80)] + pxor mm3, [GLOBAL(t80)] + movq [rdx + 40], mm3 + movq [rdx + 16], mm6 + + ; roughly 1/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7); + ; s = vp8_signed_char_clamp(qs2 - u); + ; *oq2 = s^0x80; + ; s = vp8_signed_char_clamp(ps2 + u); + ; *op2 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [GLOBAL(s9)] + pmulhw mm2, [GLOBAL(s9)] + paddw mm1, [GLOBAL(s63)] + paddw mm2, [GLOBAL(s63)] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + movq mm6, [rdx+ 8] + movq mm3, [rdx+48] + + pxor mm6, [GLOBAL(t80)] + pxor mm3, [GLOBAL(t80)] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [GLOBAL(t80)] ; mm6 = 71 61 51 41 31 21 11 01 + pxor mm3, [GLOBAL(t80)] ; mm3 = 76 66 56 46 36 26 15 06 + + ; tranpose and write back + movq mm0, [rdx] ; mm0 = 70 60 50 40 30 20 10 00 + movq mm1, mm0 ; mm0 = 70 60 50 40 30 20 10 00 + + punpcklbw mm0, mm6 ; mm0 = 31 30 21 20 11 10 01 00 + punpckhbw mm1, mm6 ; mm3 = 71 70 61 60 51 50 41 40 + + movq mm2, [rdx+16] ; mm2 = 72 62 52 42 32 22 12 02 + movq mm6, mm2 ; mm3 = 72 62 52 42 32 22 12 02 + + punpcklbw mm2, [rdx+24] ; mm2 = 33 32 23 22 13 12 03 02 + punpckhbw mm6, [rdx+24] ; mm3 = 73 72 63 62 53 52 43 42 + + movq mm5, mm0 ; mm5 = 31 30 21 20 11 10 01 00 + punpcklwd mm0, mm2 ; mm0 = 13 12 11 10 03 02 01 00 + + punpckhwd mm5, mm2 ; mm5 = 33 32 31 30 23 22 21 20 + movq mm4, mm1 ; mm4 = 71 70 61 60 51 50 41 40 + + punpcklwd mm1, mm6 ; mm1 = 53 52 51 50 43 42 41 40 + punpckhwd mm4, mm6 ; mm4 = 73 72 71 70 63 62 61 60 + + movq mm2, [rdx+32] ; mm2 = 74 64 54 44 34 24 14 04 + punpcklbw mm2, [rdx+40] ; mm2 = 35 34 25 24 15 14 05 04 + + movq mm6, mm3 ; mm6 = 76 66 56 46 36 26 15 06 + punpcklbw mm6, [rdx+56] ; mm6 = 37 36 27 26 17 16 07 06 + + movq mm7, mm2 ; mm7 = 35 34 25 24 15 14 05 04 + punpcklwd mm2, mm6 ; mm2 = 17 16 15 14 07 06 05 04 + + punpckhwd mm7, mm6 ; mm7 = 37 36 35 34 27 26 25 24 + movq mm6, mm0 ; mm6 = 13 12 11 10 03 02 01 00 + + punpckldq mm0, mm2 ; mm0 = 07 06 05 04 03 02 01 00 + punpckhdq mm6, mm2 ; mm6 = 17 16 15 14 13 12 11 10 + + movq [rsi+rax*4], mm0 ; write out + movq [rdi+rax*4], mm6 ; write out + + movq mm0, mm5 ; mm0 = 33 32 31 30 23 22 21 20 + punpckldq mm0, mm7 ; mm0 = 27 26 25 24 23 22 20 20 + + punpckhdq mm5, mm7 ; mm5 = 37 36 35 34 33 32 31 30 + movq [rsi+rax*2], mm0 ; write out + + movq [rdi+rax*2], mm5 ; write out + movq mm2, [rdx+32] ; mm2 = 74 64 54 44 34 24 14 04 + + punpckhbw mm2, [rdx+40] ; mm2 = 75 74 65 64 54 54 45 44 + punpckhbw mm3, [rdx+56] ; mm3 = 77 76 67 66 57 56 47 46 + + movq mm5, mm2 ; mm5 = 75 74 65 64 54 54 45 44 + punpcklwd mm2, mm3 ; mm2 = 57 56 55 54 47 46 45 44 + + punpckhwd mm5, mm3 ; mm5 = 77 76 75 74 67 66 65 64 + movq mm0, mm1 ; mm0= 53 52 51 50 43 42 41 40 + + movq mm3, mm4 ; mm4 = 73 72 71 70 63 62 61 60 + punpckldq mm0, mm2 ; mm0 = 47 46 45 44 43 42 41 40 + + punpckhdq mm1, mm2 ; mm1 = 57 56 55 54 53 52 51 50 + movq [rsi], mm0 ; write out + + movq [rdi], mm1 ; write out + neg rax + + punpckldq mm3, mm5 ; mm3 = 67 66 65 64 63 62 61 60 + punpckhdq mm4, mm5 ; mm4 = 77 76 75 74 73 72 71 60 + + movq [rsi+rax*2], mm3 + movq [rdi+rax*2], mm4 + + lea rsi, [rsi+rax*8] + dec rcx + + jnz .next8_mbv + + add rsp, 96 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_horizontal_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit +;) +global sym(vp8_loop_filter_simple_horizontal_edge_mmx) +sym(vp8_loop_filter_simple_horizontal_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + mov rcx, 2 ; count +.nexts8_h: + mov rdx, arg(2) ;blimit ; get blimit + movq mm3, [rdx] ; + + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + neg rax + + ; calculate mask + movq mm1, [rsi+2*rax] ; p1 + movq mm0, [rdi] ; q1 + movq mm2, mm1 + movq mm7, mm0 + movq mm4, mm0 + psubusb mm0, mm1 ; q1-=p1 + psubusb mm1, mm4 ; p1-=q1 + por mm1, mm0 ; abs(p1-q1) + pand mm1, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw mm1, 1 ; abs(p1-q1)/2 + + movq mm5, [rsi+rax] ; p0 + movq mm4, [rsi] ; q0 + movq mm0, mm4 ; q0 + movq mm6, mm5 ; p0 + psubusb mm5, mm4 ; p0-=q0 + psubusb mm4, mm6 ; q0-=p0 + por mm5, mm4 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm1 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + psubusb mm5, mm3 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > blimit + pxor mm3, mm3 + pcmpeqb mm5, mm3 + + ; start work on filters + pxor mm2, [GLOBAL(t80)] ; p1 offset to convert to signed values + pxor mm7, [GLOBAL(t80)] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + + pxor mm6, [GLOBAL(t80)] ; offset to convert to signed values + pxor mm0, [GLOBAL(t80)] ; offset to convert to signed values + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; p1 - q1 + 1 * (q0 - p0) + paddsb mm2, mm0 ; p1 - q1 + 2 * (q0 - p0) + paddsb mm2, mm0 ; p1 - q1 + 3 * (q0 - p0) + pand mm5, mm2 ; mask filter values we don't care about + + ; do + 4 side + paddsb mm5, [GLOBAL(t4)] ; 3* (q0 - p0) + (p1 - q1) + 4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + movq mm1, mm5 ; get a copy of filters + psraw mm1, 11 ; arithmetic shift right 11 + psllw mm1, 8 ; shift left 8 to put it back + + por mm0, mm1 ; put the two together to get result + + psubsb mm3, mm0 ; q0-= q0 add + pxor mm3, [GLOBAL(t80)] ; unoffset + movq [rsi], mm3 ; write back + + + ; now do +3 side + psubsb mm5, [GLOBAL(t1s)] ; +3 instead of +4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + psraw mm5, 11 ; arithmetic shift right 11 + psllw mm5, 8 ; shift left 8 to put it back + por mm0, mm5 ; put the two together to get result + + + paddsb mm6, mm0 ; p0+= p0 add + pxor mm6, [GLOBAL(t80)] ; unoffset + movq [rsi+rax], mm6 ; write back + + add rsi,8 + neg rax + dec rcx + jnz .nexts8_h + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_vertical_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit +;) +global sym(vp8_loop_filter_simple_vertical_edge_mmx) +sym(vp8_loop_filter_simple_vertical_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4- 2]; ; + mov rcx, 2 ; count +.nexts8_v: + + lea rdi, [rsi + rax]; + movd mm0, [rdi + rax * 2] ; xx xx xx xx 73 72 71 70 + + movd mm6, [rsi + rax * 2] ; xx xx xx xx 63 62 61 60 + punpcklbw mm6, mm0 ; 73 63 72 62 71 61 70 60 + + movd mm0, [rsi + rax] ; xx xx xx xx 53 52 51 50 + movd mm4, [rsi] ; xx xx xx xx 43 42 41 40 + + punpcklbw mm4, mm0 ; 53 43 52 42 51 41 50 40 + movq mm5, mm4 ; 53 43 52 42 51 41 50 40 + + punpcklwd mm4, mm6 ; 71 61 51 41 70 60 50 40 + punpckhwd mm5, mm6 ; 73 63 53 43 72 62 52 42 + + neg rax + + movd mm7, [rsi + rax] ; xx xx xx xx 33 32 31 30 + movd mm6, [rsi + rax * 2] ; xx xx xx xx 23 22 21 20 + + punpcklbw mm6, mm7 ; 33 23 32 22 31 21 30 20 + movd mm1, [rdi + rax * 4] ; xx xx xx xx 13 12 11 10 + + movd mm0, [rsi + rax * 4] ; xx xx xx xx 03 02 01 00 + punpcklbw mm0, mm1 ; 13 03 12 02 11 01 10 00 + + movq mm2, mm0 ; 13 03 12 02 11 01 10 00 + punpcklwd mm0, mm6 ; 31 21 11 01 30 20 10 00 + + punpckhwd mm2, mm6 ; 33 23 13 03 32 22 12 02 + movq mm1, mm0 ; 13 03 12 02 11 01 10 00 + + punpckldq mm0, mm4 ; 70 60 50 40 30 20 10 00 = p1 + movq mm3, mm2 ; 33 23 13 03 32 22 12 02 + + punpckhdq mm1, mm4 ; 71 61 51 41 31 21 11 01 = p0 + punpckldq mm2, mm5 ; 72 62 52 42 32 22 12 02 = q0 + + punpckhdq mm3, mm5 ; 73 63 53 43 33 23 13 03 = q1 + + + ; calculate mask + movq mm6, mm0 ; p1 + movq mm7, mm3 ; q1 + psubusb mm7, mm6 ; q1-=p1 + psubusb mm6, mm3 ; p1-=q1 + por mm6, mm7 ; abs(p1-q1) + pand mm6, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw mm6, 1 ; abs(p1-q1)/2 + + movq mm5, mm1 ; p0 + movq mm4, mm2 ; q0 + + psubusb mm5, mm2 ; p0-=q0 + psubusb mm4, mm1 ; q0-=p0 + + por mm5, mm4 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm6 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;blimit ; get blimit + movq mm7, [rdx] + + psubusb mm5, mm7 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > blimit + pxor mm7, mm7 + pcmpeqb mm5, mm7 ; mm5 = mask + + ; start work on filters + movq t0, mm0 + movq t1, mm3 + + pxor mm0, [GLOBAL(t80)] ; p1 offset to convert to signed values + pxor mm3, [GLOBAL(t80)] ; q1 offset to convert to signed values + + psubsb mm0, mm3 ; p1 - q1 + movq mm6, mm1 ; p0 + + movq mm7, mm2 ; q0 + pxor mm6, [GLOBAL(t80)] ; offset to convert to signed values + + pxor mm7, [GLOBAL(t80)] ; offset to convert to signed values + movq mm3, mm7 ; offseted ; q0 + + psubsb mm7, mm6 ; q0 - p0 + paddsb mm0, mm7 ; p1 - q1 + 1 * (q0 - p0) + + paddsb mm0, mm7 ; p1 - q1 + 2 * (q0 - p0) + paddsb mm0, mm7 ; p1 - q1 + 3 * (q0 - p0) + + pand mm5, mm0 ; mask filter values we don't care about + + paddsb mm5, [GLOBAL(t4)] ; 3* (q0 - p0) + (p1 - q1) + 4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + + movq mm7, mm5 ; get a copy of filters + psraw mm7, 11 ; arithmetic shift right 11 + psllw mm7, 8 ; shift left 8 to put it back + + por mm0, mm7 ; put the two together to get result + + psubsb mm3, mm0 ; q0-= q0sz add + pxor mm3, [GLOBAL(t80)] ; unoffset + + ; now do +3 side + psubsb mm5, [GLOBAL(t1s)] ; +3 instead of +4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + + psraw mm5, 11 ; arithmetic shift right 11 + psllw mm5, 8 ; shift left 8 to put it back + por mm0, mm5 ; put the two together to get result + + paddsb mm6, mm0 ; p0+= p0 add + pxor mm6, [GLOBAL(t80)] ; unoffset + + + movq mm0, t0 + movq mm4, t1 + + ; mm0 = 70 60 50 40 30 20 10 00 + ; mm6 = 71 61 51 41 31 21 11 01 + ; mm3 = 72 62 52 42 32 22 12 02 + ; mm4 = 73 63 53 43 33 23 13 03 + ; transpose back to write out + + movq mm1, mm0 ; + punpcklbw mm0, mm6 ; 31 30 21 20 11 10 01 00 + + punpckhbw mm1, mm6 ; 71 70 61 60 51 50 41 40 + movq mm2, mm3 ; + + punpcklbw mm2, mm4 ; 33 32 23 22 13 12 03 02 + movq mm5, mm1 ; 71 70 61 60 51 50 41 40 + + punpckhbw mm3, mm4 ; 73 72 63 62 53 52 43 42 + movq mm6, mm0 ; 31 30 21 20 11 10 01 00 + + punpcklwd mm0, mm2 ; 13 12 11 10 03 02 01 00 + punpckhwd mm6, mm2 ; 33 32 31 30 23 22 21 20 + + movd [rsi+rax*4], mm0 ; write 03 02 01 00 + punpcklwd mm1, mm3 ; 53 52 51 50 43 42 41 40 + + psrlq mm0, 32 ; xx xx xx xx 13 12 11 10 + punpckhwd mm5, mm3 ; 73 72 71 70 63 62 61 60 + + movd [rdi+rax*4], mm0 ; write 13 12 11 10 + movd [rsi+rax*2], mm6 ; write 23 22 21 20 + + psrlq mm6, 32 ; 33 32 31 30 + movd [rsi], mm1 ; write 43 42 41 40 + + movd [rsi + rax], mm6 ; write 33 32 31 30 + neg rax + + movd [rsi + rax*2], mm5 ; write 63 62 61 60 + psrlq mm1, 32 ; 53 52 51 50 + + movd [rdi], mm1 ; write out 53 52 51 50 + psrlq mm5, 32 ; 73 72 71 70 + + movd [rdi + rax*2], mm5 ; write 73 72 71 70 + + lea rsi, [rsi+rax*8] ; next 8 + + dec rcx + jnz .nexts8_v + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + +;void fast_loop_filter_vertical_edges_mmx(unsigned char *y_ptr, +; int y_stride, +; loop_filter_info *lfi) +;{ +; +; +; vp8_loop_filter_simple_vertical_edge_mmx(y_ptr+4, y_stride, lfi->flim,lfi->lim,lfi->thr,2); +; vp8_loop_filter_simple_vertical_edge_mmx(y_ptr+8, y_stride, lfi->flim,lfi->lim,lfi->thr,2); +; vp8_loop_filter_simple_vertical_edge_mmx(y_ptr+12, y_stride, lfi->flim,lfi->lim,lfi->thr,2); +;} + +SECTION_RODATA +align 16 +tfe: + times 8 db 0xfe +align 16 +t80: + times 8 db 0x80 +align 16 +t1s: + times 8 db 0x01 +align 16 +t3: + times 8 db 0x03 +align 16 +t4: + times 8 db 0x04 +align 16 +ones: + times 4 dw 0x0001 +align 16 +s27: + times 4 dw 0x1b00 +align 16 +s18: + times 4 dw 0x1200 +align 16 +s9: + times 4 dw 0x0900 +align 16 +s63: + times 4 dw 0x003f diff --git a/vp8/common/x86/loopfilter_sse2.asm b/vp8/common/x86/loopfilter_sse2.asm new file mode 100644 index 0000000..9944c33 --- /dev/null +++ b/vp8/common/x86/loopfilter_sse2.asm @@ -0,0 +1,1640 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +%define _t0 0 +%define _t1 _t0 + 16 +%define _p3 _t1 + 16 +%define _p2 _p3 + 16 +%define _p1 _p2 + 16 +%define _p0 _p1 + 16 +%define _q0 _p0 + 16 +%define _q1 _q0 + 16 +%define _q2 _q1 + 16 +%define _q3 _q2 + 16 +%define lf_var_size 160 + +; Use of pmaxub instead of psubusb to compute filter mask was seen +; in ffvp8 + +%macro LFH_FILTER_AND_HEV_MASK 1 +%if %1 + movdqa xmm2, [rdi+2*rax] ; q3 + movdqa xmm1, [rsi+2*rax] ; q2 + movdqa xmm4, [rsi+rax] ; q1 + movdqa xmm5, [rsi] ; q0 + neg rax ; negate pitch to deal with above border +%else + movlps xmm2, [rsi + rcx*2] ; q3 + movlps xmm1, [rsi + rcx] ; q2 + movlps xmm4, [rsi] ; q1 + movlps xmm5, [rsi + rax] ; q0 + + movhps xmm2, [rdi + rcx*2] + movhps xmm1, [rdi + rcx] + movhps xmm4, [rdi] + movhps xmm5, [rdi + rax] + + lea rsi, [rsi + rax*4] + lea rdi, [rdi + rax*4] + + movdqa [rsp+_q2], xmm1 ; store q2 + movdqa [rsp+_q1], xmm4 ; store q1 +%endif + movdqa xmm7, [rdx] ;limit + + movdqa xmm6, xmm1 ; q2 + movdqa xmm3, xmm4 ; q1 + + psubusb xmm1, xmm2 ; q2-=q3 + psubusb xmm2, xmm6 ; q3-=q2 + + psubusb xmm4, xmm6 ; q1-=q2 + psubusb xmm6, xmm3 ; q2-=q1 + + por xmm4, xmm6 ; abs(q2-q1) + por xmm1, xmm2 ; abs(q3-q2) + + movdqa xmm0, xmm5 ; q0 + pmaxub xmm1, xmm4 + + psubusb xmm5, xmm3 ; q0-=q1 + psubusb xmm3, xmm0 ; q1-=q0 + + por xmm5, xmm3 ; abs(q0-q1) + movdqa [rsp+_t0], xmm5 ; save to t0 + + pmaxub xmm1, xmm5 + +%if %1 + movdqa xmm2, [rsi+4*rax] ; p3 + movdqa xmm4, [rdi+4*rax] ; p2 + movdqa xmm6, [rsi+2*rax] ; p1 +%else + movlps xmm2, [rsi + rax] ; p3 + movlps xmm4, [rsi] ; p2 + movlps xmm6, [rsi + rcx] ; p1 + + movhps xmm2, [rdi + rax] + movhps xmm4, [rdi] + movhps xmm6, [rdi + rcx] + + movdqa [rsp+_p2], xmm4 ; store p2 + movdqa [rsp+_p1], xmm6 ; store p1 +%endif + + movdqa xmm5, xmm4 ; p2 + movdqa xmm3, xmm6 ; p1 + + psubusb xmm4, xmm2 ; p2-=p3 + psubusb xmm2, xmm5 ; p3-=p2 + + psubusb xmm3, xmm5 ; p1-=p2 + pmaxub xmm1, xmm4 ; abs(p3 - p2) + + psubusb xmm5, xmm6 ; p2-=p1 + pmaxub xmm1, xmm2 ; abs(p3 - p2) + + pmaxub xmm1, xmm5 ; abs(p2 - p1) + movdqa xmm2, xmm6 ; p1 + + pmaxub xmm1, xmm3 ; abs(p2 - p1) +%if %1 + movdqa xmm4, [rsi+rax] ; p0 + movdqa xmm3, [rdi] ; q1 +%else + movlps xmm4, [rsi + rcx*2] ; p0 + movhps xmm4, [rdi + rcx*2] + movdqa xmm3, [rsp+_q1] ; q1 +%endif + + movdqa xmm5, xmm4 ; p0 + psubusb xmm4, xmm6 ; p0-=p1 + + psubusb xmm6, xmm5 ; p1-=p0 + + por xmm6, xmm4 ; abs(p1 - p0) + mov rdx, arg(2) ; get blimit + + movdqa [rsp+_t1], xmm6 ; save to t1 + + movdqa xmm4, xmm3 ; q1 + pmaxub xmm1, xmm6 + + psubusb xmm3, xmm2 ; q1-=p1 + psubusb xmm2, xmm4 ; p1-=q1 + + psubusb xmm1, xmm7 + por xmm2, xmm3 ; abs(p1-q1) + + movdqa xmm7, [rdx] ; blimit + mov rdx, arg(4) ; hev get thresh + + movdqa xmm3, xmm0 ; q0 + pand xmm2, [GLOBAL(tfe)] ; set lsb of each byte to zero + + movdqa xmm6, xmm5 ; p0 + psrlw xmm2, 1 ; abs(p1-q1)/2 + + psubusb xmm5, xmm3 ; p0-=q0 + psubusb xmm3, xmm6 ; q0-=p0 + por xmm5, xmm3 ; abs(p0 - q0) + + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + + movdqa xmm4, [rsp+_t0] ; hev get abs (q1 - q0) + movdqa xmm3, [rsp+_t1] ; get abs (p1 - p0) + + paddusb xmm5, xmm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + movdqa xmm2, [rdx] ; hev + + psubusb xmm5, xmm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > blimit + psubusb xmm4, xmm2 ; hev + + psubusb xmm3, xmm2 ; hev + por xmm1, xmm5 + + pxor xmm7, xmm7 + paddb xmm4, xmm3 ; hev abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + + pcmpeqb xmm4, xmm5 ; hev + pcmpeqb xmm3, xmm3 ; hev + + pcmpeqb xmm1, xmm7 ; mask xmm1 + pxor xmm4, xmm3 ; hev +%endmacro + +%macro B_FILTER 1 + movdqa xmm3, [GLOBAL(t80)] +%if %1 == 0 + movdqa xmm2, [rsp+_p1] ; p1 + movdqa xmm7, [rsp+_q1] ; q1 +%elif %1 == 1 + movdqa xmm2, [rsi+2*rax] ; p1 + movdqa xmm7, [rdi] ; q1 +%elif %1 == 2 + movdqa xmm2, [rsp+_p1] ; p1 + movdqa xmm6, [rsp+_p0] ; p0 + movdqa xmm0, [rsp+_q0] ; q0 + movdqa xmm7, [rsp+_q1] ; q1 +%endif + + pxor xmm2, xmm3 ; p1 offset to convert to signed values + pxor xmm7, xmm3 ; q1 offset to convert to signed values + + psubsb xmm2, xmm7 ; p1 - q1 + pxor xmm6, xmm3 ; offset to convert to signed values + + pand xmm2, xmm4 ; high var mask (hvm)(p1 - q1) + pxor xmm0, xmm3 ; offset to convert to signed values + + movdqa xmm3, xmm0 ; q0 + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb xmm2, xmm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + paddsb xmm2, xmm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand xmm1, xmm2 ; mask filter values we don't care about + + movdqa xmm2, xmm1 + paddsb xmm1, [GLOBAL(t4)] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + paddsb xmm2, [GLOBAL(t3)] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + + punpckhbw xmm5, xmm2 ; axbxcxdx + punpcklbw xmm2, xmm2 ; exfxgxhx + + punpcklbw xmm0, xmm1 ; exfxgxhx + psraw xmm5, 11 ; sign extended shift right by 3 + + punpckhbw xmm1, xmm1 ; axbxcxdx + psraw xmm2, 11 ; sign extended shift right by 3 + + packsswb xmm2, xmm5 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + psraw xmm0, 11 ; sign extended shift right by 3 + + psraw xmm1, 11 ; sign extended shift right by 3 + movdqa xmm5, xmm0 ; save results + + packsswb xmm0, xmm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + + paddsb xmm6, xmm2 ; p0+= p0 add + + movdqa xmm2, [GLOBAL(ones)] + paddsw xmm5, xmm2 + paddsw xmm1, xmm2 + psraw xmm5, 1 ; partial shifted one more time for 2nd tap + psraw xmm1, 1 ; partial shifted one more time for 2nd tap + packsswb xmm5, xmm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + movdqa xmm2, [GLOBAL(t80)] + +%if %1 == 0 + movdqa xmm1, [rsp+_p1] ; p1 + lea rsi, [rsi + rcx*2] + lea rdi, [rdi + rcx*2] +%elif %1 == 1 + movdqa xmm1, [rsi+2*rax] ; p1 +%elif %1 == 2 + movdqa xmm1, [rsp+_p1] ; p1 +%endif + + pandn xmm4, xmm5 ; high edge variance additive + pxor xmm6, xmm2 ; unoffset + + pxor xmm1, xmm2 ; reoffset + psubsb xmm3, xmm0 ; q0-= q0 add + + paddsb xmm1, xmm4 ; p1+= p1 add + pxor xmm3, xmm2 ; unoffset + + pxor xmm1, xmm2 ; unoffset + psubsb xmm7, xmm4 ; q1-= q1 add + + pxor xmm7, xmm2 ; unoffset +%if %1 == 0 + movq [rsi], xmm6 ; p0 + movhps [rdi], xmm6 + movq [rsi + rax], xmm1 ; p1 + movhps [rdi + rax], xmm1 + movq [rsi + rcx], xmm3 ; q0 + movhps [rdi + rcx], xmm3 + movq [rsi + rcx*2], xmm7 ; q1 + movhps [rdi + rcx*2], xmm7 +%elif %1 == 1 + movdqa [rsi+rax], xmm6 ; write back + movdqa [rsi+2*rax], xmm1 ; write back + movdqa [rsi], xmm3 ; write back + movdqa [rdi], xmm7 ; write back +%endif + +%endmacro + +%if ABI_IS_32BIT + +;void vp8_loop_filter_horizontal_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +;) +global sym(vp8_loop_filter_horizontal_edge_sse2) +sym(vp8_loop_filter_horizontal_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step + + mov rdx, arg(3) ;limit + + lea rdi, [rsi+rax] ; rdi points to row +1 for indirect addressing + + ; calculate breakout conditions and high edge variance + LFH_FILTER_AND_HEV_MASK 1 + ; filter and write back the result + B_FILTER 1 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +%endif + +;void vp8_loop_filter_horizontal_edge_uv_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_horizontal_edge_uv_sse2) +sym(vp8_loop_filter_horizontal_edge_uv_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ; u + mov rdi, arg(5) ; v + movsxd rax, dword ptr arg(1) ; src_pixel_step + mov rcx, rax + neg rax ; negate pitch to deal with above border + + mov rdx, arg(3) ;limit + + lea rsi, [rsi + rcx] + lea rdi, [rdi + rcx] + + ; calculate breakout conditions and high edge variance + LFH_FILTER_AND_HEV_MASK 0 + ; filter and write back the result + B_FILTER 0 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +%macro MB_FILTER_AND_WRITEBACK 1 + movdqa xmm3, [GLOBAL(t80)] +%if %1 == 0 + movdqa xmm2, [rsp+_p1] ; p1 + movdqa xmm7, [rsp+_q1] ; q1 +%elif %1 == 1 + movdqa xmm2, [rsi+2*rax] ; p1 + movdqa xmm7, [rdi] ; q1 + + mov rcx, rax + neg rcx +%elif %1 == 2 + movdqa xmm2, [rsp+_p1] ; p1 + movdqa xmm6, [rsp+_p0] ; p0 + movdqa xmm0, [rsp+_q0] ; q0 + movdqa xmm7, [rsp+_q1] ; q1 +%endif + + pxor xmm2, xmm3 ; p1 offset to convert to signed values + pxor xmm7, xmm3 ; q1 offset to convert to signed values + pxor xmm6, xmm3 ; offset to convert to signed values + pxor xmm0, xmm3 ; offset to convert to signed values + + psubsb xmm2, xmm7 ; p1 - q1 + + movdqa xmm3, xmm0 ; q0 + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; 1 * (q0 - p0) + (p1 - q1) + paddsb xmm2, xmm0 ; 2 * (q0 - p0) + paddsb xmm2, xmm0 ; 3 * (q0 - p0) + (p1 - q1) + pand xmm1, xmm2 ; mask filter values we don't care about + + movdqa xmm2, xmm1 ; vp8_filter + + pand xmm2, xmm4 ; Filter2 = vp8_filter & hev + pxor xmm0, xmm0 + + pandn xmm4, xmm1 ; vp8_filter&=~hev + pxor xmm1, xmm1 + + punpcklbw xmm0, xmm4 ; Filter 2 (hi) + punpckhbw xmm1, xmm4 ; Filter 2 (lo) + + movdqa xmm5, xmm2 + + movdqa xmm4, [GLOBAL(s9)] + paddsb xmm5, [GLOBAL(t3)] ; vp8_signed_char_clamp(Filter2 + 3) + paddsb xmm2, [GLOBAL(t4)] ; vp8_signed_char_clamp(Filter2 + 4) + + pmulhw xmm1, xmm4 ; Filter 2 (lo) * 9 + pmulhw xmm0, xmm4 ; Filter 2 (hi) * 9 + + punpckhbw xmm7, xmm5 ; axbxcxdx + punpcklbw xmm5, xmm5 ; exfxgxhx + + psraw xmm7, 11 ; sign extended shift right by 3 + + psraw xmm5, 11 ; sign extended shift right by 3 + punpckhbw xmm4, xmm2 ; axbxcxdx + + punpcklbw xmm2, xmm2 ; exfxgxhx + psraw xmm4, 11 ; sign extended shift right by 3 + + packsswb xmm5, xmm7 ; Filter2 >>=3; + psraw xmm2, 11 ; sign extended shift right by 3 + + packsswb xmm2, xmm4 ; Filter1 >>=3; + + paddsb xmm6, xmm5 ; ps0 =ps0 + Fitler2 + + psubsb xmm3, xmm2 ; qs0 =qs0 - Filter1 + movdqa xmm7, xmm1 + + movdqa xmm4, [GLOBAL(s63)] + movdqa xmm5, xmm0 + movdqa xmm2, xmm5 + paddw xmm0, xmm4 ; Filter 2 (hi) * 9 + 63 + paddw xmm1, xmm4 ; Filter 2 (lo) * 9 + 63 + movdqa xmm4, xmm7 + + paddw xmm5, xmm5 ; Filter 2 (hi) * 18 + + paddw xmm7, xmm7 ; Filter 2 (lo) * 18 + paddw xmm5, xmm0 ; Filter 2 (hi) * 27 + 63 + + paddw xmm7, xmm1 ; Filter 2 (lo) * 27 + 63 + paddw xmm2, xmm0 ; Filter 2 (hi) * 18 + 63 + psraw xmm0, 7 ; (Filter 2 (hi) * 9 + 63) >> 7 + + paddw xmm4, xmm1 ; Filter 2 (lo) * 18 + 63 + psraw xmm1, 7 ; (Filter 2 (lo) * 9 + 63) >> 7 + psraw xmm2, 7 ; (Filter 2 (hi) * 18 + 63) >> 7 + + packsswb xmm0, xmm1 ; u1 = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + + psraw xmm4, 7 ; (Filter 2 (lo) * 18 + 63) >> 7 + psraw xmm5, 7 ; (Filter 2 (hi) * 27 + 63) >> 7 + psraw xmm7, 7 ; (Filter 2 (lo) * 27 + 63) >> 7 + + packsswb xmm5, xmm7 ; u3 = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + packsswb xmm2, xmm4 ; u2 = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + movdqa xmm7, [GLOBAL(t80)] + +%if %1 == 0 + movdqa xmm1, [rsp+_q1] ; q1 + movdqa xmm4, [rsp+_p1] ; p1 + lea rsi, [rsi+rcx*2] + lea rdi, [rdi+rcx*2] + +%elif %1 == 1 + movdqa xmm1, [rdi] ; q1 + movdqa xmm4, [rsi+rax*2] ; p1 +%elif %1 == 2 + movdqa xmm4, [rsp+_p1] ; p1 + movdqa xmm1, [rsp+_q1] ; q1 +%endif + + pxor xmm1, xmm7 + pxor xmm4, xmm7 + + psubsb xmm3, xmm5 ; sq = vp8_signed_char_clamp(qs0 - u3) + paddsb xmm6, xmm5 ; sp = vp8_signed_char_clamp(ps0 - u3) + psubsb xmm1, xmm2 ; sq = vp8_signed_char_clamp(qs1 - u2) + paddsb xmm4, xmm2 ; sp = vp8_signed_char_clamp(ps1 - u2) + +%if %1 == 1 + movdqa xmm2, [rdi+rax*4] ; p2 + movdqa xmm5, [rdi+rcx] ; q2 +%else + movdqa xmm2, [rsp+_p2] ; p2 + movdqa xmm5, [rsp+_q2] ; q2 +%endif + + pxor xmm1, xmm7 ; *oq1 = sq^0x80; + pxor xmm4, xmm7 ; *op1 = sp^0x80; + pxor xmm2, xmm7 + pxor xmm5, xmm7 + paddsb xmm2, xmm0 ; sp = vp8_signed_char_clamp(ps2 - u) + psubsb xmm5, xmm0 ; sq = vp8_signed_char_clamp(qs2 - u) + pxor xmm2, xmm7 ; *op2 = sp^0x80; + pxor xmm5, xmm7 ; *oq2 = sq^0x80; + pxor xmm3, xmm7 ; *oq0 = sq^0x80 + pxor xmm6, xmm7 ; *oq0 = sp^0x80 +%if %1 == 0 + movq [rsi], xmm6 ; p0 + movhps [rdi], xmm6 + movq [rsi + rcx], xmm3 ; q0 + movhps [rdi + rcx], xmm3 + lea rdx, [rcx + rcx*2] + movq [rsi+rcx*2], xmm1 ; q1 + movhps [rdi+rcx*2], xmm1 + + movq [rsi + rax], xmm4 ; p1 + movhps [rdi + rax], xmm4 + + movq [rsi+rax*2], xmm2 ; p2 + movhps [rdi+rax*2], xmm2 + + movq [rsi+rdx], xmm5 ; q2 + movhps [rdi+rdx], xmm5 +%elif %1 == 1 + movdqa [rdi+rcx], xmm5 ; q2 + movdqa [rdi], xmm1 ; q1 + movdqa [rsi], xmm3 ; q0 + movdqa [rsi+rax ], xmm6 ; p0 + movdqa [rsi+rax*2], xmm4 ; p1 + movdqa [rdi+rax*4], xmm2 ; p2 +%elif %1 == 2 + movdqa [rsp+_p1], xmm4 ; p1 + movdqa [rsp+_p0], xmm6 ; p0 + movdqa [rsp+_q0], xmm3 ; q0 + movdqa [rsp+_q1], xmm1 ; q1 +%endif + +%endmacro + + +;void vp8_mbloop_filter_horizontal_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +;) +global sym(vp8_mbloop_filter_horizontal_edge_sse2) +sym(vp8_mbloop_filter_horizontal_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step + mov rdx, arg(3) ;limit + + lea rdi, [rsi+rax] ; rdi points to row +1 for indirect addressing + + ; calculate breakout conditions and high edge variance + LFH_FILTER_AND_HEV_MASK 1 + ; filter and write back the results + MB_FILTER_AND_WRITEBACK 1 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_horizontal_edge_uv_sse2 +;( +; unsigned char *u, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; unsigned char *v +;) +global sym(vp8_mbloop_filter_horizontal_edge_uv_sse2) +sym(vp8_mbloop_filter_horizontal_edge_uv_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ; u + mov rdi, arg(5) ; v + movsxd rax, dword ptr arg(1) ; src_pixel_step + mov rcx, rax + neg rax ; negate pitch to deal with above border + mov rdx, arg(3) ;limit + + lea rsi, [rsi + rcx] + lea rdi, [rdi + rcx] + + ; calculate breakout conditions and high edge variance + LFH_FILTER_AND_HEV_MASK 0 + ; filter and write back the results + MB_FILTER_AND_WRITEBACK 0 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +%macro TRANSPOSE_16X8 2 + movq xmm4, [rsi] ; xx xx xx xx xx xx xx xx 07 06 05 04 03 02 01 00 + movq xmm1, [rdi] ; xx xx xx xx xx xx xx xx 17 16 15 14 13 12 11 10 + movq xmm0, [rsi+2*rax] ; xx xx xx xx xx xx xx xx 27 26 25 24 23 22 21 20 + movq xmm7, [rdi+2*rax] ; xx xx xx xx xx xx xx xx 37 36 35 34 33 32 31 30 + movq xmm5, [rsi+4*rax] ; xx xx xx xx xx xx xx xx 47 46 45 44 43 42 41 40 + movq xmm2, [rdi+4*rax] ; xx xx xx xx xx xx xx xx 57 56 55 54 53 52 51 50 + + punpcklbw xmm4, xmm1 ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00 + + movq xmm1, [rdi+2*rcx] ; xx xx xx xx xx xx xx xx 77 76 75 74 73 72 71 70 + + movdqa xmm3, xmm4 ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00 + punpcklbw xmm0, xmm7 ; 37 27 36 36 35 25 34 24 33 23 32 22 31 21 30 20 + + movq xmm7, [rsi+2*rcx] ; xx xx xx xx xx xx xx xx 67 66 65 64 63 62 61 60 + + punpcklbw xmm5, xmm2 ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40 +%if %1 + lea rsi, [rsi+rax*8] + lea rdi, [rdi+rax*8] +%else + mov rsi, arg(5) ; v_ptr +%endif + + movdqa xmm6, xmm5 ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40 + punpcklbw xmm7, xmm1 ; 77 67 76 66 75 65 74 64 73 63 72 62 71 61 70 60 + punpcklwd xmm5, xmm7 ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + punpckhwd xmm6, xmm7 ; 77 67 57 47 76 66 56 46 75 65 55 45 74 64 54 44 + punpcklwd xmm3, xmm0 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + +%if %1 == 0 + lea rdi, [rsi + rax - 4] ; rdi points to row +1 for indirect addressing + lea rsi, [rsi - 4] +%endif + + movdqa xmm2, xmm3 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + punpckhwd xmm4, xmm0 ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04 + + movdqa xmm7, xmm4 ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04 + punpckhdq xmm3, xmm5 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + + punpckhdq xmm7, xmm6 ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06 + + punpckldq xmm4, xmm6 ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04 + + punpckldq xmm2, xmm5 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + + movdqa [rsp+_t0], xmm2 ; save to free XMM2 + + movq xmm2, [rsi] ; xx xx xx xx xx xx xx xx 87 86 85 84 83 82 81 80 + movq xmm6, [rdi] ; xx xx xx xx xx xx xx xx 97 96 95 94 93 92 91 90 + movq xmm0, [rsi+2*rax] ; xx xx xx xx xx xx xx xx a7 a6 a5 a4 a3 a2 a1 a0 + movq xmm5, [rdi+2*rax] ; xx xx xx xx xx xx xx xx b7 b6 b5 b4 b3 b2 b1 b0 + movq xmm1, [rsi+4*rax] ; xx xx xx xx xx xx xx xx c7 c6 c5 c4 c3 c2 c1 c0 + + punpcklbw xmm2, xmm6 ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80 + + movq xmm6, [rdi+4*rax] ; xx xx xx xx xx xx xx xx d7 d6 d5 d4 d3 d2 d1 d0 + + punpcklbw xmm0, xmm5 ; b7 a7 b6 a6 b5 a5 b4 a4 b3 a3 b2 a2 b1 a1 b0 a0 + + movq xmm5, [rsi+2*rcx] ; xx xx xx xx xx xx xx xx e7 e6 e5 e4 e3 e2 e1 e0 + + punpcklbw xmm1, xmm6 ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 e1 d0 c0 + + movq xmm6, [rdi+2*rcx] ; xx xx xx xx xx xx xx xx f7 f6 f5 f4 f3 f2 f1 f0 + + punpcklbw xmm5, xmm6 ; f7 e7 f6 e6 f5 e5 f4 e4 f3 e3 f2 e2 f1 e1 f0 e0 + + movdqa xmm6, xmm1 ; + punpckhwd xmm6, xmm5 ; f7 e7 d7 c7 f6 e6 d6 c6 f5 e5 d5 c5 f4 e4 d4 c4 + + punpcklwd xmm1, xmm5 ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0 + movdqa xmm5, xmm2 ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80 + + punpcklwd xmm5, xmm0 ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80 + + punpckhwd xmm2, xmm0 ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84 + + movdqa xmm0, xmm5 + punpckldq xmm0, xmm1 ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + + punpckhdq xmm5, xmm1 ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + movdqa xmm1, xmm2 ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84 + + punpckldq xmm1, xmm6 ; f5 e5 d5 c5 b5 a5 95 85 f4 e4 d4 c4 b4 a4 94 84 + + punpckhdq xmm2, xmm6 ; f7 e7 d7 c7 b7 a7 97 87 f6 e6 d6 c6 b6 a6 96 86 + movdqa xmm6, xmm7 ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06 + + punpcklqdq xmm6, xmm2 ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06 + + punpckhqdq xmm7, xmm2 ; f7 e7 d7 c7 b7 a7 97 87 77 67 57 47 37 27 17 07 + +%if %2 == 0 + movdqa [rsp+_q3], xmm7 ; save 7 + movdqa [rsp+_q2], xmm6 ; save 6 +%endif + movdqa xmm2, xmm3 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + punpckhqdq xmm3, xmm5 ; f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + punpcklqdq xmm2, xmm5 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + movdqa [rsp+_p1], xmm2 ; save 2 + + movdqa xmm5, xmm4 ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04 + punpcklqdq xmm4, xmm1 ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + movdqa [rsp+_p0], xmm3 ; save 3 + + punpckhqdq xmm5, xmm1 ; f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05 + + movdqa [rsp+_q0], xmm4 ; save 4 + movdqa [rsp+_q1], xmm5 ; save 5 + movdqa xmm1, [rsp+_t0] + + movdqa xmm2, xmm1 ; + punpckhqdq xmm1, xmm0 ; f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + punpcklqdq xmm2, xmm0 ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + +%if %2 == 0 + movdqa [rsp+_p2], xmm1 + movdqa [rsp+_p3], xmm2 +%endif + +%endmacro + +%macro LFV_FILTER_MASK_HEV_MASK 0 + movdqa xmm0, xmm6 ; q2 + psubusb xmm0, xmm7 ; q2-q3 + + psubusb xmm7, xmm6 ; q3-q2 + movdqa xmm4, xmm5 ; q1 + + por xmm7, xmm0 ; abs (q3-q2) + psubusb xmm4, xmm6 ; q1-q2 + + movdqa xmm0, xmm1 + psubusb xmm6, xmm5 ; q2-q1 + + por xmm6, xmm4 ; abs (q2-q1) + psubusb xmm0, xmm2 ; p2 - p3; + + psubusb xmm2, xmm1 ; p3 - p2; + por xmm0, xmm2 ; abs(p2-p3) + + movdqa xmm5, [rsp+_p1] ; p1 + pmaxub xmm0, xmm7 + + movdqa xmm2, xmm5 ; p1 + psubusb xmm5, xmm1 ; p1-p2 + psubusb xmm1, xmm2 ; p2-p1 + + movdqa xmm7, xmm3 ; p0 + psubusb xmm7, xmm2 ; p0-p1 + + por xmm1, xmm5 ; abs(p2-p1) + pmaxub xmm0, xmm6 + + pmaxub xmm0, xmm1 + movdqa xmm1, xmm2 ; p1 + + psubusb xmm2, xmm3 ; p1-p0 + + por xmm2, xmm7 ; abs(p1-p0) + + pmaxub xmm0, xmm2 + + movdqa xmm5, [rsp+_q0] ; q0 + movdqa xmm7, [rsp+_q1] ; q1 + + mov rdx, arg(3) ; limit + + movdqa xmm6, xmm5 ; q0 + movdqa xmm4, xmm7 ; q1 + + psubusb xmm5, xmm7 ; q0-q1 + psubusb xmm7, xmm6 ; q1-q0 + + por xmm7, xmm5 ; abs(q1-q0) + + pmaxub xmm0, xmm7 + + psubusb xmm0, [rdx] ; limit + + mov rdx, arg(2) ; blimit + movdqa xmm5, xmm4 ; q1 + + psubusb xmm5, xmm1 ; q1-=p1 + psubusb xmm1, xmm4 ; p1-=q1 + + por xmm5, xmm1 ; abs(p1-q1) + movdqa xmm1, xmm3 ; p0 + + pand xmm5, [GLOBAL(tfe)] ; set lsb of each byte to zero + psubusb xmm1, xmm6 ; p0-q0 + + movdqa xmm4, [rdx] ; blimit + mov rdx, arg(4) ; get thresh + + psrlw xmm5, 1 ; abs(p1-q1)/2 + psubusb xmm6, xmm3 ; q0-p0 + + por xmm1, xmm6 ; abs(q0-p0) + paddusb xmm1, xmm1 ; abs(q0-p0)*2 + movdqa xmm3, [rdx] + + paddusb xmm1, xmm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + psubusb xmm2, xmm3 ; abs(q1 - q0) > thresh + + psubusb xmm7, xmm3 ; abs(p1 - p0)> thresh + + psubusb xmm1, xmm4 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > blimit + por xmm2, xmm7 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + + por xmm1, xmm0 ; mask + pcmpeqb xmm2, xmm0 + + pxor xmm0, xmm0 + pcmpeqb xmm4, xmm4 + + pcmpeqb xmm1, xmm0 + pxor xmm4, xmm2 +%endmacro + +%macro BV_TRANSPOSE 0 + ; xmm1 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + ; xmm6 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + ; xmm3 = f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + ; xmm7 = f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05 + movdqa xmm2, xmm1 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + punpcklbw xmm2, xmm6 ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + + movdqa xmm4, xmm3 ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + punpckhbw xmm1, xmm6 ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + punpcklbw xmm4, xmm7 ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04 + + punpckhbw xmm3, xmm7 ; f5 f4 e5 e4 d5 d4 c5 c4 b5 b4 a5 a4 95 94 85 84 + + movdqa xmm6, xmm2 ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + punpcklwd xmm2, xmm4 ; 35 34 33 32 25 24 23 22 15 14 13 12 05 04 03 02 + + punpckhwd xmm6, xmm4 ; 75 74 73 72 65 64 63 62 55 54 53 52 45 44 43 42 + movdqa xmm5, xmm1 ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + punpcklwd xmm1, xmm3 ; b5 b4 b3 b2 a5 a4 a3 a2 95 94 93 92 85 84 83 82 + + punpckhwd xmm5, xmm3 ; f5 f4 f3 f2 e5 e4 e3 e2 d5 d4 d3 d2 c5 c4 c3 c2 + ; xmm2 = 35 34 33 32 25 24 23 22 15 14 13 12 05 04 03 02 + ; xmm6 = 75 74 73 72 65 64 63 62 55 54 53 52 45 44 43 42 + ; xmm1 = b5 b4 b3 b2 a5 a4 a3 a2 95 94 93 92 85 84 83 82 + ; xmm5 = f5 f4 f3 f2 e5 e4 e3 e2 d5 d4 d3 d2 c5 c4 c3 c2 +%endmacro + +%macro BV_WRITEBACK 2 + movd [rsi+2], %1 + movd [rsi+4*rax+2], %2 + psrldq %1, 4 + psrldq %2, 4 + movd [rdi+2], %1 + movd [rdi+4*rax+2], %2 + psrldq %1, 4 + psrldq %2, 4 + movd [rsi+2*rax+2], %1 + movd [rsi+2*rcx+2], %2 + psrldq %1, 4 + psrldq %2, 4 + movd [rdi+2*rax+2], %1 + movd [rdi+2*rcx+2], %2 +%endmacro + +%if ABI_IS_32BIT + +;void vp8_loop_filter_vertical_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +;) +global sym(vp8_loop_filter_vertical_edge_sse2) +sym(vp8_loop_filter_vertical_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ; src_ptr + movsxd rax, dword ptr arg(1) ; src_pixel_step + + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + lea rcx, [rax*2+rax] + + ;transpose 16x8 to 8x16, and store the 8-line result on stack. + TRANSPOSE_16X8 1, 1 + + ; calculate filter mask and high edge variance + LFV_FILTER_MASK_HEV_MASK + + ; start work on filters + B_FILTER 2 + + ; tranpose and write back - only work on q1, q0, p0, p1 + BV_TRANSPOSE + ; store 16-line result + + lea rdx, [rax] + neg rdx + + BV_WRITEBACK xmm1, xmm5 + + lea rsi, [rsi+rdx*8] + lea rdi, [rdi+rdx*8] + BV_WRITEBACK xmm2, xmm6 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +%endif + +;void vp8_loop_filter_vertical_edge_uv_sse2 +;( +; unsigned char *u, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; unsigned char *v +;) +global sym(vp8_loop_filter_vertical_edge_uv_sse2) +sym(vp8_loop_filter_vertical_edge_uv_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ; u_ptr + movsxd rax, dword ptr arg(1) ; src_pixel_step + + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + lea rcx, [rax+2*rax] + + ;transpose 16x8 to 8x16, and store the 8-line result on stack. + TRANSPOSE_16X8 0, 1 + + ; calculate filter mask and high edge variance + LFV_FILTER_MASK_HEV_MASK + + ; start work on filters + B_FILTER 2 + + ; tranpose and write back - only work on q1, q0, p0, p1 + BV_TRANSPOSE + + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + + ; store 16-line result + BV_WRITEBACK xmm1, xmm5 + + mov rsi, arg(0) ; u_ptr + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + BV_WRITEBACK xmm2, xmm6 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +%macro MBV_TRANSPOSE 0 + movdqa xmm0, [rsp+_p3] ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + movdqa xmm1, xmm0 ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + + punpcklbw xmm0, xmm2 ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + punpckhbw xmm1, xmm2 ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + + movdqa xmm7, [rsp+_p1] ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + movdqa xmm6, xmm7 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + + punpcklbw xmm7, [rsp+_p0] ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + punpckhbw xmm6, [rsp+_p0] ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + movdqa xmm3, xmm0 ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + punpcklwd xmm0, xmm7 ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + + punpckhwd xmm3, xmm7 ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + movdqa xmm4, xmm1 ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + + punpcklwd xmm1, xmm6 ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + punpckhwd xmm4, xmm6 ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + + movdqa xmm7, [rsp+_q0] ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + punpcklbw xmm7, [rsp+_q1] ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04 + + movdqa xmm6, xmm5 ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06 + punpcklbw xmm6, [rsp+_q3] ; 77 76 67 66 57 56 47 46 37 36 27 26 17 16 07 06 + + movdqa xmm2, xmm7 ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04 + punpcklwd xmm7, xmm6 ; 37 36 35 34 27 26 25 24 17 16 15 14 07 06 05 04 + + punpckhwd xmm2, xmm6 ; 77 76 75 74 67 66 65 64 57 56 55 54 47 46 45 44 + movdqa xmm6, xmm0 ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + + punpckldq xmm0, xmm7 ; 17 16 15 14 13 12 11 10 07 06 05 04 03 02 01 00 + punpckhdq xmm6, xmm7 ; 37 36 35 34 33 32 31 30 27 26 25 24 23 22 21 20 +%endmacro + +%macro MBV_WRITEBACK_1 0 + movq [rsi], xmm0 + movhps [rdi], xmm0 + + movq [rsi+2*rax], xmm6 + movhps [rdi+2*rax], xmm6 + + movdqa xmm0, xmm3 ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + punpckldq xmm0, xmm2 ; 57 56 55 54 53 52 51 50 47 46 45 44 43 42 41 40 + punpckhdq xmm3, xmm2 ; 77 76 75 74 73 72 71 70 67 66 65 64 63 62 61 60 + + movq [rsi+4*rax], xmm0 + movhps [rdi+4*rax], xmm0 + + movq [rsi+2*rcx], xmm3 + movhps [rdi+2*rcx], xmm3 + + movdqa xmm7, [rsp+_q0] ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + punpckhbw xmm7, [rsp+_q1] ; f5 f4 e5 e4 d5 d4 c5 c4 b5 b4 a5 a4 95 94 85 84 + punpckhbw xmm5, [rsp+_q3] ; f7 f6 e7 e6 d7 d6 c7 c6 b7 b6 a7 a6 97 96 87 86 + + movdqa xmm0, xmm7 + punpcklwd xmm0, xmm5 ; b7 b6 b4 b4 a7 a6 a5 a4 97 96 95 94 87 86 85 84 + punpckhwd xmm7, xmm5 ; f7 f6 f5 f4 e7 e6 e5 e4 d7 d6 d5 d4 c7 c6 c5 c4 + + movdqa xmm5, xmm1 ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + punpckldq xmm1, xmm0 ; 97 96 95 94 93 92 91 90 87 86 85 83 84 82 81 80 + punpckhdq xmm5, xmm0 ; b7 b6 b5 b4 b3 b2 b1 b0 a7 a6 a5 a4 a3 a2 a1 a0 +%endmacro + +%macro MBV_WRITEBACK_2 0 + movq [rsi], xmm1 + movhps [rdi], xmm1 + + movq [rsi+2*rax], xmm5 + movhps [rdi+2*rax], xmm5 + + movdqa xmm1, xmm4 ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + punpckldq xmm1, xmm7 ; d7 d6 d5 d4 d3 d2 d1 d0 c7 c6 c5 c4 c3 c2 c1 c0 + punpckhdq xmm4, xmm7 ; f7 f6 f4 f4 f3 f2 f1 f0 e7 e6 e5 e4 e3 e2 e1 e0 + + movq [rsi+4*rax], xmm1 + movhps [rdi+4*rax], xmm1 + + movq [rsi+2*rcx], xmm4 + movhps [rdi+2*rcx], xmm4 +%endmacro + + +;void vp8_mbloop_filter_vertical_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +;) +global sym(vp8_mbloop_filter_vertical_edge_sse2) +sym(vp8_mbloop_filter_vertical_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ; src_ptr + movsxd rax, dword ptr arg(1) ; src_pixel_step + + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + lea rcx, [rax*2+rax] + + ; Transpose + TRANSPOSE_16X8 1, 0 + + ; calculate filter mask and high edge variance + LFV_FILTER_MASK_HEV_MASK + + neg rax + ; start work on filters + MB_FILTER_AND_WRITEBACK 2 + + lea rsi, [rsi+rax*8] + lea rdi, [rdi+rax*8] + + ; transpose and write back + MBV_TRANSPOSE + + neg rax + + MBV_WRITEBACK_1 + + + lea rsi, [rsi+rax*8] + lea rdi, [rdi+rax*8] + MBV_WRITEBACK_2 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_vertical_edge_uv_sse2 +;( +; unsigned char *u, +; int src_pixel_step, +; const char *blimit, +; const char *limit, +; const char *thresh, +; unsigned char *v +;) +global sym(vp8_mbloop_filter_vertical_edge_uv_sse2) +sym(vp8_mbloop_filter_vertical_edge_uv_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, lf_var_size + + mov rsi, arg(0) ; u_ptr + movsxd rax, dword ptr arg(1) ; src_pixel_step + + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + lea rcx, [rax+2*rax] + + ; Transpose + TRANSPOSE_16X8 0, 0 + + ; calculate filter mask and high edge variance + LFV_FILTER_MASK_HEV_MASK + + ; start work on filters + MB_FILTER_AND_WRITEBACK 2 + + ; transpose and write back + MBV_TRANSPOSE + + mov rsi, arg(0) ;u_ptr + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] + MBV_WRITEBACK_1 + mov rsi, arg(5) ;v_ptr + lea rsi, [rsi - 4] + lea rdi, [rsi + rax] + MBV_WRITEBACK_2 + + add rsp, lf_var_size + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_horizontal_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +;) +global sym(vp8_loop_filter_simple_horizontal_edge_sse2) +sym(vp8_loop_filter_simple_horizontal_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + SAVE_XMM 7 + GET_GOT rbx + ; end prolog + + mov rcx, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + movdqa xmm6, [GLOBAL(tfe)] + lea rdx, [rcx + rax] + neg rax + + ; calculate mask + movdqa xmm0, [rdx] ; q1 + mov rdx, arg(2) ;blimit + movdqa xmm1, [rcx+2*rax] ; p1 + + movdqa xmm2, xmm1 + movdqa xmm3, xmm0 + + psubusb xmm0, xmm1 ; q1-=p1 + psubusb xmm1, xmm3 ; p1-=q1 + por xmm1, xmm0 ; abs(p1-q1) + pand xmm1, xmm6 ; set lsb of each byte to zero + psrlw xmm1, 1 ; abs(p1-q1)/2 + + movdqa xmm7, XMMWORD PTR [rdx] + + movdqa xmm5, [rcx+rax] ; p0 + movdqa xmm4, [rcx] ; q0 + movdqa xmm0, xmm4 ; q0 + movdqa xmm6, xmm5 ; p0 + psubusb xmm5, xmm4 ; p0-=q0 + psubusb xmm4, xmm6 ; q0-=p0 + por xmm5, xmm4 ; abs(p0 - q0) + + movdqa xmm4, [GLOBAL(t80)] + + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + paddusb xmm5, xmm1 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + psubusb xmm5, xmm7 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > blimit + pxor xmm7, xmm7 + pcmpeqb xmm5, xmm7 + + + ; start work on filters + pxor xmm2, xmm4 ; p1 offset to convert to signed values + pxor xmm3, xmm4 ; q1 offset to convert to signed values + psubsb xmm2, xmm3 ; p1 - q1 + + pxor xmm6, xmm4 ; offset to convert to signed values + pxor xmm0, xmm4 ; offset to convert to signed values + movdqa xmm3, xmm0 ; q0 + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; p1 - q1 + 1 * (q0 - p0) + paddsb xmm2, xmm0 ; p1 - q1 + 2 * (q0 - p0) + paddsb xmm2, xmm0 ; p1 - q1 + 3 * (q0 - p0) + pand xmm5, xmm2 ; mask filter values we don't care about + + movdqa xmm0, xmm5 + paddsb xmm5, [GLOBAL(t3)] ; 3* (q0 - p0) + (p1 - q1) + 4 + paddsb xmm0, [GLOBAL(t4)] ; +3 instead of +4 + + movdqa xmm1, [GLOBAL(te0)] + movdqa xmm2, [GLOBAL(t1f)] + +; pxor xmm7, xmm7 + pcmpgtb xmm7, xmm0 ;save sign + pand xmm7, xmm1 ;preserve the upper 3 bits + psrlw xmm0, 3 + pand xmm0, xmm2 ;clear out upper 3 bits + por xmm0, xmm7 ;add sign + psubsb xmm3, xmm0 ; q0-= q0sz add + + pxor xmm7, xmm7 + pcmpgtb xmm7, xmm5 ;save sign + pand xmm7, xmm1 ;preserve the upper 3 bits + psrlw xmm5, 3 + pand xmm5, xmm2 ;clear out upper 3 bits + por xmm5, xmm7 ;add sign + paddsb xmm6, xmm5 ; p0+= p0 add + + pxor xmm3, xmm4 ; unoffset + movdqa [rcx], xmm3 ; write back + + pxor xmm6, xmm4 ; unoffset + movdqa [rcx+rax], xmm6 ; write back + + ; begin epilog + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_vertical_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *blimit, +;) +global sym(vp8_loop_filter_simple_vertical_edge_sse2) +sym(vp8_loop_filter_simple_vertical_edge_sse2): + push rbp ; save old base pointer value. + mov rbp, rsp ; set new base pointer value. + SHADOW_ARGS_TO_STACK 3 + SAVE_XMM 7 + GET_GOT rbx ; save callee-saved reg + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[16]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[16]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi - 2 ] + lea rdi, [rsi + rax] + lea rdx, [rsi + rax*4] + lea rcx, [rdx + rax] + + movd xmm0, [rsi] ; (high 96 bits unused) 03 02 01 00 + movd xmm1, [rdx] ; (high 96 bits unused) 43 42 41 40 + movd xmm2, [rdi] ; 13 12 11 10 + movd xmm3, [rcx] ; 53 52 51 50 + punpckldq xmm0, xmm1 ; (high 64 bits unused) 43 42 41 40 03 02 01 00 + punpckldq xmm2, xmm3 ; 53 52 51 50 13 12 11 10 + + movd xmm4, [rsi + rax*2] ; 23 22 21 20 + movd xmm5, [rdx + rax*2] ; 63 62 61 60 + movd xmm6, [rdi + rax*2] ; 33 32 31 30 + movd xmm7, [rcx + rax*2] ; 73 72 71 70 + punpckldq xmm4, xmm5 ; 63 62 61 60 23 22 21 20 + punpckldq xmm6, xmm7 ; 73 72 71 70 33 32 31 30 + + punpcklbw xmm0, xmm2 ; 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00 + punpcklbw xmm4, xmm6 ; 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20 + + movdqa xmm1, xmm0 + punpcklwd xmm0, xmm4 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm4 ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + + movdqa xmm2, xmm0 + punpckldq xmm0, xmm1 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + punpckhdq xmm2, xmm1 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + + lea rsi, [rsi + rax*8] + lea rdi, [rsi + rax] + lea rdx, [rsi + rax*4] + lea rcx, [rdx + rax] + + movd xmm4, [rsi] ; 83 82 81 80 + movd xmm1, [rdx] ; c3 c2 c1 c0 + movd xmm6, [rdi] ; 93 92 91 90 + movd xmm3, [rcx] ; d3 d2 d1 d0 + punpckldq xmm4, xmm1 ; c3 c2 c1 c0 83 82 81 80 + punpckldq xmm6, xmm3 ; d3 d2 d1 d0 93 92 91 90 + + movd xmm1, [rsi + rax*2] ; a3 a2 a1 a0 + movd xmm5, [rdx + rax*2] ; e3 e2 e1 e0 + movd xmm3, [rdi + rax*2] ; b3 b2 b1 b0 + movd xmm7, [rcx + rax*2] ; f3 f2 f1 f0 + punpckldq xmm1, xmm5 ; e3 e2 e1 e0 a3 a2 a1 a0 + punpckldq xmm3, xmm7 ; f3 f2 f1 f0 b3 b2 b1 b0 + + punpcklbw xmm4, xmm6 ; d3 c3 d2 c2 d1 c1 d0 c0 93 83 92 82 91 81 90 80 + punpcklbw xmm1, xmm3 ; f3 e3 f2 e2 f1 e1 f0 e0 b3 a3 b2 a2 b1 a1 b0 a0 + + movdqa xmm7, xmm4 + punpcklwd xmm4, xmm1 ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80 + punpckhwd xmm7, xmm1 ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0 + + movdqa xmm6, xmm4 + punpckldq xmm4, xmm7 ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + punpckhdq xmm6, xmm7 ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + + punpcklqdq xmm0, xmm4 ; p1 f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + punpckhqdq xmm1, xmm4 ; p0 f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + punpcklqdq xmm2, xmm6 ; q0 f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + punpckhqdq xmm3, xmm6 ; q1 f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + + mov rdx, arg(2) ;blimit + + ; calculate mask + movdqa xmm6, xmm0 ; p1 + movdqa xmm7, xmm3 ; q1 + psubusb xmm7, xmm0 ; q1-=p1 + psubusb xmm6, xmm3 ; p1-=q1 + por xmm6, xmm7 ; abs(p1-q1) + pand xmm6, [GLOBAL(tfe)] ; set lsb of each byte to zero + psrlw xmm6, 1 ; abs(p1-q1)/2 + + movdqa xmm7, [rdx] + + movdqa xmm5, xmm1 ; p0 + movdqa xmm4, xmm2 ; q0 + psubusb xmm5, xmm2 ; p0-=q0 + psubusb xmm4, xmm1 ; q0-=p0 + por xmm5, xmm4 ; abs(p0 - q0) + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + paddusb xmm5, xmm6 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + movdqa xmm4, [GLOBAL(t80)] + + psubusb xmm5, xmm7 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > blimit + pxor xmm7, xmm7 + pcmpeqb xmm5, xmm7 ; mm5 = mask + + ; start work on filters + movdqa t0, xmm0 + movdqa t1, xmm3 + + pxor xmm0, xmm4 ; p1 offset to convert to signed values + pxor xmm3, xmm4 ; q1 offset to convert to signed values + psubsb xmm0, xmm3 ; p1 - q1 + + pxor xmm1, xmm4 ; offset to convert to signed values + pxor xmm2, xmm4 ; offset to convert to signed values + + movdqa xmm3, xmm2 ; offseted ; q0 + psubsb xmm2, xmm1 ; q0 - p0 + paddsb xmm0, xmm2 ; p1 - q1 + 1 * (q0 - p0) + paddsb xmm0, xmm2 ; p1 - q1 + 2 * (q0 - p0) + paddsb xmm0, xmm2 ; p1 - q1 + 3 * (q0 - p0) + pand xmm5, xmm0 ; mask filter values we don't care about + + movdqa xmm0, xmm5 + paddsb xmm5, [GLOBAL(t3)] ; 3* (q0 - p0) + (p1 - q1) + 4 + paddsb xmm0, [GLOBAL(t4)] ; +3 instead of +4 + + movdqa xmm6, [GLOBAL(te0)] + movdqa xmm2, [GLOBAL(t1f)] + +; pxor xmm7, xmm7 + pcmpgtb xmm7, xmm0 ;save sign + pand xmm7, xmm6 ;preserve the upper 3 bits + psrlw xmm0, 3 + pand xmm0, xmm2 ;clear out upper 3 bits + por xmm0, xmm7 ;add sign + psubsb xmm3, xmm0 ; q0-= q0sz add + + pxor xmm7, xmm7 + pcmpgtb xmm7, xmm5 ;save sign + pand xmm7, xmm6 ;preserve the upper 3 bits + psrlw xmm5, 3 + pand xmm5, xmm2 ;clear out upper 3 bits + por xmm5, xmm7 ;add sign + paddsb xmm1, xmm5 ; p0+= p0 add + + pxor xmm3, xmm4 ; unoffset q0 + pxor xmm1, xmm4 ; unoffset p0 + + movdqa xmm0, t0 ; p1 + movdqa xmm4, t1 ; q1 + + ; write out order: xmm0 xmm2 xmm1 xmm3 + lea rdx, [rsi + rax*4] + + ; transpose back to write out + ; p1 f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + ; p0 f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + ; q0 f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + ; q1 f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + movdqa xmm6, xmm0 + punpcklbw xmm0, xmm1 ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + punpckhbw xmm6, xmm1 ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + + movdqa xmm5, xmm3 + punpcklbw xmm3, xmm4 ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + punpckhbw xmm5, xmm4 ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + movdqa xmm2, xmm0 + punpcklwd xmm0, xmm3 ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + punpckhwd xmm2, xmm3 ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + + movdqa xmm3, xmm6 + punpcklwd xmm6, xmm5 ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + punpckhwd xmm3, xmm5 ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + + movd [rsi], xmm6 ; write the second 8-line result + movd [rdx], xmm3 + psrldq xmm6, 4 + psrldq xmm3, 4 + movd [rdi], xmm6 + movd [rcx], xmm3 + psrldq xmm6, 4 + psrldq xmm3, 4 + movd [rsi + rax*2], xmm6 + movd [rdx + rax*2], xmm3 + psrldq xmm6, 4 + psrldq xmm3, 4 + movd [rdi + rax*2], xmm6 + movd [rcx + rax*2], xmm3 + + neg rax + lea rsi, [rsi + rax*8] + neg rax + lea rdi, [rsi + rax] + lea rdx, [rsi + rax*4] + lea rcx, [rdx + rax] + + movd [rsi], xmm0 ; write the first 8-line result + movd [rdx], xmm2 + psrldq xmm0, 4 + psrldq xmm2, 4 + movd [rdi], xmm0 + movd [rcx], xmm2 + psrldq xmm0, 4 + psrldq xmm2, 4 + movd [rsi + rax*2], xmm0 + movd [rdx + rax*2], xmm2 + psrldq xmm0, 4 + psrldq xmm2, 4 + movd [rdi + rax*2], xmm0 + movd [rcx + rax*2], xmm2 + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +tfe: + times 16 db 0xfe +align 16 +t80: + times 16 db 0x80 +align 16 +t1s: + times 16 db 0x01 +align 16 +t3: + times 16 db 0x03 +align 16 +t4: + times 16 db 0x04 +align 16 +ones: + times 8 dw 0x0001 +align 16 +s9: + times 8 dw 0x0900 +align 16 +s63: + times 8 dw 0x003f +align 16 +te0: + times 16 db 0xe0 +align 16 +t1f: + times 16 db 0x1f diff --git a/vp8/common/x86/loopfilter_x86.c b/vp8/common/x86/loopfilter_x86.c new file mode 100644 index 0000000..6586004 --- /dev/null +++ b/vp8/common/x86/loopfilter_x86.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vp8/common/loopfilter.h" + +#define prototype_loopfilter(sym) \ + void sym(unsigned char *src, int pitch, const unsigned char *blimit,\ + const unsigned char *limit, const unsigned char *thresh, int count) + +#define prototype_loopfilter_nc(sym) \ + void sym(unsigned char *src, int pitch, const unsigned char *blimit,\ + const unsigned char *limit, const unsigned char *thresh) + +#define prototype_simple_loopfilter(sym) \ + void sym(unsigned char *y, int ystride, const unsigned char *blimit) + +prototype_loopfilter(vp8_mbloop_filter_vertical_edge_mmx); +prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_mmx); +prototype_loopfilter(vp8_loop_filter_vertical_edge_mmx); +prototype_loopfilter(vp8_loop_filter_horizontal_edge_mmx); +prototype_simple_loopfilter(vp8_loop_filter_simple_horizontal_edge_mmx); +prototype_simple_loopfilter(vp8_loop_filter_simple_vertical_edge_mmx); + +#if HAVE_SSE2 && ARCH_X86_64 +prototype_loopfilter(vp8_loop_filter_bv_y_sse2); +prototype_loopfilter(vp8_loop_filter_bh_y_sse2); +#else +prototype_loopfilter_nc(vp8_loop_filter_vertical_edge_sse2); +prototype_loopfilter_nc(vp8_loop_filter_horizontal_edge_sse2); +#endif +prototype_loopfilter_nc(vp8_mbloop_filter_vertical_edge_sse2); +prototype_loopfilter_nc(vp8_mbloop_filter_horizontal_edge_sse2); + +extern loop_filter_uvfunction vp8_loop_filter_horizontal_edge_uv_sse2; +extern loop_filter_uvfunction vp8_loop_filter_vertical_edge_uv_sse2; +extern loop_filter_uvfunction vp8_mbloop_filter_horizontal_edge_uv_sse2; +extern loop_filter_uvfunction vp8_mbloop_filter_vertical_edge_uv_sse2; + +#if HAVE_MMX +/* Horizontal MB filtering */ +void vp8_loop_filter_mbh_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_mbloop_filter_horizontal_edge_mmx(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_mmx(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_mmx(v_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); +} + + +/* Vertical MB Filtering */ +void vp8_loop_filter_mbv_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_mbloop_filter_vertical_edge_mmx(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_mmx(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_mmx(v_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, 1); +} + + +/* Horizontal B Filtering */ +void vp8_loop_filter_bh_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_loop_filter_horizontal_edge_mmx(y_ptr + 4 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_horizontal_edge_mmx(y_ptr + 8 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_horizontal_edge_mmx(y_ptr + 12 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_mmx(u_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_mmx(v_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); +} + + +void vp8_loop_filter_bhs_mmx(unsigned char *y_ptr, int y_stride, const unsigned char *blimit) +{ + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr + 4 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr + 8 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr + 12 * y_stride, y_stride, blimit); +} + + +/* Vertical B Filtering */ +void vp8_loop_filter_bv_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_loop_filter_vertical_edge_mmx(y_ptr + 4, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_vertical_edge_mmx(y_ptr + 8, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + vp8_loop_filter_vertical_edge_mmx(y_ptr + 12, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_mmx(u_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_mmx(v_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, 1); +} + + +void vp8_loop_filter_bvs_mmx(unsigned char *y_ptr, int y_stride, const unsigned char *blimit) +{ + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr + 4, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr + 8, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr + 12, y_stride, blimit); +} +#endif + + +/* Horizontal MB filtering */ +#if HAVE_SSE2 +void vp8_loop_filter_mbh_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_mbloop_filter_horizontal_edge_sse2(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_uv_sse2(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, v_ptr); +} + + +/* Vertical MB Filtering */ +void vp8_loop_filter_mbv_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ + vp8_mbloop_filter_vertical_edge_sse2(y_ptr, y_stride, lfi->mblim, lfi->lim, lfi->hev_thr); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_uv_sse2(u_ptr, uv_stride, lfi->mblim, lfi->lim, lfi->hev_thr, v_ptr); +} + + +/* Horizontal B Filtering */ +void vp8_loop_filter_bh_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ +#if ARCH_X86_64 + vp8_loop_filter_bh_y_sse2(y_ptr, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); +#else + vp8_loop_filter_horizontal_edge_sse2(y_ptr + 4 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr); + vp8_loop_filter_horizontal_edge_sse2(y_ptr + 8 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr); + vp8_loop_filter_horizontal_edge_sse2(y_ptr + 12 * y_stride, y_stride, lfi->blim, lfi->lim, lfi->hev_thr); +#endif + + if (u_ptr) + vp8_loop_filter_horizontal_edge_uv_sse2(u_ptr + 4 * uv_stride, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, v_ptr + 4 * uv_stride); +} + + +void vp8_loop_filter_bhs_sse2(unsigned char *y_ptr, int y_stride, const unsigned char *blimit) +{ + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr + 4 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr + 8 * y_stride, y_stride, blimit); + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr + 12 * y_stride, y_stride, blimit); +} + + +/* Vertical B Filtering */ +void vp8_loop_filter_bv_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi) +{ +#if ARCH_X86_64 + vp8_loop_filter_bv_y_sse2(y_ptr, y_stride, lfi->blim, lfi->lim, lfi->hev_thr, 2); +#else + vp8_loop_filter_vertical_edge_sse2(y_ptr + 4, y_stride, lfi->blim, lfi->lim, lfi->hev_thr); + vp8_loop_filter_vertical_edge_sse2(y_ptr + 8, y_stride, lfi->blim, lfi->lim, lfi->hev_thr); + vp8_loop_filter_vertical_edge_sse2(y_ptr + 12, y_stride, lfi->blim, lfi->lim, lfi->hev_thr); +#endif + + if (u_ptr) + vp8_loop_filter_vertical_edge_uv_sse2(u_ptr + 4, uv_stride, lfi->blim, lfi->lim, lfi->hev_thr, v_ptr + 4); +} + + +void vp8_loop_filter_bvs_sse2(unsigned char *y_ptr, int y_stride, const unsigned char *blimit) +{ + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 4, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 8, y_stride, blimit); + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 12, y_stride, blimit); +} + +#endif diff --git a/vp8/common/x86/mfqe_sse2.asm b/vp8/common/x86/mfqe_sse2.asm new file mode 100644 index 0000000..10d21f3 --- /dev/null +++ b/vp8/common/x86/mfqe_sse2.asm @@ -0,0 +1,281 @@ +; +; Copyright (c) 2012 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_filter_by_weight16x16_sse2 +;( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride, +; int src_weight +;) +global sym(vp8_filter_by_weight16x16_sse2) +sym(vp8_filter_by_weight16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movd xmm0, arg(4) ; src_weight + pshuflw xmm0, xmm0, 0x0 ; replicate to all low words + punpcklqdq xmm0, xmm0 ; replicate to all hi words + + movdqa xmm1, [GLOBAL(tMFQE)] + psubw xmm1, xmm0 ; dst_weight + + mov rax, arg(0) ; src + mov rsi, arg(1) ; src_stride + mov rdx, arg(2) ; dst + mov rdi, arg(3) ; dst_stride + + mov rcx, 16 ; loop count + pxor xmm6, xmm6 + +.combine + movdqa xmm2, [rax] + movdqa xmm4, [rdx] + add rax, rsi + + ; src * src_weight + movdqa xmm3, xmm2 + punpcklbw xmm2, xmm6 + punpckhbw xmm3, xmm6 + pmullw xmm2, xmm0 + pmullw xmm3, xmm0 + + ; dst * dst_weight + movdqa xmm5, xmm4 + punpcklbw xmm4, xmm6 + punpckhbw xmm5, xmm6 + pmullw xmm4, xmm1 + pmullw xmm5, xmm1 + + ; sum, round and shift + paddw xmm2, xmm4 + paddw xmm3, xmm5 + paddw xmm2, [GLOBAL(tMFQE_round)] + paddw xmm3, [GLOBAL(tMFQE_round)] + psrlw xmm2, 4 + psrlw xmm3, 4 + + packuswb xmm2, xmm3 + movdqa [rdx], xmm2 + add rdx, rdi + + dec rcx + jnz .combine + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + + ret + +;void vp8_filter_by_weight8x8_sse2 +;( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride, +; int src_weight +;) +global sym(vp8_filter_by_weight8x8_sse2) +sym(vp8_filter_by_weight8x8_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movd xmm0, arg(4) ; src_weight + pshuflw xmm0, xmm0, 0x0 ; replicate to all low words + punpcklqdq xmm0, xmm0 ; replicate to all hi words + + movdqa xmm1, [GLOBAL(tMFQE)] + psubw xmm1, xmm0 ; dst_weight + + mov rax, arg(0) ; src + mov rsi, arg(1) ; src_stride + mov rdx, arg(2) ; dst + mov rdi, arg(3) ; dst_stride + + mov rcx, 8 ; loop count + pxor xmm4, xmm4 + +.combine + movq xmm2, [rax] + movq xmm3, [rdx] + add rax, rsi + + ; src * src_weight + punpcklbw xmm2, xmm4 + pmullw xmm2, xmm0 + + ; dst * dst_weight + punpcklbw xmm3, xmm4 + pmullw xmm3, xmm1 + + ; sum, round and shift + paddw xmm2, xmm3 + paddw xmm2, [GLOBAL(tMFQE_round)] + psrlw xmm2, 4 + + packuswb xmm2, xmm4 + movq [rdx], xmm2 + add rdx, rdi + + dec rcx + jnz .combine + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + + ret + +;void vp8_variance_and_sad_16x16_sse2 | arg +;( +; unsigned char *src1, 0 +; int stride1, 1 +; unsigned char *src2, 2 +; int stride2, 3 +; unsigned int *variance, 4 +; unsigned int *sad, 5 +;) +global sym(vp8_variance_and_sad_16x16_sse2) +sym(vp8_variance_and_sad_16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(0) ; src1 + mov rcx, arg(1) ; stride1 + mov rdx, arg(2) ; src2 + mov rdi, arg(3) ; stride2 + + mov rsi, 16 ; block height + + ; Prep accumulator registers + pxor xmm3, xmm3 ; SAD + pxor xmm4, xmm4 ; sum of src2 + pxor xmm5, xmm5 ; sum of src2^2 + + ; Because we're working with the actual output frames + ; we can't depend on any kind of data alignment. +.accumulate + movdqa xmm0, [rax] ; src1 + movdqa xmm1, [rdx] ; src2 + add rax, rcx ; src1 + stride1 + add rdx, rdi ; src2 + stride2 + + ; SAD(src1, src2) + psadbw xmm0, xmm1 + paddusw xmm3, xmm0 + + ; SUM(src2) + pxor xmm2, xmm2 + psadbw xmm2, xmm1 ; sum src2 by misusing SAD against 0 + paddusw xmm4, xmm2 + + ; pmaddubsw would be ideal if it took two unsigned values. instead, + ; it expects a signed and an unsigned value. so instead we zero extend + ; and operate on words. + pxor xmm2, xmm2 + movdqa xmm0, xmm1 + punpcklbw xmm0, xmm2 + punpckhbw xmm1, xmm2 + pmaddwd xmm0, xmm0 + pmaddwd xmm1, xmm1 + paddd xmm5, xmm0 + paddd xmm5, xmm1 + + sub rsi, 1 + jnz .accumulate + + ; phaddd only operates on adjacent double words. + ; Finalize SAD and store + movdqa xmm0, xmm3 + psrldq xmm0, 8 + paddusw xmm0, xmm3 + paddd xmm0, [GLOBAL(t128)] + psrld xmm0, 8 + + mov rax, arg(5) + movd [rax], xmm0 + + ; Accumulate sum of src2 + movdqa xmm0, xmm4 + psrldq xmm0, 8 + paddusw xmm0, xmm4 + ; Square src2. Ignore high value + pmuludq xmm0, xmm0 + psrld xmm0, 8 + + ; phaddw could be used to sum adjacent values but we want + ; all the values summed. promote to doubles, accumulate, + ; shift and sum + pxor xmm2, xmm2 + movdqa xmm1, xmm5 + punpckldq xmm1, xmm2 + punpckhdq xmm5, xmm2 + paddd xmm1, xmm5 + movdqa xmm2, xmm1 + psrldq xmm1, 8 + paddd xmm1, xmm2 + + psubd xmm1, xmm0 + + ; (variance + 128) >> 8 + paddd xmm1, [GLOBAL(t128)] + psrld xmm1, 8 + mov rax, arg(4) + + movd [rax], xmm1 + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +t128: + ddq 128 +align 16 +tMFQE: ; 1 << MFQE_PRECISION + times 8 dw 0x10 +align 16 +tMFQE_round: ; 1 << (MFQE_PRECISION - 1) + times 8 dw 0x08 + diff --git a/vp8/common/x86/postproc_mmx.asm b/vp8/common/x86/postproc_mmx.asm new file mode 100644 index 0000000..d24f740 --- /dev/null +++ b/vp8/common/x86/postproc_mmx.asm @@ -0,0 +1,579 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define VP8_FILTER_WEIGHT 128 +%define VP8_FILTER_SHIFT 7 + +;void vp8_post_proc_down_and_across_mmx +;( +; unsigned char *src_ptr, +; unsigned char *dst_ptr, +; int src_pixels_per_line, +; int dst_pixels_per_line, +; int rows, +; int cols, +; int flimit +;) +global sym(vp8_post_proc_down_and_across_mmx) +sym(vp8_post_proc_down_and_across_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + ; move the global rd onto the stack, since we don't have enough registers + ; to do PIC addressing + movq mm0, [GLOBAL(rd)] + sub rsp, 8 + movq [rsp], mm0 +%define RD [rsp] +%else +%define RD [GLOBAL(rd)] +%endif + + push rbx + lea rbx, [GLOBAL(Blur)] + movd mm2, dword ptr arg(6) ;flimit + punpcklwd mm2, mm2 + punpckldq mm2, mm2 + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;dst_ptr + + movsxd rcx, DWORD PTR arg(4) ;rows + movsxd rax, DWORD PTR arg(2) ;src_pixels_per_line ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + +.nextrow: + + xor rdx, rdx ; clear out rdx for use as loop counter +.nextcol: + + pxor mm7, mm7 ; mm7 = 00000000 + movq mm6, [rbx + 32 ] ; mm6 = kernel 2 taps + movq mm3, [rsi] ; mm4 = r0 p0..p7 + punpcklbw mm3, mm0 ; mm3 = p0..p3 + movq mm1, mm3 ; mm1 = p0..p3 + pmullw mm3, mm6 ; mm3 *= kernel 2 modifiers + + movq mm6, [rbx + 48] ; mm6 = kernel 3 taps + movq mm5, [rsi + rax] ; mm4 = r1 p0..p7 + punpcklbw mm5, mm0 ; mm5 = r1 p0..p3 + pmullw mm6, mm5 ; mm6 *= p0..p3 * kernel 3 modifiers + paddusw mm3, mm6 ; mm3 += mm6 + + ; thresholding + movq mm7, mm1 ; mm7 = r0 p0..p3 + psubusw mm7, mm5 ; mm7 = r0 p0..p3 - r1 p0..p3 + psubusw mm5, mm1 ; mm5 = r1 p0..p3 - r0 p0..p3 + paddusw mm7, mm5 ; mm7 = abs(r0 p0..p3 - r1 p0..p3) + pcmpgtw mm7, mm2 + + movq mm6, [rbx + 64 ] ; mm6 = kernel 4 modifiers + movq mm5, [rsi + 2*rax] ; mm4 = r2 p0..p7 + punpcklbw mm5, mm0 ; mm5 = r2 p0..p3 + pmullw mm6, mm5 ; mm5 *= kernel 4 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = r0 p0..p3 + psubusw mm6, mm5 ; mm6 = r0 p0..p3 - r2 p0..p3 + psubusw mm5, mm1 ; mm5 = r2 p0..p3 - r2 p0..p3 + paddusw mm6, mm5 ; mm6 = abs(r0 p0..p3 - r2 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + + neg rax + movq mm6, [rbx ] ; kernel 0 taps + movq mm5, [rsi+2*rax] ; mm4 = r-2 p0..p7 + punpcklbw mm5, mm0 ; mm5 = r-2 p0..p3 + pmullw mm6, mm5 ; mm5 *= kernel 0 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = r0 p0..p3 + psubusw mm6, mm5 ; mm6 = p0..p3 - r-2 p0..p3 + psubusw mm5, mm1 ; mm5 = r-2 p0..p3 - p0..p3 + paddusw mm6, mm5 ; mm6 = abs(r0 p0..p3 - r-2 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + movq mm6, [rbx + 16] ; kernel 1 taps + movq mm4, [rsi+rax] ; mm4 = r-1 p0..p7 + punpcklbw mm4, mm0 ; mm4 = r-1 p0..p3 + pmullw mm6, mm4 ; mm4 *= kernel 1 modifiers. + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = r0 p0..p3 + psubusw mm6, mm4 ; mm6 = p0..p3 - r-2 p0..p3 + psubusw mm4, mm1 ; mm5 = r-1 p0..p3 - p0..p3 + paddusw mm6, mm4 ; mm6 = abs(r0 p0..p3 - r-1 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + + paddusw mm3, RD ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + + pand mm1, mm7 ; mm1 select vals > thresh from source + pandn mm7, mm3 ; mm7 select vals < thresh from blurred result + paddusw mm1, mm7 ; combination + + packuswb mm1, mm0 ; pack to bytes + + movd [rdi], mm1 ; + neg rax ; pitch is positive + + + add rsi, 4 + add rdi, 4 + add rdx, 4 + + cmp edx, dword ptr arg(5) ;cols + jl .nextcol + ; done with the all cols, start the across filtering in place + sub rsi, rdx + sub rdi, rdx + + ; dup the first byte into the left border 8 times + movq mm1, [rdi] + punpcklbw mm1, mm1 + punpcklwd mm1, mm1 + punpckldq mm1, mm1 + + mov rdx, -8 + movq [rdi+rdx], mm1 + + ; dup the last byte into the right border + movsxd rdx, dword arg(5) + movq mm1, [rdi + rdx + -1] + punpcklbw mm1, mm1 + punpcklwd mm1, mm1 + punpckldq mm1, mm1 + movq [rdi+rdx], mm1 + + + push rax + xor rdx, rdx + mov rax, [rdi-4]; + +.acrossnextcol: + pxor mm7, mm7 ; mm7 = 00000000 + movq mm6, [rbx + 32 ] ; + movq mm4, [rdi+rdx] ; mm4 = p0..p7 + movq mm3, mm4 ; mm3 = p0..p7 + punpcklbw mm3, mm0 ; mm3 = p0..p3 + movq mm1, mm3 ; mm1 = p0..p3 + pmullw mm3, mm6 ; mm3 *= kernel 2 modifiers + + movq mm6, [rbx + 48] + psrlq mm4, 8 ; mm4 = p1..p7 + movq mm5, mm4 ; mm5 = p1..p7 + punpcklbw mm5, mm0 ; mm5 = p1..p4 + pmullw mm6, mm5 ; mm6 *= p1..p4 * kernel 3 modifiers + paddusw mm3, mm6 ; mm3 += mm6 + + ; thresholding + movq mm7, mm1 ; mm7 = p0..p3 + psubusw mm7, mm5 ; mm7 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm7, mm5 ; mm7 = abs(p0..p3 - p1..p4) + pcmpgtw mm7, mm2 + + movq mm6, [rbx + 64 ] + psrlq mm4, 8 ; mm4 = p2..p7 + movq mm5, mm4 ; mm5 = p2..p7 + punpcklbw mm5, mm0 ; mm5 = p2..p5 + pmullw mm6, mm5 ; mm5 *= kernel 4 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = p0..p3 + psubusw mm6, mm5 ; mm6 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm6, mm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + + movq mm6, [rbx ] + movq mm4, [rdi+rdx-2] ; mm4 = p-2..p5 + movq mm5, mm4 ; mm5 = p-2..p5 + punpcklbw mm5, mm0 ; mm5 = p-2..p1 + pmullw mm6, mm5 ; mm5 *= kernel 0 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = p0..p3 + psubusw mm6, mm5 ; mm6 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm6, mm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + movq mm6, [rbx + 16] + psrlq mm4, 8 ; mm4 = p-1..p5 + punpcklbw mm4, mm0 ; mm4 = p-1..p2 + pmullw mm6, mm4 ; mm4 *= kernel 1 modifiers. + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = p0..p3 + psubusw mm6, mm4 ; mm6 = p0..p3 - p1..p4 + psubusw mm4, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm6, mm4 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + paddusw mm3, RD ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + + pand mm1, mm7 ; mm1 select vals > thresh from source + pandn mm7, mm3 ; mm7 select vals < thresh from blurred result + paddusw mm1, mm7 ; combination + + packuswb mm1, mm0 ; pack to bytes + mov DWORD PTR [rdi+rdx-4], eax ; store previous four bytes + movd eax, mm1 + + add rdx, 4 + cmp edx, dword ptr arg(5) ;cols + jl .acrossnextcol; + + mov DWORD PTR [rdi+rdx-4], eax + pop rax + + ; done with this rwo + add rsi,rax ; next line + movsxd rax, dword ptr arg(3) ;dst_pixels_per_line ; destination pitch? + add rdi,rax ; next destination + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; destination pitch? + + dec rcx ; decrement count + jnz .nextrow ; next row + pop rbx + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%undef RD + + +;void vp8_mbpost_proc_down_mmx(unsigned char *dst, +; int pitch, int rows, int cols,int flimit) +extern sym(vp8_rv) +global sym(vp8_mbpost_proc_down_mmx) +sym(vp8_mbpost_proc_down_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 136 + + ; unsigned char d[16][8] at [rsp] + ; create flimit2 at [rsp+128] + mov eax, dword ptr arg(4) ;flimit + mov [rsp+128], eax + mov [rsp+128+4], eax +%define flimit2 [rsp+128] + +%if ABI_IS_32BIT=0 + lea r8, [GLOBAL(sym(vp8_rv))] +%endif + + ;rows +=8; + add dword ptr arg(2), 8 + + ;for(c=0; c thresh from source + pandn xmm7, xmm3 ; mm7 select vals < thresh from blurred result + paddusw xmm1, xmm7 ; combination + + packuswb xmm1, xmm0 ; pack to bytes + movq QWORD PTR [rdi], xmm1 ; + + neg rax ; pitch is positive + add rsi, 8 + add rdi, 8 + + add rdx, 8 + cmp edx, dword arg(5) ;cols + + jl .nextcol + + ; done with the all cols, start the across filtering in place + sub rsi, rdx + sub rdi, rdx + + + ; dup the first byte into the left border 8 times + movq mm1, [rdi] + punpcklbw mm1, mm1 + punpcklwd mm1, mm1 + punpckldq mm1, mm1 + + mov rdx, -8 + movq [rdi+rdx], mm1 + + ; dup the last byte into the right border + movsxd rdx, dword arg(5) + movq mm1, [rdi + rdx + -1] + punpcklbw mm1, mm1 + punpcklwd mm1, mm1 + punpckldq mm1, mm1 + movq [rdi+rdx], mm1 + + xor rdx, rdx + movq mm0, QWORD PTR [rdi-8]; + +.acrossnextcol: + movq xmm7, QWORD PTR [rdi +rdx -2] + movd xmm4, DWORD PTR [rdi +rdx +6] + + pslldq xmm4, 8 + por xmm4, xmm7 + + movdqa xmm3, xmm4 + psrldq xmm3, 2 + punpcklbw xmm3, xmm0 ; mm3 = p0..p3 + movdqa xmm1, xmm3 ; mm1 = p0..p3 + psllw xmm3, 2 + + + movdqa xmm5, xmm4 + psrldq xmm5, 3 + punpcklbw xmm5, xmm0 ; mm5 = p1..p4 + paddusw xmm3, xmm5 ; mm3 += mm6 + + ; thresholding + movdqa xmm7, xmm1 ; mm7 = p0..p3 + psubusw xmm7, xmm5 ; mm7 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm7, xmm5 ; mm7 = abs(p0..p3 - p1..p4) + pcmpgtw xmm7, xmm2 + + movdqa xmm5, xmm4 + psrldq xmm5, 4 + punpcklbw xmm5, xmm0 ; mm5 = p2..p5 + paddusw xmm3, xmm5 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = p0..p3 + psubusw xmm6, xmm5 ; mm6 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + + movdqa xmm5, xmm4 ; mm5 = p-2..p5 + punpcklbw xmm5, xmm0 ; mm5 = p-2..p1 + paddusw xmm3, xmm5 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = p0..p3 + psubusw xmm6, xmm5 ; mm6 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + psrldq xmm4, 1 ; mm4 = p-1..p5 + punpcklbw xmm4, xmm0 ; mm4 = p-1..p2 + paddusw xmm3, xmm4 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = p0..p3 + psubusw xmm6, xmm4 ; mm6 = p0..p3 - p1..p4 + psubusw xmm4, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm4 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + paddusw xmm3, RD42 ; mm3 += round value + psraw xmm3, 3 ; mm3 /= 8 + + pand xmm1, xmm7 ; mm1 select vals > thresh from source + pandn xmm7, xmm3 ; mm7 select vals < thresh from blurred result + paddusw xmm1, xmm7 ; combination + + packuswb xmm1, xmm0 ; pack to bytes + movq QWORD PTR [rdi+rdx-8], mm0 ; store previous four bytes + movdq2q mm0, xmm1 + + add rdx, 8 + cmp edx, dword arg(5) ;cols + jl .acrossnextcol; + + ; last 8 pixels + movq QWORD PTR [rdi+rdx-8], mm0 + + ; done with this rwo + add rsi,rax ; next line + mov eax, dword arg(3) ;dst_pixels_per_line ; destination pitch? + add rdi,rax ; next destination + mov eax, dword arg(2) ;src_pixels_per_line ; destination pitch? + + dec rcx ; decrement count + jnz .nextrow ; next row + +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + add rsp,16 + pop rsp +%endif + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret +%undef RD42 + + +;void vp8_mbpost_proc_down_xmm(unsigned char *dst, +; int pitch, int rows, int cols,int flimit) +extern sym(vp8_rv) +global sym(vp8_mbpost_proc_down_xmm) +sym(vp8_mbpost_proc_down_xmm): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 128+16 + + ; unsigned char d[16][8] at [rsp] + ; create flimit2 at [rsp+128] + mov eax, dword ptr arg(4) ;flimit + mov [rsp+128], eax + mov [rsp+128+4], eax + mov [rsp+128+8], eax + mov [rsp+128+12], eax +%define flimit4 [rsp+128] + +%if ABI_IS_32BIT=0 + lea r8, [GLOBAL(sym(vp8_rv))] +%endif + + ;rows +=8; + add dword arg(2), 8 + + ;for(c=0; c +#undef rand + +extern int rand(void) +{ + return __rand(); +} +#endif diff --git a/vp8/common/x86/recon_mmx.asm b/vp8/common/x86/recon_mmx.asm new file mode 100644 index 0000000..19c0faf --- /dev/null +++ b/vp8/common/x86/recon_mmx.asm @@ -0,0 +1,274 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;void copy_mem8x8_mmx( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem8x8_mmx) +sym(vp8_copy_mem8x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movq mm0, [rsi] + + movsxd rax, dword ptr arg(1) ;src_stride; + mov rdi, arg(2) ;dst; + + movq mm1, [rsi+rax] + movq mm2, [rsi+rax*2] + + movsxd rcx, dword ptr arg(3) ;dst_stride + lea rsi, [rsi+rax*2] + + movq [rdi], mm0 + add rsi, rax + + movq [rdi+rcx], mm1 + movq [rdi+rcx*2], mm2 + + + lea rdi, [rdi+rcx*2] + movq mm3, [rsi] + + add rdi, rcx + movq mm4, [rsi+rax] + + movq mm5, [rsi+rax*2] + movq [rdi], mm3 + + lea rsi, [rsi+rax*2] + movq [rdi+rcx], mm4 + + movq [rdi+rcx*2], mm5 + lea rdi, [rdi+rcx*2] + + movq mm0, [rsi+rax] + movq mm1, [rsi+rax*2] + + movq [rdi+rcx], mm0 + movq [rdi+rcx*2],mm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void copy_mem8x4_mmx( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem8x4_mmx) +sym(vp8_copy_mem8x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movq mm0, [rsi] + + movsxd rax, dword ptr arg(1) ;src_stride; + mov rdi, arg(2) ;dst; + + movq mm1, [rsi+rax] + movq mm2, [rsi+rax*2] + + movsxd rcx, dword ptr arg(3) ;dst_stride + lea rsi, [rsi+rax*2] + + movq [rdi], mm0 + movq [rdi+rcx], mm1 + + movq [rdi+rcx*2], mm2 + lea rdi, [rdi+rcx*2] + + movq mm3, [rsi+rax] + movq [rdi+rcx], mm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void copy_mem16x16_mmx( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem16x16_mmx) +sym(vp8_copy_mem16x16_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movsxd rax, dword ptr arg(1) ;src_stride; + + mov rdi, arg(2) ;dst; + movsxd rcx, dword ptr arg(3) ;dst_stride + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq [rdi], mm0 + movq [rdi+8], mm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/common/x86/recon_sse2.asm b/vp8/common/x86/recon_sse2.asm new file mode 100644 index 0000000..7b6e3cf --- /dev/null +++ b/vp8/common/x86/recon_sse2.asm @@ -0,0 +1,1080 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void copy_mem16x16_sse2( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem16x16_sse2) +sym(vp8_copy_mem16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movdqu xmm0, [rsi] + + movsxd rax, dword ptr arg(1) ;src_stride; + mov rdi, arg(2) ;dst; + + movdqu xmm1, [rsi+rax] + movdqu xmm2, [rsi+rax*2] + + movsxd rcx, dword ptr arg(3) ;dst_stride + lea rsi, [rsi+rax*2] + + movdqa [rdi], xmm0 + add rsi, rax + + movdqa [rdi+rcx], xmm1 + movdqa [rdi+rcx*2],xmm2 + + lea rdi, [rdi+rcx*2] + movdqu xmm3, [rsi] + + add rdi, rcx + movdqu xmm4, [rsi+rax] + + movdqu xmm5, [rsi+rax*2] + lea rsi, [rsi+rax*2] + + movdqa [rdi], xmm3 + add rsi, rax + + movdqa [rdi+rcx], xmm4 + movdqa [rdi+rcx*2],xmm5 + + lea rdi, [rdi+rcx*2] + movdqu xmm0, [rsi] + + add rdi, rcx + movdqu xmm1, [rsi+rax] + + movdqu xmm2, [rsi+rax*2] + lea rsi, [rsi+rax*2] + + movdqa [rdi], xmm0 + add rsi, rax + + movdqa [rdi+rcx], xmm1 + + movdqa [rdi+rcx*2], xmm2 + movdqu xmm3, [rsi] + + movdqu xmm4, [rsi+rax] + lea rdi, [rdi+rcx*2] + + add rdi, rcx + movdqu xmm5, [rsi+rax*2] + + lea rsi, [rsi+rax*2] + movdqa [rdi], xmm3 + + add rsi, rax + movdqa [rdi+rcx], xmm4 + + movdqa [rdi+rcx*2],xmm5 + movdqu xmm0, [rsi] + + lea rdi, [rdi+rcx*2] + movdqu xmm1, [rsi+rax] + + add rdi, rcx + movdqu xmm2, [rsi+rax*2] + + lea rsi, [rsi+rax*2] + movdqa [rdi], xmm0 + + movdqa [rdi+rcx], xmm1 + movdqa [rdi+rcx*2],xmm2 + + movdqu xmm3, [rsi+rax] + lea rdi, [rdi+rcx*2] + + movdqa [rdi+rcx], xmm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_intra_pred_uv_dc_mmx2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +global sym(vp8_intra_pred_uv_dc_mmx2) +sym(vp8_intra_pred_uv_dc_mmx2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + ; from top + mov rdi, arg(2) ;above; + mov rsi, arg(3) ;left; + movsxd rax, dword ptr arg(4) ;left_stride; + pxor mm0, mm0 + movq mm1, [rdi] + lea rdi, [rax*3] + psadbw mm1, mm0 + ; from left + movzx ecx, byte [rsi] + movzx edx, byte [rsi+rax*1] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + + movzx edx, byte [rsi+rdi] + lea rsi, [rsi+rax*4] + add ecx, edx + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + + ; add up + pextrw edx, mm1, 0x0 + lea edx, [edx+ecx+8] + sar edx, 4 + movd mm1, edx + movsxd rcx, dword ptr arg(1) ;dst_stride + pshufw mm1, mm1, 0x0 + mov rdi, arg(0) ;dst; + packuswb mm1, mm1 + + ; write out + lea rax, [rcx*3] + lea rdx, [rdi+rcx*4] + + movq [rdi ], mm1 + movq [rdi+rcx ], mm1 + movq [rdi+rcx*2], mm1 + movq [rdi+rax ], mm1 + movq [rdx ], mm1 + movq [rdx+rcx ], mm1 + movq [rdx+rcx*2], mm1 + movq [rdx+rax ], mm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_uv_dctop_mmx2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +global sym(vp8_intra_pred_uv_dctop_mmx2) +sym(vp8_intra_pred_uv_dctop_mmx2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;arg(3), arg(4) not used + + ; from top + mov rsi, arg(2) ;above; + pxor mm0, mm0 + movq mm1, [rsi] + psadbw mm1, mm0 + + ; add up + paddw mm1, [GLOBAL(dc_4)] + psraw mm1, 3 + pshufw mm1, mm1, 0x0 + packuswb mm1, mm1 + + ; write out + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + lea rax, [rcx*3] + + movq [rdi ], mm1 + movq [rdi+rcx ], mm1 + movq [rdi+rcx*2], mm1 + movq [rdi+rax ], mm1 + lea rdi, [rdi+rcx*4] + movq [rdi ], mm1 + movq [rdi+rcx ], mm1 + movq [rdi+rcx*2], mm1 + movq [rdi+rax ], mm1 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_uv_dcleft_mmx2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +global sym(vp8_intra_pred_uv_dcleft_mmx2) +sym(vp8_intra_pred_uv_dcleft_mmx2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + ;arg(2) not used + + ; from left + mov rsi, arg(3) ;left; + movsxd rax, dword ptr arg(4) ;left_stride; + lea rdi, [rax*3] + movzx ecx, byte [rsi] + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + lea edx, [ecx+edx+4] + + ; add up + shr edx, 3 + movd mm1, edx + pshufw mm1, mm1, 0x0 + packuswb mm1, mm1 + + ; write out + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + lea rax, [rcx*3] + + movq [rdi ], mm1 + movq [rdi+rcx ], mm1 + movq [rdi+rcx*2], mm1 + movq [rdi+rax ], mm1 + lea rdi, [rdi+rcx*4] + movq [rdi ], mm1 + movq [rdi+rcx ], mm1 + movq [rdi+rcx*2], mm1 + movq [rdi+rax ], mm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_uv_dc128_mmx( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +global sym(vp8_intra_pred_uv_dc128_mmx) +sym(vp8_intra_pred_uv_dc128_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + ; end prolog + + ;arg(2), arg(3), arg(4) not used + + ; write out + movq mm1, [GLOBAL(dc_128)] + mov rax, arg(0) ;dst; + movsxd rdx, dword ptr arg(1) ;dst_stride + lea rcx, [rdx*3] + + movq [rax ], mm1 + movq [rax+rdx ], mm1 + movq [rax+rdx*2], mm1 + movq [rax+rcx ], mm1 + lea rax, [rax+rdx*4] + movq [rax ], mm1 + movq [rax+rdx ], mm1 + movq [rax+rdx*2], mm1 + movq [rax+rcx ], mm1 + + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_uv_tm_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +%macro vp8_intra_pred_uv_tm 1 +global sym(vp8_intra_pred_uv_tm_%1) +sym(vp8_intra_pred_uv_tm_%1): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ; read top row + mov edx, 4 + mov rsi, arg(2) ;above + movsxd rax, dword ptr arg(4) ;left_stride; + pxor xmm0, xmm0 +%ifidn %1, ssse3 + movdqa xmm2, [GLOBAL(dc_1024)] +%endif + movq xmm1, [rsi] + punpcklbw xmm1, xmm0 + + ; set up left ptrs ans subtract topleft + movd xmm3, [rsi-1] + mov rsi, arg(3) ;left; +%ifidn %1, sse2 + punpcklbw xmm3, xmm0 + pshuflw xmm3, xmm3, 0x0 + punpcklqdq xmm3, xmm3 +%else + pshufb xmm3, xmm2 +%endif + psubw xmm1, xmm3 + + ; set up dest ptrs + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + +.vp8_intra_pred_uv_tm_%1_loop: + movd xmm3, [rsi] + movd xmm5, [rsi+rax] +%ifidn %1, sse2 + punpcklbw xmm3, xmm0 + punpcklbw xmm5, xmm0 + pshuflw xmm3, xmm3, 0x0 + pshuflw xmm5, xmm5, 0x0 + punpcklqdq xmm3, xmm3 + punpcklqdq xmm5, xmm5 +%else + pshufb xmm3, xmm2 + pshufb xmm5, xmm2 +%endif + paddw xmm3, xmm1 + paddw xmm5, xmm1 + packuswb xmm3, xmm5 + movq [rdi ], xmm3 + movhps[rdi+rcx], xmm3 + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rcx*2] + dec edx + jnz .vp8_intra_pred_uv_tm_%1_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%endmacro + +vp8_intra_pred_uv_tm sse2 +vp8_intra_pred_uv_tm ssse3 + +;void vp8_intra_pred_uv_ve_mmx( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +global sym(vp8_intra_pred_uv_ve_mmx) +sym(vp8_intra_pred_uv_ve_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + ; end prolog + + ; arg(3), arg(4) not used + + ; read from top + mov rax, arg(2) ;src; + + movq mm1, [rax] + + ; write out + mov rax, arg(0) ;dst; + movsxd rdx, dword ptr arg(1) ;dst_stride + lea rcx, [rdx*3] + + movq [rax ], mm1 + movq [rax+rdx ], mm1 + movq [rax+rdx*2], mm1 + movq [rax+rcx ], mm1 + lea rax, [rax+rdx*4] + movq [rax ], mm1 + movq [rax+rdx ], mm1 + movq [rax+rdx*2], mm1 + movq [rax+rcx ], mm1 + + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_uv_ho_mmx2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +%macro vp8_intra_pred_uv_ho 1 +global sym(vp8_intra_pred_uv_ho_%1) +sym(vp8_intra_pred_uv_ho_%1): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi +%ifidn %1, ssse3 +%ifndef GET_GOT_SAVE_ARG + push rbx +%endif + GET_GOT rbx +%endif + ; end prolog + + ;arg(2) not used + + ; read from left and write out +%ifidn %1, mmx2 + mov edx, 4 +%endif + mov rsi, arg(3) ;left + movsxd rax, dword ptr arg(4) ;left_stride; + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride +%ifidn %1, ssse3 + lea rdx, [rcx*3] + movdqa xmm2, [GLOBAL(dc_00001111)] + lea rbx, [rax*3] +%endif + +%ifidn %1, mmx2 +.vp8_intra_pred_uv_ho_%1_loop: + movd mm0, [rsi] + movd mm1, [rsi+rax] + punpcklbw mm0, mm0 + punpcklbw mm1, mm1 + pshufw mm0, mm0, 0x0 + pshufw mm1, mm1, 0x0 + movq [rdi ], mm0 + movq [rdi+rcx], mm1 + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rcx*2] + dec edx + jnz .vp8_intra_pred_uv_ho_%1_loop +%else + movd xmm0, [rsi] + movd xmm3, [rsi+rax] + movd xmm1, [rsi+rax*2] + movd xmm4, [rsi+rbx] + punpcklbw xmm0, xmm3 + punpcklbw xmm1, xmm4 + pshufb xmm0, xmm2 + pshufb xmm1, xmm2 + movq [rdi ], xmm0 + movhps [rdi+rcx], xmm0 + movq [rdi+rcx*2], xmm1 + movhps [rdi+rdx], xmm1 + lea rsi, [rsi+rax*4] + lea rdi, [rdi+rcx*4] + movd xmm0, [rsi] + movd xmm3, [rsi+rax] + movd xmm1, [rsi+rax*2] + movd xmm4, [rsi+rbx] + punpcklbw xmm0, xmm3 + punpcklbw xmm1, xmm4 + pshufb xmm0, xmm2 + pshufb xmm1, xmm2 + movq [rdi ], xmm0 + movhps [rdi+rcx], xmm0 + movq [rdi+rcx*2], xmm1 + movhps [rdi+rdx], xmm1 +%endif + + ; begin epilog +%ifidn %1, ssse3 + RESTORE_GOT +%ifndef GET_GOT_SAVE_ARG + pop rbx +%endif +%endif + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret +%endmacro + +vp8_intra_pred_uv_ho mmx2 +vp8_intra_pred_uv_ho ssse3 + +;void vp8_intra_pred_y_dc_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +global sym(vp8_intra_pred_y_dc_sse2) +sym(vp8_intra_pred_y_dc_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + ; from top + mov rdi, arg(2) ;above + mov rsi, arg(3) ;left + movsxd rax, dword ptr arg(4) ;left_stride; + + pxor xmm0, xmm0 + movdqa xmm1, [rdi] + psadbw xmm1, xmm0 + movq xmm2, xmm1 + punpckhqdq xmm1, xmm1 + paddw xmm1, xmm2 + + ; from left + lea rdi, [rax*3] + + movzx ecx, byte [rsi] + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + + ; add up + pextrw edx, xmm1, 0x0 + lea edx, [edx+ecx+16] + sar edx, 5 + movd xmm1, edx + ; FIXME use pshufb for ssse3 version + pshuflw xmm1, xmm1, 0x0 + punpcklqdq xmm1, xmm1 + packuswb xmm1, xmm1 + + ; write out + mov rsi, 2 + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + lea rax, [rcx*3] + +.label + movdqa [rdi ], xmm1 + movdqa [rdi+rcx ], xmm1 + movdqa [rdi+rcx*2], xmm1 + movdqa [rdi+rax ], xmm1 + lea rdi, [rdi+rcx*4] + movdqa [rdi ], xmm1 + movdqa [rdi+rcx ], xmm1 + movdqa [rdi+rcx*2], xmm1 + movdqa [rdi+rax ], xmm1 + lea rdi, [rdi+rcx*4] + dec rsi + jnz .label + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_y_dctop_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +global sym(vp8_intra_pred_y_dctop_sse2) +sym(vp8_intra_pred_y_dctop_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + GET_GOT rbx + ; end prolog + + ;arg(3), arg(4) not used + + ; from top + mov rcx, arg(2) ;above; + pxor xmm0, xmm0 + movdqa xmm1, [rcx] + psadbw xmm1, xmm0 + movdqa xmm2, xmm1 + punpckhqdq xmm1, xmm1 + paddw xmm1, xmm2 + + ; add up + paddw xmm1, [GLOBAL(dc_8)] + psraw xmm1, 4 + ; FIXME use pshufb for ssse3 version + pshuflw xmm1, xmm1, 0x0 + punpcklqdq xmm1, xmm1 + packuswb xmm1, xmm1 + + ; write out + mov rsi, 2 + mov rdx, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + lea rax, [rcx*3] + +.label + movdqa [rdx ], xmm1 + movdqa [rdx+rcx ], xmm1 + movdqa [rdx+rcx*2], xmm1 + movdqa [rdx+rax ], xmm1 + lea rdx, [rdx+rcx*4] + movdqa [rdx ], xmm1 + movdqa [rdx+rcx ], xmm1 + movdqa [rdx+rcx*2], xmm1 + movdqa [rdx+rax ], xmm1 + lea rdx, [rdx+rcx*4] + dec rsi + jnz .label + + ; begin epilog + RESTORE_GOT + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_y_dcleft_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +global sym(vp8_intra_pred_y_dcleft_sse2) +sym(vp8_intra_pred_y_dcleft_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + ;arg(2) not used + + ; from left + mov rsi, arg(3) ;left; + movsxd rax, dword ptr arg(4) ;left_stride; + + lea rdi, [rax*3] + movzx ecx, byte [rsi] + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + add ecx, edx + lea rsi, [rsi+rax*4] + movzx edx, byte [rsi] + add ecx, edx + movzx edx, byte [rsi+rax] + add ecx, edx + movzx edx, byte [rsi+rax*2] + add ecx, edx + movzx edx, byte [rsi+rdi] + lea edx, [ecx+edx+8] + + ; add up + shr edx, 4 + movd xmm1, edx + ; FIXME use pshufb for ssse3 version + pshuflw xmm1, xmm1, 0x0 + punpcklqdq xmm1, xmm1 + packuswb xmm1, xmm1 + + ; write out + mov rsi, 2 + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + lea rax, [rcx*3] + +.label + movdqa [rdi ], xmm1 + movdqa [rdi+rcx ], xmm1 + movdqa [rdi+rcx*2], xmm1 + movdqa [rdi+rax ], xmm1 + lea rdi, [rdi+rcx*4] + movdqa [rdi ], xmm1 + movdqa [rdi+rcx ], xmm1 + movdqa [rdi+rcx*2], xmm1 + movdqa [rdi+rax ], xmm1 + lea rdi, [rdi+rcx*4] + dec rsi + jnz .label + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_y_dc128_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +global sym(vp8_intra_pred_y_dc128_sse2) +sym(vp8_intra_pred_y_dc128_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + GET_GOT rbx + ; end prolog + + ;arg(2), arg(3), arg(4) not used + + ; write out + mov rsi, 2 + movdqa xmm1, [GLOBAL(dc_128)] + mov rax, arg(0) ;dst; + movsxd rdx, dword ptr arg(1) ;dst_stride + lea rcx, [rdx*3] + +.label + movdqa [rax ], xmm1 + movdqa [rax+rdx ], xmm1 + movdqa [rax+rdx*2], xmm1 + movdqa [rax+rcx ], xmm1 + lea rax, [rax+rdx*4] + movdqa [rax ], xmm1 + movdqa [rax+rdx ], xmm1 + movdqa [rax+rdx*2], xmm1 + movdqa [rax+rcx ], xmm1 + lea rax, [rax+rdx*4] + dec rsi + jnz .label + + ; begin epilog + RESTORE_GOT + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_y_tm_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +%macro vp8_intra_pred_y_tm 1 +global sym(vp8_intra_pred_y_tm_%1) +sym(vp8_intra_pred_y_tm_%1): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + GET_GOT rbx + ; end prolog + + ; read top row + mov edx, 8 + mov rsi, arg(2) ;above + movsxd rax, dword ptr arg(4) ;left_stride; + pxor xmm0, xmm0 +%ifidn %1, ssse3 + movdqa xmm3, [GLOBAL(dc_1024)] +%endif + movdqa xmm1, [rsi] + movdqa xmm2, xmm1 + punpcklbw xmm1, xmm0 + punpckhbw xmm2, xmm0 + + ; set up left ptrs ans subtract topleft + movd xmm4, [rsi-1] + mov rsi, arg(3) ;left +%ifidn %1, sse2 + punpcklbw xmm4, xmm0 + pshuflw xmm4, xmm4, 0x0 + punpcklqdq xmm4, xmm4 +%else + pshufb xmm4, xmm3 +%endif + psubw xmm1, xmm4 + psubw xmm2, xmm4 + + ; set up dest ptrs + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride +vp8_intra_pred_y_tm_%1_loop: + movd xmm4, [rsi] + movd xmm5, [rsi+rax] +%ifidn %1, sse2 + punpcklbw xmm4, xmm0 + punpcklbw xmm5, xmm0 + pshuflw xmm4, xmm4, 0x0 + pshuflw xmm5, xmm5, 0x0 + punpcklqdq xmm4, xmm4 + punpcklqdq xmm5, xmm5 +%else + pshufb xmm4, xmm3 + pshufb xmm5, xmm3 +%endif + movdqa xmm6, xmm4 + movdqa xmm7, xmm5 + paddw xmm4, xmm1 + paddw xmm6, xmm2 + paddw xmm5, xmm1 + paddw xmm7, xmm2 + packuswb xmm4, xmm6 + packuswb xmm5, xmm7 + movdqa [rdi ], xmm4 + movdqa [rdi+rcx], xmm5 + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rcx*2] + dec edx + jnz vp8_intra_pred_y_tm_%1_loop + + ; begin epilog + RESTORE_GOT + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret +%endmacro + +vp8_intra_pred_y_tm sse2 +vp8_intra_pred_y_tm ssse3 + +;void vp8_intra_pred_y_ve_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride +; ) +global sym(vp8_intra_pred_y_ve_sse2) +sym(vp8_intra_pred_y_ve_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + ; end prolog + + ;arg(3), arg(4) not used + + mov rax, arg(2) ;above; + mov rsi, 2 + movsxd rdx, dword ptr arg(1) ;dst_stride + + ; read from top + movdqa xmm1, [rax] + + ; write out + mov rax, arg(0) ;dst; + lea rcx, [rdx*3] + +.label + movdqa [rax ], xmm1 + movdqa [rax+rdx ], xmm1 + movdqa [rax+rdx*2], xmm1 + movdqa [rax+rcx ], xmm1 + lea rax, [rax+rdx*4] + movdqa [rax ], xmm1 + movdqa [rax+rdx ], xmm1 + movdqa [rax+rdx*2], xmm1 + movdqa [rax+rcx ], xmm1 + lea rax, [rax+rdx*4] + dec rsi + jnz .label + + ; begin epilog + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_intra_pred_y_ho_sse2( +; unsigned char *dst, +; int dst_stride +; unsigned char *above, +; unsigned char *left, +; int left_stride, +; ) +global sym(vp8_intra_pred_y_ho_sse2) +sym(vp8_intra_pred_y_ho_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + ;arg(2) not used + + ; read from left and write out + mov edx, 8 + mov rsi, arg(3) ;left; + movsxd rax, dword ptr arg(4) ;left_stride; + mov rdi, arg(0) ;dst; + movsxd rcx, dword ptr arg(1) ;dst_stride + +vp8_intra_pred_y_ho_sse2_loop: + movd xmm0, [rsi] + movd xmm1, [rsi+rax] + ; FIXME use pshufb for ssse3 version + punpcklbw xmm0, xmm0 + punpcklbw xmm1, xmm1 + pshuflw xmm0, xmm0, 0x0 + pshuflw xmm1, xmm1, 0x0 + punpcklqdq xmm0, xmm0 + punpcklqdq xmm1, xmm1 + movdqa [rdi ], xmm0 + movdqa [rdi+rcx], xmm1 + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rcx*2] + dec edx + jnz vp8_intra_pred_y_ho_sse2_loop + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +dc_128: + times 16 db 128 +dc_4: + times 4 dw 4 +align 16 +dc_8: + times 8 dw 8 +align 16 +dc_1024: + times 8 dw 0x400 +align 16 +dc_00001111: + times 8 db 0 + times 8 db 1 diff --git a/vp8/common/x86/recon_wrapper_sse2.c b/vp8/common/x86/recon_wrapper_sse2.c new file mode 100644 index 0000000..b482faa --- /dev/null +++ b/vp8/common/x86/recon_wrapper_sse2.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/blockd.h" + +#define build_intra_predictors_mbuv_prototype(sym) \ + void sym(unsigned char *dst, int dst_stride, \ + const unsigned char *above, \ + const unsigned char *left, int left_stride) +typedef build_intra_predictors_mbuv_prototype((*build_intra_predictors_mbuv_fn_t)); + +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_dc_mmx2); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_dctop_mmx2); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_dcleft_mmx2); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_dc128_mmx); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_ho_mmx2); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_ho_ssse3); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_ve_mmx); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_tm_sse2); +extern build_intra_predictors_mbuv_prototype(vp8_intra_pred_uv_tm_ssse3); + +static void vp8_build_intra_predictors_mbuv_x86(MACROBLOCKD *x, + unsigned char * uabove_row, + unsigned char * vabove_row, + unsigned char *dst_u, + unsigned char *dst_v, + int dst_stride, + unsigned char * uleft, + unsigned char * vleft, + int left_stride, + build_intra_predictors_mbuv_fn_t tm_func, + build_intra_predictors_mbuv_fn_t ho_func) +{ + int mode = x->mode_info_context->mbmi.uv_mode; + build_intra_predictors_mbuv_fn_t fn; + + switch (mode) { + case V_PRED: fn = vp8_intra_pred_uv_ve_mmx; break; + case H_PRED: fn = ho_func; break; + case TM_PRED: fn = tm_func; break; + case DC_PRED: + if (x->up_available) { + if (x->left_available) { + fn = vp8_intra_pred_uv_dc_mmx2; break; + } else { + fn = vp8_intra_pred_uv_dctop_mmx2; break; + } + } else if (x->left_available) { + fn = vp8_intra_pred_uv_dcleft_mmx2; break; + } else { + fn = vp8_intra_pred_uv_dc128_mmx; break; + } + break; + default: return; + } + + fn(dst_u, dst_stride, uabove_row, uleft, left_stride); + fn(dst_v, dst_stride, vabove_row, vleft, left_stride); +} + +void vp8_build_intra_predictors_mbuv_s_sse2(MACROBLOCKD *x, + unsigned char * uabove_row, + unsigned char * vabove_row, + unsigned char * uleft, + unsigned char * vleft, + int left_stride, + unsigned char * upred_ptr, + unsigned char * vpred_ptr, + int pred_stride) +{ + vp8_build_intra_predictors_mbuv_x86(x, + uabove_row, vabove_row, + upred_ptr, + vpred_ptr, pred_stride, + uleft, + vleft, + left_stride, + vp8_intra_pred_uv_tm_sse2, + vp8_intra_pred_uv_ho_mmx2); +} + +void vp8_build_intra_predictors_mbuv_s_ssse3(MACROBLOCKD *x, + unsigned char * uabove_row, + unsigned char * vabove_row, + unsigned char * uleft, + unsigned char * vleft, + int left_stride, + unsigned char * upred_ptr, + unsigned char * vpred_ptr, + int pred_stride) +{ + vp8_build_intra_predictors_mbuv_x86(x, + uabove_row, vabove_row, + upred_ptr, + vpred_ptr, pred_stride, + uleft, + vleft, + left_stride, + vp8_intra_pred_uv_tm_ssse3, + vp8_intra_pred_uv_ho_ssse3); +} + +#define build_intra_predictors_mby_prototype(sym) \ + void sym(unsigned char *dst, int dst_stride, \ + const unsigned char *above, \ + const unsigned char *left, int left_stride) +typedef build_intra_predictors_mby_prototype((*build_intra_predictors_mby_fn_t)); + +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_dc_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_dctop_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_dcleft_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_dc128_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_ho_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_ve_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_tm_sse2); +extern build_intra_predictors_mby_prototype(vp8_intra_pred_y_tm_ssse3); + +static void vp8_build_intra_predictors_mby_x86(MACROBLOCKD *x, + unsigned char * yabove_row, + unsigned char *dst_y, + int dst_stride, + unsigned char * yleft, + int left_stride, + build_intra_predictors_mby_fn_t tm_func) +{ + int mode = x->mode_info_context->mbmi.mode; + build_intra_predictors_mbuv_fn_t fn; + + switch (mode) { + case V_PRED: fn = vp8_intra_pred_y_ve_sse2; break; + case H_PRED: fn = vp8_intra_pred_y_ho_sse2; break; + case TM_PRED: fn = tm_func; break; + case DC_PRED: + if (x->up_available) { + if (x->left_available) { + fn = vp8_intra_pred_y_dc_sse2; break; + } else { + fn = vp8_intra_pred_y_dctop_sse2; break; + } + } else if (x->left_available) { + fn = vp8_intra_pred_y_dcleft_sse2; break; + } else { + fn = vp8_intra_pred_y_dc128_sse2; break; + } + break; + default: return; + } + + fn(dst_y, dst_stride, yabove_row, yleft, left_stride); + return; +} + +void vp8_build_intra_predictors_mby_s_sse2(MACROBLOCKD *x, + unsigned char * yabove_row, + unsigned char * yleft, + int left_stride, + unsigned char * ypred_ptr, + int y_stride) +{ + vp8_build_intra_predictors_mby_x86(x, yabove_row, ypred_ptr, + y_stride, yleft, left_stride, + vp8_intra_pred_y_tm_sse2); +} + +void vp8_build_intra_predictors_mby_s_ssse3(MACROBLOCKD *x, + unsigned char * yabove_row, + unsigned char * yleft, + int left_stride, + unsigned char * ypred_ptr, + int y_stride) +{ + vp8_build_intra_predictors_mby_x86(x, yabove_row, ypred_ptr, + y_stride, yleft, left_stride, + vp8_intra_pred_y_tm_ssse3); + +} diff --git a/vp8/common/x86/sad_mmx.asm b/vp8/common/x86/sad_mmx.asm new file mode 100644 index 0000000..407b399 --- /dev/null +++ b/vp8/common/x86/sad_mmx.asm @@ -0,0 +1,427 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +global sym(vp8_sad16x16_mmx) +global sym(vp8_sad8x16_mmx) +global sym(vp8_sad8x8_mmx) +global sym(vp8_sad4x4_mmx) +global sym(vp8_sad16x8_mmx) + +;unsigned int vp8_sad16x16_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad16x16_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + + lea rcx, [rcx+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +.x16x16sad_mmx_loop: + + movq mm0, QWORD PTR [rsi] + movq mm2, QWORD PTR [rsi+8] + + movq mm1, QWORD PTR [rdi] + movq mm3, QWORD PTR [rdi+8] + + movq mm4, mm0 + movq mm5, mm2 + + psubusb mm0, mm1 + psubusb mm1, mm4 + + psubusb mm2, mm3 + psubusb mm3, mm5 + + por mm0, mm1 + por mm2, mm3 + + movq mm1, mm0 + movq mm3, mm2 + + punpcklbw mm0, mm6 + punpcklbw mm2, mm6 + + punpckhbw mm1, mm6 + punpckhbw mm3, mm6 + + paddw mm0, mm2 + paddw mm1, mm3 + + + lea rsi, [rsi+rax] + add rdi, rdx + + paddw mm7, mm0 + paddw mm7, mm1 + + cmp rsi, rcx + jne .x16x16sad_mmx_loop + + + movq mm0, mm7 + + punpcklwd mm0, mm6 + punpckhwd mm7, mm6 + + paddw mm0, mm7 + movq mm7, mm0 + + + psrlq mm0, 32 + paddw mm7, mm0 + + movq rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad8x16_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad8x16_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + + lea rcx, [rcx+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +.x8x16sad_mmx_loop: + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + movq mm2, mm0 + psubusb mm0, mm1 + + psubusb mm1, mm2 + por mm0, mm1 + + movq mm2, mm0 + punpcklbw mm0, mm6 + + punpckhbw mm2, mm6 + lea rsi, [rsi+rax] + + add rdi, rdx + paddw mm7, mm0 + + paddw mm7, mm2 + cmp rsi, rcx + + jne .x8x16sad_mmx_loop + + movq mm0, mm7 + punpcklwd mm0, mm6 + + punpckhwd mm7, mm6 + paddw mm0, mm7 + + movq mm7, mm0 + psrlq mm0, 32 + + paddw mm7, mm0 + movq rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad8x8_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad8x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +.x8x8sad_mmx_loop: + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + movq mm2, mm0 + psubusb mm0, mm1 + + psubusb mm1, mm2 + por mm0, mm1 + + movq mm2, mm0 + punpcklbw mm0, mm6 + + punpckhbw mm2, mm6 + paddw mm0, mm2 + + lea rsi, [rsi+rax] + add rdi, rdx + + paddw mm7, mm0 + cmp rsi, rcx + + jne .x8x8sad_mmx_loop + + movq mm0, mm7 + punpcklwd mm0, mm6 + + punpckhwd mm7, mm6 + paddw mm0, mm7 + + movq mm7, mm0 + psrlq mm0, 32 + + paddw mm7, mm0 + movq rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad4x4_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + movd mm0, DWORD PTR [rsi] + movd mm1, DWORD PTR [rdi] + + movd mm2, DWORD PTR [rsi+rax] + movd mm3, DWORD PTR [rdi+rdx] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + movq mm2, mm0 + psubusb mm0, mm1 + + psubusb mm1, mm2 + por mm0, mm1 + + movq mm2, mm0 + pxor mm3, mm3 + + punpcklbw mm0, mm3 + punpckhbw mm2, mm3 + + paddw mm0, mm2 + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + movd mm4, DWORD PTR [rsi] + movd mm5, DWORD PTR [rdi] + + movd mm6, DWORD PTR [rsi+rax] + movd mm7, DWORD PTR [rdi+rdx] + + punpcklbw mm4, mm6 + punpcklbw mm5, mm7 + + movq mm6, mm4 + psubusb mm4, mm5 + + psubusb mm5, mm6 + por mm4, mm5 + + movq mm5, mm4 + punpcklbw mm4, mm3 + + punpckhbw mm5, mm3 + paddw mm4, mm5 + + paddw mm0, mm4 + movq mm1, mm0 + + punpcklwd mm0, mm3 + punpckhwd mm1, mm3 + + paddw mm0, mm1 + movq mm1, mm0 + + psrlq mm0, 32 + paddw mm0, mm1 + + movq rax, mm0 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad16x8_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad16x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +.x16x8sad_mmx_loop: + + movq mm0, [rsi] + movq mm1, [rdi] + + movq mm2, [rsi+8] + movq mm3, [rdi+8] + + movq mm4, mm0 + movq mm5, mm2 + + psubusb mm0, mm1 + psubusb mm1, mm4 + + psubusb mm2, mm3 + psubusb mm3, mm5 + + por mm0, mm1 + por mm2, mm3 + + movq mm1, mm0 + movq mm3, mm2 + + punpcklbw mm0, mm6 + punpckhbw mm1, mm6 + + punpcklbw mm2, mm6 + punpckhbw mm3, mm6 + + + paddw mm0, mm2 + paddw mm1, mm3 + + paddw mm0, mm1 + lea rsi, [rsi+rax] + + add rdi, rdx + paddw mm7, mm0 + + cmp rsi, rcx + jne .x16x8sad_mmx_loop + + movq mm0, mm7 + punpcklwd mm0, mm6 + + punpckhwd mm7, mm6 + paddw mm0, mm7 + + movq mm7, mm0 + psrlq mm0, 32 + + paddw mm7, mm0 + movq rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/common/x86/sad_sse2.asm b/vp8/common/x86/sad_sse2.asm new file mode 100644 index 0000000..0b01d7b --- /dev/null +++ b/vp8/common/x86/sad_sse2.asm @@ -0,0 +1,410 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;unsigned int vp8_sad16x16_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad16x16_wmt) +sym(vp8_sad16x16_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + SAVE_XMM 6 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + + lea rcx, [rcx+rax*8] + pxor xmm6, xmm6 + +.x16x16sad_wmt_loop: + + movq xmm0, QWORD PTR [rsi] + movq xmm2, QWORD PTR [rsi+8] + + movq xmm1, QWORD PTR [rdi] + movq xmm3, QWORD PTR [rdi+8] + + movq xmm4, QWORD PTR [rsi+rax] + movq xmm5, QWORD PTR [rdi+rdx] + + + punpcklbw xmm0, xmm2 + punpcklbw xmm1, xmm3 + + psadbw xmm0, xmm1 + movq xmm2, QWORD PTR [rsi+rax+8] + + movq xmm3, QWORD PTR [rdi+rdx+8] + lea rsi, [rsi+rax*2] + + lea rdi, [rdi+rdx*2] + punpcklbw xmm4, xmm2 + + punpcklbw xmm5, xmm3 + psadbw xmm4, xmm5 + + paddw xmm6, xmm0 + paddw xmm6, xmm4 + + cmp rsi, rcx + jne .x16x16sad_wmt_loop + + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movq rax, xmm0 + + ; begin epilog + pop rdi + pop rsi + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_sad8x16_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int max_sad) +global sym(vp8_sad8x16_wmt) +sym(vp8_sad8x16_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + + lea rcx, [rcx+rbx*8] + pxor mm7, mm7 + +.x8x16sad_wmt_loop: + + movq rax, mm7 + cmp eax, arg(4) + jg .x8x16sad_wmt_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + movq mm2, QWORD PTR [rsi+rbx] + movq mm3, QWORD PTR [rdi+rdx] + + psadbw mm0, mm1 + psadbw mm2, mm3 + + lea rsi, [rsi+rbx*2] + lea rdi, [rdi+rdx*2] + + paddw mm7, mm0 + paddw mm7, mm2 + + cmp rsi, rcx + jne .x8x16sad_wmt_loop + + movq rax, mm7 + +.x8x16sad_wmt_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad8x8_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad8x8_wmt) +sym(vp8_sad8x8_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + pxor mm7, mm7 + +.x8x8sad_wmt_loop: + + movq rax, mm7 + cmp eax, arg(4) + jg .x8x8sad_wmt_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + psadbw mm0, mm1 + lea rsi, [rsi+rbx] + + add rdi, rdx + paddw mm7, mm0 + + cmp rsi, rcx + jne .x8x8sad_wmt_loop + + movq rax, mm7 +.x8x8sad_wmt_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_sad4x4_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad4x4_wmt) +sym(vp8_sad4x4_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + movd mm0, DWORD PTR [rsi] + movd mm1, DWORD PTR [rdi] + + movd mm2, DWORD PTR [rsi+rax] + movd mm3, DWORD PTR [rdi+rdx] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + psadbw mm0, mm1 + lea rsi, [rsi+rax*2] + + lea rdi, [rdi+rdx*2] + movd mm4, DWORD PTR [rsi] + + movd mm5, DWORD PTR [rdi] + movd mm6, DWORD PTR [rsi+rax] + + movd mm7, DWORD PTR [rdi+rdx] + punpcklbw mm4, mm6 + + punpcklbw mm5, mm7 + psadbw mm4, mm5 + + paddw mm0, mm4 + movq rax, mm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad16x8_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad16x8_wmt) +sym(vp8_sad16x8_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + pxor mm7, mm7 + +.x16x8sad_wmt_loop: + + movq rax, mm7 + cmp eax, arg(4) + jg .x16x8sad_wmt_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm2, QWORD PTR [rsi+8] + + movq mm1, QWORD PTR [rdi] + movq mm3, QWORD PTR [rdi+8] + + movq mm4, QWORD PTR [rsi+rbx] + movq mm5, QWORD PTR [rdi+rdx] + + psadbw mm0, mm1 + psadbw mm2, mm3 + + movq mm1, QWORD PTR [rsi+rbx+8] + movq mm3, QWORD PTR [rdi+rdx+8] + + psadbw mm4, mm5 + psadbw mm1, mm3 + + lea rsi, [rsi+rbx*2] + lea rdi, [rdi+rdx*2] + + paddw mm0, mm2 + paddw mm4, mm1 + + paddw mm7, mm0 + paddw mm7, mm4 + + cmp rsi, rcx + jne .x16x8sad_wmt_loop + + movq rax, mm7 + +.x16x8sad_wmt_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_copy32xn_sse2( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *dst_ptr, +; int dst_stride, +; int height); +global sym(vp8_copy32xn_sse2) +sym(vp8_copy32xn_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;dst_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;dst_stride + movsxd rcx, dword ptr arg(4) ;height + +.block_copy_sse2_loopx4: + movdqu xmm0, XMMWORD PTR [rsi] + movdqu xmm1, XMMWORD PTR [rsi + 16] + movdqu xmm2, XMMWORD PTR [rsi + rax] + movdqu xmm3, XMMWORD PTR [rsi + rax + 16] + + lea rsi, [rsi+rax*2] + + movdqu xmm4, XMMWORD PTR [rsi] + movdqu xmm5, XMMWORD PTR [rsi + 16] + movdqu xmm6, XMMWORD PTR [rsi + rax] + movdqu xmm7, XMMWORD PTR [rsi + rax + 16] + + lea rsi, [rsi+rax*2] + + movdqa XMMWORD PTR [rdi], xmm0 + movdqa XMMWORD PTR [rdi + 16], xmm1 + movdqa XMMWORD PTR [rdi + rdx], xmm2 + movdqa XMMWORD PTR [rdi + rdx + 16], xmm3 + + lea rdi, [rdi+rdx*2] + + movdqa XMMWORD PTR [rdi], xmm4 + movdqa XMMWORD PTR [rdi + 16], xmm5 + movdqa XMMWORD PTR [rdi + rdx], xmm6 + movdqa XMMWORD PTR [rdi + rdx + 16], xmm7 + + lea rdi, [rdi+rdx*2] + + sub rcx, 4 + cmp rcx, 4 + jge .block_copy_sse2_loopx4 + + cmp rcx, 0 + je .copy_is_done + +.block_copy_sse2_loop: + movdqu xmm0, XMMWORD PTR [rsi] + movdqu xmm1, XMMWORD PTR [rsi + 16] + lea rsi, [rsi+rax] + + movdqa XMMWORD PTR [rdi], xmm0 + movdqa XMMWORD PTR [rdi + 16], xmm1 + lea rdi, [rdi+rdx] + + sub rcx, 1 + jne .block_copy_sse2_loop + +.copy_is_done: + ; begin epilog + pop rdi + pop rsi + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/common/x86/sad_sse3.asm b/vp8/common/x86/sad_sse3.asm new file mode 100644 index 0000000..c2af3c8 --- /dev/null +++ b/vp8/common/x86/sad_sse3.asm @@ -0,0 +1,960 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + +%include "vpx_ports/x86_abi_support.asm" + +%macro STACK_FRAME_CREATE_X3 0 +%if ABI_IS_32BIT + %define src_ptr rsi + %define src_stride rax + %define ref_ptr rdi + %define ref_stride rdx + %define end_ptr rcx + %define ret_var rbx + %define result_ptr arg(4) + %define max_sad arg(4) + %define height dword ptr arg(4) + push rbp + mov rbp, rsp + push rsi + push rdi + push rbx + + mov rsi, arg(0) ; src_ptr + mov rdi, arg(2) ; ref_ptr + + movsxd rax, dword ptr arg(1) ; src_stride + movsxd rdx, dword ptr arg(3) ; ref_stride +%else + %ifidn __OUTPUT_FORMAT__,x64 + SAVE_XMM 7, u + %define src_ptr rcx + %define src_stride rdx + %define ref_ptr r8 + %define ref_stride r9 + %define end_ptr r10 + %define ret_var r11 + %define result_ptr [rsp+xmm_stack_space+8+4*8] + %define max_sad [rsp+xmm_stack_space+8+4*8] + %define height dword ptr [rsp+xmm_stack_space+8+4*8] + %else + %define src_ptr rdi + %define src_stride rsi + %define ref_ptr rdx + %define ref_stride rcx + %define end_ptr r9 + %define ret_var r10 + %define result_ptr r8 + %define max_sad r8 + %define height r8 + %endif +%endif + +%endmacro + +%macro STACK_FRAME_DESTROY_X3 0 + %define src_ptr + %define src_stride + %define ref_ptr + %define ref_stride + %define end_ptr + %define ret_var + %define result_ptr + %define max_sad + %define height + +%if ABI_IS_32BIT + pop rbx + pop rdi + pop rsi + pop rbp +%else + %ifidn __OUTPUT_FORMAT__,x64 + RESTORE_XMM + %endif +%endif + ret +%endmacro + +%macro STACK_FRAME_CREATE_X4 0 +%if ABI_IS_32BIT + %define src_ptr rsi + %define src_stride rax + %define r0_ptr rcx + %define r1_ptr rdx + %define r2_ptr rbx + %define r3_ptr rdi + %define ref_stride rbp + %define result_ptr arg(4) + push rbp + mov rbp, rsp + push rsi + push rdi + push rbx + + push rbp + mov rdi, arg(2) ; ref_ptr_base + + LOAD_X4_ADDRESSES rdi, rcx, rdx, rax, rdi + + mov rsi, arg(0) ; src_ptr + + movsxd rbx, dword ptr arg(1) ; src_stride + movsxd rbp, dword ptr arg(3) ; ref_stride + + xchg rbx, rax +%else + %ifidn __OUTPUT_FORMAT__,x64 + SAVE_XMM 7, u + %define src_ptr rcx + %define src_stride rdx + %define r0_ptr rsi + %define r1_ptr r10 + %define r2_ptr r11 + %define r3_ptr r8 + %define ref_stride r9 + %define result_ptr [rsp+xmm_stack_space+16+4*8] + push rsi + + LOAD_X4_ADDRESSES r8, r0_ptr, r1_ptr, r2_ptr, r3_ptr + %else + %define src_ptr rdi + %define src_stride rsi + %define r0_ptr r9 + %define r1_ptr r10 + %define r2_ptr r11 + %define r3_ptr rdx + %define ref_stride rcx + %define result_ptr r8 + + LOAD_X4_ADDRESSES rdx, r0_ptr, r1_ptr, r2_ptr, r3_ptr + + %endif +%endif +%endmacro + +%macro STACK_FRAME_DESTROY_X4 0 + %define src_ptr + %define src_stride + %define r0_ptr + %define r1_ptr + %define r2_ptr + %define r3_ptr + %define ref_stride + %define result_ptr + +%if ABI_IS_32BIT + pop rbx + pop rdi + pop rsi + pop rbp +%else + %ifidn __OUTPUT_FORMAT__,x64 + pop rsi + RESTORE_XMM + %endif +%endif + ret +%endmacro + +%macro PROCESS_16X2X3 5 +%if %1==0 + movdqa xmm0, XMMWORD PTR [%2] + lddqu xmm5, XMMWORD PTR [%3] + lddqu xmm6, XMMWORD PTR [%3+1] + lddqu xmm7, XMMWORD PTR [%3+2] + + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, XMMWORD PTR [%2] + lddqu xmm1, XMMWORD PTR [%3] + lddqu xmm2, XMMWORD PTR [%3+1] + lddqu xmm3, XMMWORD PTR [%3+2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endif + movdqa xmm0, XMMWORD PTR [%2+%4] + lddqu xmm1, XMMWORD PTR [%3+%5] + lddqu xmm2, XMMWORD PTR [%3+%5+1] + lddqu xmm3, XMMWORD PTR [%3+%5+2] + +%if %1==0 || %1==1 + lea %2, [%2+%4*2] + lea %3, [%3+%5*2] +%endif + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endmacro + +%macro PROCESS_8X2X3 5 +%if %1==0 + movq mm0, QWORD PTR [%2] + movq mm5, QWORD PTR [%3] + movq mm6, QWORD PTR [%3+1] + movq mm7, QWORD PTR [%3+2] + + psadbw mm5, mm0 + psadbw mm6, mm0 + psadbw mm7, mm0 +%else + movq mm0, QWORD PTR [%2] + movq mm1, QWORD PTR [%3] + movq mm2, QWORD PTR [%3+1] + movq mm3, QWORD PTR [%3+2] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm5, mm1 + paddw mm6, mm2 + paddw mm7, mm3 +%endif + movq mm0, QWORD PTR [%2+%4] + movq mm1, QWORD PTR [%3+%5] + movq mm2, QWORD PTR [%3+%5+1] + movq mm3, QWORD PTR [%3+%5+2] + +%if %1==0 || %1==1 + lea %2, [%2+%4*2] + lea %3, [%3+%5*2] +%endif + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm5, mm1 + paddw mm6, mm2 + paddw mm7, mm3 +%endmacro + +%macro LOAD_X4_ADDRESSES 5 + mov %2, [%1+REG_SZ_BYTES*0] + mov %3, [%1+REG_SZ_BYTES*1] + + mov %4, [%1+REG_SZ_BYTES*2] + mov %5, [%1+REG_SZ_BYTES*3] +%endmacro + +%macro PROCESS_16X2X4 8 +%if %1==0 + movdqa xmm0, XMMWORD PTR [%2] + lddqu xmm4, XMMWORD PTR [%3] + lddqu xmm5, XMMWORD PTR [%4] + lddqu xmm6, XMMWORD PTR [%5] + lddqu xmm7, XMMWORD PTR [%6] + + psadbw xmm4, xmm0 + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, XMMWORD PTR [%2] + lddqu xmm1, XMMWORD PTR [%3] + lddqu xmm2, XMMWORD PTR [%4] + lddqu xmm3, XMMWORD PTR [%5] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm4, xmm1 + lddqu xmm1, XMMWORD PTR [%6] + paddw xmm5, xmm2 + paddw xmm6, xmm3 + + psadbw xmm1, xmm0 + paddw xmm7, xmm1 +%endif + movdqa xmm0, XMMWORD PTR [%2+%7] + lddqu xmm1, XMMWORD PTR [%3+%8] + lddqu xmm2, XMMWORD PTR [%4+%8] + lddqu xmm3, XMMWORD PTR [%5+%8] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm4, xmm1 + lddqu xmm1, XMMWORD PTR [%6+%8] + paddw xmm5, xmm2 + paddw xmm6, xmm3 + +%if %1==0 || %1==1 + lea %2, [%2+%7*2] + lea %3, [%3+%8*2] + + lea %4, [%4+%8*2] + lea %5, [%5+%8*2] + + lea %6, [%6+%8*2] +%endif + psadbw xmm1, xmm0 + paddw xmm7, xmm1 + +%endmacro + +%macro PROCESS_8X2X4 8 +%if %1==0 + movq mm0, QWORD PTR [%2] + movq mm4, QWORD PTR [%3] + movq mm5, QWORD PTR [%4] + movq mm6, QWORD PTR [%5] + movq mm7, QWORD PTR [%6] + + psadbw mm4, mm0 + psadbw mm5, mm0 + psadbw mm6, mm0 + psadbw mm7, mm0 +%else + movq mm0, QWORD PTR [%2] + movq mm1, QWORD PTR [%3] + movq mm2, QWORD PTR [%4] + movq mm3, QWORD PTR [%5] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm4, mm1 + movq mm1, QWORD PTR [%6] + paddw mm5, mm2 + paddw mm6, mm3 + + psadbw mm1, mm0 + paddw mm7, mm1 +%endif + movq mm0, QWORD PTR [%2+%7] + movq mm1, QWORD PTR [%3+%8] + movq mm2, QWORD PTR [%4+%8] + movq mm3, QWORD PTR [%5+%8] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm4, mm1 + movq mm1, QWORD PTR [%6+%8] + paddw mm5, mm2 + paddw mm6, mm3 + +%if %1==0 || %1==1 + lea %2, [%2+%7*2] + lea %3, [%3+%8*2] + + lea %4, [%4+%8*2] + lea %5, [%5+%8*2] + + lea %6, [%6+%8*2] +%endif + psadbw mm1, mm0 + paddw mm7, mm1 + +%endmacro + +;void int vp8_sad16x16x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x16x3_sse3) +sym(vp8_sad16x16x3_sse3): + + STACK_FRAME_CREATE_X3 + + PROCESS_16X2X3 0, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 2, src_ptr, ref_ptr, src_stride, ref_stride + + mov rcx, result_ptr + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rcx], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rcx+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rcx+8], xmm0 + + STACK_FRAME_DESTROY_X3 + +;void int vp8_sad16x8x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x8x3_sse3) +sym(vp8_sad16x8x3_sse3): + + STACK_FRAME_CREATE_X3 + + PROCESS_16X2X3 0, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_16X2X3 2, src_ptr, ref_ptr, src_stride, ref_stride + + mov rcx, result_ptr + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rcx], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rcx+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rcx+8], xmm0 + + STACK_FRAME_DESTROY_X3 + +;void int vp8_sad8x16x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x16x3_sse3) +sym(vp8_sad8x16x3_sse3): + + STACK_FRAME_CREATE_X3 + + PROCESS_8X2X3 0, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 2, src_ptr, ref_ptr, src_stride, ref_stride + + mov rcx, result_ptr + + punpckldq mm5, mm6 + + movq [rcx], mm5 + movd [rcx+8], mm7 + + STACK_FRAME_DESTROY_X3 + +;void int vp8_sad8x8x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x8x3_sse3) +sym(vp8_sad8x8x3_sse3): + + STACK_FRAME_CREATE_X3 + + PROCESS_8X2X3 0, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 1, src_ptr, ref_ptr, src_stride, ref_stride + PROCESS_8X2X3 2, src_ptr, ref_ptr, src_stride, ref_stride + + mov rcx, result_ptr + + punpckldq mm5, mm6 + + movq [rcx], mm5 + movd [rcx+8], mm7 + + STACK_FRAME_DESTROY_X3 + +;void int vp8_sad4x4x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad4x4x3_sse3) +sym(vp8_sad4x4x3_sse3): + + STACK_FRAME_CREATE_X3 + + movd mm0, DWORD PTR [src_ptr] + movd mm1, DWORD PTR [ref_ptr] + + movd mm2, DWORD PTR [src_ptr+src_stride] + movd mm3, DWORD PTR [ref_ptr+ref_stride] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + movd mm4, DWORD PTR [ref_ptr+1] + movd mm5, DWORD PTR [ref_ptr+2] + + movd mm2, DWORD PTR [ref_ptr+ref_stride+1] + movd mm3, DWORD PTR [ref_ptr+ref_stride+2] + + psadbw mm1, mm0 + + punpcklbw mm4, mm2 + punpcklbw mm5, mm3 + + psadbw mm4, mm0 + psadbw mm5, mm0 + + lea src_ptr, [src_ptr+src_stride*2] + lea ref_ptr, [ref_ptr+ref_stride*2] + + movd mm0, DWORD PTR [src_ptr] + movd mm2, DWORD PTR [ref_ptr] + + movd mm3, DWORD PTR [src_ptr+src_stride] + movd mm6, DWORD PTR [ref_ptr+ref_stride] + + punpcklbw mm0, mm3 + punpcklbw mm2, mm6 + + movd mm3, DWORD PTR [ref_ptr+1] + movd mm7, DWORD PTR [ref_ptr+2] + + psadbw mm2, mm0 + + paddw mm1, mm2 + + movd mm2, DWORD PTR [ref_ptr+ref_stride+1] + movd mm6, DWORD PTR [ref_ptr+ref_stride+2] + + punpcklbw mm3, mm2 + punpcklbw mm7, mm6 + + psadbw mm3, mm0 + psadbw mm7, mm0 + + paddw mm3, mm4 + paddw mm7, mm5 + + mov rcx, result_ptr + + punpckldq mm1, mm3 + + movq [rcx], mm1 + movd [rcx+8], mm7 + + STACK_FRAME_DESTROY_X3 + +;unsigned int vp8_sad16x16_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int max_sad) +;%define lddqu movdqu +global sym(vp8_sad16x16_sse3) +sym(vp8_sad16x16_sse3): + + STACK_FRAME_CREATE_X3 + + mov end_ptr, 4 + pxor xmm7, xmm7 + +.vp8_sad16x16_sse3_loop: + movdqa xmm0, XMMWORD PTR [src_ptr] + movdqu xmm1, XMMWORD PTR [ref_ptr] + movdqa xmm2, XMMWORD PTR [src_ptr+src_stride] + movdqu xmm3, XMMWORD PTR [ref_ptr+ref_stride] + + lea src_ptr, [src_ptr+src_stride*2] + lea ref_ptr, [ref_ptr+ref_stride*2] + + movdqa xmm4, XMMWORD PTR [src_ptr] + movdqu xmm5, XMMWORD PTR [ref_ptr] + movdqa xmm6, XMMWORD PTR [src_ptr+src_stride] + + psadbw xmm0, xmm1 + + movdqu xmm1, XMMWORD PTR [ref_ptr+ref_stride] + + psadbw xmm2, xmm3 + psadbw xmm4, xmm5 + psadbw xmm6, xmm1 + + lea src_ptr, [src_ptr+src_stride*2] + lea ref_ptr, [ref_ptr+ref_stride*2] + + paddw xmm7, xmm0 + paddw xmm7, xmm2 + paddw xmm7, xmm4 + paddw xmm7, xmm6 + + sub end_ptr, 1 + jne .vp8_sad16x16_sse3_loop + + movq xmm0, xmm7 + psrldq xmm7, 8 + paddw xmm0, xmm7 + movq rax, xmm0 + + STACK_FRAME_DESTROY_X3 + +;void vp8_copy32xn_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *dst_ptr, +; int dst_stride, +; int height); +global sym(vp8_copy32xn_sse3) +sym(vp8_copy32xn_sse3): + + STACK_FRAME_CREATE_X3 + +.block_copy_sse3_loopx4: + lea end_ptr, [src_ptr+src_stride*2] + + movdqu xmm0, XMMWORD PTR [src_ptr] + movdqu xmm1, XMMWORD PTR [src_ptr + 16] + movdqu xmm2, XMMWORD PTR [src_ptr + src_stride] + movdqu xmm3, XMMWORD PTR [src_ptr + src_stride + 16] + movdqu xmm4, XMMWORD PTR [end_ptr] + movdqu xmm5, XMMWORD PTR [end_ptr + 16] + movdqu xmm6, XMMWORD PTR [end_ptr + src_stride] + movdqu xmm7, XMMWORD PTR [end_ptr + src_stride + 16] + + lea src_ptr, [src_ptr+src_stride*4] + + lea end_ptr, [ref_ptr+ref_stride*2] + + movdqa XMMWORD PTR [ref_ptr], xmm0 + movdqa XMMWORD PTR [ref_ptr + 16], xmm1 + movdqa XMMWORD PTR [ref_ptr + ref_stride], xmm2 + movdqa XMMWORD PTR [ref_ptr + ref_stride + 16], xmm3 + movdqa XMMWORD PTR [end_ptr], xmm4 + movdqa XMMWORD PTR [end_ptr + 16], xmm5 + movdqa XMMWORD PTR [end_ptr + ref_stride], xmm6 + movdqa XMMWORD PTR [end_ptr + ref_stride + 16], xmm7 + + lea ref_ptr, [ref_ptr+ref_stride*4] + + sub height, 4 + cmp height, 4 + jge .block_copy_sse3_loopx4 + + ;Check to see if there is more rows need to be copied. + cmp height, 0 + je .copy_is_done + +.block_copy_sse3_loop: + movdqu xmm0, XMMWORD PTR [src_ptr] + movdqu xmm1, XMMWORD PTR [src_ptr + 16] + lea src_ptr, [src_ptr+src_stride] + + movdqa XMMWORD PTR [ref_ptr], xmm0 + movdqa XMMWORD PTR [ref_ptr + 16], xmm1 + lea ref_ptr, [ref_ptr+ref_stride] + + sub height, 1 + jne .block_copy_sse3_loop + +.copy_is_done: + STACK_FRAME_DESTROY_X3 + +;void vp8_sad16x16x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr_base, +; int ref_stride, +; int *results) +global sym(vp8_sad16x16x4d_sse3) +sym(vp8_sad16x16x4d_sse3): + + STACK_FRAME_CREATE_X4 + + PROCESS_16X2X4 0, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 2, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + +%if ABI_IS_32BIT + pop rbp +%endif + mov rcx, result_ptr + + movq xmm0, xmm4 + psrldq xmm4, 8 + + paddw xmm0, xmm4 + movd [rcx], xmm0 +;- + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rcx+4], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rcx+8], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rcx+12], xmm0 + + STACK_FRAME_DESTROY_X4 + +;void vp8_sad16x8x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr_base, +; int ref_stride, +; int *results) +global sym(vp8_sad16x8x4d_sse3) +sym(vp8_sad16x8x4d_sse3): + + STACK_FRAME_CREATE_X4 + + PROCESS_16X2X4 0, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_16X2X4 2, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + +%if ABI_IS_32BIT + pop rbp +%endif + mov rcx, result_ptr + + movq xmm0, xmm4 + psrldq xmm4, 8 + + paddw xmm0, xmm4 + movd [rcx], xmm0 +;- + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rcx+4], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rcx+8], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rcx+12], xmm0 + + STACK_FRAME_DESTROY_X4 + +;void int vp8_sad8x16x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x16x4d_sse3) +sym(vp8_sad8x16x4d_sse3): + + STACK_FRAME_CREATE_X4 + + PROCESS_8X2X4 0, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 2, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + +%if ABI_IS_32BIT + pop rbp +%endif + mov rcx, result_ptr + + punpckldq mm4, mm5 + punpckldq mm6, mm7 + + movq [rcx], mm4 + movq [rcx+8], mm6 + + STACK_FRAME_DESTROY_X4 + +;void int vp8_sad8x8x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x8x4d_sse3) +sym(vp8_sad8x8x4d_sse3): + + STACK_FRAME_CREATE_X4 + + PROCESS_8X2X4 0, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 1, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + PROCESS_8X2X4 2, src_ptr, r0_ptr, r1_ptr, r2_ptr, r3_ptr, src_stride, ref_stride + +%if ABI_IS_32BIT + pop rbp +%endif + mov rcx, result_ptr + + punpckldq mm4, mm5 + punpckldq mm6, mm7 + + movq [rcx], mm4 + movq [rcx+8], mm6 + + STACK_FRAME_DESTROY_X4 + +;void int vp8_sad4x4x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad4x4x4d_sse3) +sym(vp8_sad4x4x4d_sse3): + + STACK_FRAME_CREATE_X4 + + movd mm0, DWORD PTR [src_ptr] + movd mm1, DWORD PTR [r0_ptr] + + movd mm2, DWORD PTR [src_ptr+src_stride] + movd mm3, DWORD PTR [r0_ptr+ref_stride] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + movd mm4, DWORD PTR [r1_ptr] + movd mm5, DWORD PTR [r2_ptr] + + movd mm6, DWORD PTR [r3_ptr] + movd mm2, DWORD PTR [r1_ptr+ref_stride] + + movd mm3, DWORD PTR [r2_ptr+ref_stride] + movd mm7, DWORD PTR [r3_ptr+ref_stride] + + psadbw mm1, mm0 + + punpcklbw mm4, mm2 + punpcklbw mm5, mm3 + + punpcklbw mm6, mm7 + psadbw mm4, mm0 + + psadbw mm5, mm0 + psadbw mm6, mm0 + + + + lea src_ptr, [src_ptr+src_stride*2] + lea r0_ptr, [r0_ptr+ref_stride*2] + + lea r1_ptr, [r1_ptr+ref_stride*2] + lea r2_ptr, [r2_ptr+ref_stride*2] + + lea r3_ptr, [r3_ptr+ref_stride*2] + + movd mm0, DWORD PTR [src_ptr] + movd mm2, DWORD PTR [r0_ptr] + + movd mm3, DWORD PTR [src_ptr+src_stride] + movd mm7, DWORD PTR [r0_ptr+ref_stride] + + punpcklbw mm0, mm3 + punpcklbw mm2, mm7 + + movd mm3, DWORD PTR [r1_ptr] + movd mm7, DWORD PTR [r2_ptr] + + psadbw mm2, mm0 +%if ABI_IS_32BIT + mov rax, rbp + + pop rbp +%define ref_stride rax +%endif + mov rsi, result_ptr + + paddw mm1, mm2 + movd [rsi], mm1 + + movd mm2, DWORD PTR [r1_ptr+ref_stride] + movd mm1, DWORD PTR [r2_ptr+ref_stride] + + punpcklbw mm3, mm2 + punpcklbw mm7, mm1 + + psadbw mm3, mm0 + psadbw mm7, mm0 + + movd mm2, DWORD PTR [r3_ptr] + movd mm1, DWORD PTR [r3_ptr+ref_stride] + + paddw mm3, mm4 + paddw mm7, mm5 + + movd [rsi+4], mm3 + punpcklbw mm2, mm1 + + movd [rsi+8], mm7 + psadbw mm2, mm0 + + paddw mm2, mm6 + movd [rsi+12], mm2 + + + STACK_FRAME_DESTROY_X4 + diff --git a/vp8/common/x86/sad_sse4.asm b/vp8/common/x86/sad_sse4.asm new file mode 100644 index 0000000..03ecec4 --- /dev/null +++ b/vp8/common/x86/sad_sse4.asm @@ -0,0 +1,353 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%macro PROCESS_16X2X8 1 +%if %1 + movdqa xmm0, XMMWORD PTR [rsi] + movq xmm1, MMWORD PTR [rdi] + movq xmm3, MMWORD PTR [rdi+8] + movq xmm2, MMWORD PTR [rdi+16] + punpcklqdq xmm1, xmm3 + punpcklqdq xmm3, xmm2 + + movdqa xmm2, xmm1 + mpsadbw xmm1, xmm0, 0x0 + mpsadbw xmm2, xmm0, 0x5 + + psrldq xmm0, 8 + + movdqa xmm4, xmm3 + mpsadbw xmm3, xmm0, 0x0 + mpsadbw xmm4, xmm0, 0x5 + + paddw xmm1, xmm2 + paddw xmm1, xmm3 + paddw xmm1, xmm4 +%else + movdqa xmm0, XMMWORD PTR [rsi] + movq xmm5, MMWORD PTR [rdi] + movq xmm3, MMWORD PTR [rdi+8] + movq xmm2, MMWORD PTR [rdi+16] + punpcklqdq xmm5, xmm3 + punpcklqdq xmm3, xmm2 + + movdqa xmm2, xmm5 + mpsadbw xmm5, xmm0, 0x0 + mpsadbw xmm2, xmm0, 0x5 + + psrldq xmm0, 8 + + movdqa xmm4, xmm3 + mpsadbw xmm3, xmm0, 0x0 + mpsadbw xmm4, xmm0, 0x5 + + paddw xmm5, xmm2 + paddw xmm5, xmm3 + paddw xmm5, xmm4 + + paddw xmm1, xmm5 +%endif + movdqa xmm0, XMMWORD PTR [rsi + rax] + movq xmm5, MMWORD PTR [rdi+ rdx] + movq xmm3, MMWORD PTR [rdi+ rdx+8] + movq xmm2, MMWORD PTR [rdi+ rdx+16] + punpcklqdq xmm5, xmm3 + punpcklqdq xmm3, xmm2 + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + movdqa xmm2, xmm5 + mpsadbw xmm5, xmm0, 0x0 + mpsadbw xmm2, xmm0, 0x5 + + psrldq xmm0, 8 + movdqa xmm4, xmm3 + mpsadbw xmm3, xmm0, 0x0 + mpsadbw xmm4, xmm0, 0x5 + + paddw xmm5, xmm2 + paddw xmm5, xmm3 + paddw xmm5, xmm4 + + paddw xmm1, xmm5 +%endmacro + +%macro PROCESS_8X2X8 1 +%if %1 + movq xmm0, MMWORD PTR [rsi] + movq xmm1, MMWORD PTR [rdi] + movq xmm3, MMWORD PTR [rdi+8] + punpcklqdq xmm1, xmm3 + + movdqa xmm2, xmm1 + mpsadbw xmm1, xmm0, 0x0 + mpsadbw xmm2, xmm0, 0x5 + paddw xmm1, xmm2 +%else + movq xmm0, MMWORD PTR [rsi] + movq xmm5, MMWORD PTR [rdi] + movq xmm3, MMWORD PTR [rdi+8] + punpcklqdq xmm5, xmm3 + + movdqa xmm2, xmm5 + mpsadbw xmm5, xmm0, 0x0 + mpsadbw xmm2, xmm0, 0x5 + paddw xmm5, xmm2 + + paddw xmm1, xmm5 +%endif + movq xmm0, MMWORD PTR [rsi + rax] + movq xmm5, MMWORD PTR [rdi+ rdx] + movq xmm3, MMWORD PTR [rdi+ rdx+8] + punpcklqdq xmm5, xmm3 + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + movdqa xmm2, xmm5 + mpsadbw xmm5, xmm0, 0x0 + mpsadbw xmm2, xmm0, 0x5 + paddw xmm5, xmm2 + + paddw xmm1, xmm5 +%endmacro + +%macro PROCESS_4X2X8 1 +%if %1 + movd xmm0, [rsi] + movq xmm1, MMWORD PTR [rdi] + movq xmm3, MMWORD PTR [rdi+8] + punpcklqdq xmm1, xmm3 + + mpsadbw xmm1, xmm0, 0x0 +%else + movd xmm0, [rsi] + movq xmm5, MMWORD PTR [rdi] + movq xmm3, MMWORD PTR [rdi+8] + punpcklqdq xmm5, xmm3 + + mpsadbw xmm5, xmm0, 0x0 + + paddw xmm1, xmm5 +%endif + movd xmm0, [rsi + rax] + movq xmm5, MMWORD PTR [rdi+ rdx] + movq xmm3, MMWORD PTR [rdi+ rdx+8] + punpcklqdq xmm5, xmm3 + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + mpsadbw xmm5, xmm0, 0x0 + + paddw xmm1, xmm5 +%endmacro + + +;void vp8_sad16x16x8_sse4( +; const unsigned char *src_ptr, +; int src_stride, +; const unsigned char *ref_ptr, +; int ref_stride, +; unsigned short *sad_array); +global sym(vp8_sad16x16x8_sse4) +sym(vp8_sad16x16x8_sse4): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_16X2X8 1 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + + mov rdi, arg(4) ;Results + movdqa XMMWORD PTR [rdi], xmm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_sad16x8x8_sse4( +; const unsigned char *src_ptr, +; int src_stride, +; const unsigned char *ref_ptr, +; int ref_stride, +; unsigned short *sad_array +;); +global sym(vp8_sad16x8x8_sse4) +sym(vp8_sad16x8x8_sse4): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_16X2X8 1 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + PROCESS_16X2X8 0 + + mov rdi, arg(4) ;Results + movdqa XMMWORD PTR [rdi], xmm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_sad8x8x8_sse4( +; const unsigned char *src_ptr, +; int src_stride, +; const unsigned char *ref_ptr, +; int ref_stride, +; unsigned short *sad_array +;); +global sym(vp8_sad8x8x8_sse4) +sym(vp8_sad8x8x8_sse4): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_8X2X8 1 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + + mov rdi, arg(4) ;Results + movdqa XMMWORD PTR [rdi], xmm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_sad8x16x8_sse4( +; const unsigned char *src_ptr, +; int src_stride, +; const unsigned char *ref_ptr, +; int ref_stride, +; unsigned short *sad_array +;); +global sym(vp8_sad8x16x8_sse4) +sym(vp8_sad8x16x8_sse4): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_8X2X8 1 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + PROCESS_8X2X8 0 + mov rdi, arg(4) ;Results + movdqa XMMWORD PTR [rdi], xmm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_sad4x4x8_c( +; const unsigned char *src_ptr, +; int src_stride, +; const unsigned char *ref_ptr, +; int ref_stride, +; unsigned short *sad_array +;); +global sym(vp8_sad4x4x8_sse4) +sym(vp8_sad4x4x8_sse4): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_4X2X8 1 + PROCESS_4X2X8 0 + + mov rdi, arg(4) ;Results + movdqa XMMWORD PTR [rdi], xmm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + + + diff --git a/vp8/common/x86/sad_ssse3.asm b/vp8/common/x86/sad_ssse3.asm new file mode 100644 index 0000000..95b6c89 --- /dev/null +++ b/vp8/common/x86/sad_ssse3.asm @@ -0,0 +1,370 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%macro PROCESS_16X2X3 1 +%if %1 + movdqa xmm0, XMMWORD PTR [rsi] + lddqu xmm5, XMMWORD PTR [rdi] + lddqu xmm6, XMMWORD PTR [rdi+1] + lddqu xmm7, XMMWORD PTR [rdi+2] + + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, XMMWORD PTR [rsi] + lddqu xmm1, XMMWORD PTR [rdi] + lddqu xmm2, XMMWORD PTR [rdi+1] + lddqu xmm3, XMMWORD PTR [rdi+2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endif + movdqa xmm0, XMMWORD PTR [rsi+rax] + lddqu xmm1, XMMWORD PTR [rdi+rdx] + lddqu xmm2, XMMWORD PTR [rdi+rdx+1] + lddqu xmm3, XMMWORD PTR [rdi+rdx+2] + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endmacro + +%macro PROCESS_16X2X3_OFFSET 2 +%if %1 + movdqa xmm0, XMMWORD PTR [rsi] + movdqa xmm4, XMMWORD PTR [rdi] + movdqa xmm7, XMMWORD PTR [rdi+16] + + movdqa xmm5, xmm7 + palignr xmm5, xmm4, %2 + + movdqa xmm6, xmm7 + palignr xmm6, xmm4, (%2+1) + + palignr xmm7, xmm4, (%2+2) + + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, XMMWORD PTR [rsi] + movdqa xmm4, XMMWORD PTR [rdi] + movdqa xmm3, XMMWORD PTR [rdi+16] + + movdqa xmm1, xmm3 + palignr xmm1, xmm4, %2 + + movdqa xmm2, xmm3 + palignr xmm2, xmm4, (%2+1) + + palignr xmm3, xmm4, (%2+2) + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endif + movdqa xmm0, XMMWORD PTR [rsi+rax] + movdqa xmm4, XMMWORD PTR [rdi+rdx] + movdqa xmm3, XMMWORD PTR [rdi+rdx+16] + + movdqa xmm1, xmm3 + palignr xmm1, xmm4, %2 + + movdqa xmm2, xmm3 + palignr xmm2, xmm4, (%2+1) + + palignr xmm3, xmm4, (%2+2) + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endmacro + +%macro PROCESS_16X16X3_OFFSET 2 +%2_aligned_by_%1: + + sub rdi, %1 + + PROCESS_16X2X3_OFFSET 1, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + + jmp %2_store_off + +%endmacro + +%macro PROCESS_16X8X3_OFFSET 2 +%2_aligned_by_%1: + + sub rdi, %1 + + PROCESS_16X2X3_OFFSET 1, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + + jmp %2_store_off + +%endmacro + +;void int vp8_sad16x16x3_ssse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x16x3_ssse3) +sym(vp8_sad16x16x3_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + push rsi + push rdi + push rcx + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + mov rdx, 0xf + and rdx, rdi + + jmp .vp8_sad16x16x3_ssse3_skiptable +.vp8_sad16x16x3_ssse3_jumptable: + dd .vp8_sad16x16x3_ssse3_aligned_by_0 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_1 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_2 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_3 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_4 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_5 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_6 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_7 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_8 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_9 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_10 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_11 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_12 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_13 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_14 - .vp8_sad16x16x3_ssse3_do_jump + dd .vp8_sad16x16x3_ssse3_aligned_by_15 - .vp8_sad16x16x3_ssse3_do_jump +.vp8_sad16x16x3_ssse3_skiptable: + + call .vp8_sad16x16x3_ssse3_do_jump +.vp8_sad16x16x3_ssse3_do_jump: + pop rcx ; get the address of do_jump + mov rax, .vp8_sad16x16x3_ssse3_jumptable - .vp8_sad16x16x3_ssse3_do_jump + add rax, rcx ; get the absolute address of vp8_sad16x16x3_ssse3_jumptable + + movsxd rax, dword [rax + 4*rdx] ; get the 32 bit offset from the jumptable + add rcx, rax + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + jmp rcx + + PROCESS_16X16X3_OFFSET 0, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 1, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 2, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 3, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 4, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 5, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 6, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 7, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 8, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 9, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 10, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 11, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 12, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 13, .vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 14, .vp8_sad16x16x3_ssse3 + +.vp8_sad16x16x3_ssse3_aligned_by_15: + PROCESS_16X2X3 1 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + +.vp8_sad16x16x3_ssse3_store_off: + mov rdi, arg(4) ;Results + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+8], xmm0 + + ; begin epilog + pop rcx + pop rdi + pop rsi + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad16x8x3_ssse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x8x3_ssse3) +sym(vp8_sad16x8x3_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + SAVE_XMM 7 + push rsi + push rdi + push rcx + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + mov rdx, 0xf + and rdx, rdi + + jmp .vp8_sad16x8x3_ssse3_skiptable +.vp8_sad16x8x3_ssse3_jumptable: + dd .vp8_sad16x8x3_ssse3_aligned_by_0 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_1 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_2 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_3 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_4 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_5 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_6 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_7 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_8 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_9 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_10 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_11 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_12 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_13 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_14 - .vp8_sad16x8x3_ssse3_do_jump + dd .vp8_sad16x8x3_ssse3_aligned_by_15 - .vp8_sad16x8x3_ssse3_do_jump +.vp8_sad16x8x3_ssse3_skiptable: + + call .vp8_sad16x8x3_ssse3_do_jump +.vp8_sad16x8x3_ssse3_do_jump: + pop rcx ; get the address of do_jump + mov rax, .vp8_sad16x8x3_ssse3_jumptable - .vp8_sad16x8x3_ssse3_do_jump + add rax, rcx ; get the absolute address of vp8_sad16x8x3_ssse3_jumptable + + movsxd rax, dword [rax + 4*rdx] ; get the 32 bit offset from the jumptable + add rcx, rax + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + jmp rcx + + PROCESS_16X8X3_OFFSET 0, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 1, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 2, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 3, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 4, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 5, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 6, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 7, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 8, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 9, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 10, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 11, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 12, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 13, .vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 14, .vp8_sad16x8x3_ssse3 + +.vp8_sad16x8x3_ssse3_aligned_by_15: + + PROCESS_16X2X3 1 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + +.vp8_sad16x8x3_ssse3_store_off: + mov rdi, arg(4) ;Results + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+8], xmm0 + + ; begin epilog + pop rcx + pop rdi + pop rsi + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/common/x86/subpixel_mmx.asm b/vp8/common/x86/subpixel_mmx.asm new file mode 100644 index 0000000..5528fd0 --- /dev/null +++ b/vp8/common/x86/subpixel_mmx.asm @@ -0,0 +1,702 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +extern sym(vp8_bilinear_filters_x86_8) + + +%define BLOCK_HEIGHT_WIDTH 4 +%define vp8_filter_weight 128 +%define VP8_FILTER_SHIFT 7 + + +;void vp8_filter_block1d_h6_mmx +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +global sym(vp8_filter_block1d_h6_mmx) +sym(vp8_filter_block1d_h6_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(6) ;vp8_filter + + movq mm1, [rdx + 16] ; do both the negative taps first!!! + movq mm2, [rdx + 32] ; + movq mm6, [rdx + 48] ; + movq mm7, [rdx + 64] ; + + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(5) ;output_width ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + +.nextrow: + movq mm3, [rsi-2] ; mm3 = p-2..p5 + movq mm4, mm3 ; mm4 = p-2..p5 + psrlq mm3, 8 ; mm3 = p-1..p5 + punpcklbw mm3, mm0 ; mm3 = p-1..p2 + pmullw mm3, mm1 ; mm3 *= kernel 1 modifiers. + + movq mm5, mm4 ; mm5 = p-2..p5 + punpckhbw mm4, mm0 ; mm5 = p2..p5 + pmullw mm4, mm7 ; mm5 *= kernel 4 modifiers + paddsw mm3, mm4 ; mm3 += mm5 + + movq mm4, mm5 ; mm4 = p-2..p5; + psrlq mm5, 16 ; mm5 = p0..p5; + punpcklbw mm5, mm0 ; mm5 = p0..p3 + pmullw mm5, mm2 ; mm5 *= kernel 2 modifiers + paddsw mm3, mm5 ; mm3 += mm5 + + movq mm5, mm4 ; mm5 = p-2..p5 + psrlq mm4, 24 ; mm4 = p1..p5 + punpcklbw mm4, mm0 ; mm4 = p1..p4 + pmullw mm4, mm6 ; mm5 *= kernel 3 modifiers + paddsw mm3, mm4 ; mm3 += mm5 + + ; do outer positive taps + movd mm4, [rsi+3] + punpcklbw mm4, mm0 ; mm5 = p3..p6 + pmullw mm4, [rdx+80] ; mm5 *= kernel 0 modifiers + paddsw mm3, mm4 ; mm3 += mm5 + + punpcklbw mm5, mm0 ; mm5 = p-2..p1 + pmullw mm5, [rdx] ; mm5 *= kernel 5 modifiers + paddsw mm3, mm5 ; mm3 += mm5 + + paddsw mm3, [GLOBAL(rd)] ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + packuswb mm3, mm0 ; pack and unpack to saturate + punpcklbw mm3, mm0 ; + + movq [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, dword ptr arg(2) ;src_pixels_per_line ; next line + add rdi, rax; +%else + movsxd r8, dword ptr arg(2) ;src_pixels_per_line + add rdi, rax; + + add rsi, r8 ; next line +%endif + + dec rcx ; decrement count + jnz .nextrow ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1dc_v6_mmx +;( +; short *src_ptr, +; unsigned char *output_ptr, +; int output_pitch, +; unsigned int pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +global sym(vp8_filter_block1dc_v6_mmx) +sym(vp8_filter_block1dc_v6_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movq mm5, [GLOBAL(rd)] + push rbx + mov rbx, arg(7) ;vp8_filter + movq mm1, [rbx + 16] ; do both the negative taps first!!! + movq mm2, [rbx + 32] ; + movq mm6, [rbx + 48] ; + movq mm7, [rbx + 64] ; + + movsxd rdx, dword ptr arg(3) ;pixels_per_line + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + sub rsi, rdx + sub rsi, rdx + movsxd rcx, DWORD PTR arg(5) ;output_height + movsxd rax, DWORD PTR arg(2) ;output_pitch ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + + +.nextrow_cv: + movq mm3, [rsi+rdx] ; mm3 = p0..p8 = row -1 + pmullw mm3, mm1 ; mm3 *= kernel 1 modifiers. + + + movq mm4, [rsi + 4*rdx] ; mm4 = p0..p3 = row 2 + pmullw mm4, mm7 ; mm4 *= kernel 4 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi + 2*rdx] ; mm4 = p0..p3 = row 0 + pmullw mm4, mm2 ; mm4 *= kernel 2 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi] ; mm4 = p0..p3 = row -2 + pmullw mm4, [rbx] ; mm4 *= kernel 0 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + + add rsi, rdx ; move source forward 1 line to avoid 3 * pitch + movq mm4, [rsi + 2*rdx] ; mm4 = p0..p3 = row 1 + pmullw mm4, mm6 ; mm4 *= kernel 3 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi + 4*rdx] ; mm4 = p0..p3 = row 3 + pmullw mm4, [rbx +80] ; mm4 *= kernel 3 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + + paddsw mm3, mm5 ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + packuswb mm3, mm0 ; pack and saturate + + movd [rdi],mm3 ; store the results in the destination + ; the subsequent iterations repeat 3 out of 4 of these reads. Since the + ; recon block should be in cache this shouldn't cost much. Its obviously + ; avoidable!!!. + lea rdi, [rdi+rax] ; + dec rcx ; decrement count + jnz .nextrow_cv ; next row + + pop rbx + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void bilinear_predict8x8_mmx +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict8x8_mmx) +sym(vp8_bilinear_predict8x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = vp8_bilinear_filters_x86_8[xoffset]; + ;const short *VFilter = vp8_bilinear_filters_x86_8[yoffset]; + + movsxd rax, dword ptr arg(2) ;xoffset + mov rdi, arg(4) ;dst_ptr ; + + shl rax, 5 ; offset * 32 + lea rcx, [GLOBAL(sym(vp8_bilinear_filters_x86_8))] + + add rax, rcx ; HFilter + mov rsi, arg(0) ;src_ptr ; + + movsxd rdx, dword ptr arg(5) ;dst_pitch + movq mm1, [rax] ; + + movq mm2, [rax+16] ; + movsxd rax, dword ptr arg(3) ;yoffset + + pxor mm0, mm0 ; + + shl rax, 5 ; offset*32 + add rax, rcx ; VFilter + + lea rcx, [rdi+rdx*8] ; + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line ; + + + + ; get the first horizontal line done ; + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [GLOBAL(rd)] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + add rsi, rdx ; next line +.next_row_8x8: + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + movq mm5, mm7 ; + movq mm6, mm7 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 + + pmullw mm5, [rax] ; + pmullw mm6, [rax] ; + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [GLOBAL(rd)] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + + pmullw mm3, [rax+16] ; + pmullw mm4, [rax+16] ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [GLOBAL(rd)] ; + psraw mm4, VP8_FILTER_SHIFT ; + + packuswb mm3, mm4 + + movq [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, rdx ; next line + add rdi, dword ptr arg(5) ;dst_pitch ; +%else + movsxd r8, dword ptr arg(5) ;dst_pitch + add rsi, rdx ; next line + add rdi, r8 ;dst_pitch +%endif + cmp rdi, rcx ; + jne .next_row_8x8 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void bilinear_predict8x4_mmx +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict8x4_mmx) +sym(vp8_bilinear_predict8x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = vp8_bilinear_filters_x86_8[xoffset]; + ;const short *VFilter = vp8_bilinear_filters_x86_8[yoffset]; + + movsxd rax, dword ptr arg(2) ;xoffset + mov rdi, arg(4) ;dst_ptr ; + + lea rcx, [GLOBAL(sym(vp8_bilinear_filters_x86_8))] + shl rax, 5 + + mov rsi, arg(0) ;src_ptr ; + add rax, rcx + + movsxd rdx, dword ptr arg(5) ;dst_pitch + movq mm1, [rax] ; + + movq mm2, [rax+16] ; + movsxd rax, dword ptr arg(3) ;yoffset + + pxor mm0, mm0 ; + shl rax, 5 + + add rax, rcx + lea rcx, [rdi+rdx*4] ; + + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line ; + + ; get the first horizontal line done ; + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [GLOBAL(rd)] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + add rsi, rdx ; next line +.next_row_8x4: + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + movq mm5, mm7 ; + movq mm6, mm7 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 + + pmullw mm5, [rax] ; + pmullw mm6, [rax] ; + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [GLOBAL(rd)] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + + pmullw mm3, [rax+16] ; + pmullw mm4, [rax+16] ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [GLOBAL(rd)] ; + psraw mm4, VP8_FILTER_SHIFT ; + + packuswb mm3, mm4 + + movq [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, rdx ; next line + add rdi, dword ptr arg(5) ;dst_pitch ; +%else + movsxd r8, dword ptr arg(5) ;dst_pitch + add rsi, rdx ; next line + add rdi, r8 +%endif + cmp rdi, rcx ; + jne .next_row_8x4 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void bilinear_predict4x4_mmx +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict4x4_mmx) +sym(vp8_bilinear_predict4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = vp8_bilinear_filters_x86_8[xoffset]; + ;const short *VFilter = vp8_bilinear_filters_x86_8[yoffset]; + + movsxd rax, dword ptr arg(2) ;xoffset + mov rdi, arg(4) ;dst_ptr ; + + lea rcx, [GLOBAL(sym(vp8_bilinear_filters_x86_8))] + shl rax, 5 + + add rax, rcx ; HFilter + mov rsi, arg(0) ;src_ptr ; + + movsxd rdx, dword ptr arg(5) ;ldst_pitch + movq mm1, [rax] ; + + movq mm2, [rax+16] ; + movsxd rax, dword ptr arg(3) ;yoffset + + pxor mm0, mm0 ; + shl rax, 5 + + add rax, rcx + lea rcx, [rdi+rdx*4] ; + + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line ; + + ; get the first horizontal line done ; + movd mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + + pmullw mm3, mm1 ; + movd mm5, [rsi+1] ; + + punpcklbw mm5, mm0 ; + pmullw mm5, mm2 ; + + paddw mm3, mm5 ; + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movq mm7, mm3 ; + packuswb mm7, mm0 ; + + add rsi, rdx ; next line +.next_row_4x4: + movd mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + + pmullw mm3, mm1 ; + movd mm5, [rsi+1] ; + + punpcklbw mm5, mm0 ; + pmullw mm5, mm2 ; + + paddw mm3, mm5 ; + + movq mm5, mm7 ; + punpcklbw mm5, mm0 ; + + pmullw mm5, [rax] ; + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + movq mm7, mm3 ; + + packuswb mm7, mm0 ; + + pmullw mm3, [rax+16] ; + paddw mm3, mm5 ; + + + paddw mm3, [GLOBAL(rd)] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + packuswb mm3, mm0 + movd [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, rdx ; next line + add rdi, dword ptr arg(5) ;dst_pitch ; +%else + movsxd r8, dword ptr arg(5) ;dst_pitch ; + add rsi, rdx ; next line + add rdi, r8 +%endif + + cmp rdi, rcx ; + jne .next_row_4x4 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + +SECTION_RODATA +align 16 +rd: + times 4 dw 0x40 + +align 16 +global HIDDEN_DATA(sym(vp8_six_tap_mmx)) +sym(vp8_six_tap_mmx): + times 8 dw 0 + times 8 dw 0 + times 8 dw 128 + times 8 dw 0 + times 8 dw 0 + times 8 dw 0 + + times 8 dw 0 + times 8 dw -6 + times 8 dw 123 + times 8 dw 12 + times 8 dw -1 + times 8 dw 0 + + times 8 dw 2 + times 8 dw -11 + times 8 dw 108 + times 8 dw 36 + times 8 dw -8 + times 8 dw 1 + + times 8 dw 0 + times 8 dw -9 + times 8 dw 93 + times 8 dw 50 + times 8 dw -6 + times 8 dw 0 + + times 8 dw 3 + times 8 dw -16 + times 8 dw 77 + times 8 dw 77 + times 8 dw -16 + times 8 dw 3 + + times 8 dw 0 + times 8 dw -6 + times 8 dw 50 + times 8 dw 93 + times 8 dw -9 + times 8 dw 0 + + times 8 dw 1 + times 8 dw -8 + times 8 dw 36 + times 8 dw 108 + times 8 dw -11 + times 8 dw 2 + + times 8 dw 0 + times 8 dw -1 + times 8 dw 12 + times 8 dw 123 + times 8 dw -6 + times 8 dw 0 + + diff --git a/vp8/common/x86/subpixel_sse2.asm b/vp8/common/x86/subpixel_sse2.asm new file mode 100644 index 0000000..cb550af --- /dev/null +++ b/vp8/common/x86/subpixel_sse2.asm @@ -0,0 +1,1372 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +extern sym(vp8_bilinear_filters_x86_8) + +%define BLOCK_HEIGHT_WIDTH 4 +%define VP8_FILTER_WEIGHT 128 +%define VP8_FILTER_SHIFT 7 + + +;/************************************************************************************ +; Notes: filter_block1d_h6 applies a 6 tap filter horizontally to the input pixels. The +; input pixel array has output_height rows. This routine assumes that output_height is an +; even number. This function handles 8 pixels in horizontal direction, calculating ONE +; rows each iteration to take advantage of the 128 bits operations. +;*************************************************************************************/ +;void vp8_filter_block1d8_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short *vp8_filter +;) +global sym(vp8_filter_block1d8_h6_sse2) +sym(vp8_filter_block1d8_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(6) ;vp8_filter + mov rsi, arg(0) ;src_ptr + + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;output_width +%endif + pxor xmm0, xmm0 ; clear xmm0 for unpack + +.filter_block1d8_h6_rowloop: + movq xmm3, MMWORD PTR [rsi - 2] + movq xmm1, MMWORD PTR [rsi + 6] + + prefetcht2 [rsi+rax-2] + + pslldq xmm1, 8 + por xmm1, xmm3 + + movdqa xmm4, xmm1 + movdqa xmm5, xmm1 + + movdqa xmm6, xmm1 + movdqa xmm7, xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm1, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm1, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm1, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm1 + paddsw xmm4, [GLOBAL(rd)] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + punpcklbw xmm4, xmm0 + + movdqa XMMWORD Ptr [rdi], xmm4 + lea rsi, [rsi + rax] + +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(5) ;[output_width] +%else + add rdi, r8 +%endif + dec rcx + + jnz .filter_block1d8_h6_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d16_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short *vp8_filter +;) +;/************************************************************************************ +; Notes: filter_block1d_h6 applies a 6 tap filter horizontally to the input pixels. The +; input pixel array has output_height rows. This routine assumes that output_height is an +; even number. This function handles 8 pixels in horizontal direction, calculating ONE +; rows each iteration to take advantage of the 128 bits operations. +;*************************************************************************************/ +global sym(vp8_filter_block1d16_h6_sse2) +sym(vp8_filter_block1d16_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(6) ;vp8_filter + mov rsi, arg(0) ;src_ptr + + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;output_width +%endif + + pxor xmm0, xmm0 ; clear xmm0 for unpack + +.filter_block1d16_h6_sse2_rowloop: + movq xmm3, MMWORD PTR [rsi - 2] + movq xmm1, MMWORD PTR [rsi + 6] + + movq xmm2, MMWORD PTR [rsi +14] + pslldq xmm2, 8 + + por xmm2, xmm1 + prefetcht2 [rsi+rax-2] + + pslldq xmm1, 8 + por xmm1, xmm3 + + movdqa xmm4, xmm1 + movdqa xmm5, xmm1 + + movdqa xmm6, xmm1 + movdqa xmm7, xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm1, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm1, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm1, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm1 + paddsw xmm4, [GLOBAL(rd)] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + punpcklbw xmm4, xmm0 + + movdqa XMMWORD Ptr [rdi], xmm4 + + movdqa xmm3, xmm2 + movdqa xmm4, xmm2 + + movdqa xmm5, xmm2 + movdqa xmm6, xmm2 + + movdqa xmm7, xmm2 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm2, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm2, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm2, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm2 + paddsw xmm4, [GLOBAL(rd)] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + punpcklbw xmm4, xmm0 + + movdqa XMMWORD Ptr [rdi+16], xmm4 + + lea rsi, [rsi + rax] +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(5) ;[output_width] +%else + add rdi, r8 +%endif + + dec rcx + jnz .filter_block1d16_h6_sse2_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d8_v6_sse2 +;( +; short *src_ptr, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +;/************************************************************************************ +; Notes: filter_block1d8_v6 applies a 6 tap filter vertically to the input pixels. The +; input pixel array has output_height rows. +;*************************************************************************************/ +global sym(vp8_filter_block1d8_v6_sse2) +sym(vp8_filter_block1d8_v6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(7) ;vp8_filter + movsxd rdx, dword ptr arg(3) ;pixels_per_line + + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + + sub rsi, rdx + sub rsi, rdx + + movsxd rcx, DWORD PTR arg(5) ;[output_height] + pxor xmm0, xmm0 ; clear xmm0 + + movdqa xmm7, XMMWORD PTR [GLOBAL(rd)] +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(2) ; dst_ptich +%endif + +.vp8_filter_block1d8_v6_sse2_loop: + movdqa xmm1, XMMWORD PTR [rsi] + pmullw xmm1, [rax] + + movdqa xmm2, XMMWORD PTR [rsi + rdx] + pmullw xmm2, [rax + 16] + + movdqa xmm3, XMMWORD PTR [rsi + rdx * 2] + pmullw xmm3, [rax + 32] + + movdqa xmm5, XMMWORD PTR [rsi + rdx * 4] + pmullw xmm5, [rax + 64] + + add rsi, rdx + movdqa xmm4, XMMWORD PTR [rsi + rdx * 2] + + pmullw xmm4, [rax + 48] + movdqa xmm6, XMMWORD PTR [rsi + rdx * 4] + + pmullw xmm6, [rax + 80] + + paddsw xmm2, xmm5 + paddsw xmm2, xmm3 + + paddsw xmm2, xmm1 + paddsw xmm2, xmm4 + + paddsw xmm2, xmm6 + paddsw xmm2, xmm7 + + psraw xmm2, 7 + packuswb xmm2, xmm0 ; pack and saturate + + movq QWORD PTR [rdi], xmm2 ; store the results in the destination +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(2) ;[dst_ptich] +%else + add rdi, r8 +%endif + dec rcx ; decrement count + jnz .vp8_filter_block1d8_v6_sse2_loop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d16_v6_sse2 +;( +; unsigned short *src_ptr, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; const short *vp8_filter +;) +;/************************************************************************************ +; Notes: filter_block1d16_v6 applies a 6 tap filter vertically to the input pixels. The +; input pixel array has output_height rows. +;*************************************************************************************/ +global sym(vp8_filter_block1d16_v6_sse2) +sym(vp8_filter_block1d16_v6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(7) ;vp8_filter + movsxd rdx, dword ptr arg(3) ;pixels_per_line + + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + + sub rsi, rdx + sub rsi, rdx + + movsxd rcx, DWORD PTR arg(5) ;[output_height] +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(2) ; dst_ptich +%endif + +.vp8_filter_block1d16_v6_sse2_loop: +; The order for adding 6-tap is 2 5 3 1 4 6. Read in data in that order. + movdqa xmm1, XMMWORD PTR [rsi + rdx] ; line 2 + movdqa xmm2, XMMWORD PTR [rsi + rdx + 16] + pmullw xmm1, [rax + 16] + pmullw xmm2, [rax + 16] + + movdqa xmm3, XMMWORD PTR [rsi + rdx * 4] ; line 5 + movdqa xmm4, XMMWORD PTR [rsi + rdx * 4 + 16] + pmullw xmm3, [rax + 64] + pmullw xmm4, [rax + 64] + + movdqa xmm5, XMMWORD PTR [rsi + rdx * 2] ; line 3 + movdqa xmm6, XMMWORD PTR [rsi + rdx * 2 + 16] + pmullw xmm5, [rax + 32] + pmullw xmm6, [rax + 32] + + movdqa xmm7, XMMWORD PTR [rsi] ; line 1 + movdqa xmm0, XMMWORD PTR [rsi + 16] + pmullw xmm7, [rax] + pmullw xmm0, [rax] + + paddsw xmm1, xmm3 + paddsw xmm2, xmm4 + paddsw xmm1, xmm5 + paddsw xmm2, xmm6 + paddsw xmm1, xmm7 + paddsw xmm2, xmm0 + + add rsi, rdx + + movdqa xmm3, XMMWORD PTR [rsi + rdx * 2] ; line 4 + movdqa xmm4, XMMWORD PTR [rsi + rdx * 2 + 16] + pmullw xmm3, [rax + 48] + pmullw xmm4, [rax + 48] + + movdqa xmm5, XMMWORD PTR [rsi + rdx * 4] ; line 6 + movdqa xmm6, XMMWORD PTR [rsi + rdx * 4 + 16] + pmullw xmm5, [rax + 80] + pmullw xmm6, [rax + 80] + + movdqa xmm7, XMMWORD PTR [GLOBAL(rd)] + pxor xmm0, xmm0 ; clear xmm0 + + paddsw xmm1, xmm3 + paddsw xmm2, xmm4 + paddsw xmm1, xmm5 + paddsw xmm2, xmm6 + + paddsw xmm1, xmm7 + paddsw xmm2, xmm7 + + psraw xmm1, 7 + psraw xmm2, 7 + + packuswb xmm1, xmm2 ; pack and saturate + movdqa XMMWORD PTR [rdi], xmm1 ; store the results in the destination +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(2) ;[dst_ptich] +%else + add rdi, r8 +%endif + dec rcx ; decrement count + jnz .vp8_filter_block1d16_v6_sse2_loop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d8_h6_only_sse2 +;( +; unsigned char *src_ptr, +; unsigned int src_pixels_per_line, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int output_height, +; const short *vp8_filter +;) +; First-pass filter only when yoffset==0 +global sym(vp8_filter_block1d8_h6_only_sse2) +sym(vp8_filter_block1d8_h6_only_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(5) ;vp8_filter + mov rsi, arg(0) ;src_ptr + + mov rdi, arg(2) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(1) ;src_pixels_per_line ; Pitch for Source +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(3) ;dst_ptich +%endif + pxor xmm0, xmm0 ; clear xmm0 for unpack + +.filter_block1d8_h6_only_rowloop: + movq xmm3, MMWORD PTR [rsi - 2] + movq xmm1, MMWORD PTR [rsi + 6] + + prefetcht2 [rsi+rax-2] + + pslldq xmm1, 8 + por xmm1, xmm3 + + movdqa xmm4, xmm1 + movdqa xmm5, xmm1 + + movdqa xmm6, xmm1 + movdqa xmm7, xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm1, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm1, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm1, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm1 + paddsw xmm4, [GLOBAL(rd)] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + + movq QWORD PTR [rdi], xmm4 ; store the results in the destination + lea rsi, [rsi + rax] + +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(3) ;dst_ptich +%else + add rdi, r8 +%endif + dec rcx + + jnz .filter_block1d8_h6_only_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d16_h6_only_sse2 +;( +; unsigned char *src_ptr, +; unsigned int src_pixels_per_line, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int output_height, +; const short *vp8_filter +;) +; First-pass filter only when yoffset==0 +global sym(vp8_filter_block1d16_h6_only_sse2) +sym(vp8_filter_block1d16_h6_only_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(5) ;vp8_filter + mov rsi, arg(0) ;src_ptr + + mov rdi, arg(2) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(1) ;src_pixels_per_line ; Pitch for Source +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(3) ;dst_ptich +%endif + + pxor xmm0, xmm0 ; clear xmm0 for unpack + +.filter_block1d16_h6_only_sse2_rowloop: + movq xmm3, MMWORD PTR [rsi - 2] + movq xmm1, MMWORD PTR [rsi + 6] + + movq xmm2, MMWORD PTR [rsi +14] + pslldq xmm2, 8 + + por xmm2, xmm1 + prefetcht2 [rsi+rax-2] + + pslldq xmm1, 8 + por xmm1, xmm3 + + movdqa xmm4, xmm1 + movdqa xmm5, xmm1 + + movdqa xmm6, xmm1 + movdqa xmm7, xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm1, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm1, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm1, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm1 + paddsw xmm4, [GLOBAL(rd)] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 ; lower 8 bytes + + movq QWORD Ptr [rdi], xmm4 ; store the results in the destination + + movdqa xmm3, xmm2 + movdqa xmm4, xmm2 + + movdqa xmm5, xmm2 + movdqa xmm6, xmm2 + + movdqa xmm7, xmm2 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm2, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm2, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm2, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm2 + paddsw xmm4, [GLOBAL(rd)] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 ; higher 8 bytes + + movq QWORD Ptr [rdi+8], xmm4 ; store the results in the destination + + lea rsi, [rsi + rax] +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(3) ;dst_ptich +%else + add rdi, r8 +%endif + + dec rcx + jnz .filter_block1d16_h6_only_sse2_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d8_v6_only_sse2 +;( +; unsigned char *src_ptr, +; unsigned int src_pixels_per_line, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int output_height, +; const short *vp8_filter +;) +; Second-pass filter only when xoffset==0 +global sym(vp8_filter_block1d8_v6_only_sse2) +sym(vp8_filter_block1d8_v6_only_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line + + mov rax, arg(5) ;vp8_filter + + pxor xmm0, xmm0 ; clear xmm0 + + movdqa xmm7, XMMWORD PTR [GLOBAL(rd)] +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(3) ; dst_ptich +%endif + +.vp8_filter_block1d8_v6_only_sse2_loop: + movq xmm1, MMWORD PTR [rsi] + movq xmm2, MMWORD PTR [rsi + rdx] + movq xmm3, MMWORD PTR [rsi + rdx * 2] + movq xmm5, MMWORD PTR [rsi + rdx * 4] + add rsi, rdx + movq xmm4, MMWORD PTR [rsi + rdx * 2] + movq xmm6, MMWORD PTR [rsi + rdx * 4] + + punpcklbw xmm1, xmm0 + pmullw xmm1, [rax] + + punpcklbw xmm2, xmm0 + pmullw xmm2, [rax + 16] + + punpcklbw xmm3, xmm0 + pmullw xmm3, [rax + 32] + + punpcklbw xmm5, xmm0 + pmullw xmm5, [rax + 64] + + punpcklbw xmm4, xmm0 + pmullw xmm4, [rax + 48] + + punpcklbw xmm6, xmm0 + pmullw xmm6, [rax + 80] + + paddsw xmm2, xmm5 + paddsw xmm2, xmm3 + + paddsw xmm2, xmm1 + paddsw xmm2, xmm4 + + paddsw xmm2, xmm6 + paddsw xmm2, xmm7 + + psraw xmm2, 7 + packuswb xmm2, xmm0 ; pack and saturate + + movq QWORD PTR [rdi], xmm2 ; store the results in the destination +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;[dst_ptich] +%else + add rdi, r8 +%endif + dec rcx ; decrement count + jnz .vp8_filter_block1d8_v6_only_sse2_loop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_unpack_block1d16_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int output_height, +; unsigned int output_width +;) +global sym(vp8_unpack_block1d16_h6_sse2) +sym(vp8_unpack_block1d16_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(3) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source + + pxor xmm0, xmm0 ; clear xmm0 for unpack +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(4) ;output_width ; Pitch for Source +%endif + +.unpack_block1d16_h6_sse2_rowloop: + movq xmm1, MMWORD PTR [rsi] ; 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 -2 + movq xmm3, MMWORD PTR [rsi+8] ; make copy of xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + punpcklbw xmm1, xmm0 + + movdqa XMMWORD Ptr [rdi], xmm1 + movdqa XMMWORD Ptr [rdi + 16], xmm3 + + lea rsi, [rsi + rax] +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(4) ;[output_width] +%else + add rdi, r8 +%endif + dec rcx + jnz .unpack_block1d16_h6_sse2_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_bilinear_predict16x16_sse2 +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +extern sym(vp8_bilinear_filters_x86_8) +global sym(vp8_bilinear_predict16x16_sse2) +sym(vp8_bilinear_predict16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = vp8_bilinear_filters_x86_8[xoffset] + ;const short *VFilter = vp8_bilinear_filters_x86_8[yoffset] + + lea rcx, [GLOBAL(sym(vp8_bilinear_filters_x86_8))] + movsxd rax, dword ptr arg(2) ;xoffset + + cmp rax, 0 ;skip first_pass filter if xoffset=0 + je .b16x16_sp_only + + shl rax, 5 + add rax, rcx ;HFilter + + mov rdi, arg(4) ;dst_ptr + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(5) ;dst_pitch + + movdqa xmm1, [rax] + movdqa xmm2, [rax+16] + + movsxd rax, dword ptr arg(3) ;yoffset + + cmp rax, 0 ;skip second_pass filter if yoffset=0 + je .b16x16_fp_only + + shl rax, 5 + add rax, rcx ;VFilter + + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line + + pxor xmm0, xmm0 + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;dst_pitch +%endif + ; get the first horizontal line done + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movdqa xmm4, xmm3 ; make a copy of current line + + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm1 + + movdqu xmm5, [rsi+1] + movdqa xmm6, xmm5 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, xmm2 + pmullw xmm6, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [GLOBAL(rd)] + psraw xmm4, VP8_FILTER_SHIFT + + movdqa xmm7, xmm3 + packuswb xmm7, xmm4 + + add rsi, rdx ; next line +.next_row: + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movdqa xmm4, xmm3 ; make a copy of current line + + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm1 + + movdqu xmm5, [rsi+1] + movdqa xmm6, xmm5 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, xmm2 + pmullw xmm6, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + movdqa xmm5, xmm7 + movdqa xmm6, xmm7 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, [rax] + pmullw xmm6, [rax] + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [GLOBAL(rd)] + psraw xmm4, VP8_FILTER_SHIFT + + movdqa xmm7, xmm3 + packuswb xmm7, xmm4 + + pmullw xmm3, [rax+16] + pmullw xmm4, [rax+16] + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [GLOBAL(rd)] + psraw xmm4, VP8_FILTER_SHIFT + + packuswb xmm3, xmm4 + movdqa [rdi], xmm3 ; store the results in the destination + + add rsi, rdx ; next line +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(5) ;dst_pitch +%else + add rdi, r8 +%endif + + cmp rdi, rcx + jne .next_row + + jmp .done + +.b16x16_sp_only: + movsxd rax, dword ptr arg(3) ;yoffset + shl rax, 5 + add rax, rcx ;VFilter + + mov rdi, arg(4) ;dst_ptr + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(5) ;dst_pitch + + movdqa xmm1, [rax] + movdqa xmm2, [rax+16] + + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + + pxor xmm0, xmm0 + + ; get the first horizontal line done + movdqu xmm7, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + + add rsi, rax ; next line +.next_row_spo: + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + + movdqa xmm5, xmm7 + movdqa xmm6, xmm7 + + movdqa xmm4, xmm3 ; make a copy of current line + movdqa xmm7, xmm3 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm5, xmm1 + pmullw xmm6, xmm1 + pmullw xmm3, xmm2 + pmullw xmm4, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [GLOBAL(rd)] + psraw xmm4, VP8_FILTER_SHIFT + + packuswb xmm3, xmm4 + movdqa [rdi], xmm3 ; store the results in the destination + + add rsi, rax ; next line + add rdi, rdx ;dst_pitch + cmp rdi, rcx + jne .next_row_spo + + jmp .done + +.b16x16_fp_only: + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + pxor xmm0, xmm0 + +.next_row_fpo: + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movdqa xmm4, xmm3 ; make a copy of current line + + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm1 + + movdqu xmm5, [rsi+1] + movdqa xmm6, xmm5 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, xmm2 + pmullw xmm6, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [GLOBAL(rd)] + psraw xmm4, VP8_FILTER_SHIFT + + packuswb xmm3, xmm4 + movdqa [rdi], xmm3 ; store the results in the destination + + add rsi, rax ; next line + add rdi, rdx ; dst_pitch + cmp rdi, rcx + jne .next_row_fpo + +.done: + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_bilinear_predict8x8_sse2 +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict8x8_sse2) +sym(vp8_bilinear_predict8x8_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 144 ; reserve 144 bytes + + ;const short *HFilter = vp8_bilinear_filters_x86_8[xoffset] + ;const short *VFilter = vp8_bilinear_filters_x86_8[yoffset] + lea rcx, [GLOBAL(sym(vp8_bilinear_filters_x86_8))] + + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line + + ;Read 9-line unaligned data in and put them on stack. This gives a big + ;performance boost. + movdqu xmm0, [rsi] + lea rax, [rdx + rdx*2] + movdqu xmm1, [rsi+rdx] + movdqu xmm2, [rsi+rdx*2] + add rsi, rax + movdqu xmm3, [rsi] + movdqu xmm4, [rsi+rdx] + movdqu xmm5, [rsi+rdx*2] + add rsi, rax + movdqu xmm6, [rsi] + movdqu xmm7, [rsi+rdx] + + movdqa XMMWORD PTR [rsp], xmm0 + + movdqu xmm0, [rsi+rdx*2] + + movdqa XMMWORD PTR [rsp+16], xmm1 + movdqa XMMWORD PTR [rsp+32], xmm2 + movdqa XMMWORD PTR [rsp+48], xmm3 + movdqa XMMWORD PTR [rsp+64], xmm4 + movdqa XMMWORD PTR [rsp+80], xmm5 + movdqa XMMWORD PTR [rsp+96], xmm6 + movdqa XMMWORD PTR [rsp+112], xmm7 + movdqa XMMWORD PTR [rsp+128], xmm0 + + movsxd rax, dword ptr arg(2) ;xoffset + shl rax, 5 + add rax, rcx ;HFilter + + mov rdi, arg(4) ;dst_ptr + movsxd rdx, dword ptr arg(5) ;dst_pitch + + movdqa xmm1, [rax] + movdqa xmm2, [rax+16] + + movsxd rax, dword ptr arg(3) ;yoffset + shl rax, 5 + add rax, rcx ;VFilter + + lea rcx, [rdi+rdx*8] + + movdqa xmm5, [rax] + movdqa xmm6, [rax+16] + + pxor xmm0, xmm0 + + ; get the first horizontal line done + movdqa xmm3, XMMWORD PTR [rsp] + movdqa xmm4, xmm3 ; make a copy of current line + psrldq xmm4, 1 + + punpcklbw xmm3, xmm0 ; 00 01 02 03 04 05 06 07 + punpcklbw xmm4, xmm0 ; 01 02 03 04 05 06 07 08 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm2 + + paddw xmm3, xmm4 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movdqa xmm7, xmm3 + add rsp, 16 ; next line +.next_row8x8: + movdqa xmm3, XMMWORD PTR [rsp] ; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + movdqa xmm4, xmm3 ; make a copy of current line + psrldq xmm4, 1 + + punpcklbw xmm3, xmm0 ; 00 01 02 03 04 05 06 07 + punpcklbw xmm4, xmm0 ; 01 02 03 04 05 06 07 08 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm2 + + paddw xmm3, xmm4 + pmullw xmm7, xmm5 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movdqa xmm4, xmm3 + + pmullw xmm3, xmm6 + paddw xmm3, xmm7 + + movdqa xmm7, xmm4 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + packuswb xmm3, xmm0 + movq [rdi], xmm3 ; store the results in the destination + + add rsp, 16 ; next line + add rdi, rdx + + cmp rdi, rcx + jne .next_row8x8 + + ;add rsp, 144 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +align 16 +rd: + times 8 dw 0x40 diff --git a/vp8/common/x86/subpixel_ssse3.asm b/vp8/common/x86/subpixel_ssse3.asm new file mode 100644 index 0000000..6bca82b --- /dev/null +++ b/vp8/common/x86/subpixel_ssse3.asm @@ -0,0 +1,1507 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define BLOCK_HEIGHT_WIDTH 4 +%define VP8_FILTER_WEIGHT 128 +%define VP8_FILTER_SHIFT 7 + + +;/************************************************************************************ +; Notes: filter_block1d_h6 applies a 6 tap filter horizontally to the input pixels. The +; input pixel array has output_height rows. This routine assumes that output_height is an +; even number. This function handles 8 pixels in horizontal direction, calculating ONE +; rows each iteration to take advantage of the 128 bits operations. +; +; This is an implementation of some of the SSE optimizations first seen in ffvp8 +; +;*************************************************************************************/ +;void vp8_filter_block1d8_h6_ssse3 +;( +; unsigned char *src_ptr, +; unsigned int src_pixels_per_line, +; unsigned char *output_ptr, +; unsigned int output_pitch, +; unsigned int output_height, +; unsigned int vp8_filter_index +;) +global sym(vp8_filter_block1d8_h6_ssse3) +sym(vp8_filter_block1d8_h6_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, DWORD PTR arg(5) ;table index + xor rsi, rsi + shl rdx, 4 + + movdqa xmm7, [GLOBAL(rd)] + + lea rax, [GLOBAL(k0_k5)] + add rax, rdx + mov rdi, arg(2) ;output_ptr + + cmp esi, DWORD PTR [rax] + je vp8_filter_block1d8_h4_ssse3 + + movdqa xmm4, XMMWORD PTR [rax] ;k0_k5 + movdqa xmm5, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm6, XMMWORD PTR [rax+128] ;k1_k3 + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + movsxd rcx, dword ptr arg(4) ;output_height + + movsxd rdx, dword ptr arg(3) ;output_pitch + + sub rdi, rdx +;xmm3 free +.filter_block1d8_h6_rowloop_ssse3: + movq xmm0, MMWORD PTR [rsi - 2] ; -2 -1 0 1 2 3 4 5 + + movq xmm2, MMWORD PTR [rsi + 3] ; 3 4 5 6 7 8 9 10 + + punpcklbw xmm0, xmm2 ; -2 3 -1 4 0 5 1 6 2 7 3 8 4 9 5 10 + + movdqa xmm1, xmm0 + pmaddubsw xmm0, xmm4 + + movdqa xmm2, xmm1 + pshufb xmm1, [GLOBAL(shuf2bfrom1)] + + pshufb xmm2, [GLOBAL(shuf3bfrom1)] + pmaddubsw xmm1, xmm5 + + lea rdi, [rdi + rdx] + pmaddubsw xmm2, xmm6 + + lea rsi, [rsi + rax] + dec rcx + + paddsw xmm0, xmm1 + paddsw xmm2, xmm7 + + paddsw xmm0, xmm2 + + psraw xmm0, 7 + + packuswb xmm0, xmm0 + + movq MMWORD Ptr [rdi], xmm0 + jnz .filter_block1d8_h6_rowloop_ssse3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +vp8_filter_block1d8_h4_ssse3: + movdqa xmm5, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm6, XMMWORD PTR [rax+128] ;k1_k3 + + movdqa xmm3, XMMWORD PTR [GLOBAL(shuf2bfrom1)] + movdqa xmm4, XMMWORD PTR [GLOBAL(shuf3bfrom1)] + + mov rsi, arg(0) ;src_ptr + + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + movsxd rcx, dword ptr arg(4) ;output_height + + movsxd rdx, dword ptr arg(3) ;output_pitch + + sub rdi, rdx + +.filter_block1d8_h4_rowloop_ssse3: + movq xmm0, MMWORD PTR [rsi - 2] ; -2 -1 0 1 2 3 4 5 + + movq xmm1, MMWORD PTR [rsi + 3] ; 3 4 5 6 7 8 9 10 + + punpcklbw xmm0, xmm1 ; -2 3 -1 4 0 5 1 6 2 7 3 8 4 9 5 10 + + movdqa xmm2, xmm0 + pshufb xmm0, xmm3 + + pshufb xmm2, xmm4 + pmaddubsw xmm0, xmm5 + + lea rdi, [rdi + rdx] + pmaddubsw xmm2, xmm6 + + lea rsi, [rsi + rax] + dec rcx + + paddsw xmm0, xmm7 + + paddsw xmm0, xmm2 + + psraw xmm0, 7 + + packuswb xmm0, xmm0 + + movq MMWORD Ptr [rdi], xmm0 + + jnz .filter_block1d8_h4_rowloop_ssse3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret +;void vp8_filter_block1d16_h6_ssse3 +;( +; unsigned char *src_ptr, +; unsigned int src_pixels_per_line, +; unsigned char *output_ptr, +; unsigned int output_pitch, +; unsigned int output_height, +; unsigned int vp8_filter_index +;) +global sym(vp8_filter_block1d16_h6_ssse3) +sym(vp8_filter_block1d16_h6_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, DWORD PTR arg(5) ;table index + xor rsi, rsi + shl rdx, 4 ; + + lea rax, [GLOBAL(k0_k5)] + add rax, rdx + + mov rdi, arg(2) ;output_ptr + + mov rsi, arg(0) ;src_ptr + + movdqa xmm4, XMMWORD PTR [rax] ;k0_k5 + movdqa xmm5, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm6, XMMWORD PTR [rax+128] ;k1_k3 + + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rdx, dword ptr arg(3) ;output_pitch + +.filter_block1d16_h6_rowloop_ssse3: + movq xmm0, MMWORD PTR [rsi - 2] ; -2 -1 0 1 2 3 4 5 + + movq xmm3, MMWORD PTR [rsi + 3] ; 3 4 5 6 7 8 9 10 + + punpcklbw xmm0, xmm3 ; -2 3 -1 4 0 5 1 6 2 7 3 8 4 9 5 10 + + movdqa xmm1, xmm0 + pmaddubsw xmm0, xmm4 + + movdqa xmm2, xmm1 + pshufb xmm1, [GLOBAL(shuf2bfrom1)] + + pshufb xmm2, [GLOBAL(shuf3bfrom1)] + movq xmm3, MMWORD PTR [rsi + 6] + + pmaddubsw xmm1, xmm5 + movq xmm7, MMWORD PTR [rsi + 11] + + pmaddubsw xmm2, xmm6 + punpcklbw xmm3, xmm7 + + paddsw xmm0, xmm1 + movdqa xmm1, xmm3 + + pmaddubsw xmm3, xmm4 + paddsw xmm0, xmm2 + + movdqa xmm2, xmm1 + paddsw xmm0, [GLOBAL(rd)] + + pshufb xmm1, [GLOBAL(shuf2bfrom1)] + pshufb xmm2, [GLOBAL(shuf3bfrom1)] + + psraw xmm0, 7 + pmaddubsw xmm1, xmm5 + + pmaddubsw xmm2, xmm6 + packuswb xmm0, xmm0 + + lea rsi, [rsi + rax] + paddsw xmm3, xmm1 + + paddsw xmm3, xmm2 + + paddsw xmm3, [GLOBAL(rd)] + + psraw xmm3, 7 + + packuswb xmm3, xmm3 + + punpcklqdq xmm0, xmm3 + + movdqa XMMWORD Ptr [rdi], xmm0 + + lea rdi, [rdi + rdx] + dec rcx + jnz .filter_block1d16_h6_rowloop_ssse3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_filter_block1d4_h6_ssse3 +;( +; unsigned char *src_ptr, +; unsigned int src_pixels_per_line, +; unsigned char *output_ptr, +; unsigned int output_pitch, +; unsigned int output_height, +; unsigned int vp8_filter_index +;) +global sym(vp8_filter_block1d4_h6_ssse3) +sym(vp8_filter_block1d4_h6_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, DWORD PTR arg(5) ;table index + xor rsi, rsi + shl rdx, 4 ; + + lea rax, [GLOBAL(k0_k5)] + add rax, rdx + movdqa xmm7, [GLOBAL(rd)] + + cmp esi, DWORD PTR [rax] + je .vp8_filter_block1d4_h4_ssse3 + + movdqa xmm4, XMMWORD PTR [rax] ;k0_k5 + movdqa xmm5, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm6, XMMWORD PTR [rax+128] ;k1_k3 + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;output_ptr + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + movsxd rcx, dword ptr arg(4) ;output_height + + movsxd rdx, dword ptr arg(3) ;output_pitch + +;xmm3 free +.filter_block1d4_h6_rowloop_ssse3: + movdqu xmm0, XMMWORD PTR [rsi - 2] + + movdqa xmm1, xmm0 + pshufb xmm0, [GLOBAL(shuf1b)] + + movdqa xmm2, xmm1 + pshufb xmm1, [GLOBAL(shuf2b)] + pmaddubsw xmm0, xmm4 + pshufb xmm2, [GLOBAL(shuf3b)] + pmaddubsw xmm1, xmm5 + +;-- + pmaddubsw xmm2, xmm6 + + lea rsi, [rsi + rax] +;-- + paddsw xmm0, xmm1 + paddsw xmm0, xmm7 + pxor xmm1, xmm1 + paddsw xmm0, xmm2 + psraw xmm0, 7 + packuswb xmm0, xmm0 + + movd DWORD PTR [rdi], xmm0 + + add rdi, rdx + dec rcx + jnz .filter_block1d4_h6_rowloop_ssse3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +.vp8_filter_block1d4_h4_ssse3: + movdqa xmm5, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm6, XMMWORD PTR [rax+128] ;k1_k3 + movdqa xmm0, XMMWORD PTR [GLOBAL(shuf2b)] + movdqa xmm3, XMMWORD PTR [GLOBAL(shuf3b)] + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;output_ptr + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + movsxd rcx, dword ptr arg(4) ;output_height + + movsxd rdx, dword ptr arg(3) ;output_pitch + +.filter_block1d4_h4_rowloop_ssse3: + movdqu xmm1, XMMWORD PTR [rsi - 2] + + movdqa xmm2, xmm1 + pshufb xmm1, xmm0 ;;[GLOBAL(shuf2b)] + pshufb xmm2, xmm3 ;;[GLOBAL(shuf3b)] + pmaddubsw xmm1, xmm5 + +;-- + pmaddubsw xmm2, xmm6 + + lea rsi, [rsi + rax] +;-- + paddsw xmm1, xmm7 + paddsw xmm1, xmm2 + psraw xmm1, 7 + packuswb xmm1, xmm1 + + movd DWORD PTR [rdi], xmm1 + + add rdi, rdx + dec rcx + jnz .filter_block1d4_h4_rowloop_ssse3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + + +;void vp8_filter_block1d16_v6_ssse3 +;( +; unsigned char *src_ptr, +; unsigned int src_pitch, +; unsigned char *output_ptr, +; unsigned int out_pitch, +; unsigned int output_height, +; unsigned int vp8_filter_index +;) +global sym(vp8_filter_block1d16_v6_ssse3) +sym(vp8_filter_block1d16_v6_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, DWORD PTR arg(5) ;table index + xor rsi, rsi + shl rdx, 4 ; + + lea rax, [GLOBAL(k0_k5)] + add rax, rdx + + cmp esi, DWORD PTR [rax] + je .vp8_filter_block1d16_v4_ssse3 + + movdqa xmm5, XMMWORD PTR [rax] ;k0_k5 + movdqa xmm6, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm7, XMMWORD PTR [rax+128] ;k1_k3 + + mov rsi, arg(0) ;src_ptr + movsxd rdx, DWORD PTR arg(1) ;pixels_per_line + mov rdi, arg(2) ;output_ptr + +%if ABI_IS_32BIT=0 + movsxd r8, DWORD PTR arg(3) ;out_pitch +%endif + mov rax, rsi + movsxd rcx, DWORD PTR arg(4) ;output_height + add rax, rdx + + +.vp8_filter_block1d16_v6_ssse3_loop: + movq xmm1, MMWORD PTR [rsi] ;A + movq xmm2, MMWORD PTR [rsi + rdx] ;B + movq xmm3, MMWORD PTR [rsi + rdx * 2] ;C + movq xmm4, MMWORD PTR [rax + rdx * 2] ;D + movq xmm0, MMWORD PTR [rsi + rdx * 4] ;E + + punpcklbw xmm2, xmm4 ;B D + punpcklbw xmm3, xmm0 ;C E + + movq xmm0, MMWORD PTR [rax + rdx * 4] ;F + + pmaddubsw xmm3, xmm6 + punpcklbw xmm1, xmm0 ;A F + pmaddubsw xmm2, xmm7 + pmaddubsw xmm1, xmm5 + + paddsw xmm2, xmm3 + paddsw xmm2, xmm1 + paddsw xmm2, [GLOBAL(rd)] + psraw xmm2, 7 + packuswb xmm2, xmm2 + + movq MMWORD PTR [rdi], xmm2 ;store the results + + movq xmm1, MMWORD PTR [rsi + 8] ;A + movq xmm2, MMWORD PTR [rsi + rdx + 8] ;B + movq xmm3, MMWORD PTR [rsi + rdx * 2 + 8] ;C + movq xmm4, MMWORD PTR [rax + rdx * 2 + 8] ;D + movq xmm0, MMWORD PTR [rsi + rdx * 4 + 8] ;E + + punpcklbw xmm2, xmm4 ;B D + punpcklbw xmm3, xmm0 ;C E + + movq xmm0, MMWORD PTR [rax + rdx * 4 + 8] ;F + pmaddubsw xmm3, xmm6 + punpcklbw xmm1, xmm0 ;A F + pmaddubsw xmm2, xmm7 + pmaddubsw xmm1, xmm5 + + add rsi, rdx + add rax, rdx +;-- +;-- + paddsw xmm2, xmm3 + paddsw xmm2, xmm1 + paddsw xmm2, [GLOBAL(rd)] + psraw xmm2, 7 + packuswb xmm2, xmm2 + + movq MMWORD PTR [rdi+8], xmm2 + +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;out_pitch +%else + add rdi, r8 +%endif + dec rcx + jnz .vp8_filter_block1d16_v6_ssse3_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +.vp8_filter_block1d16_v4_ssse3: + movdqa xmm6, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm7, XMMWORD PTR [rax+128] ;k1_k3 + + mov rsi, arg(0) ;src_ptr + movsxd rdx, DWORD PTR arg(1) ;pixels_per_line + mov rdi, arg(2) ;output_ptr + +%if ABI_IS_32BIT=0 + movsxd r8, DWORD PTR arg(3) ;out_pitch +%endif + mov rax, rsi + movsxd rcx, DWORD PTR arg(4) ;output_height + add rax, rdx + +.vp8_filter_block1d16_v4_ssse3_loop: + movq xmm2, MMWORD PTR [rsi + rdx] ;B + movq xmm3, MMWORD PTR [rsi + rdx * 2] ;C + movq xmm4, MMWORD PTR [rax + rdx * 2] ;D + movq xmm0, MMWORD PTR [rsi + rdx * 4] ;E + + punpcklbw xmm2, xmm4 ;B D + punpcklbw xmm3, xmm0 ;C E + + pmaddubsw xmm3, xmm6 + pmaddubsw xmm2, xmm7 + movq xmm5, MMWORD PTR [rsi + rdx + 8] ;B + movq xmm1, MMWORD PTR [rsi + rdx * 2 + 8] ;C + movq xmm4, MMWORD PTR [rax + rdx * 2 + 8] ;D + movq xmm0, MMWORD PTR [rsi + rdx * 4 + 8] ;E + + paddsw xmm2, [GLOBAL(rd)] + paddsw xmm2, xmm3 + psraw xmm2, 7 + packuswb xmm2, xmm2 + + punpcklbw xmm5, xmm4 ;B D + punpcklbw xmm1, xmm0 ;C E + + pmaddubsw xmm1, xmm6 + pmaddubsw xmm5, xmm7 + + movdqa xmm4, [GLOBAL(rd)] + add rsi, rdx + add rax, rdx +;-- +;-- + paddsw xmm5, xmm1 + paddsw xmm5, xmm4 + psraw xmm5, 7 + packuswb xmm5, xmm5 + + punpcklqdq xmm2, xmm5 + + movdqa XMMWORD PTR [rdi], xmm2 + +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;out_pitch +%else + add rdi, r8 +%endif + dec rcx + jnz .vp8_filter_block1d16_v4_ssse3_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_filter_block1d8_v6_ssse3 +;( +; unsigned char *src_ptr, +; unsigned int src_pitch, +; unsigned char *output_ptr, +; unsigned int out_pitch, +; unsigned int output_height, +; unsigned int vp8_filter_index +;) +global sym(vp8_filter_block1d8_v6_ssse3) +sym(vp8_filter_block1d8_v6_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, DWORD PTR arg(5) ;table index + xor rsi, rsi + shl rdx, 4 ; + + lea rax, [GLOBAL(k0_k5)] + add rax, rdx + + movsxd rdx, DWORD PTR arg(1) ;pixels_per_line + mov rdi, arg(2) ;output_ptr +%if ABI_IS_32BIT=0 + movsxd r8, DWORD PTR arg(3) ; out_pitch +%endif + movsxd rcx, DWORD PTR arg(4) ;[output_height] + + cmp esi, DWORD PTR [rax] + je .vp8_filter_block1d8_v4_ssse3 + + movdqa xmm5, XMMWORD PTR [rax] ;k0_k5 + movdqa xmm6, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm7, XMMWORD PTR [rax+128] ;k1_k3 + + mov rsi, arg(0) ;src_ptr + + mov rax, rsi + add rax, rdx + +.vp8_filter_block1d8_v6_ssse3_loop: + movq xmm1, MMWORD PTR [rsi] ;A + movq xmm2, MMWORD PTR [rsi + rdx] ;B + movq xmm3, MMWORD PTR [rsi + rdx * 2] ;C + movq xmm4, MMWORD PTR [rax + rdx * 2] ;D + movq xmm0, MMWORD PTR [rsi + rdx * 4] ;E + + punpcklbw xmm2, xmm4 ;B D + punpcklbw xmm3, xmm0 ;C E + + movq xmm0, MMWORD PTR [rax + rdx * 4] ;F + movdqa xmm4, [GLOBAL(rd)] + + pmaddubsw xmm3, xmm6 + punpcklbw xmm1, xmm0 ;A F + pmaddubsw xmm2, xmm7 + pmaddubsw xmm1, xmm5 + add rsi, rdx + add rax, rdx +;-- +;-- + paddsw xmm2, xmm3 + paddsw xmm2, xmm1 + paddsw xmm2, xmm4 + psraw xmm2, 7 + packuswb xmm2, xmm2 + + movq MMWORD PTR [rdi], xmm2 + +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;[out_pitch] +%else + add rdi, r8 +%endif + dec rcx + jnz .vp8_filter_block1d8_v6_ssse3_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +.vp8_filter_block1d8_v4_ssse3: + movdqa xmm6, XMMWORD PTR [rax+256] ;k2_k4 + movdqa xmm7, XMMWORD PTR [rax+128] ;k1_k3 + movdqa xmm5, [GLOBAL(rd)] + + mov rsi, arg(0) ;src_ptr + + mov rax, rsi + add rax, rdx + +.vp8_filter_block1d8_v4_ssse3_loop: + movq xmm2, MMWORD PTR [rsi + rdx] ;B + movq xmm3, MMWORD PTR [rsi + rdx * 2] ;C + movq xmm4, MMWORD PTR [rax + rdx * 2] ;D + movq xmm0, MMWORD PTR [rsi + rdx * 4] ;E + + punpcklbw xmm2, xmm4 ;B D + punpcklbw xmm3, xmm0 ;C E + + pmaddubsw xmm3, xmm6 + pmaddubsw xmm2, xmm7 + add rsi, rdx + add rax, rdx +;-- +;-- + paddsw xmm2, xmm3 + paddsw xmm2, xmm5 + psraw xmm2, 7 + packuswb xmm2, xmm2 + + movq MMWORD PTR [rdi], xmm2 + +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;[out_pitch] +%else + add rdi, r8 +%endif + dec rcx + jnz .vp8_filter_block1d8_v4_ssse3_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret +;void vp8_filter_block1d4_v6_ssse3 +;( +; unsigned char *src_ptr, +; unsigned int src_pitch, +; unsigned char *output_ptr, +; unsigned int out_pitch, +; unsigned int output_height, +; unsigned int vp8_filter_index +;) +global sym(vp8_filter_block1d4_v6_ssse3) +sym(vp8_filter_block1d4_v6_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, DWORD PTR arg(5) ;table index + xor rsi, rsi + shl rdx, 4 ; + + lea rax, [GLOBAL(k0_k5)] + add rax, rdx + + movsxd rdx, DWORD PTR arg(1) ;pixels_per_line + mov rdi, arg(2) ;output_ptr +%if ABI_IS_32BIT=0 + movsxd r8, DWORD PTR arg(3) ; out_pitch +%endif + movsxd rcx, DWORD PTR arg(4) ;[output_height] + + cmp esi, DWORD PTR [rax] + je .vp8_filter_block1d4_v4_ssse3 + + movq mm5, MMWORD PTR [rax] ;k0_k5 + movq mm6, MMWORD PTR [rax+256] ;k2_k4 + movq mm7, MMWORD PTR [rax+128] ;k1_k3 + + mov rsi, arg(0) ;src_ptr + + mov rax, rsi + add rax, rdx + +.vp8_filter_block1d4_v6_ssse3_loop: + movd mm1, DWORD PTR [rsi] ;A + movd mm2, DWORD PTR [rsi + rdx] ;B + movd mm3, DWORD PTR [rsi + rdx * 2] ;C + movd mm4, DWORD PTR [rax + rdx * 2] ;D + movd mm0, DWORD PTR [rsi + rdx * 4] ;E + + punpcklbw mm2, mm4 ;B D + punpcklbw mm3, mm0 ;C E + + movd mm0, DWORD PTR [rax + rdx * 4] ;F + + movq mm4, [GLOBAL(rd)] + + pmaddubsw mm3, mm6 + punpcklbw mm1, mm0 ;A F + pmaddubsw mm2, mm7 + pmaddubsw mm1, mm5 + add rsi, rdx + add rax, rdx +;-- +;-- + paddsw mm2, mm3 + paddsw mm2, mm1 + paddsw mm2, mm4 + psraw mm2, 7 + packuswb mm2, mm2 + + movd DWORD PTR [rdi], mm2 + +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;[out_pitch] +%else + add rdi, r8 +%endif + dec rcx + jnz .vp8_filter_block1d4_v6_ssse3_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +.vp8_filter_block1d4_v4_ssse3: + movq mm6, MMWORD PTR [rax+256] ;k2_k4 + movq mm7, MMWORD PTR [rax+128] ;k1_k3 + movq mm5, MMWORD PTR [GLOBAL(rd)] + + mov rsi, arg(0) ;src_ptr + + mov rax, rsi + add rax, rdx + +.vp8_filter_block1d4_v4_ssse3_loop: + movd mm2, DWORD PTR [rsi + rdx] ;B + movd mm3, DWORD PTR [rsi + rdx * 2] ;C + movd mm4, DWORD PTR [rax + rdx * 2] ;D + movd mm0, DWORD PTR [rsi + rdx * 4] ;E + + punpcklbw mm2, mm4 ;B D + punpcklbw mm3, mm0 ;C E + + pmaddubsw mm3, mm6 + pmaddubsw mm2, mm7 + add rsi, rdx + add rax, rdx +;-- +;-- + paddsw mm2, mm3 + paddsw mm2, mm5 + psraw mm2, 7 + packuswb mm2, mm2 + + movd DWORD PTR [rdi], mm2 + +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(3) ;[out_pitch] +%else + add rdi, r8 +%endif + dec rcx + jnz .vp8_filter_block1d4_v4_ssse3_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_bilinear_predict16x16_ssse3 +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict16x16_ssse3) +sym(vp8_bilinear_predict16x16_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + lea rcx, [GLOBAL(vp8_bilinear_filters_ssse3)] + movsxd rax, dword ptr arg(2) ; xoffset + + cmp rax, 0 ; skip first_pass filter if xoffset=0 + je .b16x16_sp_only + + shl rax, 4 + lea rax, [rax + rcx] ; HFilter + + mov rdi, arg(4) ; dst_ptr + mov rsi, arg(0) ; src_ptr + movsxd rdx, dword ptr arg(5) ; dst_pitch + + movdqa xmm1, [rax] + + movsxd rax, dword ptr arg(3) ; yoffset + + cmp rax, 0 ; skip second_pass filter if yoffset=0 + je .b16x16_fp_only + + shl rax, 4 + lea rax, [rax + rcx] ; VFilter + + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rdx, dword ptr arg(1) ; src_pixels_per_line + + movdqa xmm2, [rax] + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ; dst_pitch +%endif + movq xmm3, [rsi] ; 00 01 02 03 04 05 06 07 + movq xmm5, [rsi+1] ; 01 02 03 04 05 06 07 08 + + punpcklbw xmm3, xmm5 ; 00 01 01 02 02 03 03 04 04 05 05 06 06 07 07 08 + movq xmm4, [rsi+8] ; 08 09 10 11 12 13 14 15 + + movq xmm5, [rsi+9] ; 09 10 11 12 13 14 15 16 + + lea rsi, [rsi + rdx] ; next line + + pmaddubsw xmm3, xmm1 ; 00 02 04 06 08 10 12 14 + + punpcklbw xmm4, xmm5 ; 08 09 09 10 10 11 11 12 12 13 13 14 14 15 15 16 + pmaddubsw xmm4, xmm1 ; 01 03 05 07 09 11 13 15 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [GLOBAL(rd)] ; xmm4 += round value + psraw xmm4, VP8_FILTER_SHIFT ; xmm4 /= 128 + + movdqa xmm7, xmm3 + packuswb xmm7, xmm4 ; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + +.next_row: + movq xmm6, [rsi] ; 00 01 02 03 04 05 06 07 + movq xmm5, [rsi+1] ; 01 02 03 04 05 06 07 08 + + punpcklbw xmm6, xmm5 + movq xmm4, [rsi+8] ; 08 09 10 11 12 13 14 15 + + movq xmm5, [rsi+9] ; 09 10 11 12 13 14 15 16 + lea rsi, [rsi + rdx] ; next line + + pmaddubsw xmm6, xmm1 + + punpcklbw xmm4, xmm5 + pmaddubsw xmm4, xmm1 + + paddw xmm6, [GLOBAL(rd)] ; xmm6 += round value + psraw xmm6, VP8_FILTER_SHIFT ; xmm6 /= 128 + + paddw xmm4, [GLOBAL(rd)] ; xmm4 += round value + psraw xmm4, VP8_FILTER_SHIFT ; xmm4 /= 128 + + packuswb xmm6, xmm4 + movdqa xmm5, xmm7 + + punpcklbw xmm5, xmm6 + pmaddubsw xmm5, xmm2 + + punpckhbw xmm7, xmm6 + pmaddubsw xmm7, xmm2 + + paddw xmm5, [GLOBAL(rd)] ; xmm5 += round value + psraw xmm5, VP8_FILTER_SHIFT ; xmm5 /= 128 + + paddw xmm7, [GLOBAL(rd)] ; xmm7 += round value + psraw xmm7, VP8_FILTER_SHIFT ; xmm7 /= 128 + + packuswb xmm5, xmm7 + movdqa xmm7, xmm6 + + movdqa [rdi], xmm5 ; store the results in the destination +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(5) ; dst_pitch +%else + add rdi, r8 +%endif + + cmp rdi, rcx + jne .next_row + + jmp .done + +.b16x16_sp_only: + movsxd rax, dword ptr arg(3) ; yoffset + shl rax, 4 + lea rax, [rax + rcx] ; VFilter + + mov rdi, arg(4) ; dst_ptr + mov rsi, arg(0) ; src_ptr + movsxd rdx, dword ptr arg(5) ; dst_pitch + + movdqa xmm1, [rax] ; VFilter + + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rax, dword ptr arg(1) ; src_pixels_per_line + + ; get the first horizontal line done + movq xmm4, [rsi] ; load row 0 + movq xmm2, [rsi + 8] ; load row 0 + + lea rsi, [rsi + rax] ; next line +.next_row_sp: + movq xmm3, [rsi] ; load row + 1 + movq xmm5, [rsi + 8] ; load row + 1 + + punpcklbw xmm4, xmm3 + punpcklbw xmm2, xmm5 + + pmaddubsw xmm4, xmm1 + movq xmm7, [rsi + rax] ; load row + 2 + + pmaddubsw xmm2, xmm1 + movq xmm6, [rsi + rax + 8] ; load row + 2 + + punpcklbw xmm3, xmm7 + punpcklbw xmm5, xmm6 + + pmaddubsw xmm3, xmm1 + paddw xmm4, [GLOBAL(rd)] + + pmaddubsw xmm5, xmm1 + paddw xmm2, [GLOBAL(rd)] + + psraw xmm4, VP8_FILTER_SHIFT + psraw xmm2, VP8_FILTER_SHIFT + + packuswb xmm4, xmm2 + paddw xmm3, [GLOBAL(rd)] + + movdqa [rdi], xmm4 ; store row 0 + paddw xmm5, [GLOBAL(rd)] + + psraw xmm3, VP8_FILTER_SHIFT + psraw xmm5, VP8_FILTER_SHIFT + + packuswb xmm3, xmm5 + movdqa xmm4, xmm7 + + movdqa [rdi + rdx],xmm3 ; store row 1 + lea rsi, [rsi + 2*rax] + + movdqa xmm2, xmm6 + lea rdi, [rdi + 2*rdx] + + cmp rdi, rcx + jne .next_row_sp + + jmp .done + +.b16x16_fp_only: + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rax, dword ptr arg(1) ; src_pixels_per_line + +.next_row_fp: + movq xmm2, [rsi] ; 00 01 02 03 04 05 06 07 + movq xmm4, [rsi+1] ; 01 02 03 04 05 06 07 08 + + punpcklbw xmm2, xmm4 + movq xmm3, [rsi+8] ; 08 09 10 11 12 13 14 15 + + pmaddubsw xmm2, xmm1 + movq xmm4, [rsi+9] ; 09 10 11 12 13 14 15 16 + + lea rsi, [rsi + rax] ; next line + punpcklbw xmm3, xmm4 + + pmaddubsw xmm3, xmm1 + movq xmm5, [rsi] + + paddw xmm2, [GLOBAL(rd)] + movq xmm7, [rsi+1] + + movq xmm6, [rsi+8] + psraw xmm2, VP8_FILTER_SHIFT + + punpcklbw xmm5, xmm7 + movq xmm7, [rsi+9] + + paddw xmm3, [GLOBAL(rd)] + pmaddubsw xmm5, xmm1 + + psraw xmm3, VP8_FILTER_SHIFT + punpcklbw xmm6, xmm7 + + packuswb xmm2, xmm3 + pmaddubsw xmm6, xmm1 + + movdqa [rdi], xmm2 ; store the results in the destination + paddw xmm5, [GLOBAL(rd)] + + lea rdi, [rdi + rdx] ; dst_pitch + psraw xmm5, VP8_FILTER_SHIFT + + paddw xmm6, [GLOBAL(rd)] + psraw xmm6, VP8_FILTER_SHIFT + + packuswb xmm5, xmm6 + lea rsi, [rsi + rax] ; next line + + movdqa [rdi], xmm5 ; store the results in the destination + lea rdi, [rdi + rdx] ; dst_pitch + + cmp rdi, rcx + + jne .next_row_fp + +.done: + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_bilinear_predict8x8_ssse3 +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict8x8_ssse3) +sym(vp8_bilinear_predict8x8_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 144 ; reserve 144 bytes + + lea rcx, [GLOBAL(vp8_bilinear_filters_ssse3)] + + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line + + ;Read 9-line unaligned data in and put them on stack. This gives a big + ;performance boost. + movdqu xmm0, [rsi] + lea rax, [rdx + rdx*2] + movdqu xmm1, [rsi+rdx] + movdqu xmm2, [rsi+rdx*2] + add rsi, rax + movdqu xmm3, [rsi] + movdqu xmm4, [rsi+rdx] + movdqu xmm5, [rsi+rdx*2] + add rsi, rax + movdqu xmm6, [rsi] + movdqu xmm7, [rsi+rdx] + + movdqa XMMWORD PTR [rsp], xmm0 + + movdqu xmm0, [rsi+rdx*2] + + movdqa XMMWORD PTR [rsp+16], xmm1 + movdqa XMMWORD PTR [rsp+32], xmm2 + movdqa XMMWORD PTR [rsp+48], xmm3 + movdqa XMMWORD PTR [rsp+64], xmm4 + movdqa XMMWORD PTR [rsp+80], xmm5 + movdqa XMMWORD PTR [rsp+96], xmm6 + movdqa XMMWORD PTR [rsp+112], xmm7 + movdqa XMMWORD PTR [rsp+128], xmm0 + + movsxd rax, dword ptr arg(2) ; xoffset + cmp rax, 0 ; skip first_pass filter if xoffset=0 + je .b8x8_sp_only + + shl rax, 4 + add rax, rcx ; HFilter + + mov rdi, arg(4) ; dst_ptr + movsxd rdx, dword ptr arg(5) ; dst_pitch + + movdqa xmm0, [rax] + + movsxd rax, dword ptr arg(3) ; yoffset + cmp rax, 0 ; skip second_pass filter if yoffset=0 + je .b8x8_fp_only + + shl rax, 4 + lea rax, [rax + rcx] ; VFilter + + lea rcx, [rdi+rdx*8] + + movdqa xmm1, [rax] + + ; get the first horizontal line done + movdqa xmm3, [rsp] ; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + movdqa xmm5, xmm3 ; 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 xx + + psrldq xmm5, 1 + lea rsp, [rsp + 16] ; next line + + punpcklbw xmm3, xmm5 ; 00 01 01 02 02 03 03 04 04 05 05 06 06 07 07 08 + pmaddubsw xmm3, xmm0 ; 00 02 04 06 08 10 12 14 + + paddw xmm3, [GLOBAL(rd)] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movdqa xmm7, xmm3 + packuswb xmm7, xmm7 ; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + +.next_row: + movdqa xmm6, [rsp] ; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + lea rsp, [rsp + 16] ; next line + + movdqa xmm5, xmm6 + + psrldq xmm5, 1 + + punpcklbw xmm6, xmm5 + pmaddubsw xmm6, xmm0 + + paddw xmm6, [GLOBAL(rd)] ; xmm6 += round value + psraw xmm6, VP8_FILTER_SHIFT ; xmm6 /= 128 + + packuswb xmm6, xmm6 + + punpcklbw xmm7, xmm6 + pmaddubsw xmm7, xmm1 + + paddw xmm7, [GLOBAL(rd)] ; xmm7 += round value + psraw xmm7, VP8_FILTER_SHIFT ; xmm7 /= 128 + + packuswb xmm7, xmm7 + + movq [rdi], xmm7 ; store the results in the destination + lea rdi, [rdi + rdx] + + movdqa xmm7, xmm6 + + cmp rdi, rcx + jne .next_row + + jmp .done8x8 + +.b8x8_sp_only: + movsxd rax, dword ptr arg(3) ; yoffset + shl rax, 4 + lea rax, [rax + rcx] ; VFilter + + mov rdi, arg(4) ;dst_ptr + movsxd rdx, dword ptr arg(5) ; dst_pitch + + movdqa xmm0, [rax] ; VFilter + + movq xmm1, XMMWORD PTR [rsp] + movq xmm2, XMMWORD PTR [rsp+16] + + movq xmm3, XMMWORD PTR [rsp+32] + punpcklbw xmm1, xmm2 + + movq xmm4, XMMWORD PTR [rsp+48] + punpcklbw xmm2, xmm3 + + movq xmm5, XMMWORD PTR [rsp+64] + punpcklbw xmm3, xmm4 + + movq xmm6, XMMWORD PTR [rsp+80] + punpcklbw xmm4, xmm5 + + movq xmm7, XMMWORD PTR [rsp+96] + punpcklbw xmm5, xmm6 + + pmaddubsw xmm1, xmm0 + pmaddubsw xmm2, xmm0 + + pmaddubsw xmm3, xmm0 + pmaddubsw xmm4, xmm0 + + pmaddubsw xmm5, xmm0 + punpcklbw xmm6, xmm7 + + pmaddubsw xmm6, xmm0 + paddw xmm1, [GLOBAL(rd)] + + paddw xmm2, [GLOBAL(rd)] + psraw xmm1, VP8_FILTER_SHIFT + + paddw xmm3, [GLOBAL(rd)] + psraw xmm2, VP8_FILTER_SHIFT + + paddw xmm4, [GLOBAL(rd)] + psraw xmm3, VP8_FILTER_SHIFT + + paddw xmm5, [GLOBAL(rd)] + psraw xmm4, VP8_FILTER_SHIFT + + paddw xmm6, [GLOBAL(rd)] + psraw xmm5, VP8_FILTER_SHIFT + + psraw xmm6, VP8_FILTER_SHIFT + packuswb xmm1, xmm1 + + packuswb xmm2, xmm2 + movq [rdi], xmm1 + + packuswb xmm3, xmm3 + movq [rdi+rdx], xmm2 + + packuswb xmm4, xmm4 + movq xmm1, XMMWORD PTR [rsp+112] + + lea rdi, [rdi + 2*rdx] + movq xmm2, XMMWORD PTR [rsp+128] + + packuswb xmm5, xmm5 + movq [rdi], xmm3 + + packuswb xmm6, xmm6 + movq [rdi+rdx], xmm4 + + lea rdi, [rdi + 2*rdx] + punpcklbw xmm7, xmm1 + + movq [rdi], xmm5 + pmaddubsw xmm7, xmm0 + + movq [rdi+rdx], xmm6 + punpcklbw xmm1, xmm2 + + pmaddubsw xmm1, xmm0 + paddw xmm7, [GLOBAL(rd)] + + psraw xmm7, VP8_FILTER_SHIFT + paddw xmm1, [GLOBAL(rd)] + + psraw xmm1, VP8_FILTER_SHIFT + packuswb xmm7, xmm7 + + packuswb xmm1, xmm1 + lea rdi, [rdi + 2*rdx] + + movq [rdi], xmm7 + + movq [rdi+rdx], xmm1 + lea rsp, [rsp + 144] + + jmp .done8x8 + +.b8x8_fp_only: + lea rcx, [rdi+rdx*8] + +.next_row_fp: + movdqa xmm1, XMMWORD PTR [rsp] + movdqa xmm3, XMMWORD PTR [rsp+16] + + movdqa xmm2, xmm1 + movdqa xmm5, XMMWORD PTR [rsp+32] + + psrldq xmm2, 1 + movdqa xmm7, XMMWORD PTR [rsp+48] + + movdqa xmm4, xmm3 + psrldq xmm4, 1 + + movdqa xmm6, xmm5 + psrldq xmm6, 1 + + punpcklbw xmm1, xmm2 + pmaddubsw xmm1, xmm0 + + punpcklbw xmm3, xmm4 + pmaddubsw xmm3, xmm0 + + punpcklbw xmm5, xmm6 + pmaddubsw xmm5, xmm0 + + movdqa xmm2, xmm7 + psrldq xmm2, 1 + + punpcklbw xmm7, xmm2 + pmaddubsw xmm7, xmm0 + + paddw xmm1, [GLOBAL(rd)] + psraw xmm1, VP8_FILTER_SHIFT + + paddw xmm3, [GLOBAL(rd)] + psraw xmm3, VP8_FILTER_SHIFT + + paddw xmm5, [GLOBAL(rd)] + psraw xmm5, VP8_FILTER_SHIFT + + paddw xmm7, [GLOBAL(rd)] + psraw xmm7, VP8_FILTER_SHIFT + + packuswb xmm1, xmm1 + packuswb xmm3, xmm3 + + packuswb xmm5, xmm5 + movq [rdi], xmm1 + + packuswb xmm7, xmm7 + movq [rdi+rdx], xmm3 + + lea rdi, [rdi + 2*rdx] + movq [rdi], xmm5 + + lea rsp, [rsp + 4*16] + movq [rdi+rdx], xmm7 + + lea rdi, [rdi + 2*rdx] + cmp rdi, rcx + + jne .next_row_fp + + lea rsp, [rsp + 16] + +.done8x8: + ;add rsp, 144 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +shuf1b: + db 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12 +shuf2b: + db 2, 4, 3, 5, 4, 6, 5, 7, 6, 8, 7, 9, 8, 10, 9, 11 +shuf3b: + db 1, 3, 2, 4, 3, 5, 4, 6, 5, 7, 6, 8, 7, 9, 8, 10 + +align 16 +shuf2bfrom1: + db 4, 8, 6, 1, 8, 3, 1, 5, 3, 7, 5, 9, 7,11, 9,13 +align 16 +shuf3bfrom1: + db 2, 6, 4, 8, 6, 1, 8, 3, 1, 5, 3, 7, 5, 9, 7,11 + +align 16 +rd: + times 8 dw 0x40 + +align 16 +k0_k5: + times 8 db 0, 0 ;placeholder + times 8 db 0, 0 + times 8 db 2, 1 + times 8 db 0, 0 + times 8 db 3, 3 + times 8 db 0, 0 + times 8 db 1, 2 + times 8 db 0, 0 +k1_k3: + times 8 db 0, 0 ;placeholder + times 8 db -6, 12 + times 8 db -11, 36 + times 8 db -9, 50 + times 8 db -16, 77 + times 8 db -6, 93 + times 8 db -8, 108 + times 8 db -1, 123 +k2_k4: + times 8 db 128, 0 ;placeholder + times 8 db 123, -1 + times 8 db 108, -8 + times 8 db 93, -6 + times 8 db 77, -16 + times 8 db 50, -9 + times 8 db 36, -11 + times 8 db 12, -6 +align 16 +vp8_bilinear_filters_ssse3: + times 8 db 128, 0 + times 8 db 112, 16 + times 8 db 96, 32 + times 8 db 80, 48 + times 8 db 64, 64 + times 8 db 48, 80 + times 8 db 32, 96 + times 8 db 16, 112 + diff --git a/vp8/common/x86/variance_impl_mmx.asm b/vp8/common/x86/variance_impl_mmx.asm new file mode 100644 index 0000000..2be8bbe --- /dev/null +++ b/vp8/common/x86/variance_impl_mmx.asm @@ -0,0 +1,851 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;unsigned int vp8_get_mb_ss_mmx( short *src_ptr ) +global sym(vp8_get_mb_ss_mmx) +sym(vp8_get_mb_ss_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + sub rsp, 8 + ; end prolog + + mov rax, arg(0) ;src_ptr + mov rcx, 16 + pxor mm4, mm4 + +.NEXTROW: + movq mm0, [rax] + movq mm1, [rax+8] + movq mm2, [rax+16] + movq mm3, [rax+24] + pmaddwd mm0, mm0 + pmaddwd mm1, mm1 + pmaddwd mm2, mm2 + pmaddwd mm3, mm3 + + paddd mm4, mm0 + paddd mm4, mm1 + paddd mm4, mm2 + paddd mm4, mm3 + + add rax, 32 + dec rcx + ja .NEXTROW + movq QWORD PTR [rsp], mm4 + + ;return sum[0]+sum[1]; + movsxd rax, dword ptr [rsp] + movsxd rcx, dword ptr [rsp+4] + add rax, rcx + + + ; begin epilog + add rsp, 8 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_get8x8var_mmx +;( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *SSE, +; int *Sum +;) +global sym(vp8_get8x8var_mmx) +sym(vp8_get8x8var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + push rbx + sub rsp, 16 + ; end prolog + + + pxor mm5, mm5 ; Blank mmx6 + pxor mm6, mm6 ; Blank mmx7 + pxor mm7, mm7 ; Blank mmx7 + + mov rax, arg(0) ;[src_ptr] ; Load base addresses + mov rbx, arg(2) ;[ref_ptr] + movsxd rcx, dword ptr arg(1) ;[source_stride] + movsxd rdx, dword ptr arg(3) ;[recon_stride] + + ; Row 1 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm1, [rbx] ; Copy eight bytes to mm1 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + + ; Row 2 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 3 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 4 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 5 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + ; movq mm4, [rbx + rdx] + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 6 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 7 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 8 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Now accumulate the final results. + movq QWORD PTR [rsp+8], mm5 ; copy back accumulated results into normal memory + movq QWORD PTR [rsp], mm7 ; copy back accumulated results into normal memory + movsx rdx, WORD PTR [rsp+8] + movsx rcx, WORD PTR [rsp+10] + movsx rbx, WORD PTR [rsp+12] + movsx rax, WORD PTR [rsp+14] + add rdx, rcx + add rbx, rax + add rdx, rbx ;XSum + movsxd rax, DWORD PTR [rsp] + movsxd rcx, DWORD PTR [rsp+4] + add rax, rcx ;XXSum + mov rsi, arg(4) ;SSE + mov rdi, arg(5) ;Sum + mov dword ptr [rsi], eax + mov dword ptr [rdi], edx + xor rax, rax ; return 0 + + + ; begin epilog + add rsp, 16 + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + + +;unsigned int +;vp8_get4x4var_mmx +;( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *SSE, +; int *Sum +;) +global sym(vp8_get4x4var_mmx) +sym(vp8_get4x4var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + push rbx + sub rsp, 16 + ; end prolog + + + pxor mm5, mm5 ; Blank mmx6 + pxor mm6, mm6 ; Blank mmx7 + pxor mm7, mm7 ; Blank mmx7 + + mov rax, arg(0) ;[src_ptr] ; Load base addresses + mov rbx, arg(2) ;[ref_ptr] + movsxd rcx, dword ptr arg(1) ;[source_stride] + movsxd rdx, dword ptr arg(3) ;[recon_stride] + + ; Row 1 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm1, [rbx] ; Copy eight bytes to mm1 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + paddw mm5, mm0 ; accumulate differences in mm5 + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + + ; Row 2 + movq mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + paddw mm5, mm0 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 3 + movq mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + paddw mm5, mm0 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 4 + movq mm0, [rax] ; Copy eight bytes to mm0 + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + + paddw mm5, mm0 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + paddd mm7, mm0 ; accumulate in mm7 + + + ; Now accumulate the final results. + movq QWORD PTR [rsp+8], mm5 ; copy back accumulated results into normal memory + movq QWORD PTR [rsp], mm7 ; copy back accumulated results into normal memory + movsx rdx, WORD PTR [rsp+8] + movsx rcx, WORD PTR [rsp+10] + movsx rbx, WORD PTR [rsp+12] + movsx rax, WORD PTR [rsp+14] + add rdx, rcx + add rbx, rax + add rdx, rbx ;XSum + movsxd rax, DWORD PTR [rsp] + movsxd rcx, DWORD PTR [rsp+4] + add rax, rcx ;XXSum + mov rsi, arg(4) ;SSE + mov rdi, arg(5) ;Sum + mov dword ptr [rsi], eax + mov dword ptr [rdi], edx + xor rax, rax ; return 0 + + + ; begin epilog + add rsp, 16 + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + + +;unsigned int +;vp8_get4x4sse_cs_mmx +;( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride +;) +global sym(vp8_get4x4sse_cs_mmx) +sym(vp8_get4x4sse_cs_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + push rbx + ; end prolog + + + pxor mm6, mm6 ; Blank mmx7 + pxor mm7, mm7 ; Blank mmx7 + + mov rax, arg(0) ;[src_ptr] ; Load base addresses + mov rbx, arg(2) ;[ref_ptr] + movsxd rcx, dword ptr arg(1) ;[source_stride] + movsxd rdx, dword ptr arg(3) ;[recon_stride] + ; Row 1 + movd mm0, [rax] ; Copy eight bytes to mm0 + movd mm1, [rbx] ; Copy eight bytes to mm1 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movd mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 2 + movd mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movd mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 3 + movd mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm1, mm6 + punpcklbw mm0, mm6 ; unpack to higher prrcision + psubsw mm0, mm1 ; A-B (low order) to MM0 + + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movd mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 4 + movd mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + pmaddwd mm0, mm0 ; square and accumulate + paddd mm7, mm0 ; accumulate in mm7 + + movq mm0, mm7 ; + psrlq mm7, 32 + + paddd mm0, mm7 + movq rax, mm0 + + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +%define mmx_filter_shift 7 + +;void vp8_filter_block2d_bil4x4_var_mmx +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned short *HFilter, +; unsigned short *VFilter, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_filter_block2d_bil4x4_var_mmx) +sym(vp8_filter_block2d_bil4x4_var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + + pxor mm6, mm6 ; + pxor mm7, mm7 ; + + mov rax, arg(4) ;HFilter ; + mov rdx, arg(5) ;VFilter ; + + mov rsi, arg(0) ;ref_ptr ; + mov rdi, arg(2) ;src_ptr ; + + mov rcx, 4 ; + pxor mm0, mm0 ; + + movd mm1, [rsi] ; + movd mm3, [rsi+1] ; + + punpcklbw mm1, mm0 ; + pmullw mm1, [rax] ; + + punpcklbw mm3, mm0 ; + pmullw mm3, [rax+8] ; + + paddw mm1, mm3 ; + paddw mm1, [GLOBAL(mmx_bi_rd)] ; + + psraw mm1, mmx_filter_shift ; + movq mm5, mm1 + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line ; + add rsi, r8 +%endif + +.filter_block2d_bil4x4_var_mmx_loop: + + movd mm1, [rsi] ; + movd mm3, [rsi+1] ; + + punpcklbw mm1, mm0 ; + pmullw mm1, [rax] ; + + punpcklbw mm3, mm0 ; + pmullw mm3, [rax+8] ; + + paddw mm1, mm3 ; + paddw mm1, [GLOBAL(mmx_bi_rd)] ; + + psraw mm1, mmx_filter_shift ; + movq mm3, mm5 ; + + movq mm5, mm1 ; + pmullw mm3, [rdx] ; + + pmullw mm1, [rdx+8] ; + paddw mm1, mm3 ; + + + paddw mm1, [GLOBAL(mmx_bi_rd)] ; + psraw mm1, mmx_filter_shift ; + + movd mm3, [rdi] ; + punpcklbw mm3, mm0 ; + + psubw mm1, mm3 ; + paddw mm6, mm1 ; + + pmaddwd mm1, mm1 ; + paddd mm7, mm1 ; + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; + add rdi, dword ptr arg(3) ;src_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line + add rsi, r8 + add rdi, r9 +%endif + sub rcx, 1 ; + jnz .filter_block2d_bil4x4_var_mmx_loop ; + + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rdi, arg(6) ;sum + mov rsi, arg(7) ;sumsquared + + movd dword ptr [rdi], mm2 ; + movd dword ptr [rsi], mm4 ; + + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + + +;void vp8_filter_block2d_bil_var_mmx +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; unsigned short *HFilter, +; unsigned short *VFilter, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_filter_block2d_bil_var_mmx) +sym(vp8_filter_block2d_bil_var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + pxor mm6, mm6 ; + pxor mm7, mm7 ; + mov rax, arg(5) ;HFilter ; + + mov rdx, arg(6) ;VFilter ; + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + + pxor mm0, mm0 ; + movq mm1, [rsi] ; + + movq mm3, [rsi+1] ; + movq mm2, mm1 ; + + movq mm4, mm3 ; + punpcklbw mm1, mm0 ; + + punpckhbw mm2, mm0 ; + pmullw mm1, [rax] ; + + pmullw mm2, [rax] ; + punpcklbw mm3, mm0 ; + + punpckhbw mm4, mm0 ; + pmullw mm3, [rax+8] ; + + pmullw mm4, [rax+8] ; + paddw mm1, mm3 ; + + paddw mm2, mm4 ; + paddw mm1, [GLOBAL(mmx_bi_rd)] ; + + psraw mm1, mmx_filter_shift ; + paddw mm2, [GLOBAL(mmx_bi_rd)] ; + + psraw mm2, mmx_filter_shift ; + movq mm5, mm1 + + packuswb mm5, mm2 ; +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + add rsi, r8 +%endif + +.filter_block2d_bil_var_mmx_loop: + + movq mm1, [rsi] ; + movq mm3, [rsi+1] ; + + movq mm2, mm1 ; + movq mm4, mm3 ; + + punpcklbw mm1, mm0 ; + punpckhbw mm2, mm0 ; + + pmullw mm1, [rax] ; + pmullw mm2, [rax] ; + + punpcklbw mm3, mm0 ; + punpckhbw mm4, mm0 ; + + pmullw mm3, [rax+8] ; + pmullw mm4, [rax+8] ; + + paddw mm1, mm3 ; + paddw mm2, mm4 ; + + paddw mm1, [GLOBAL(mmx_bi_rd)] ; + psraw mm1, mmx_filter_shift ; + + paddw mm2, [GLOBAL(mmx_bi_rd)] ; + psraw mm2, mmx_filter_shift ; + + movq mm3, mm5 ; + movq mm4, mm5 ; + + punpcklbw mm3, mm0 ; + punpckhbw mm4, mm0 ; + + movq mm5, mm1 ; + packuswb mm5, mm2 ; + + pmullw mm3, [rdx] ; + pmullw mm4, [rdx] ; + + pmullw mm1, [rdx+8] ; + pmullw mm2, [rdx+8] ; + + paddw mm1, mm3 ; + paddw mm2, mm4 ; + + paddw mm1, [GLOBAL(mmx_bi_rd)] ; + paddw mm2, [GLOBAL(mmx_bi_rd)] ; + + psraw mm1, mmx_filter_shift ; + psraw mm2, mmx_filter_shift ; + + movq mm3, [rdi] ; + movq mm4, mm3 ; + + punpcklbw mm3, mm0 ; + punpckhbw mm4, mm0 ; + + psubw mm1, mm3 ; + psubw mm2, mm4 ; + + paddw mm6, mm1 ; + pmaddwd mm1, mm1 ; + + paddw mm6, mm2 ; + pmaddwd mm2, mm2 ; + + paddd mm7, mm1 ; + paddd mm7, mm2 ; + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; + add rdi, dword ptr arg(3) ;src_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line ; + movsxd r9, dword ptr arg(3) ;src_pixels_per_line ; + add rsi, r8 + add rdi, r9 +%endif + sub rcx, 1 ; + jnz .filter_block2d_bil_var_mmx_loop ; + + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rdi, arg(7) ;sum + mov rsi, arg(8) ;sumsquared + + movd dword ptr [rdi], mm2 ; + movd dword ptr [rsi], mm4 ; + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +;short mmx_bi_rd[4] = { 64, 64, 64, 64}; +align 16 +mmx_bi_rd: + times 4 dw 64 diff --git a/vp8/common/x86/variance_impl_sse2.asm b/vp8/common/x86/variance_impl_sse2.asm new file mode 100644 index 0000000..7629220 --- /dev/null +++ b/vp8/common/x86/variance_impl_sse2.asm @@ -0,0 +1,1359 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define xmm_filter_shift 7 + +;unsigned int vp8_get_mb_ss_sse2 +;( +; short *src_ptr +;) +global sym(vp8_get_mb_ss_sse2) +sym(vp8_get_mb_ss_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 1 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + + mov rax, arg(0) ;[src_ptr] + mov rcx, 8 + pxor xmm4, xmm4 + +.NEXTROW: + movdqa xmm0, [rax] + movdqa xmm1, [rax+16] + movdqa xmm2, [rax+32] + movdqa xmm3, [rax+48] + pmaddwd xmm0, xmm0 + pmaddwd xmm1, xmm1 + pmaddwd xmm2, xmm2 + pmaddwd xmm3, xmm3 + + paddd xmm0, xmm1 + paddd xmm2, xmm3 + paddd xmm4, xmm0 + paddd xmm4, xmm2 + + add rax, 0x40 + dec rcx + ja .NEXTROW + + movdqa xmm3,xmm4 + psrldq xmm4,8 + paddd xmm4,xmm3 + movdqa xmm3,xmm4 + psrldq xmm4,4 + paddd xmm4,xmm3 + movq rax,xmm4 + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_get16x16var_sse2 +;( +; unsigned char * src_ptr, +; int source_stride, +; unsigned char * ref_ptr, +; int recon_stride, +; unsigned int * SSE, +; int * Sum +;) +global sym(vp8_get16x16var_sse2) +sym(vp8_get16x16var_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + push rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;[src_ptr] + mov rdi, arg(2) ;[ref_ptr] + + movsxd rax, DWORD PTR arg(1) ;[source_stride] + movsxd rdx, DWORD PTR arg(3) ;[recon_stride] + + ; Prefetch data + lea rcx, [rax+rax*2] + prefetcht0 [rsi] + prefetcht0 [rsi+rax] + prefetcht0 [rsi+rax*2] + prefetcht0 [rsi+rcx] + lea rbx, [rsi+rax*4] + prefetcht0 [rbx] + prefetcht0 [rbx+rax] + prefetcht0 [rbx+rax*2] + prefetcht0 [rbx+rcx] + + lea rcx, [rdx+rdx*2] + prefetcht0 [rdi] + prefetcht0 [rdi+rdx] + prefetcht0 [rdi+rdx*2] + prefetcht0 [rdi+rcx] + lea rbx, [rdi+rdx*4] + prefetcht0 [rbx] + prefetcht0 [rbx+rdx] + prefetcht0 [rbx+rdx*2] + prefetcht0 [rbx+rcx] + + pxor xmm0, xmm0 ; clear xmm0 for unpack + pxor xmm7, xmm7 ; clear xmm7 for accumulating diffs + + pxor xmm6, xmm6 ; clear xmm6 for accumulating sse + mov rcx, 16 + +.var16loop: + movdqu xmm1, XMMWORD PTR [rsi] + movdqu xmm2, XMMWORD PTR [rdi] + + prefetcht0 [rsi+rax*8] + prefetcht0 [rdi+rdx*8] + + movdqa xmm3, xmm1 + movdqa xmm4, xmm2 + + + punpcklbw xmm1, xmm0 + punpckhbw xmm3, xmm0 + + punpcklbw xmm2, xmm0 + punpckhbw xmm4, xmm0 + + + psubw xmm1, xmm2 + psubw xmm3, xmm4 + + paddw xmm7, xmm1 + pmaddwd xmm1, xmm1 + + paddw xmm7, xmm3 + pmaddwd xmm3, xmm3 + + paddd xmm6, xmm1 + paddd xmm6, xmm3 + + add rsi, rax + add rdi, rdx + + sub rcx, 1 + jnz .var16loop + + + movdqa xmm1, xmm6 + pxor xmm6, xmm6 + + pxor xmm5, xmm5 + punpcklwd xmm6, xmm7 + + punpckhwd xmm5, xmm7 + psrad xmm5, 16 + + psrad xmm6, 16 + paddd xmm6, xmm5 + + movdqa xmm2, xmm1 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + movdqa xmm7, xmm6 + + paddd xmm1, xmm2 + punpckldq xmm6, xmm0 + + punpckhdq xmm7, xmm0 + paddd xmm6, xmm7 + + movdqa xmm2, xmm1 + movdqa xmm7, xmm6 + + psrldq xmm1, 8 + psrldq xmm6, 8 + + paddd xmm7, xmm6 + paddd xmm1, xmm2 + + mov rax, arg(5) ;[Sum] + mov rdi, arg(4) ;[SSE] + + movd DWORD PTR [rax], xmm7 + movd DWORD PTR [rdi], xmm1 + + + ; begin epilog + pop rdi + pop rsi + pop rbx + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + + + +;unsigned int vp8_get8x8var_sse2 +;( +; unsigned char * src_ptr, +; int source_stride, +; unsigned char * ref_ptr, +; int recon_stride, +; unsigned int * SSE, +; int * Sum +;) +global sym(vp8_get8x8var_sse2) +sym(vp8_get8x8var_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + mov rsi, arg(0) ;[src_ptr] + mov rdi, arg(2) ;[ref_ptr] + + movsxd rax, DWORD PTR arg(1) ;[source_stride] + movsxd rdx, DWORD PTR arg(3) ;[recon_stride] + + pxor xmm0, xmm0 ; clear xmm0 for unpack + pxor xmm7, xmm7 ; clear xmm7 for accumulating diffs + + movq xmm1, QWORD PTR [rsi] + movq xmm2, QWORD PTR [rdi] + + punpcklbw xmm1, xmm0 + punpcklbw xmm2, xmm0 + + psubsw xmm1, xmm2 + paddw xmm7, xmm1 + + pmaddwd xmm1, xmm1 + + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + movq xmm2, QWORD PTR[rsi + rax * 2] + movq xmm3, QWORD PTR[rdi + rdx * 2] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + lea rsi, [rsi + rax * 2] + lea rdi, [rdi + rdx * 2] + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + movq xmm2, QWORD PTR[rsi + rax *2] + movq xmm3, QWORD PTR[rdi + rdx *2] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + lea rsi, [rsi + rax * 2] + lea rdi, [rdi + rdx * 2] + + + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + movq xmm2, QWORD PTR[rsi + rax *2] + movq xmm3, QWORD PTR[rdi + rdx *2] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + lea rsi, [rsi + rax * 2] + lea rdi, [rdi + rdx * 2] + + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + movdqa xmm6, xmm7 + punpcklwd xmm6, xmm0 + + punpckhwd xmm7, xmm0 + movdqa xmm2, xmm1 + + paddw xmm6, xmm7 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + movdqa xmm7, xmm6 + + paddd xmm1, xmm2 + punpckldq xmm6, xmm0 + + punpckhdq xmm7, xmm0 + paddw xmm6, xmm7 + + movdqa xmm2, xmm1 + movdqa xmm7, xmm6 + + psrldq xmm1, 8 + psrldq xmm6, 8 + + paddw xmm7, xmm6 + paddd xmm1, xmm2 + + mov rax, arg(5) ;[Sum] + mov rdi, arg(4) ;[SSE] + + movq rdx, xmm7 + movsx rcx, dx + + mov dword ptr [rax], ecx + movd DWORD PTR [rdi], xmm1 + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_filter_block2d_bil_var_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int xoffset, +; int yoffset, +; int *sum, +; unsigned int *sumsquared;; +; +;) +global sym(vp8_filter_block2d_bil_var_sse2) +sym(vp8_filter_block2d_bil_var_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + push rbx + ; end prolog + + pxor xmm6, xmm6 ; + pxor xmm7, xmm7 ; + + lea rsi, [GLOBAL(xmm_bi_rd)] ; rounding + movdqa xmm4, XMMWORD PTR [rsi] + + lea rcx, [GLOBAL(vp8_bilinear_filters_sse2)] + movsxd rax, dword ptr arg(5) ; xoffset + + cmp rax, 0 ; skip first_pass filter if xoffset=0 + je filter_block2d_bil_var_sse2_sp_only + + shl rax, 5 ; point to filter coeff with xoffset + lea rax, [rax + rcx] ; HFilter + + movsxd rdx, dword ptr arg(6) ; yoffset + + cmp rdx, 0 ; skip second_pass filter if yoffset=0 + je filter_block2d_bil_var_sse2_fp_only + + shl rdx, 5 + lea rdx, [rdx + rcx] ; VFilter + + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + + pxor xmm0, xmm0 ; + movq xmm1, QWORD PTR [rsi] ; + movq xmm3, QWORD PTR [rsi+1] ; + + punpcklbw xmm1, xmm0 ; + pmullw xmm1, [rax] ; + punpcklbw xmm3, xmm0 + pmullw xmm3, [rax+16] ; + + paddw xmm1, xmm3 ; + paddw xmm1, xmm4 ; + psraw xmm1, xmm_filter_shift ; + movdqa xmm5, xmm1 + + movsxd rbx, dword ptr arg(1) ;ref_pixels_per_line + lea rsi, [rsi + rbx] +%if ABI_IS_32BIT=0 + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + +filter_block2d_bil_var_sse2_loop: + movq xmm1, QWORD PTR [rsi] ; + movq xmm3, QWORD PTR [rsi+1] ; + + punpcklbw xmm1, xmm0 ; + pmullw xmm1, [rax] ; + punpcklbw xmm3, xmm0 ; + pmullw xmm3, [rax+16] ; + + paddw xmm1, xmm3 ; + paddw xmm1, xmm4 ; + psraw xmm1, xmm_filter_shift ; + + movdqa xmm3, xmm5 ; + movdqa xmm5, xmm1 ; + + pmullw xmm3, [rdx] ; + pmullw xmm1, [rdx+16] ; + paddw xmm1, xmm3 ; + paddw xmm1, xmm4 ; + psraw xmm1, xmm_filter_shift ; + + movq xmm3, QWORD PTR [rdi] ; + punpcklbw xmm3, xmm0 ; + + psubw xmm1, xmm3 ; + paddw xmm6, xmm1 ; + + pmaddwd xmm1, xmm1 ; + paddd xmm7, xmm1 ; + + lea rsi, [rsi + rbx] ;ref_pixels_per_line +%if ABI_IS_32BIT + add rdi, dword ptr arg(3) ;src_pixels_per_line +%else + lea rdi, [rdi + r9] +%endif + + sub rcx, 1 ; + jnz filter_block2d_bil_var_sse2_loop ; + + jmp filter_block2d_bil_variance + +filter_block2d_bil_var_sse2_sp_only: + movsxd rdx, dword ptr arg(6) ; yoffset + + cmp rdx, 0 ; skip all if both xoffset=0 and yoffset=0 + je filter_block2d_bil_var_sse2_full_pixel + + shl rdx, 5 + lea rdx, [rdx + rcx] ; VFilter + + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 ; + movq xmm1, QWORD PTR [rsi] ; + punpcklbw xmm1, xmm0 ; + + movsxd rbx, dword ptr arg(3) ;src_pixels_per_line + lea rsi, [rsi + rax] + +filter_block2d_bil_sp_only_loop: + movq xmm3, QWORD PTR [rsi] ; + punpcklbw xmm3, xmm0 ; + movdqa xmm5, xmm3 + + pmullw xmm1, [rdx] ; + pmullw xmm3, [rdx+16] ; + paddw xmm1, xmm3 ; + paddw xmm1, xmm4 ; + psraw xmm1, xmm_filter_shift ; + + movq xmm3, QWORD PTR [rdi] ; + punpcklbw xmm3, xmm0 ; + + psubw xmm1, xmm3 ; + paddw xmm6, xmm1 ; + + pmaddwd xmm1, xmm1 ; + paddd xmm7, xmm1 ; + + movdqa xmm1, xmm5 ; + lea rsi, [rsi + rax] ;ref_pixels_per_line + lea rdi, [rdi + rbx] ;src_pixels_per_line + + sub rcx, 1 ; + jnz filter_block2d_bil_sp_only_loop ; + + jmp filter_block2d_bil_variance + +filter_block2d_bil_var_sse2_full_pixel: + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + movsxd rbx, dword ptr arg(3) ;src_pixels_per_line + pxor xmm0, xmm0 ; + +filter_block2d_bil_full_pixel_loop: + movq xmm1, QWORD PTR [rsi] ; + punpcklbw xmm1, xmm0 ; + + movq xmm2, QWORD PTR [rdi] ; + punpcklbw xmm2, xmm0 ; + + psubw xmm1, xmm2 ; + paddw xmm6, xmm1 ; + + pmaddwd xmm1, xmm1 ; + paddd xmm7, xmm1 ; + + lea rsi, [rsi + rax] ;ref_pixels_per_line + lea rdi, [rdi + rbx] ;src_pixels_per_line + + sub rcx, 1 ; + jnz filter_block2d_bil_full_pixel_loop ; + + jmp filter_block2d_bil_variance + +filter_block2d_bil_var_sse2_fp_only: + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rdx, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 ; + movsxd rbx, dword ptr arg(3) ;src_pixels_per_line + +filter_block2d_bil_fp_only_loop: + movq xmm1, QWORD PTR [rsi] ; + movq xmm3, QWORD PTR [rsi+1] ; + + punpcklbw xmm1, xmm0 ; + pmullw xmm1, [rax] ; + punpcklbw xmm3, xmm0 ; + pmullw xmm3, [rax+16] ; + + paddw xmm1, xmm3 ; + paddw xmm1, xmm4 ; + psraw xmm1, xmm_filter_shift ; + + movq xmm3, QWORD PTR [rdi] ; + punpcklbw xmm3, xmm0 ; + + psubw xmm1, xmm3 ; + paddw xmm6, xmm1 ; + + pmaddwd xmm1, xmm1 ; + paddd xmm7, xmm1 ; + lea rsi, [rsi + rdx] + lea rdi, [rdi + rbx] ;src_pixels_per_line + + sub rcx, 1 ; + jnz filter_block2d_bil_fp_only_loop ; + + jmp filter_block2d_bil_variance + +filter_block2d_bil_variance: + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(7) ; sum + mov rdi, arg(8) ; sumsquared + + movd [rsi], mm2 ; xsum + movd [rdi], mm4 ; xxsum + + ; begin epilog + pop rbx + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_half_horiz_vert_variance8x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_horiz_vert_variance8x_h_sse2) +sym(vp8_half_horiz_vert_variance8x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 ; + + movq xmm5, QWORD PTR [rsi] ; xmm5 = s0,s1,s2..s8 + movq xmm3, QWORD PTR [rsi+1] ; xmm3 = s1,s2,s3..s9 + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) horizontal line 1 + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; next source +%else + add rsi, r8 +%endif + +vp8_half_horiz_vert_variance8x_h_1: + + movq xmm1, QWORD PTR [rsi] ; + movq xmm2, QWORD PTR [rsi+1] ; + pavgb xmm1, xmm2 ; xmm1 = avg(xmm1,xmm3) horizontal line i+1 + + pavgb xmm5, xmm1 ; xmm = vertical average of the above + punpcklbw xmm5, xmm0 ; xmm5 = words of above + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d8 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + + movdqa xmm5, xmm1 ; save xmm1 for use on the next row + +%if ABI_IS_32BIT + add esi, dword ptr arg(1) ;ref_pixels_per_line ; next source + add edi, dword ptr arg(3) ;src_pixels_per_line ; next destination +%else + add rsi, r8 + add rdi, r9 +%endif + + sub rcx, 1 ; + jnz vp8_half_horiz_vert_variance8x_h_1 ; + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(5) ; sum + mov rdi, arg(6) ; sumsquared + + movd [rsi], mm2 ; + movd [rdi], mm4 ; + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_half_horiz_vert_variance16x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_horiz_vert_variance16x_h_sse2) +sym(vp8_half_horiz_vert_variance16x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + movsxd rdx, dword ptr arg(3) ;src_pixels_per_line + + pxor xmm0, xmm0 ; + + movdqu xmm5, XMMWORD PTR [rsi] + movdqu xmm3, XMMWORD PTR [rsi+1] + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) horizontal line 1 + + lea rsi, [rsi + rax] + +vp8_half_horiz_vert_variance16x_h_1: + movdqu xmm1, XMMWORD PTR [rsi] ; + movdqu xmm2, XMMWORD PTR [rsi+1] ; + pavgb xmm1, xmm2 ; xmm1 = avg(xmm1,xmm3) horizontal line i+1 + + pavgb xmm5, xmm1 ; xmm = vertical average of the above + + movdqa xmm4, xmm5 + punpcklbw xmm5, xmm0 ; xmm5 = words of above + punpckhbw xmm4, xmm0 + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d7 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + psubw xmm5, xmm3 ; xmm5 -= xmm3 + + movq xmm3, QWORD PTR [rdi+8] + punpcklbw xmm3, xmm0 + psubw xmm4, xmm3 + + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + paddw xmm6, xmm4 + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + pmaddwd xmm4, xmm4 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + paddd xmm7, xmm4 + + movdqa xmm5, xmm1 ; save xmm1 for use on the next row + + lea rsi, [rsi + rax] + lea rdi, [rdi + rdx] + + sub rcx, 1 ; + jnz vp8_half_horiz_vert_variance16x_h_1 ; + + pxor xmm1, xmm1 + pxor xmm5, xmm5 + + punpcklwd xmm0, xmm6 + punpckhwd xmm1, xmm6 + psrad xmm0, 16 + psrad xmm1, 16 + paddd xmm0, xmm1 + movdqa xmm1, xmm0 + + movdqa xmm6, xmm7 + punpckldq xmm6, xmm5 + punpckhdq xmm7, xmm5 + paddd xmm6, xmm7 + + punpckldq xmm0, xmm5 + punpckhdq xmm1, xmm5 + paddd xmm0, xmm1 + + movdqa xmm7, xmm6 + movdqa xmm1, xmm0 + + psrldq xmm7, 8 + psrldq xmm1, 8 + + paddd xmm6, xmm7 + paddd xmm0, xmm1 + + mov rsi, arg(5) ;[Sum] + mov rdi, arg(6) ;[SSE] + + movd [rsi], xmm0 + movd [rdi], xmm6 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_half_vert_variance8x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_vert_variance8x_h_sse2) +sym(vp8_half_vert_variance8x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 ; +vp8_half_vert_variance8x_h_1: + movq xmm5, QWORD PTR [rsi] ; xmm5 = s0,s1,s2..s8 + movq xmm3, QWORD PTR [rsi+rax] ; xmm3 = s1,s2,s3..s9 + + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) + punpcklbw xmm5, xmm0 ; xmm5 = words of above + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d8 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + +%if ABI_IS_32BIT + add esi, dword ptr arg(1) ;ref_pixels_per_line ; next source + add edi, dword ptr arg(3) ;src_pixels_per_line ; next destination +%else + add rsi, r8 + add rdi, r9 +%endif + + sub rcx, 1 ; + jnz vp8_half_vert_variance8x_h_1 ; + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(5) ; sum + mov rdi, arg(6) ; sumsquared + + movd [rsi], mm2 ; + movd [rdi], mm4 ; + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_half_vert_variance16x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_vert_variance16x_h_sse2) +sym(vp8_half_vert_variance16x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr + + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + movsxd rdx, dword ptr arg(3) ;src_pixels_per_line + + movdqu xmm5, XMMWORD PTR [rsi] + lea rsi, [rsi + rax ] + pxor xmm0, xmm0 + +vp8_half_vert_variance16x_h_1: + movdqu xmm3, XMMWORD PTR [rsi] + + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) + movdqa xmm4, xmm5 + punpcklbw xmm5, xmm0 + punpckhbw xmm4, xmm0 + + movq xmm2, QWORD PTR [rdi] + punpcklbw xmm2, xmm0 + psubw xmm5, xmm2 + movq xmm2, QWORD PTR [rdi+8] + punpcklbw xmm2, xmm0 + psubw xmm4, xmm2 + + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + paddw xmm6, xmm4 + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + pmaddwd xmm4, xmm4 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + paddd xmm7, xmm4 + + movdqa xmm5, xmm3 + + lea rsi, [rsi + rax] + lea rdi, [rdi + rdx] + + sub rcx, 1 + jnz vp8_half_vert_variance16x_h_1 + + pxor xmm1, xmm1 + pxor xmm5, xmm5 + + punpcklwd xmm0, xmm6 + punpckhwd xmm1, xmm6 + psrad xmm0, 16 + psrad xmm1, 16 + paddd xmm0, xmm1 + movdqa xmm1, xmm0 + + movdqa xmm6, xmm7 + punpckldq xmm6, xmm5 + punpckhdq xmm7, xmm5 + paddd xmm6, xmm7 + + punpckldq xmm0, xmm5 + punpckhdq xmm1, xmm5 + paddd xmm0, xmm1 + + movdqa xmm7, xmm6 + movdqa xmm1, xmm0 + + psrldq xmm7, 8 + psrldq xmm1, 8 + + paddd xmm6, xmm7 + paddd xmm0, xmm1 + + mov rsi, arg(5) ;[Sum] + mov rdi, arg(6) ;[SSE] + + movd [rsi], xmm0 + movd [rdi], xmm6 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_half_horiz_variance8x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_horiz_variance8x_h_sse2) +sym(vp8_half_horiz_variance8x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + + pxor xmm0, xmm0 ; +vp8_half_horiz_variance8x_h_1: + movq xmm5, QWORD PTR [rsi] ; xmm5 = s0,s1,s2..s8 + movq xmm3, QWORD PTR [rsi+1] ; xmm3 = s1,s2,s3..s9 + + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) + punpcklbw xmm5, xmm0 ; xmm5 = words of above + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d8 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + +%if ABI_IS_32BIT + add esi, dword ptr arg(1) ;ref_pixels_per_line ; next source + add edi, dword ptr arg(3) ;src_pixels_per_line ; next destination +%else + add rsi, r8 + add rdi, r9 +%endif + sub rcx, 1 ; + jnz vp8_half_horiz_variance8x_h_1 ; + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(5) ; sum + mov rdi, arg(6) ; sumsquared + + movd [rsi], mm2 ; + movd [rdi], mm4 ; + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_half_horiz_variance16x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_horiz_variance16x_h_sse2) +sym(vp8_half_horiz_variance16x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + movsxd rdx, dword ptr arg(3) ;src_pixels_per_line + + pxor xmm0, xmm0 ; + +vp8_half_horiz_variance16x_h_1: + movdqu xmm5, XMMWORD PTR [rsi] ; xmm5 = s0,s1,s2..s15 + movdqu xmm3, XMMWORD PTR [rsi+1] ; xmm3 = s1,s2,s3..s16 + + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) + movdqa xmm1, xmm5 + punpcklbw xmm5, xmm0 ; xmm5 = words of above + punpckhbw xmm1, xmm0 + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d7 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + movq xmm2, QWORD PTR [rdi+8] + punpcklbw xmm2, xmm0 + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + psubw xmm1, xmm2 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + paddw xmm6, xmm1 + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + pmaddwd xmm1, xmm1 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + paddd xmm7, xmm1 + + lea rsi, [rsi + rax] + lea rdi, [rdi + rdx] + + sub rcx, 1 ; + jnz vp8_half_horiz_variance16x_h_1 ; + + pxor xmm1, xmm1 + pxor xmm5, xmm5 + + punpcklwd xmm0, xmm6 + punpckhwd xmm1, xmm6 + psrad xmm0, 16 + psrad xmm1, 16 + paddd xmm0, xmm1 + movdqa xmm1, xmm0 + + movdqa xmm6, xmm7 + punpckldq xmm6, xmm5 + punpckhdq xmm7, xmm5 + paddd xmm6, xmm7 + + punpckldq xmm0, xmm5 + punpckhdq xmm1, xmm5 + paddd xmm0, xmm1 + + movdqa xmm7, xmm6 + movdqa xmm1, xmm0 + + psrldq xmm7, 8 + psrldq xmm1, 8 + + paddd xmm6, xmm7 + paddd xmm0, xmm1 + + mov rsi, arg(5) ;[Sum] + mov rdi, arg(6) ;[SSE] + + movd [rsi], xmm0 + movd [rdi], xmm6 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +; short xmm_bi_rd[8] = { 64, 64, 64, 64,64, 64, 64, 64}; +align 16 +xmm_bi_rd: + times 8 dw 64 +align 16 +vp8_bilinear_filters_sse2: + dw 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0 + dw 112, 112, 112, 112, 112, 112, 112, 112, 16, 16, 16, 16, 16, 16, 16, 16 + dw 96, 96, 96, 96, 96, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32 + dw 80, 80, 80, 80, 80, 80, 80, 80, 48, 48, 48, 48, 48, 48, 48, 48 + dw 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + dw 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80 + dw 32, 32, 32, 32, 32, 32, 32, 32, 96, 96, 96, 96, 96, 96, 96, 96 + dw 16, 16, 16, 16, 16, 16, 16, 16, 112, 112, 112, 112, 112, 112, 112, 112 diff --git a/vp8/common/x86/variance_impl_ssse3.asm b/vp8/common/x86/variance_impl_ssse3.asm new file mode 100644 index 0000000..97e8b0e --- /dev/null +++ b/vp8/common/x86/variance_impl_ssse3.asm @@ -0,0 +1,364 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define xmm_filter_shift 7 + + +;void vp8_filter_block2d_bil_var_ssse3 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int xoffset, +; int yoffset, +; int *sum, +; unsigned int *sumsquared;; +; +;) +;Note: The filter coefficient at offset=0 is 128. Since the second register +;for Pmaddubsw is signed bytes, we must calculate zero offset seperately. +global sym(vp8_filter_block2d_bil_var_ssse3) +sym(vp8_filter_block2d_bil_var_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + pxor xmm6, xmm6 + pxor xmm7, xmm7 + + lea rcx, [GLOBAL(vp8_bilinear_filters_ssse3)] + movsxd rax, dword ptr arg(5) ; xoffset + + cmp rax, 0 ; skip first_pass filter if xoffset=0 + je .filter_block2d_bil_var_ssse3_sp_only + + shl rax, 4 ; point to filter coeff with xoffset + lea rax, [rax + rcx] ; HFilter + + movsxd rdx, dword ptr arg(6) ; yoffset + + cmp rdx, 0 ; skip second_pass filter if yoffset=0 + je .filter_block2d_bil_var_ssse3_fp_only + + shl rdx, 4 + lea rdx, [rdx + rcx] ; VFilter + + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + + movdqu xmm0, XMMWORD PTR [rsi] + movdqu xmm1, XMMWORD PTR [rsi+1] + movdqa xmm2, xmm0 + + punpcklbw xmm0, xmm1 + punpckhbw xmm2, xmm1 + pmaddubsw xmm0, [rax] + pmaddubsw xmm2, [rax] + + paddw xmm0, [GLOBAL(xmm_bi_rd)] + paddw xmm2, [GLOBAL(xmm_bi_rd)] + psraw xmm0, xmm_filter_shift + psraw xmm2, xmm_filter_shift + + packuswb xmm0, xmm2 + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line + lea rsi, [rsi + r8] +%endif + +.filter_block2d_bil_var_ssse3_loop: + movdqu xmm1, XMMWORD PTR [rsi] + movdqu xmm2, XMMWORD PTR [rsi+1] + movdqa xmm3, xmm1 + + punpcklbw xmm1, xmm2 + punpckhbw xmm3, xmm2 + pmaddubsw xmm1, [rax] + pmaddubsw xmm3, [rax] + + paddw xmm1, [GLOBAL(xmm_bi_rd)] + paddw xmm3, [GLOBAL(xmm_bi_rd)] + psraw xmm1, xmm_filter_shift + psraw xmm3, xmm_filter_shift + packuswb xmm1, xmm3 + + movdqa xmm2, xmm0 + movdqa xmm0, xmm1 + movdqa xmm3, xmm2 + + punpcklbw xmm2, xmm1 + punpckhbw xmm3, xmm1 + pmaddubsw xmm2, [rdx] + pmaddubsw xmm3, [rdx] + + paddw xmm2, [GLOBAL(xmm_bi_rd)] + paddw xmm3, [GLOBAL(xmm_bi_rd)] + psraw xmm2, xmm_filter_shift + psraw xmm3, xmm_filter_shift + + movq xmm1, QWORD PTR [rdi] + pxor xmm4, xmm4 + punpcklbw xmm1, xmm4 + movq xmm5, QWORD PTR [rdi+8] + punpcklbw xmm5, xmm4 + + psubw xmm2, xmm1 + psubw xmm3, xmm5 + paddw xmm6, xmm2 + paddw xmm6, xmm3 + pmaddwd xmm2, xmm2 + pmaddwd xmm3, xmm3 + paddd xmm7, xmm2 + paddd xmm7, xmm3 + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line + add rdi, dword ptr arg(3) ;src_pixels_per_line +%else + lea rsi, [rsi + r8] + lea rdi, [rdi + r9] +%endif + + sub rcx, 1 + jnz .filter_block2d_bil_var_ssse3_loop + + jmp .filter_block2d_bil_variance + +.filter_block2d_bil_var_ssse3_sp_only: + movsxd rdx, dword ptr arg(6) ; yoffset + + cmp rdx, 0 ; Both xoffset =0 and yoffset=0 + je .filter_block2d_bil_var_ssse3_full_pixel + + shl rdx, 4 + lea rdx, [rdx + rcx] ; VFilter + + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + + movdqu xmm1, XMMWORD PTR [rsi] + movdqa xmm0, xmm1 + +%if ABI_IS_32BIT=0 + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + lea rsi, [rsi + rax] + +.filter_block2d_bil_sp_only_loop: + movdqu xmm3, XMMWORD PTR [rsi] + movdqa xmm2, xmm1 + movdqa xmm0, xmm3 + + punpcklbw xmm1, xmm3 + punpckhbw xmm2, xmm3 + pmaddubsw xmm1, [rdx] + pmaddubsw xmm2, [rdx] + + paddw xmm1, [GLOBAL(xmm_bi_rd)] + paddw xmm2, [GLOBAL(xmm_bi_rd)] + psraw xmm1, xmm_filter_shift + psraw xmm2, xmm_filter_shift + + movq xmm3, QWORD PTR [rdi] + pxor xmm4, xmm4 + punpcklbw xmm3, xmm4 + movq xmm5, QWORD PTR [rdi+8] + punpcklbw xmm5, xmm4 + + psubw xmm1, xmm3 + psubw xmm2, xmm5 + paddw xmm6, xmm1 + paddw xmm6, xmm2 + pmaddwd xmm1, xmm1 + pmaddwd xmm2, xmm2 + paddd xmm7, xmm1 + paddd xmm7, xmm2 + + movdqa xmm1, xmm0 + lea rsi, [rsi + rax] ;ref_pixels_per_line + +%if ABI_IS_32BIT + add rdi, dword ptr arg(3) ;src_pixels_per_line +%else + lea rdi, [rdi + r9] +%endif + + sub rcx, 1 + jnz .filter_block2d_bil_sp_only_loop + + jmp .filter_block2d_bil_variance + +.filter_block2d_bil_var_ssse3_full_pixel: + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + movsxd rdx, dword ptr arg(3) ;src_pixels_per_line + pxor xmm0, xmm0 + +.filter_block2d_bil_full_pixel_loop: + movq xmm1, QWORD PTR [rsi] + punpcklbw xmm1, xmm0 + movq xmm2, QWORD PTR [rsi+8] + punpcklbw xmm2, xmm0 + + movq xmm3, QWORD PTR [rdi] + punpcklbw xmm3, xmm0 + movq xmm4, QWORD PTR [rdi+8] + punpcklbw xmm4, xmm0 + + psubw xmm1, xmm3 + psubw xmm2, xmm4 + paddw xmm6, xmm1 + paddw xmm6, xmm2 + pmaddwd xmm1, xmm1 + pmaddwd xmm2, xmm2 + paddd xmm7, xmm1 + paddd xmm7, xmm2 + + lea rsi, [rsi + rax] ;ref_pixels_per_line + lea rdi, [rdi + rdx] ;src_pixels_per_line + sub rcx, 1 + jnz .filter_block2d_bil_full_pixel_loop + + jmp .filter_block2d_bil_variance + +.filter_block2d_bil_var_ssse3_fp_only: + mov rsi, arg(0) ;ref_ptr + mov rdi, arg(2) ;src_ptr + movsxd rcx, dword ptr arg(4) ;Height + movsxd rdx, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 + +%if ABI_IS_32BIT=0 + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + +.filter_block2d_bil_fp_only_loop: + movdqu xmm1, XMMWORD PTR [rsi] + movdqu xmm2, XMMWORD PTR [rsi+1] + movdqa xmm3, xmm1 + + punpcklbw xmm1, xmm2 + punpckhbw xmm3, xmm2 + pmaddubsw xmm1, [rax] + pmaddubsw xmm3, [rax] + + paddw xmm1, [GLOBAL(xmm_bi_rd)] + paddw xmm3, [GLOBAL(xmm_bi_rd)] + psraw xmm1, xmm_filter_shift + psraw xmm3, xmm_filter_shift + + movq xmm2, XMMWORD PTR [rdi] + pxor xmm4, xmm4 + punpcklbw xmm2, xmm4 + movq xmm5, QWORD PTR [rdi+8] + punpcklbw xmm5, xmm4 + + psubw xmm1, xmm2 + psubw xmm3, xmm5 + paddw xmm6, xmm1 + paddw xmm6, xmm3 + pmaddwd xmm1, xmm1 + pmaddwd xmm3, xmm3 + paddd xmm7, xmm1 + paddd xmm7, xmm3 + + lea rsi, [rsi + rdx] +%if ABI_IS_32BIT + add rdi, dword ptr arg(3) ;src_pixels_per_line +%else + lea rdi, [rdi + r9] +%endif + + sub rcx, 1 + jnz .filter_block2d_bil_fp_only_loop + + jmp .filter_block2d_bil_variance + +.filter_block2d_bil_variance: + pxor xmm0, xmm0 + pxor xmm1, xmm1 + pxor xmm5, xmm5 + + punpcklwd xmm0, xmm6 + punpckhwd xmm1, xmm6 + psrad xmm0, 16 + psrad xmm1, 16 + paddd xmm0, xmm1 + movdqa xmm1, xmm0 + + movdqa xmm6, xmm7 + punpckldq xmm6, xmm5 + punpckhdq xmm7, xmm5 + paddd xmm6, xmm7 + + punpckldq xmm0, xmm5 + punpckhdq xmm1, xmm5 + paddd xmm0, xmm1 + + movdqa xmm7, xmm6 + movdqa xmm1, xmm0 + + psrldq xmm7, 8 + psrldq xmm1, 8 + + paddd xmm6, xmm7 + paddd xmm0, xmm1 + + mov rsi, arg(7) ;[Sum] + mov rdi, arg(8) ;[SSE] + + movd [rsi], xmm0 + movd [rdi], xmm6 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +align 16 +xmm_bi_rd: + times 8 dw 64 +align 16 +vp8_bilinear_filters_ssse3: + times 8 db 128, 0 + times 8 db 112, 16 + times 8 db 96, 32 + times 8 db 80, 48 + times 8 db 64, 64 + times 8 db 48, 80 + times 8 db 32, 96 + times 8 db 16, 112 diff --git a/vp8/common/x86/variance_mmx.c b/vp8/common/x86/variance_mmx.c new file mode 100644 index 0000000..0c4dd4a --- /dev/null +++ b/vp8/common/x86/variance_mmx.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vp8/common/variance.h" +#include "vp8/common/pragmas.h" +#include "vpx_ports/mem.h" +#include "vp8/common/x86/filter_x86.h" + +extern void filter_block1d_h6_mmx +( + const unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + short *filter +); +extern void filter_block1d_v6_mmx +( + const short *src_ptr, + unsigned char *output_ptr, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + short *filter +); + +extern unsigned int vp8_get_mb_ss_mmx(const short *src_ptr); +extern unsigned int vp8_get8x8var_mmx +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +extern unsigned int vp8_get4x4var_mmx +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +extern void vp8_filter_block2d_bil4x4_var_mmx +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); +extern void vp8_filter_block2d_bil_var_mmx +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); + + +unsigned int vp8_variance4x4_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_get4x4var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 4)); + +} + +unsigned int vp8_variance8x8_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + *sse = var; + + return (var - ((unsigned int)(avg * avg) >> 6)); + +} + +unsigned int vp8_mse16x16_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3; + + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse2, &sum2) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride + 8, source_stride, ref_ptr + 8 * recon_stride + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + *sse = var; + return var; +} + + +unsigned int vp8_variance16x16_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3, avg; + + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse2, &sum2) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride + 8, source_stride, ref_ptr + 8 * recon_stride + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + avg = sum0 + sum1 + sum2 + sum3; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 8)); +} + +unsigned int vp8_variance16x8_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 7)); + +} + + +unsigned int vp8_variance8x16_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse1, &sum1) ; + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + + return (var - ((unsigned int)(avg * avg) >> 7)); + +} + + +unsigned int vp8_sub_pixel_variance4x4_mmx +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse) + +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil4x4_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((unsigned int)(xsum * xsum) >> 4)); +} + + +unsigned int vp8_sub_pixel_variance8x8_mmx +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((unsigned int)(xsum * xsum) >> 6)); +} + +unsigned int vp8_sub_pixel_variance16x16_mmx +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 8)); + + +} + +unsigned int vp8_sub_pixel_mse16x16_mmx( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + vp8_sub_pixel_variance16x16_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); + return *sse; +} + +unsigned int vp8_sub_pixel_variance16x8_mmx +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 8, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 7)); +} + +unsigned int vp8_sub_pixel_variance8x16_mmx +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((unsigned int)(xsum * xsum) >> 7)); +} + + +unsigned int vp8_variance_halfpixvar16x16_h_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 4, 0, + ref_ptr, recon_stride, sse); +} + + +unsigned int vp8_variance_halfpixvar16x16_v_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 0, 4, + ref_ptr, recon_stride, sse); +} + + +unsigned int vp8_variance_halfpixvar16x16_hv_mmx( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + return vp8_sub_pixel_variance16x16_mmx(src_ptr, source_stride, 4, 4, + ref_ptr, recon_stride, sse); +} diff --git a/vp8/common/x86/variance_sse2.c b/vp8/common/x86/variance_sse2.c new file mode 100644 index 0000000..2769a30 --- /dev/null +++ b/vp8/common/x86/variance_sse2.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vp8/common/variance.h" +#include "vp8/common/pragmas.h" +#include "vpx_ports/mem.h" +#include "vp8/common/x86/filter_x86.h" + +extern void filter_block1d_h6_mmx(const unsigned char *src_ptr, unsigned short *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *filter); +extern void filter_block1d_v6_mmx(const short *src_ptr, unsigned char *output_ptr, unsigned int pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *filter); +extern void filter_block1d8_h6_sse2(const unsigned char *src_ptr, unsigned short *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *filter); +extern void filter_block1d8_v6_sse2(const short *src_ptr, unsigned char *output_ptr, unsigned int pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *filter); + +extern void vp8_filter_block2d_bil4x4_var_mmx +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); + +extern unsigned int vp8_get4x4var_mmx +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); + +unsigned int vp8_get_mb_ss_sse2 +( + const short *src_ptr +); +unsigned int vp8_get16x16var_sse2 +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +unsigned int vp8_get8x8var_sse2 +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +void vp8_filter_block2d_bil_var_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int xoffset, + int yoffset, + int *sum, + unsigned int *sumsquared +); +void vp8_half_horiz_vert_variance8x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_horiz_vert_variance16x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_horiz_variance8x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_horiz_variance16x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_vert_variance8x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_vert_variance16x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); + +unsigned int vp8_variance4x4_wmt( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_get4x4var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 4)); + +} + +unsigned int vp8_variance8x8_wmt +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 6)); + +} + + +unsigned int vp8_variance16x16_wmt +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0; + int sum0; + + + vp8_get16x16var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + *sse = sse0; + return (sse0 - ((unsigned int)(sum0 * sum0) >> 8)); +} +unsigned int vp8_mse16x16_wmt( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + + unsigned int sse0; + int sum0; + vp8_get16x16var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + *sse = sse0; + return sse0; + +} + + +unsigned int vp8_variance16x8_wmt +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_sse2(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 7)); + +} + +unsigned int vp8_variance8x16_wmt +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_sse2(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse1, &sum1) ; + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + return (var - ((unsigned int)(avg * avg) >> 7)); + +} + +unsigned int vp8_sub_pixel_variance4x4_wmt +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil4x4_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, + vp8_bilinear_filters_x86_4[xoffset], vp8_bilinear_filters_x86_4[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((unsigned int)(xsum * xsum) >> 4)); +} + + +unsigned int vp8_sub_pixel_variance8x8_wmt +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum; + unsigned int xxsum; + + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance8x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum, &xxsum); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance8x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum, &xxsum); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance8x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum, &xxsum); + } + else + { + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + xoffset, yoffset, + &xsum, &xxsum); + } + + *sse = xxsum; + return (xxsum - ((unsigned int)(xsum * xsum) >> 6)); +} + +unsigned int vp8_sub_pixel_variance16x16_wmt +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + // note we could avoid these if statements if the calling function + // just called the appropriate functions inside. + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + } + else + { + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + xoffset, yoffset, + &xsum0, &xxsum0 + ); + + vp8_filter_block2d_bil_var_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + xoffset, yoffset, + &xsum1, &xxsum1 + ); + xsum0 += xsum1; + xxsum0 += xxsum1; + } + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 8)); +} + +unsigned int vp8_sub_pixel_mse16x16_wmt( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + vp8_sub_pixel_variance16x16_wmt(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); + return *sse; +} + +unsigned int vp8_sub_pixel_variance16x8_wmt +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse + +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum0, &xxsum0); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum0, &xxsum0); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum0, &xxsum0); + } + else + { + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + xoffset, yoffset, + &xsum0, &xxsum0); + + vp8_filter_block2d_bil_var_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 8, + xoffset, yoffset, + &xsum1, &xxsum1); + xsum0 += xsum1; + xxsum0 += xxsum1; + } + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 7)); +} + +unsigned int vp8_sub_pixel_variance8x16_wmt +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum; + unsigned int xxsum; + + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance8x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum, &xxsum); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance8x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum, &xxsum); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance8x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum, &xxsum); + } + else + { + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + xoffset, yoffset, + &xsum, &xxsum); + } + + *sse = xxsum; + return (xxsum - ((unsigned int)(xsum * xsum) >> 7)); +} + + +unsigned int vp8_variance_halfpixvar16x16_h_wmt( + const unsigned char *src_ptr, + int src_pixels_per_line, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse) +{ + int xsum0; + unsigned int xxsum0; + + vp8_half_horiz_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 8)); +} + + +unsigned int vp8_variance_halfpixvar16x16_v_wmt( + const unsigned char *src_ptr, + int src_pixels_per_line, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse) +{ + int xsum0; + unsigned int xxsum0; + vp8_half_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 8)); +} + + +unsigned int vp8_variance_halfpixvar16x16_hv_wmt( + const unsigned char *src_ptr, + int src_pixels_per_line, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse) +{ + int xsum0; + unsigned int xxsum0; + + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 8)); +} diff --git a/vp8/common/x86/variance_ssse3.c b/vp8/common/x86/variance_ssse3.c new file mode 100644 index 0000000..1be0d92 --- /dev/null +++ b/vp8/common/x86/variance_ssse3.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vp8/common/variance.h" +#include "vp8/common/pragmas.h" +#include "vpx_ports/mem.h" + +extern unsigned int vp8_get16x16var_sse2 +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +extern void vp8_half_horiz_vert_variance16x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +extern void vp8_half_horiz_variance16x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +extern void vp8_half_vert_variance16x_h_sse2 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +extern void vp8_filter_block2d_bil_var_ssse3 +( + const unsigned char *ref_ptr, + int ref_pixels_per_line, + const unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int xoffset, + int yoffset, + int *sum, + unsigned int *sumsquared +); + +unsigned int vp8_sub_pixel_variance16x16_ssse3 +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0; + unsigned int xxsum0; + + // note we could avoid these if statements if the calling function + // just called the appropriate functions inside. + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + } + else + { + vp8_filter_block2d_bil_var_ssse3( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + xoffset, yoffset, + &xsum0, &xxsum0); + } + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 8)); +} + +unsigned int vp8_sub_pixel_variance16x8_ssse3 +( + const unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + const unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse + +) +{ + int xsum0; + unsigned int xxsum0; + + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum0, &xxsum0); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum0, &xxsum0); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + &xsum0, &xxsum0); + } + else + { + vp8_filter_block2d_bil_var_ssse3( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + xoffset, yoffset, + &xsum0, &xxsum0); + } + + *sse = xxsum0; + return (xxsum0 - ((unsigned int)(xsum0 * xsum0) >> 7)); +} diff --git a/vp8/common/x86/vp8_asm_stubs.c b/vp8/common/x86/vp8_asm_stubs.c new file mode 100644 index 0000000..23a7fdc --- /dev/null +++ b/vp8/common/x86/vp8_asm_stubs.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx_ports/mem.h" +#include "filter_x86.h" + +extern const short vp8_six_tap_mmx[8][6*8]; + +extern void vp8_filter_block1d_h6_mmx +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1dc_v6_mmx +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d8_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d16_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d8_v6_sse2 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int dst_ptich, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d16_v6_sse2 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int dst_ptich, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_unpack_block1d16_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_height, + unsigned int output_width +); +extern void vp8_filter_block1d8_h6_only_sse2 +( + unsigned char *src_ptr, + unsigned int src_pixels_per_line, + unsigned char *output_ptr, + int dst_ptich, + unsigned int output_height, + const short *vp8_filter +); +extern void vp8_filter_block1d16_h6_only_sse2 +( + unsigned char *src_ptr, + unsigned int src_pixels_per_line, + unsigned char *output_ptr, + int dst_ptich, + unsigned int output_height, + const short *vp8_filter +); +extern void vp8_filter_block1d8_v6_only_sse2 +( + unsigned char *src_ptr, + unsigned int src_pixels_per_line, + unsigned char *output_ptr, + int dst_ptich, + unsigned int output_height, + const short *vp8_filter +); + + +#if HAVE_MMX +void vp8_sixtap_predict4x4_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 16*16); /* Temp data bufffer used in filtering */ + const short *HFilter, *VFilter; + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 9, 8, HFilter); + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 8, dst_ptr, dst_pitch, 8, 4 , 4, 4, VFilter); + +} + + +void vp8_sixtap_predict16x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 24*24); /* Temp data bufffer used in filtering */ + + const short *HFilter, *VFilter; + + + HFilter = vp8_six_tap_mmx[xoffset]; + + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 21, 32, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 4, FData2 + 4, src_pixels_per_line, 1, 21, 32, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 8, FData2 + 8, src_pixels_per_line, 1, 21, 32, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 12, FData2 + 12, src_pixels_per_line, 1, 21, 32, HFilter); + + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 32, dst_ptr, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 36, dst_ptr + 4, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 40, dst_ptr + 8, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 44, dst_ptr + 12, dst_pitch, 32, 16 , 16, 16, VFilter); + +} + + +void vp8_sixtap_predict8x8_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ + + const short *HFilter, *VFilter; + + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 13, 16, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 4, FData2 + 4, src_pixels_per_line, 1, 13, 16, HFilter); + + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 8, 8, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 20, dst_ptr + 4, dst_pitch, 16, 8 , 8, 8, VFilter); + +} + + +void vp8_sixtap_predict8x4_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ + + const short *HFilter, *VFilter; + + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 9, 16, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 4, FData2 + 4, src_pixels_per_line, 1, 9, 16, HFilter); + + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 4, 8, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 20, dst_ptr + 4, dst_pitch, 16, 8 , 4, 8, VFilter); + +} + + + +void vp8_bilinear_predict16x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + vp8_bilinear_predict8x8_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pitch); + vp8_bilinear_predict8x8_mmx(src_ptr + 8, src_pixels_per_line, xoffset, yoffset, dst_ptr + 8, dst_pitch); + vp8_bilinear_predict8x8_mmx(src_ptr + 8 * src_pixels_per_line, src_pixels_per_line, xoffset, yoffset, dst_ptr + dst_pitch * 8, dst_pitch); + vp8_bilinear_predict8x8_mmx(src_ptr + 8 * src_pixels_per_line + 8, src_pixels_per_line, xoffset, yoffset, dst_ptr + dst_pitch * 8 + 8, dst_pitch); +} +#endif + + +#if HAVE_SSE2 +void vp8_sixtap_predict16x16_sse2 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch + +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 24*24); /* Temp data bufffer used in filtering */ + + const short *HFilter, *VFilter; + + if (xoffset) + { + if (yoffset) + { + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d16_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 21, 32, HFilter); + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d16_v6_sse2(FData2 + 32, dst_ptr, dst_pitch, 32, 16 , 16, dst_pitch, VFilter); + } + else + { + /* First-pass only */ + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d16_h6_only_sse2(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 16, HFilter); + } + } + else + { + /* Second-pass only */ + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_unpack_block1d16_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 21, 32); + vp8_filter_block1d16_v6_sse2(FData2 + 32, dst_ptr, dst_pitch, 32, 16 , 16, dst_pitch, VFilter); + } +} + + +void vp8_sixtap_predict8x8_sse2 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ + const short *HFilter, *VFilter; + + if (xoffset) + { + if (yoffset) + { + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d8_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 13, 16, HFilter); + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_sse2(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 8, dst_pitch, VFilter); + } + else + { + /* First-pass only */ + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d8_h6_only_sse2(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 8, HFilter); + } + } + else + { + /* Second-pass only */ + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_only_sse2(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, dst_ptr, dst_pitch, 8, VFilter); + } +} + + +void vp8_sixtap_predict8x4_sse2 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); /* Temp data bufffer used in filtering */ + const short *HFilter, *VFilter; + + if (xoffset) + { + if (yoffset) + { + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d8_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 9, 16, HFilter); + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_sse2(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 4, dst_pitch, VFilter); + } + else + { + /* First-pass only */ + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d8_h6_only_sse2(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 4, HFilter); + } + } + else + { + /* Second-pass only */ + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_only_sse2(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, dst_ptr, dst_pitch, 4, VFilter); + } +} + +#endif + +#if HAVE_SSSE3 + +extern void vp8_filter_block1d8_h6_ssse3 +( + unsigned char *src_ptr, + unsigned int src_pixels_per_line, + unsigned char *output_ptr, + unsigned int output_pitch, + unsigned int output_height, + unsigned int vp8_filter_index +); + +extern void vp8_filter_block1d16_h6_ssse3 +( + unsigned char *src_ptr, + unsigned int src_pixels_per_line, + unsigned char *output_ptr, + unsigned int output_pitch, + unsigned int output_height, + unsigned int vp8_filter_index +); + +extern void vp8_filter_block1d16_v6_ssse3 +( + unsigned char *src_ptr, + unsigned int src_pitch, + unsigned char *output_ptr, + unsigned int out_pitch, + unsigned int output_height, + unsigned int vp8_filter_index +); + +extern void vp8_filter_block1d8_v6_ssse3 +( + unsigned char *src_ptr, + unsigned int src_pitch, + unsigned char *output_ptr, + unsigned int out_pitch, + unsigned int output_height, + unsigned int vp8_filter_index +); + +extern void vp8_filter_block1d4_h6_ssse3 +( + unsigned char *src_ptr, + unsigned int src_pixels_per_line, + unsigned char *output_ptr, + unsigned int output_pitch, + unsigned int output_height, + unsigned int vp8_filter_index +); + +extern void vp8_filter_block1d4_v6_ssse3 +( + unsigned char *src_ptr, + unsigned int src_pitch, + unsigned char *output_ptr, + unsigned int out_pitch, + unsigned int output_height, + unsigned int vp8_filter_index +); + +void vp8_sixtap_predict16x16_ssse3 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch + +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 24*24); + + if (xoffset) + { + if (yoffset) + { + vp8_filter_block1d16_h6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, FData2, 16, 21, xoffset); + vp8_filter_block1d16_v6_ssse3(FData2 , 16, dst_ptr, dst_pitch, 16, yoffset); + } + else + { + /* First-pass only */ + vp8_filter_block1d16_h6_ssse3(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 16, xoffset); + } + } + else + { + /* Second-pass only */ + vp8_filter_block1d16_v6_ssse3(src_ptr - (2 * src_pixels_per_line) , src_pixels_per_line, dst_ptr, dst_pitch, 16, yoffset); + } +} + +void vp8_sixtap_predict8x8_ssse3 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 256); + + if (xoffset) + { + if (yoffset) + { + vp8_filter_block1d8_h6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, FData2, 8, 13, xoffset); + vp8_filter_block1d8_v6_ssse3(FData2, 8, dst_ptr, dst_pitch, 8, yoffset); + } + else + { + vp8_filter_block1d8_h6_ssse3(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 8, xoffset); + } + } + else + { + /* Second-pass only */ + vp8_filter_block1d8_v6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, dst_ptr, dst_pitch, 8, yoffset); + } +} + + +void vp8_sixtap_predict8x4_ssse3 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 256); + + if (xoffset) + { + if (yoffset) + { + vp8_filter_block1d8_h6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, FData2, 8, 9, xoffset); + vp8_filter_block1d8_v6_ssse3(FData2, 8, dst_ptr, dst_pitch, 4, yoffset); + } + else + { + /* First-pass only */ + vp8_filter_block1d8_h6_ssse3(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 4, xoffset); + } + } + else + { + /* Second-pass only */ + vp8_filter_block1d8_v6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, dst_ptr, dst_pitch, 4, yoffset); + } +} + +void vp8_sixtap_predict4x4_ssse3 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned char, FData2, 4*9); + + if (xoffset) + { + if (yoffset) + { + vp8_filter_block1d4_h6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, FData2, 4, 9, xoffset); + vp8_filter_block1d4_v6_ssse3(FData2, 4, dst_ptr, dst_pitch, 4, yoffset); + } + else + { + vp8_filter_block1d4_h6_ssse3(src_ptr, src_pixels_per_line, dst_ptr, dst_pitch, 4, xoffset); + } + } + else + { + vp8_filter_block1d4_v6_ssse3(src_ptr - (2 * src_pixels_per_line), src_pixels_per_line, dst_ptr, dst_pitch, 4, yoffset); + } + +} + +#endif diff --git a/vp8/decoder/asm_dec_offsets.c b/vp8/decoder/asm_dec_offsets.c new file mode 100644 index 0000000..842a0d5 --- /dev/null +++ b/vp8/decoder/asm_dec_offsets.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_ports/asm_offsets.h" +#include "onyxd_int.h" + +BEGIN + +DEFINE(bool_decoder_user_buffer_end, offsetof(BOOL_DECODER, user_buffer_end)); +DEFINE(bool_decoder_user_buffer, offsetof(BOOL_DECODER, user_buffer)); +DEFINE(bool_decoder_value, offsetof(BOOL_DECODER, value)); +DEFINE(bool_decoder_count, offsetof(BOOL_DECODER, count)); +DEFINE(bool_decoder_range, offsetof(BOOL_DECODER, range)); + +END + +/* add asserts for any offset that is not supported by assembly code */ +/* add asserts for any size that is not supported by assembly code */ diff --git a/vp8/decoder/dboolhuff.c b/vp8/decoder/dboolhuff.c new file mode 100644 index 0000000..7e7b05a --- /dev/null +++ b/vp8/decoder/dboolhuff.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "dboolhuff.h" +#include "vpx_ports/mem.h" +#include "vpx_mem/vpx_mem.h" + +int vp8dx_start_decode(BOOL_DECODER *br, + const unsigned char *source, + unsigned int source_sz) +{ + br->user_buffer_end = source+source_sz; + br->user_buffer = source; + br->value = 0; + br->count = -8; + br->range = 255; + + if (source_sz && !source) + return 1; + + /* Populate the buffer */ + vp8dx_bool_decoder_fill(br); + + return 0; +} + + +void vp8dx_bool_decoder_fill(BOOL_DECODER *br) +{ + const unsigned char *bufptr; + const unsigned char *bufend; + VP8_BD_VALUE value; + int count; + bufend = br->user_buffer_end; + bufptr = br->user_buffer; + value = br->value; + count = br->count; + + VP8DX_BOOL_DECODER_FILL(count, value, bufptr, bufend); + + br->user_buffer = bufptr; + br->value = value; + br->count = count; +} diff --git a/vp8/decoder/dboolhuff.h b/vp8/decoder/dboolhuff.h new file mode 100644 index 0000000..880c185 --- /dev/null +++ b/vp8/decoder/dboolhuff.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef DBOOLHUFF_H +#define DBOOLHUFF_H +#include +#include +#include "vpx_config.h" +#include "vpx_ports/mem.h" +#include "vpx/vpx_integer.h" + +typedef size_t VP8_BD_VALUE; + +# define VP8_BD_VALUE_SIZE ((int)sizeof(VP8_BD_VALUE)*CHAR_BIT) +/*This is meant to be a large, positive constant that can still be efficiently + loaded as an immediate (on platforms like ARM, for example). + Even relatively modest values like 100 would work fine.*/ +# define VP8_LOTS_OF_BITS (0x40000000) + +typedef struct +{ + const unsigned char *user_buffer_end; + const unsigned char *user_buffer; + VP8_BD_VALUE value; + int count; + unsigned int range; +} BOOL_DECODER; + +DECLARE_ALIGNED(16, extern const unsigned char, vp8_norm[256]); + +int vp8dx_start_decode(BOOL_DECODER *br, + const unsigned char *source, + unsigned int source_sz); + +void vp8dx_bool_decoder_fill(BOOL_DECODER *br); + +/*The refill loop is used in several places, so define it in a macro to make + sure they're all consistent. + An inline function would be cleaner, but has a significant penalty, because + multiple BOOL_DECODER fields must be modified, and the compiler is not smart + enough to eliminate the stores to those fields and the subsequent reloads + from them when inlining the function.*/ +#define VP8DX_BOOL_DECODER_FILL(_count,_value,_bufptr,_bufend) \ + do \ + { \ + int shift = VP8_BD_VALUE_SIZE - 8 - ((_count) + 8); \ + int loop_end, x; \ + size_t bits_left = ((_bufend)-(_bufptr))*CHAR_BIT; \ + \ + x = shift + CHAR_BIT - bits_left; \ + loop_end = 0; \ + if(x >= 0) \ + { \ + (_count) += VP8_LOTS_OF_BITS; \ + loop_end = x; \ + if(!bits_left) break; \ + } \ + while(shift >= loop_end) \ + { \ + (_count) += CHAR_BIT; \ + (_value) |= (VP8_BD_VALUE)*(_bufptr)++ << shift; \ + shift -= CHAR_BIT; \ + } \ + } \ + while(0) \ + + +static int vp8dx_decode_bool(BOOL_DECODER *br, int probability) { + unsigned int bit = 0; + VP8_BD_VALUE value; + unsigned int split; + VP8_BD_VALUE bigsplit; + int count; + unsigned int range; + + split = 1 + (((br->range - 1) * probability) >> 8); + + if(br->count < 0) + vp8dx_bool_decoder_fill(br); + + value = br->value; + count = br->count; + + bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); + + range = split; + + if (value >= bigsplit) + { + range = br->range - split; + value = value - bigsplit; + bit = 1; + } + + { + register unsigned int shift = vp8_norm[range]; + range <<= shift; + value <<= shift; + count -= shift; + } + br->value = value; + br->count = count; + br->range = range; + + return bit; +} + +static int vp8_decode_value(BOOL_DECODER *br, int bits) +{ + int z = 0; + int bit; + + for (bit = bits - 1; bit >= 0; bit--) + { + z |= (vp8dx_decode_bool(br, 0x80) << bit); + } + + return z; +} + +static int vp8dx_bool_error(BOOL_DECODER *br) +{ + /* Check if we have reached the end of the buffer. + * + * Variable 'count' stores the number of bits in the 'value' buffer, minus + * 8. The top byte is part of the algorithm, and the remainder is buffered + * to be shifted into it. So if count == 8, the top 16 bits of 'value' are + * occupied, 8 for the algorithm and 8 in the buffer. + * + * When reading a byte from the user's buffer, count is filled with 8 and + * one byte is filled into the value buffer. When we reach the end of the + * data, count is additionally filled with VP8_LOTS_OF_BITS. So when + * count == VP8_LOTS_OF_BITS - 1, the user's data has been exhausted. + */ + if ((br->count > VP8_BD_VALUE_SIZE) && (br->count < VP8_LOTS_OF_BITS)) + { + /* We have tried to decode bits after the end of + * stream was encountered. + */ + return 1; + } + + /* No error. */ + return 0; +} +#endif diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c new file mode 100644 index 0000000..51e2420 --- /dev/null +++ b/vp8/decoder/decodemv.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "treereader.h" +#include "vp8/common/entropymv.h" +#include "vp8/common/entropymode.h" +#include "onyxd_int.h" +#include "vp8/common/findnearmv.h" + +#if CONFIG_DEBUG +#include +#endif +static B_PREDICTION_MODE read_bmode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_bmode_tree, p); + + return (B_PREDICTION_MODE)i; +} + +static MB_PREDICTION_MODE read_ymode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_ymode_tree, p); + + return (MB_PREDICTION_MODE)i; +} + +static MB_PREDICTION_MODE read_kf_ymode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_kf_ymode_tree, p); + + return (MB_PREDICTION_MODE)i; +} + +static MB_PREDICTION_MODE read_uv_mode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_uv_mode_tree, p); + + return (MB_PREDICTION_MODE)i; +} + +static void read_kf_modes(VP8D_COMP *pbi, MODE_INFO *mi) +{ + vp8_reader *const bc = & pbi->bc; + const int mis = pbi->common.mode_info_stride; + + mi->mbmi.ref_frame = INTRA_FRAME; + mi->mbmi.mode = read_kf_ymode(bc, pbi->common.kf_ymode_prob); + + if (mi->mbmi.mode == B_PRED) + { + int i = 0; + mi->mbmi.is_4x4 = 1; + + do + { + const B_PREDICTION_MODE A = above_block_mode(mi, i, mis); + const B_PREDICTION_MODE L = left_block_mode(mi, i); + + mi->bmi[i].as_mode = + read_bmode(bc, pbi->common.kf_bmode_prob [A] [L]); + } + while (++i < 16); + } + + mi->mbmi.uv_mode = read_uv_mode(bc, pbi->common.kf_uv_mode_prob); +} + +static int read_mvcomponent(vp8_reader *r, const MV_CONTEXT *mvc) +{ + const vp8_prob *const p = (const vp8_prob *) mvc; + int x = 0; + + if (vp8_read(r, p [mvpis_short])) /* Large */ + { + int i = 0; + + do + { + x += vp8_read(r, p [MVPbits + i]) << i; + } + while (++i < 3); + + i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ + + do + { + x += vp8_read(r, p [MVPbits + i]) << i; + } + while (--i > 3); + + if (!(x & 0xFFF0) || vp8_read(r, p [MVPbits + 3])) + x += 8; + } + else /* small */ + x = vp8_treed_read(r, vp8_small_mvtree, p + MVPshort); + + if (x && vp8_read(r, p [MVPsign])) + x = -x; + + return x; +} + +static void read_mv(vp8_reader *r, MV *mv, const MV_CONTEXT *mvc) +{ + mv->row = (short)(read_mvcomponent(r, mvc) << 1); + mv->col = (short)(read_mvcomponent(r, ++mvc) << 1); +} + + +static void read_mvcontexts(vp8_reader *bc, MV_CONTEXT *mvc) +{ + int i = 0; + + do + { + const vp8_prob *up = vp8_mv_update_probs[i].prob; + vp8_prob *p = (vp8_prob *)(mvc + i); + vp8_prob *const pstop = p + MVPcount; + + do + { + if (vp8_read(bc, *up++)) + { + const vp8_prob x = (vp8_prob)vp8_read_literal(bc, 7); + + *p = x ? x << 1 : 1; + } + } + while (++p < pstop); + } + while (++i < 2); +} + +static const unsigned char mbsplit_fill_count[4] = {8, 8, 4, 1}; +static const unsigned char mbsplit_fill_offset[4][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15}, + { 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15}, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} +}; + + +static void mb_mode_mv_init(VP8D_COMP *pbi) +{ + vp8_reader *const bc = & pbi->bc; + MV_CONTEXT *const mvc = pbi->common.fc.mvc; + +#if CONFIG_ERROR_CONCEALMENT + /* Default is that no macroblock is corrupt, therefore we initialize + * mvs_corrupt_from_mb to something very big, which we can be sure is + * outside the frame. */ + pbi->mvs_corrupt_from_mb = UINT_MAX; +#endif + pbi->prob_skip_false = 0; + if (pbi->common.mb_no_coeff_skip) + pbi->prob_skip_false = (vp8_prob)vp8_read_literal(bc, 8); + + if(pbi->common.frame_type != KEY_FRAME) + { + pbi->prob_intra = (vp8_prob)vp8_read_literal(bc, 8); + pbi->prob_last = (vp8_prob)vp8_read_literal(bc, 8); + pbi->prob_gf = (vp8_prob)vp8_read_literal(bc, 8); + + if (vp8_read_bit(bc)) + { + int i = 0; + + do + { + pbi->common.fc.ymode_prob[i] = + (vp8_prob) vp8_read_literal(bc, 8); + } + while (++i < 4); + } + + if (vp8_read_bit(bc)) + { + int i = 0; + + do + { + pbi->common.fc.uv_mode_prob[i] = + (vp8_prob) vp8_read_literal(bc, 8); + } + while (++i < 3); + } + + read_mvcontexts(bc, mvc); + } +} + +const vp8_prob vp8_sub_mv_ref_prob3 [8][VP8_SUBMVREFS-1] = +{ + { 147, 136, 18 }, /* SUBMVREF_NORMAL */ + { 223, 1 , 34 }, /* SUBMVREF_LEFT_ABOVE_SAME */ + { 106, 145, 1 }, /* SUBMVREF_LEFT_ZED */ + { 208, 1 , 1 }, /* SUBMVREF_LEFT_ABOVE_ZED */ + { 179, 121, 1 }, /* SUBMVREF_ABOVE_ZED */ + { 223, 1 , 34 }, /* SUBMVREF_LEFT_ABOVE_SAME */ + { 179, 121, 1 }, /* SUBMVREF_ABOVE_ZED */ + { 208, 1 , 1 } /* SUBMVREF_LEFT_ABOVE_ZED */ +}; + +static +const vp8_prob * get_sub_mv_ref_prob(const int left, const int above) +{ + int lez = (left == 0); + int aez = (above == 0); + int lea = (left == above); + const vp8_prob * prob; + + prob = vp8_sub_mv_ref_prob3[(aez << 2) | + (lez << 1) | + (lea)]; + + return prob; +} + +static void decode_split_mv(vp8_reader *const bc, MODE_INFO *mi, + const MODE_INFO *left_mb, const MODE_INFO *above_mb, + MB_MODE_INFO *mbmi, int_mv best_mv, + MV_CONTEXT *const mvc, int mb_to_left_edge, + int mb_to_right_edge, int mb_to_top_edge, + int mb_to_bottom_edge) +{ + int s; /* split configuration (16x8, 8x16, 8x8, 4x4) */ + int num_p; /* number of partitions in the split configuration + (see vp8_mbsplit_count) */ + int j = 0; + + s = 3; + num_p = 16; + if( vp8_read(bc, 110) ) + { + s = 2; + num_p = 4; + if( vp8_read(bc, 111) ) + { + s = vp8_read(bc, 150); + num_p = 2; + } + } + + do /* for each subset j */ + { + int_mv leftmv, abovemv; + int_mv blockmv; + int k; /* first block in subset j */ + + const vp8_prob *prob; + k = vp8_mbsplit_offset[s][j]; + + if (!(k & 3)) + { + /* On L edge, get from MB to left of us */ + if(left_mb->mbmi.mode != SPLITMV) + leftmv.as_int = left_mb->mbmi.mv.as_int; + else + leftmv.as_int = (left_mb->bmi + k + 4 - 1)->mv.as_int; + } + else + leftmv.as_int = (mi->bmi + k - 1)->mv.as_int; + + if (!(k >> 2)) + { + /* On top edge, get from MB above us */ + if(above_mb->mbmi.mode != SPLITMV) + abovemv.as_int = above_mb->mbmi.mv.as_int; + else + abovemv.as_int = (above_mb->bmi + k + 16 - 4)->mv.as_int; + } + else + abovemv.as_int = (mi->bmi + k - 4)->mv.as_int; + + prob = get_sub_mv_ref_prob(leftmv.as_int, abovemv.as_int); + + if( vp8_read(bc, prob[0]) ) + { + if( vp8_read(bc, prob[1]) ) + { + blockmv.as_int = 0; + if( vp8_read(bc, prob[2]) ) + { + blockmv.as_mv.row = read_mvcomponent(bc, &mvc[0]) << 1; + blockmv.as_mv.row += best_mv.as_mv.row; + blockmv.as_mv.col = read_mvcomponent(bc, &mvc[1]) << 1; + blockmv.as_mv.col += best_mv.as_mv.col; + + mbmi->need_to_clamp_mvs |= vp8_check_mv_bounds(&blockmv, + mb_to_left_edge, + mb_to_right_edge, + mb_to_top_edge, + mb_to_bottom_edge); + } + } + else + { + blockmv.as_int = abovemv.as_int; + mbmi->need_to_clamp_mvs |= above_mb->mbmi.need_to_clamp_mvs; + } + } + else + { + blockmv.as_int = leftmv.as_int; + mbmi->need_to_clamp_mvs |= left_mb->mbmi.need_to_clamp_mvs; + } + + { + /* Fill (uniform) modes, mvs of jth subset. + Must do it here because ensuing subsets can + refer back to us via "left" or "above". */ + const unsigned char *fill_offset; + unsigned int fill_count = mbsplit_fill_count[s]; + + fill_offset = &mbsplit_fill_offset[s] + [(unsigned char)j * mbsplit_fill_count[s]]; + + do { + mi->bmi[ *fill_offset].mv.as_int = blockmv.as_int; + fill_offset++; + }while (--fill_count); + } + + } + while (++j < num_p); + + mbmi->partitioning = s; +} + +static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi) +{ + vp8_reader *const bc = & pbi->bc; + mbmi->ref_frame = (MV_REFERENCE_FRAME) vp8_read(bc, pbi->prob_intra); + if (mbmi->ref_frame) /* inter MB */ + { + enum {CNT_INTRA, CNT_NEAREST, CNT_NEAR, CNT_SPLITMV}; + int cnt[4]; + int *cntx = cnt; + int_mv near_mvs[4]; + int_mv *nmv = near_mvs; + const int mis = pbi->mb.mode_info_stride; + const MODE_INFO *above = mi - mis; + const MODE_INFO *left = mi - 1; + const MODE_INFO *aboveleft = above - 1; + int *ref_frame_sign_bias = pbi->common.ref_frame_sign_bias; + + mbmi->need_to_clamp_mvs = 0; + + if (vp8_read(bc, pbi->prob_last)) + { + mbmi->ref_frame = + (MV_REFERENCE_FRAME)((int)(2 + vp8_read(bc, pbi->prob_gf))); + } + + /* Zero accumulators */ + nmv[0].as_int = nmv[1].as_int = nmv[2].as_int = 0; + cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0; + + /* Process above */ + if (above->mbmi.ref_frame != INTRA_FRAME) + { + if (above->mbmi.mv.as_int) + { + (++nmv)->as_int = above->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[above->mbmi.ref_frame], + mbmi->ref_frame, nmv, ref_frame_sign_bias); + ++cntx; + } + + *cntx += 2; + } + + /* Process left */ + if (left->mbmi.ref_frame != INTRA_FRAME) + { + if (left->mbmi.mv.as_int) + { + int_mv this_mv; + + this_mv.as_int = left->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[left->mbmi.ref_frame], + mbmi->ref_frame, &this_mv, ref_frame_sign_bias); + + if (this_mv.as_int != nmv->as_int) + { + (++nmv)->as_int = this_mv.as_int; + ++cntx; + } + + *cntx += 2; + } + else + cnt[CNT_INTRA] += 2; + } + + /* Process above left */ + if (aboveleft->mbmi.ref_frame != INTRA_FRAME) + { + if (aboveleft->mbmi.mv.as_int) + { + int_mv this_mv; + + this_mv.as_int = aboveleft->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[aboveleft->mbmi.ref_frame], + mbmi->ref_frame, &this_mv, ref_frame_sign_bias); + + if (this_mv.as_int != nmv->as_int) + { + (++nmv)->as_int = this_mv.as_int; + ++cntx; + } + + *cntx += 1; + } + else + cnt[CNT_INTRA] += 1; + } + + if( vp8_read(bc, vp8_mode_contexts [cnt[CNT_INTRA]] [0]) ) + { + + /* If we have three distinct MV's ... */ + /* See if above-left MV can be merged with NEAREST */ + cnt[CNT_NEAREST] += ( (cnt[CNT_SPLITMV] > 0) & + (nmv->as_int == near_mvs[CNT_NEAREST].as_int)); + + /* Swap near and nearest if necessary */ + if (cnt[CNT_NEAR] > cnt[CNT_NEAREST]) + { + int tmp; + tmp = cnt[CNT_NEAREST]; + cnt[CNT_NEAREST] = cnt[CNT_NEAR]; + cnt[CNT_NEAR] = tmp; + tmp = near_mvs[CNT_NEAREST].as_int; + near_mvs[CNT_NEAREST].as_int = near_mvs[CNT_NEAR].as_int; + near_mvs[CNT_NEAR].as_int = tmp; + } + + if( vp8_read(bc, vp8_mode_contexts [cnt[CNT_NEAREST]] [1]) ) + { + + if( vp8_read(bc, vp8_mode_contexts [cnt[CNT_NEAR]] [2]) ) + { + int mb_to_top_edge; + int mb_to_bottom_edge; + int mb_to_left_edge; + int mb_to_right_edge; + MV_CONTEXT *const mvc = pbi->common.fc.mvc; + int near_index; + + mb_to_top_edge = pbi->mb.mb_to_top_edge; + mb_to_bottom_edge = pbi->mb.mb_to_bottom_edge; + mb_to_top_edge -= LEFT_TOP_MARGIN; + mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN; + mb_to_right_edge = pbi->mb.mb_to_right_edge; + mb_to_right_edge += RIGHT_BOTTOM_MARGIN; + mb_to_left_edge = pbi->mb.mb_to_left_edge; + mb_to_left_edge -= LEFT_TOP_MARGIN; + + /* Use near_mvs[0] to store the "best" MV */ + near_index = CNT_INTRA + + (cnt[CNT_NEAREST] >= cnt[CNT_INTRA]); + + vp8_clamp_mv2(&near_mvs[near_index], &pbi->mb); + + cnt[CNT_SPLITMV] = ((above->mbmi.mode == SPLITMV) + + (left->mbmi.mode == SPLITMV)) * 2 + + (aboveleft->mbmi.mode == SPLITMV); + + if( vp8_read(bc, vp8_mode_contexts [cnt[CNT_SPLITMV]] [3]) ) + { + decode_split_mv(bc, mi, left, above, + mbmi, + near_mvs[near_index], + mvc, mb_to_left_edge, + mb_to_right_edge, + mb_to_top_edge, + mb_to_bottom_edge); + mbmi->mv.as_int = mi->bmi[15].mv.as_int; + mbmi->mode = SPLITMV; + mbmi->is_4x4 = 1; + } + else + { + int_mv *const mbmi_mv = & mbmi->mv; + read_mv(bc, &mbmi_mv->as_mv, (const MV_CONTEXT *) mvc); + mbmi_mv->as_mv.row += near_mvs[near_index].as_mv.row; + mbmi_mv->as_mv.col += near_mvs[near_index].as_mv.col; + + /* Don't need to check this on NEARMV and NEARESTMV + * modes since those modes clamp the MV. The NEWMV mode + * does not, so signal to the prediction stage whether + * special handling may be required. + */ + mbmi->need_to_clamp_mvs = + vp8_check_mv_bounds(mbmi_mv, mb_to_left_edge, + mb_to_right_edge, + mb_to_top_edge, + mb_to_bottom_edge); + mbmi->mode = NEWMV; + } + } + else + { + mbmi->mode = NEARMV; + vp8_clamp_mv2(&near_mvs[CNT_NEAR], &pbi->mb); + mbmi->mv.as_int = near_mvs[CNT_NEAR].as_int; + } + } + else + { + mbmi->mode = NEARESTMV; + vp8_clamp_mv2(&near_mvs[CNT_NEAREST], &pbi->mb); + mbmi->mv.as_int = near_mvs[CNT_NEAREST].as_int; + } + } + else + { + mbmi->mode = ZEROMV; + mbmi->mv.as_int = 0; + } + +#if CONFIG_ERROR_CONCEALMENT + if(pbi->ec_enabled && (mbmi->mode != SPLITMV)) + { + mi->bmi[ 0].mv.as_int = + mi->bmi[ 1].mv.as_int = + mi->bmi[ 2].mv.as_int = + mi->bmi[ 3].mv.as_int = + mi->bmi[ 4].mv.as_int = + mi->bmi[ 5].mv.as_int = + mi->bmi[ 6].mv.as_int = + mi->bmi[ 7].mv.as_int = + mi->bmi[ 8].mv.as_int = + mi->bmi[ 9].mv.as_int = + mi->bmi[10].mv.as_int = + mi->bmi[11].mv.as_int = + mi->bmi[12].mv.as_int = + mi->bmi[13].mv.as_int = + mi->bmi[14].mv.as_int = + mi->bmi[15].mv.as_int = mbmi->mv.as_int; + } +#endif + } + else + { + /* required for left and above block mv */ + mbmi->mv.as_int = 0; + + /* MB is intra coded */ + if ((mbmi->mode = read_ymode(bc, pbi->common.fc.ymode_prob)) == B_PRED) + { + int j = 0; + mbmi->is_4x4 = 1; + do + { + mi->bmi[j].as_mode = read_bmode(bc, pbi->common.fc.bmode_prob); + } + while (++j < 16); + } + + mbmi->uv_mode = read_uv_mode(bc, pbi->common.fc.uv_mode_prob); + } + +} + +static void read_mb_features(vp8_reader *r, MB_MODE_INFO *mi, MACROBLOCKD *x) +{ + /* Is segmentation enabled */ + if (x->segmentation_enabled && x->update_mb_segmentation_map) + { + /* If so then read the segment id. */ + if (vp8_read(r, x->mb_segment_tree_probs[0])) + mi->segment_id = + (unsigned char)(2 + vp8_read(r, x->mb_segment_tree_probs[2])); + else + mi->segment_id = + (unsigned char)(vp8_read(r, x->mb_segment_tree_probs[1])); + } +} + +static void decode_mb_mode_mvs(VP8D_COMP *pbi, MODE_INFO *mi, + MB_MODE_INFO *mbmi) +{ + /* Read the Macroblock segmentation map if it is being updated explicitly + * this frame (reset to 0 above by default) + * By default on a key frame reset all MBs to segment 0 + */ + if (pbi->mb.update_mb_segmentation_map) + read_mb_features(&pbi->bc, &mi->mbmi, &pbi->mb); + else if(pbi->common.frame_type == KEY_FRAME) + mi->mbmi.segment_id = 0; + + /* Read the macroblock coeff skip flag if this feature is in use, + * else default to 0 */ + if (pbi->common.mb_no_coeff_skip) + mi->mbmi.mb_skip_coeff = vp8_read(&pbi->bc, pbi->prob_skip_false); + else + mi->mbmi.mb_skip_coeff = 0; + + mi->mbmi.is_4x4 = 0; + if(pbi->common.frame_type == KEY_FRAME) + read_kf_modes(pbi, mi); + else + read_mb_modes_mv(pbi, mi, &mi->mbmi); + +} + +void vp8_decode_mode_mvs(VP8D_COMP *pbi) +{ + MODE_INFO *mi = pbi->common.mi; + int mb_row = -1; + int mb_to_right_edge_start; + + mb_mode_mv_init(pbi); + + pbi->mb.mb_to_top_edge = 0; + pbi->mb.mb_to_bottom_edge = ((pbi->common.mb_rows - 1) * 16) << 3; + mb_to_right_edge_start = ((pbi->common.mb_cols - 1) * 16) << 3; + + while (++mb_row < pbi->common.mb_rows) + { + int mb_col = -1; + + pbi->mb.mb_to_left_edge = 0; + pbi->mb.mb_to_right_edge = mb_to_right_edge_start; + + while (++mb_col < pbi->common.mb_cols) + { +#if CONFIG_ERROR_CONCEALMENT + int mb_num = mb_row * pbi->common.mb_cols + mb_col; +#endif + + decode_mb_mode_mvs(pbi, mi, &mi->mbmi); + +#if CONFIG_ERROR_CONCEALMENT + /* look for corruption. set mvs_corrupt_from_mb to the current + * mb_num if the frame is corrupt from this macroblock. */ + if (vp8dx_bool_error(&pbi->bc) && mb_num < pbi->mvs_corrupt_from_mb) + { + pbi->mvs_corrupt_from_mb = mb_num; + /* no need to continue since the partition is corrupt from + * here on. + */ + return; + } +#endif + + pbi->mb.mb_to_left_edge -= (16 << 3); + pbi->mb.mb_to_right_edge -= (16 << 3); + mi++; /* next macroblock */ + } + pbi->mb.mb_to_top_edge -= (16 << 3); + pbi->mb.mb_to_bottom_edge -= (16 << 3); + + mi++; /* skip left predictor each row */ + } +} diff --git a/vp8/decoder/decodemv.h b/vp8/decoder/decodemv.h new file mode 100644 index 0000000..9403424 --- /dev/null +++ b/vp8/decoder/decodemv.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "onyxd_int.h" + +void vp8_decode_mode_mvs(VP8D_COMP *); diff --git a/vp8/decoder/decoderthreading.h b/vp8/decoder/decoderthreading.h new file mode 100644 index 0000000..60c39d1 --- /dev/null +++ b/vp8/decoder/decoderthreading.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + + + + +#ifndef _DECODER_THREADING_H +#define _DECODER_THREADING_H + +#if CONFIG_MULTITHREAD +extern void vp8mt_decode_mb_rows(VP8D_COMP *pbi, MACROBLOCKD *xd); +extern void vp8_decoder_remove_threads(VP8D_COMP *pbi); +extern void vp8_decoder_create_threads(VP8D_COMP *pbi); +extern void vp8mt_alloc_temp_buffers(VP8D_COMP *pbi, int width, int prev_mb_rows); +extern void vp8mt_de_alloc_temp_buffers(VP8D_COMP *pbi, int mb_rows); +#endif + +#endif diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c new file mode 100644 index 0000000..62a068b --- /dev/null +++ b/vp8/decoder/decodframe.c @@ -0,0 +1,1192 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "onyxd_int.h" +#include "vp8/common/header.h" +#include "vp8/common/reconintra4x4.h" +#include "vp8/common/reconinter.h" +#include "detokenize.h" +#include "vp8/common/invtrans.h" +#include "vp8/common/alloccommon.h" +#include "vp8/common/entropymode.h" +#include "vp8/common/quant_common.h" +#include "vpx_scale/vpxscale.h" +#include "vp8/common/setupintrarecon.h" + +#include "decodemv.h" +#include "vp8/common/extend.h" +#if CONFIG_ERROR_CONCEALMENT +#include "error_concealment.h" +#endif +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/threading.h" +#include "decoderthreading.h" +#include "dboolhuff.h" + +#include +#include + +void vp8cx_init_de_quantizer(VP8D_COMP *pbi) +{ + int Q; + VP8_COMMON *const pc = & pbi->common; + + for (Q = 0; Q < QINDEX_RANGE; Q++) + { + pc->Y1dequant[Q][0] = (short)vp8_dc_quant(Q, pc->y1dc_delta_q); + pc->Y2dequant[Q][0] = (short)vp8_dc2quant(Q, pc->y2dc_delta_q); + pc->UVdequant[Q][0] = (short)vp8_dc_uv_quant(Q, pc->uvdc_delta_q); + + pc->Y1dequant[Q][1] = (short)vp8_ac_yquant(Q); + pc->Y2dequant[Q][1] = (short)vp8_ac2quant(Q, pc->y2ac_delta_q); + pc->UVdequant[Q][1] = (short)vp8_ac_uv_quant(Q, pc->uvac_delta_q); + } +} + +void vp8_mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + int i; + int QIndex; + MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi; + VP8_COMMON *const pc = & pbi->common; + + /* Decide whether to use the default or alternate baseline Q value. */ + if (xd->segmentation_enabled) + { + /* Abs Value */ + if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA) + QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + + /* Delta Value */ + else + { + QIndex = pc->base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; /* Clamp to valid range */ + } + } + else + QIndex = pc->base_qindex; + + /* Set up the macroblock dequant constants */ + xd->dequant_y1_dc[0] = 1; + xd->dequant_y1[0] = pc->Y1dequant[QIndex][0]; + xd->dequant_y2[0] = pc->Y2dequant[QIndex][0]; + xd->dequant_uv[0] = pc->UVdequant[QIndex][0]; + + for (i = 1; i < 16; i++) + { + xd->dequant_y1_dc[i] = + xd->dequant_y1[i] = pc->Y1dequant[QIndex][1]; + xd->dequant_y2[i] = pc->Y2dequant[QIndex][1]; + xd->dequant_uv[i] = pc->UVdequant[QIndex][1]; + } +} + +static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, + unsigned int mb_idx) +{ + MB_PREDICTION_MODE mode; + int i; +#if CONFIG_ERROR_CONCEALMENT + int corruption_detected = 0; +#endif + + if (xd->mode_info_context->mbmi.mb_skip_coeff) + { + vp8_reset_mb_tokens_context(xd); + } + else if (!vp8dx_bool_error(xd->current_bc)) + { + int eobtotal; + eobtotal = vp8_decode_mb_tokens(pbi, xd); + + /* Special case: Force the loopfilter to skip when eobtotal is zero */ + xd->mode_info_context->mbmi.mb_skip_coeff = (eobtotal==0); + } + + mode = xd->mode_info_context->mbmi.mode; + + if (xd->segmentation_enabled) + vp8_mb_init_dequantizer(pbi, xd); + + +#if CONFIG_ERROR_CONCEALMENT + + if(pbi->ec_active) + { + int throw_residual; + /* When we have independent partitions we can apply residual even + * though other partitions within the frame are corrupt. + */ + throw_residual = (!pbi->independent_partitions && + pbi->frame_corrupt_residual); + throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc)); + + if ((mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual)) + { + /* MB with corrupt residuals or corrupt mode/motion vectors. + * Better to use the predictor as reconstruction. + */ + pbi->frame_corrupt_residual = 1; + vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); + vp8_conceal_corrupt_mb(xd); + + + corruption_detected = 1; + + /* force idct to be skipped for B_PRED and use the + * prediction only for reconstruction + * */ + vpx_memset(xd->eobs, 0, 25); + } + } +#endif + + /* do prediction */ + if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) + { + vp8_build_intra_predictors_mbuv_s(xd, + xd->recon_above[1], + xd->recon_above[2], + xd->recon_left[1], + xd->recon_left[2], + xd->recon_left_stride[1], + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride); + + if (mode != B_PRED) + { + vp8_build_intra_predictors_mby_s(xd, + xd->recon_above[0], + xd->recon_left[0], + xd->recon_left_stride[0], + xd->dst.y_buffer, + xd->dst.y_stride); + } + else + { + short *DQC = xd->dequant_y1; + int dst_stride = xd->dst.y_stride; + unsigned char *base_dst = xd->dst.y_buffer; + + /* clear out residual eob info */ + if(xd->mode_info_context->mbmi.mb_skip_coeff) + vpx_memset(xd->eobs, 0, 25); + + intra_prediction_down_copy(xd, xd->recon_above[0] + 16); + + for (i = 0; i < 16; i++) + { + BLOCKD *b = &xd->block[i]; + int b_mode = xd->mode_info_context->bmi[i].as_mode; + unsigned char *yabove; + unsigned char *yleft; + int left_stride; + unsigned char top_left; + + yabove = base_dst + b->offset - dst_stride; + yleft = base_dst + b->offset - 1; + left_stride = dst_stride; + top_left = yabove[-1]; + + // vp8_intra4x4_predict (base_dst + b->offset, dst_stride, b_mode, + // base_dst + b->offset, dst_stride ); + vp8_intra4x4_predict_d_c(yabove, yleft, left_stride, + b_mode, + base_dst + b->offset, dst_stride, + top_left); + + if (xd->eobs[i]) + { + if (xd->eobs[i] > 1) + { + vp8_dequant_idct_add + (b->qcoeff, DQC, + base_dst + b->offset, dst_stride); + } + else + { + vp8_dc_only_idct_add + (b->qcoeff[0] * DQC[0], + base_dst + b->offset, dst_stride, + base_dst + b->offset, dst_stride); + ((int *)b->qcoeff)[0] = 0; + } + } + } + } + } + else + { + vp8_build_inter_predictors_mb(xd); + } + + +#if CONFIG_ERROR_CONCEALMENT + if (corruption_detected) + { + return; + } +#endif + + if(!xd->mode_info_context->mbmi.mb_skip_coeff) + { + /* dequantization and idct */ + if (mode != B_PRED) + { + short *DQC = xd->dequant_y1; + + if (mode != SPLITMV) + { + BLOCKD *b = &xd->block[24]; + + /* do 2nd order transform on the dc block */ + if (xd->eobs[24] > 1) + { + vp8_dequantize_b(b, xd->dequant_y2); + + vp8_short_inv_walsh4x4(&b->dqcoeff[0], + xd->qcoeff); + ((int *)b->qcoeff)[0] = 0; + ((int *)b->qcoeff)[1] = 0; + ((int *)b->qcoeff)[2] = 0; + ((int *)b->qcoeff)[3] = 0; + ((int *)b->qcoeff)[4] = 0; + ((int *)b->qcoeff)[5] = 0; + ((int *)b->qcoeff)[6] = 0; + ((int *)b->qcoeff)[7] = 0; + } + else + { + b->dqcoeff[0] = b->qcoeff[0] * xd->dequant_y2[0]; + vp8_short_inv_walsh4x4_1(&b->dqcoeff[0], + xd->qcoeff); + ((int *)b->qcoeff)[0] = 0; + } + + /* override the dc dequant constant in order to preserve the + * dc components + */ + DQC = xd->dequant_y1_dc; + } + + vp8_dequant_idct_add_y_block + (xd->qcoeff, DQC, + xd->dst.y_buffer, + xd->dst.y_stride, xd->eobs); + } + + vp8_dequant_idct_add_uv_block + (xd->qcoeff+16*16, xd->dequant_uv, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride, xd->eobs+16); + } +} + +static int get_delta_q(vp8_reader *bc, int prev, int *q_update) +{ + int ret_val = 0; + + if (vp8_read_bit(bc)) + { + ret_val = vp8_read_literal(bc, 4); + + if (vp8_read_bit(bc)) + ret_val = -ret_val; + } + + /* Trigger a quantizer update if the delta-q value has changed */ + if (ret_val != prev) + *q_update = 1; + + return ret_val; +} + +#ifdef PACKET_TESTING +#include +FILE *vpxlog = 0; +#endif + +static void decode_mb_rows(VP8D_COMP *pbi) +{ + VP8_COMMON *const pc = & pbi->common; + MACROBLOCKD *const xd = & pbi->mb; + + int ibc = 0; + int num_part = 1 << pc->multi_token_partition; + + int recon_yoffset, recon_uvoffset; + int mb_row, mb_col; + int mb_idx = 0; + int dst_fb_idx = pc->new_fb_idx; + int recon_y_stride = pc->yv12_fb[dst_fb_idx].y_stride; + int recon_uv_stride = pc->yv12_fb[dst_fb_idx].uv_stride; + + unsigned char *ref_buffer[MAX_REF_FRAMES][3]; + unsigned char *dst_buffer[3]; + int i; + int ref_fb_index[MAX_REF_FRAMES]; + int ref_fb_corrupted[MAX_REF_FRAMES]; + + ref_fb_corrupted[INTRA_FRAME] = 0; + + ref_fb_index[LAST_FRAME] = pc->lst_fb_idx; + ref_fb_index[GOLDEN_FRAME] = pc->gld_fb_idx; + ref_fb_index[ALTREF_FRAME] = pc->alt_fb_idx; + + for(i = 1; i < MAX_REF_FRAMES; i++) + { + ref_buffer[i][0] = pc->yv12_fb[ref_fb_index[i]].y_buffer; + ref_buffer[i][1] = pc->yv12_fb[ref_fb_index[i]].u_buffer; + ref_buffer[i][2] = pc->yv12_fb[ref_fb_index[i]].v_buffer; + + ref_fb_corrupted[i] = pc->yv12_fb[ref_fb_index[i]].corrupted; + } + + dst_buffer[0] = pc->yv12_fb[dst_fb_idx].y_buffer; + dst_buffer[1] = pc->yv12_fb[dst_fb_idx].u_buffer; + dst_buffer[2] = pc->yv12_fb[dst_fb_idx].v_buffer; + + xd->up_available = 0; + + /* Decode the individual macro block */ + for (mb_row = 0; mb_row < pc->mb_rows; mb_row++) + { + if (num_part > 1) + { + xd->current_bc = & pbi->mbc[ibc]; + ibc++; + + if (ibc == num_part) + ibc = 0; + } + + recon_yoffset = mb_row * recon_y_stride * 16; + recon_uvoffset = mb_row * recon_uv_stride * 8; + + /* reset contexts */ + xd->above_context = pc->above_context; + vpx_memset(xd->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); + + xd->left_available = 0; + + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + + xd->recon_above[0] = dst_buffer[0] + recon_yoffset; + xd->recon_above[1] = dst_buffer[1] + recon_uvoffset; + xd->recon_above[2] = dst_buffer[2] + recon_uvoffset; + + xd->recon_left[0] = xd->recon_above[0] - 1; + xd->recon_left[1] = xd->recon_above[1] - 1; + xd->recon_left[2] = xd->recon_above[2] - 1; + + xd->recon_above[0] -= xd->dst.y_stride; + xd->recon_above[1] -= xd->dst.uv_stride; + xd->recon_above[2] -= xd->dst.uv_stride; + + //TODO: move to outside row loop + xd->recon_left_stride[0] = xd->dst.y_stride; + xd->recon_left_stride[1] = xd->dst.uv_stride; + + for (mb_col = 0; mb_col < pc->mb_cols; mb_col++) + { + /* Distance of Mb to the various image edges. + * These are specified to 8th pel as they are always compared to values + * that are in 1/8th pel units + */ + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + +#if CONFIG_ERROR_CONCEALMENT + { + int corrupt_residual = (!pbi->independent_partitions && + pbi->frame_corrupt_residual) || + vp8dx_bool_error(xd->current_bc); + if (pbi->ec_active && + xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME && + corrupt_residual) + { + /* We have an intra block with corrupt coefficients, better to + * conceal with an inter block. Interpolate MVs from neighboring + * MBs. + * + * Note that for the first mb with corrupt residual in a frame, + * we might not discover that before decoding the residual. That + * happens after this check, and therefore no inter concealment + * will be done. + */ + vp8_interpolate_motion(xd, + mb_row, mb_col, + pc->mb_rows, pc->mb_cols, + pc->mode_info_stride); + } + } +#endif + + xd->dst.y_buffer = dst_buffer[0] + recon_yoffset; + xd->dst.u_buffer = dst_buffer[1] + recon_uvoffset; + xd->dst.v_buffer = dst_buffer[2] + recon_uvoffset; + + xd->pre.y_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][0] + recon_yoffset; + xd->pre.u_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][1] + recon_uvoffset; + xd->pre.v_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][2] + recon_uvoffset; + + /* propagate errors from reference frames */ + xd->corrupted |= ref_fb_corrupted[xd->mode_info_context->mbmi.ref_frame]; + + decode_macroblock(pbi, xd, mb_idx); + + mb_idx++; + xd->left_available = 1; + + /* check if the boolean decoder has suffered an error */ + xd->corrupted |= vp8dx_bool_error(xd->current_bc); + + xd->recon_above[0] += 16; + xd->recon_above[1] += 8; + xd->recon_above[2] += 8; + xd->recon_left[0] += 16; + xd->recon_left[1] += 8; + xd->recon_left[2] += 8; + + + recon_yoffset += 16; + recon_uvoffset += 8; + + ++xd->mode_info_context; /* next mb */ + + xd->above_context++; + + } + + /* adjust to the next row of mbs */ + vp8_extend_mb_row( + &pc->yv12_fb[dst_fb_idx], + xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8 + ); + + ++xd->mode_info_context; /* skip prediction column */ + xd->up_available = 1; + + } +} + +static unsigned int read_partition_size(const unsigned char *cx_size) +{ + const unsigned int size = + cx_size[0] + (cx_size[1] << 8) + (cx_size[2] << 16); + return size; +} + +static int read_is_valid(const unsigned char *start, + size_t len, + const unsigned char *end) +{ + return (start + len > start && start + len <= end); +} + +static unsigned int read_available_partition_size( + VP8D_COMP *pbi, + const unsigned char *token_part_sizes, + const unsigned char *fragment_start, + const unsigned char *first_fragment_end, + const unsigned char *fragment_end, + int i, + int num_part) +{ + VP8_COMMON* pc = &pbi->common; + const unsigned char *partition_size_ptr = token_part_sizes + i * 3; + unsigned int partition_size = 0; + ptrdiff_t bytes_left = fragment_end - fragment_start; + /* Calculate the length of this partition. The last partition + * size is implicit. If the partition size can't be read, then + * either use the remaining data in the buffer (for EC mode) + * or throw an error. + */ + if (i < num_part - 1) + { + if (read_is_valid(partition_size_ptr, 3, first_fragment_end)) + partition_size = read_partition_size(partition_size_ptr); + else if (pbi->ec_active) + partition_size = bytes_left; + else + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated partition size data"); + } + else + partition_size = bytes_left; + + /* Validate the calculated partition length. If the buffer + * described by the partition can't be fully read, then restrict + * it to the portion that can be (for EC mode) or throw an error. + */ + if (!read_is_valid(fragment_start, partition_size, fragment_end)) + { + if (pbi->ec_active) + partition_size = bytes_left; + else + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet or corrupt partition " + "%d length", i + 1); + } + return partition_size; +} + + +static void setup_token_decoder(VP8D_COMP *pbi, + const unsigned char* token_part_sizes) +{ + vp8_reader *bool_decoder = &pbi->bc2; + unsigned int partition_idx; + int fragment_idx; + int num_token_partitions; + const unsigned char *first_fragment_end = pbi->fragments[0] + + pbi->fragment_sizes[0]; + + TOKEN_PARTITION multi_token_partition = + (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2); + if (!vp8dx_bool_error(&pbi->bc)) + pbi->common.multi_token_partition = multi_token_partition; + num_token_partitions = 1 << pbi->common.multi_token_partition; + if (num_token_partitions > 1) + { + CHECK_MEM_ERROR(pbi->mbc, vpx_malloc(num_token_partitions * + sizeof(vp8_reader))); + bool_decoder = pbi->mbc; + } + + /* Check for partitions within the fragments and unpack the fragments + * so that each fragment pointer points to its corresponding partition. */ + for (fragment_idx = 0; fragment_idx < pbi->num_fragments; ++fragment_idx) + { + unsigned int fragment_size = pbi->fragment_sizes[fragment_idx]; + const unsigned char *fragment_end = pbi->fragments[fragment_idx] + + fragment_size; + /* Special case for handling the first partition since we have already + * read its size. */ + if (fragment_idx == 0) + { + /* Size of first partition + token partition sizes element */ + ptrdiff_t ext_first_part_size = token_part_sizes - + pbi->fragments[0] + 3 * (num_token_partitions - 1); + fragment_size -= ext_first_part_size; + if (fragment_size > 0) + { + pbi->fragment_sizes[0] = ext_first_part_size; + /* The fragment contains an additional partition. Move to + * next. */ + fragment_idx++; + pbi->fragments[fragment_idx] = pbi->fragments[0] + + pbi->fragment_sizes[0]; + } + } + /* Split the chunk into partitions read from the bitstream */ + while (fragment_size > 0) + { + ptrdiff_t partition_size = read_available_partition_size( + pbi, + token_part_sizes, + pbi->fragments[fragment_idx], + first_fragment_end, + fragment_end, + fragment_idx - 1, + num_token_partitions); + pbi->fragment_sizes[fragment_idx] = partition_size; + fragment_size -= partition_size; + assert(fragment_idx <= num_token_partitions); + if (fragment_size > 0) + { + /* The fragment contains an additional partition. + * Move to next. */ + fragment_idx++; + pbi->fragments[fragment_idx] = + pbi->fragments[fragment_idx - 1] + partition_size; + } + } + } + + pbi->num_fragments = num_token_partitions + 1; + + for (partition_idx = 1; partition_idx < pbi->num_fragments; ++partition_idx) + { + if (vp8dx_start_decode(bool_decoder, + pbi->fragments[partition_idx], + pbi->fragment_sizes[partition_idx])) + vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate bool decoder %d", + partition_idx); + + bool_decoder++; + } + +#if CONFIG_MULTITHREAD + /* Clamp number of decoder threads */ + if (pbi->decoding_thread_count > num_token_partitions - 1) + pbi->decoding_thread_count = num_token_partitions - 1; +#endif +} + +static void stop_token_decoder(VP8D_COMP *pbi) +{ + VP8_COMMON *pc = &pbi->common; + + if (pc->multi_token_partition != ONE_PARTITION) + { + vpx_free(pbi->mbc); + pbi->mbc = NULL; + } +} + +static void init_frame(VP8D_COMP *pbi) +{ + VP8_COMMON *const pc = & pbi->common; + MACROBLOCKD *const xd = & pbi->mb; + + if (pc->frame_type == KEY_FRAME) + { + /* Various keyframe initializations */ + vpx_memcpy(pc->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); + + vp8_init_mbmode_probs(pc); + + vp8_default_coef_probs(pc); + vp8_kf_default_bmode_probs(pc->kf_bmode_prob); + + /* reset the segment feature data to 0 with delta coding (Default state). */ + vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); + xd->mb_segement_abs_delta = SEGMENT_DELTADATA; + + /* reset the mode ref deltasa for loop filter */ + vpx_memset(xd->ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas)); + vpx_memset(xd->mode_lf_deltas, 0, sizeof(xd->mode_lf_deltas)); + + /* All buffers are implicitly updated on key frames. */ + pc->refresh_golden_frame = 1; + pc->refresh_alt_ref_frame = 1; + pc->copy_buffer_to_gf = 0; + pc->copy_buffer_to_arf = 0; + + /* Note that Golden and Altref modes cannot be used on a key frame so + * ref_frame_sign_bias[] is undefined and meaningless + */ + pc->ref_frame_sign_bias[GOLDEN_FRAME] = 0; + pc->ref_frame_sign_bias[ALTREF_FRAME] = 0; + } + else + { + if (!pc->use_bilinear_mc_filter) + pc->mcomp_filter_type = SIXTAP; + else + pc->mcomp_filter_type = BILINEAR; + + /* To enable choice of different interploation filters */ + if (pc->mcomp_filter_type == SIXTAP) + { + xd->subpixel_predict = vp8_sixtap_predict4x4; + xd->subpixel_predict8x4 = vp8_sixtap_predict8x4; + xd->subpixel_predict8x8 = vp8_sixtap_predict8x8; + xd->subpixel_predict16x16 = vp8_sixtap_predict16x16; + } + else + { + xd->subpixel_predict = vp8_bilinear_predict4x4; + xd->subpixel_predict8x4 = vp8_bilinear_predict8x4; + xd->subpixel_predict8x8 = vp8_bilinear_predict8x8; + xd->subpixel_predict16x16 = vp8_bilinear_predict16x16; + } + + if (pbi->decoded_key_frame && pbi->ec_enabled && !pbi->ec_active) + pbi->ec_active = 1; + } + + xd->left_context = &pc->left_context; + xd->mode_info_context = pc->mi; + xd->frame_type = pc->frame_type; + xd->mode_info_context->mbmi.mode = DC_PRED; + xd->mode_info_stride = pc->mode_info_stride; + xd->corrupted = 0; /* init without corruption */ + + xd->fullpixel_mask = 0xffffffff; + if(pc->full_pixel) + xd->fullpixel_mask = 0xfffffff8; + +} + +int vp8_decode_frame(VP8D_COMP *pbi) +{ + vp8_reader *const bc = & pbi->bc; + VP8_COMMON *const pc = & pbi->common; + MACROBLOCKD *const xd = & pbi->mb; + const unsigned char *data = pbi->fragments[0]; + const unsigned char *data_end = data + pbi->fragment_sizes[0]; + ptrdiff_t first_partition_length_in_bytes; + + int i, j, k, l; + const int *const mb_feature_data_bits = vp8_mb_feature_data_bits; + int corrupt_tokens = 0; + int prev_independent_partitions = pbi->independent_partitions; + + /* start with no corruption of current frame */ + xd->corrupted = 0; + pc->yv12_fb[pc->new_fb_idx].corrupted = 0; + + if (data_end - data < 3) + { + if (!pbi->ec_active) + { + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet"); + } + + /* Declare the missing frame as an inter frame since it will + be handled as an inter frame when we have estimated its + motion vectors. */ + pc->frame_type = INTER_FRAME; + pc->version = 0; + pc->show_frame = 1; + first_partition_length_in_bytes = 0; + } + else + { + pc->frame_type = (FRAME_TYPE)(data[0] & 1); + pc->version = (data[0] >> 1) & 7; + pc->show_frame = (data[0] >> 4) & 1; + first_partition_length_in_bytes = + (data[0] | (data[1] << 8) | (data[2] << 16)) >> 5; + + if (!pbi->ec_active && (data + first_partition_length_in_bytes > data_end + || data + first_partition_length_in_bytes < data)) + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet or corrupt partition 0 length"); + + data += 3; + + vp8_setup_version(pc); + + if (pc->frame_type == KEY_FRAME) + { + const int Width = pc->Width; + const int Height = pc->Height; + + /* vet via sync code */ + /* When error concealment is enabled we should only check the sync + * code if we have enough bits available + */ + if (!pbi->ec_active || data + 3 < data_end) + { + if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a) + vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM, + "Invalid frame sync code"); + } + + /* If error concealment is enabled we should only parse the new size + * if we have enough data. Otherwise we will end up with the wrong + * size. + */ + if (!pbi->ec_active || data + 6 < data_end) + { + pc->Width = (data[3] | (data[4] << 8)) & 0x3fff; + pc->horiz_scale = data[4] >> 6; + pc->Height = (data[5] | (data[6] << 8)) & 0x3fff; + pc->vert_scale = data[6] >> 6; + } + data += 7; + + if (Width != pc->Width || Height != pc->Height) + { + int prev_mb_rows = pc->mb_rows; + + if (pc->Width <= 0) + { + pc->Width = Width; + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Invalid frame width"); + } + + if (pc->Height <= 0) + { + pc->Height = Height; + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Invalid frame height"); + } + + if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate frame buffers"); + +#if CONFIG_ERROR_CONCEALMENT + pbi->overlaps = NULL; + if (pbi->ec_enabled) + { + if (vp8_alloc_overlap_lists(pbi)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate overlap lists " + "for error concealment"); + } +#endif + +#if CONFIG_MULTITHREAD + if (pbi->b_multithreaded_rd) + vp8mt_alloc_temp_buffers(pbi, pc->Width, prev_mb_rows); +#endif + } + } + } + + if ((!pbi->decoded_key_frame && pc->frame_type != KEY_FRAME) || + pc->Width == 0 || pc->Height == 0) + { + return -1; + } + + init_frame(pbi); + + if (vp8dx_start_decode(bc, data, data_end - data)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate bool decoder 0"); + if (pc->frame_type == KEY_FRAME) { + pc->clr_type = (YUV_TYPE)vp8_read_bit(bc); + pc->clamp_type = (CLAMP_TYPE)vp8_read_bit(bc); + } + + /* Is segmentation enabled */ + xd->segmentation_enabled = (unsigned char)vp8_read_bit(bc); + + if (xd->segmentation_enabled) + { + /* Signal whether or not the segmentation map is being explicitly updated this frame. */ + xd->update_mb_segmentation_map = (unsigned char)vp8_read_bit(bc); + xd->update_mb_segmentation_data = (unsigned char)vp8_read_bit(bc); + + if (xd->update_mb_segmentation_data) + { + xd->mb_segement_abs_delta = (unsigned char)vp8_read_bit(bc); + + vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); + + /* For each segmentation feature (Quant and loop filter level) */ + for (i = 0; i < MB_LVL_MAX; i++) + { + for (j = 0; j < MAX_MB_SEGMENTS; j++) + { + /* Frame level data */ + if (vp8_read_bit(bc)) + { + xd->segment_feature_data[i][j] = (signed char)vp8_read_literal(bc, mb_feature_data_bits[i]); + + if (vp8_read_bit(bc)) + xd->segment_feature_data[i][j] = -xd->segment_feature_data[i][j]; + } + else + xd->segment_feature_data[i][j] = 0; + } + } + } + + if (xd->update_mb_segmentation_map) + { + /* Which macro block level features are enabled */ + vpx_memset(xd->mb_segment_tree_probs, 255, sizeof(xd->mb_segment_tree_probs)); + + /* Read the probs used to decode the segment id for each macro block. */ + for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) + { + /* If not explicitly set value is defaulted to 255 by memset above */ + if (vp8_read_bit(bc)) + xd->mb_segment_tree_probs[i] = (vp8_prob)vp8_read_literal(bc, 8); + } + } + } + else + { + /* No segmentation updates on this frame */ + xd->update_mb_segmentation_map = 0; + xd->update_mb_segmentation_data = 0; + } + + /* Read the loop filter level and type */ + pc->filter_type = (LOOPFILTERTYPE) vp8_read_bit(bc); + pc->filter_level = vp8_read_literal(bc, 6); + pc->sharpness_level = vp8_read_literal(bc, 3); + + /* Read in loop filter deltas applied at the MB level based on mode or ref frame. */ + xd->mode_ref_lf_delta_update = 0; + xd->mode_ref_lf_delta_enabled = (unsigned char)vp8_read_bit(bc); + + if (xd->mode_ref_lf_delta_enabled) + { + /* Do the deltas need to be updated */ + xd->mode_ref_lf_delta_update = (unsigned char)vp8_read_bit(bc); + + if (xd->mode_ref_lf_delta_update) + { + /* Send update */ + for (i = 0; i < MAX_REF_LF_DELTAS; i++) + { + if (vp8_read_bit(bc)) + { + /*sign = vp8_read_bit( bc );*/ + xd->ref_lf_deltas[i] = (signed char)vp8_read_literal(bc, 6); + + if (vp8_read_bit(bc)) /* Apply sign */ + xd->ref_lf_deltas[i] = xd->ref_lf_deltas[i] * -1; + } + } + + /* Send update */ + for (i = 0; i < MAX_MODE_LF_DELTAS; i++) + { + if (vp8_read_bit(bc)) + { + /*sign = vp8_read_bit( bc );*/ + xd->mode_lf_deltas[i] = (signed char)vp8_read_literal(bc, 6); + + if (vp8_read_bit(bc)) /* Apply sign */ + xd->mode_lf_deltas[i] = xd->mode_lf_deltas[i] * -1; + } + } + } + } + + setup_token_decoder(pbi, data + first_partition_length_in_bytes); + + xd->current_bc = &pbi->bc2; + + /* Read the default quantizers. */ + { + int Q, q_update; + + Q = vp8_read_literal(bc, 7); /* AC 1st order Q = default */ + pc->base_qindex = Q; + q_update = 0; + pc->y1dc_delta_q = get_delta_q(bc, pc->y1dc_delta_q, &q_update); + pc->y2dc_delta_q = get_delta_q(bc, pc->y2dc_delta_q, &q_update); + pc->y2ac_delta_q = get_delta_q(bc, pc->y2ac_delta_q, &q_update); + pc->uvdc_delta_q = get_delta_q(bc, pc->uvdc_delta_q, &q_update); + pc->uvac_delta_q = get_delta_q(bc, pc->uvac_delta_q, &q_update); + + if (q_update) + vp8cx_init_de_quantizer(pbi); + + /* MB level dequantizer setup */ + vp8_mb_init_dequantizer(pbi, &pbi->mb); + } + + /* Determine if the golden frame or ARF buffer should be updated and how. + * For all non key frames the GF and ARF refresh flags and sign bias + * flags must be set explicitly. + */ + if (pc->frame_type != KEY_FRAME) + { + /* Should the GF or ARF be updated from the current frame */ + pc->refresh_golden_frame = vp8_read_bit(bc); +#if CONFIG_ERROR_CONCEALMENT + /* Assume we shouldn't refresh golden if the bit is missing */ + xd->corrupted |= vp8dx_bool_error(bc); + if (pbi->ec_active && xd->corrupted) + pc->refresh_golden_frame = 0; +#endif + + pc->refresh_alt_ref_frame = vp8_read_bit(bc); +#if CONFIG_ERROR_CONCEALMENT + /* Assume we shouldn't refresh altref if the bit is missing */ + xd->corrupted |= vp8dx_bool_error(bc); + if (pbi->ec_active && xd->corrupted) + pc->refresh_alt_ref_frame = 0; +#endif + + /* Buffer to buffer copy flags. */ + pc->copy_buffer_to_gf = 0; + + if (!pc->refresh_golden_frame) + pc->copy_buffer_to_gf = vp8_read_literal(bc, 2); + +#if CONFIG_ERROR_CONCEALMENT + /* Assume we shouldn't copy to the golden if the bit is missing */ + xd->corrupted |= vp8dx_bool_error(bc); + if (pbi->ec_active && xd->corrupted) + pc->copy_buffer_to_gf = 0; +#endif + + pc->copy_buffer_to_arf = 0; + + if (!pc->refresh_alt_ref_frame) + pc->copy_buffer_to_arf = vp8_read_literal(bc, 2); + +#if CONFIG_ERROR_CONCEALMENT + /* Assume we shouldn't copy to the alt-ref if the bit is missing */ + xd->corrupted |= vp8dx_bool_error(bc); + if (pbi->ec_active && xd->corrupted) + pc->copy_buffer_to_arf = 0; +#endif + + + pc->ref_frame_sign_bias[GOLDEN_FRAME] = vp8_read_bit(bc); + pc->ref_frame_sign_bias[ALTREF_FRAME] = vp8_read_bit(bc); + } + + pc->refresh_entropy_probs = vp8_read_bit(bc); +#if CONFIG_ERROR_CONCEALMENT + /* Assume we shouldn't refresh the probabilities if the bit is + * missing */ + xd->corrupted |= vp8dx_bool_error(bc); + if (pbi->ec_active && xd->corrupted) + pc->refresh_entropy_probs = 0; +#endif + if (pc->refresh_entropy_probs == 0) + { + vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc)); + } + + pc->refresh_last_frame = pc->frame_type == KEY_FRAME || vp8_read_bit(bc); + +#if CONFIG_ERROR_CONCEALMENT + /* Assume we should refresh the last frame if the bit is missing */ + xd->corrupted |= vp8dx_bool_error(bc); + if (pbi->ec_active && xd->corrupted) + pc->refresh_last_frame = 1; +#endif + + if (0) + { + FILE *z = fopen("decodestats.stt", "a"); + fprintf(z, "%6d F:%d,G:%d,A:%d,L:%d,Q:%d\n", + pc->current_video_frame, + pc->frame_type, + pc->refresh_golden_frame, + pc->refresh_alt_ref_frame, + pc->refresh_last_frame, + pc->base_qindex); + fclose(z); + } + + { + pbi->independent_partitions = 1; + + /* read coef probability tree */ + for (i = 0; i < BLOCK_TYPES; i++) + for (j = 0; j < COEF_BANDS; j++) + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + for (l = 0; l < ENTROPY_NODES; l++) + { + + vp8_prob *const p = pc->fc.coef_probs [i][j][k] + l; + + if (vp8_read(bc, vp8_coef_update_probs [i][j][k][l])) + { + *p = (vp8_prob)vp8_read_literal(bc, 8); + + } + if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l]) + pbi->independent_partitions = 0; + + } + } + + vpx_memcpy(&xd->pre, &pc->yv12_fb[pc->lst_fb_idx], sizeof(YV12_BUFFER_CONFIG)); + vpx_memcpy(&xd->dst, &pc->yv12_fb[pc->new_fb_idx], sizeof(YV12_BUFFER_CONFIG)); + + /* set up frame new frame for intra coded blocks */ +#if CONFIG_MULTITHREAD + if (!(pbi->b_multithreaded_rd) || pc->multi_token_partition == ONE_PARTITION || !(pc->filter_level)) +#endif + vp8_setup_intra_recon(&pc->yv12_fb[pc->new_fb_idx]); + + vp8_setup_block_dptrs(xd); + + vp8_build_block_doffsets(xd); + + /* clear out the coeff buffer */ + vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); + + /* Read the mb_no_coeff_skip flag */ + pc->mb_no_coeff_skip = (int)vp8_read_bit(bc); + + + vp8_decode_mode_mvs(pbi); + +#if CONFIG_ERROR_CONCEALMENT + if (pbi->ec_active && + pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows) + { + /* Motion vectors are missing in this frame. We will try to estimate + * them and then continue decoding the frame as usual */ + vp8_estimate_missing_mvs(pbi); + } +#endif + + vpx_memset(pc->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES) * pc->mb_cols); + pbi->frame_corrupt_residual = 0; + +#if CONFIG_MULTITHREAD + if (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION) + { + int i; + vp8mt_decode_mb_rows(pbi, xd); + vp8_yv12_extend_frame_borders(&pc->yv12_fb[pc->new_fb_idx]); /*cm->frame_to_show);*/ + for (i = 0; i < pbi->decoding_thread_count; ++i) + corrupt_tokens |= pbi->mb_row_di[i].mbd.corrupted; + } + else +#endif + { + decode_mb_rows(pbi); + corrupt_tokens |= xd->corrupted; + } + + stop_token_decoder(pbi); + + /* Collect information about decoder corruption. */ + /* 1. Check first boolean decoder for errors. */ + pc->yv12_fb[pc->new_fb_idx].corrupted = vp8dx_bool_error(bc); + /* 2. Check the macroblock information */ + pc->yv12_fb[pc->new_fb_idx].corrupted |= corrupt_tokens; + + if (!pbi->decoded_key_frame) + { + if (pc->frame_type == KEY_FRAME && + !pc->yv12_fb[pc->new_fb_idx].corrupted) + pbi->decoded_key_frame = 1; + else + vpx_internal_error(&pbi->common.error, VPX_CODEC_CORRUPT_FRAME, + "A stream must start with a complete key frame"); + } + + /* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes \n",bc->pos+pbi->bc2.pos); */ + + /* If this was a kf or Gf note the Q used */ + if ((pc->frame_type == KEY_FRAME) || + pc->refresh_golden_frame || pc->refresh_alt_ref_frame) + { + pc->last_kf_gf_q = pc->base_qindex; + } + + if (pc->refresh_entropy_probs == 0) + { + vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc)); + pbi->independent_partitions = prev_independent_partitions; + } + +#ifdef PACKET_TESTING + { + FILE *f = fopen("decompressor.VP8", "ab"); + unsigned int size = pbi->bc2.pos + pbi->bc.pos + 8; + fwrite((void *) &size, 4, 1, f); + fwrite((void *) pbi->Source, size, 1, f); + fclose(f); + } +#endif + + return 0; +} diff --git a/vp8/decoder/detokenize.c b/vp8/decoder/detokenize.c new file mode 100644 index 0000000..0c39848 --- /dev/null +++ b/vp8/decoder/detokenize.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/blockd.h" +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_ports/mem.h" +#include "detokenize.h" + +void vp8_reset_mb_tokens_context(MACROBLOCKD *x) +{ + ENTROPY_CONTEXT *a_ctx = ((ENTROPY_CONTEXT *)x->above_context); + ENTROPY_CONTEXT *l_ctx = ((ENTROPY_CONTEXT *)x->left_context); + + vpx_memset(a_ctx, 0, sizeof(ENTROPY_CONTEXT_PLANES)-1); + vpx_memset(l_ctx, 0, sizeof(ENTROPY_CONTEXT_PLANES)-1); + + /* Clear entropy contexts for Y2 blocks */ + if (!x->mode_info_context->mbmi.is_4x4) + { + a_ctx[8] = l_ctx[8] = 0; + } +} + +/* + ------------------------------------------------------------------------------ + Residual decoding (Paragraph 13.2 / 13.3) +*/ +static const uint8_t kBands[16 + 1] = { + 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 0 /* extra entry as sentinel */ +}; + +static const uint8_t kCat3[] = { 173, 148, 140, 0 }; +static const uint8_t kCat4[] = { 176, 155, 140, 135, 0 }; +static const uint8_t kCat5[] = { 180, 157, 141, 134, 130, 0 }; +static const uint8_t kCat6[] = + { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0 }; +static const uint8_t* const kCat3456[] = { kCat3, kCat4, kCat5, kCat6 }; +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +#define VP8GetBit vp8dx_decode_bool +#define NUM_PROBAS 11 +#define NUM_CTX 3 + +typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting + +static int GetSigned(BOOL_DECODER *br, int value_to_sign) +{ + int split = (br->range + 1) >> 1; + VP8_BD_VALUE bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); + int v; + + if(br->count < 0) + vp8dx_bool_decoder_fill(br); + + if ( br->value < bigsplit ) + { + br->range = split; + v= value_to_sign; + } + else + { + br->range = br->range-split; + br->value = br->value-bigsplit; + v = -value_to_sign; + } + br->range +=br->range; + br->value +=br->value; + br->count--; + + return v; +} +/* + Returns the position of the last non-zero coeff plus one + (and 0 if there's no coeff at all) +*/ +static int GetCoeffs(BOOL_DECODER *br, ProbaArray prob, + int ctx, int n, int16_t* out) +{ + const uint8_t* p = prob[n][ctx]; + if (!VP8GetBit(br, p[0])) + { /* first EOB is more a 'CBP' bit. */ + return 0; + } + while (1) + { + ++n; + if (!VP8GetBit(br, p[1])) + { + p = prob[kBands[n]][0]; + } + else + { /* non zero coeff */ + int v, j; + if (!VP8GetBit(br, p[2])) + { + p = prob[kBands[n]][1]; + v = 1; + } + else + { + if (!VP8GetBit(br, p[3])) + { + if (!VP8GetBit(br, p[4])) + { + v = 2; + } + else + { + v = 3 + VP8GetBit(br, p[5]); + } + } + else + { + if (!VP8GetBit(br, p[6])) + { + if (!VP8GetBit(br, p[7])) + { + v = 5 + VP8GetBit(br, 159); + } else + { + v = 7 + 2 * VP8GetBit(br, 165); + v += VP8GetBit(br, 145); + } + } + else + { + const uint8_t* tab; + const int bit1 = VP8GetBit(br, p[8]); + const int bit0 = VP8GetBit(br, p[9 + bit1]); + const int cat = 2 * bit1 + bit0; + v = 0; + for (tab = kCat3456[cat]; *tab; ++tab) + { + v += v + VP8GetBit(br, *tab); + } + v += 3 + (8 << cat); + } + } + p = prob[kBands[n]][2]; + } + j = kZigzag[n - 1]; + + out[j] = GetSigned(br, v); + + if (n == 16 || !VP8GetBit(br, p[0])) + { /* EOB */ + return n; + } + } + if (n == 16) + { + return 16; + } + } +} + +int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) +{ + BOOL_DECODER *bc = x->current_bc; + const FRAME_CONTEXT * const fc = &dx->common.fc; + char *eobs = x->eobs; + + int i; + int nonzeros; + int eobtotal = 0; + + short *qcoeff_ptr; + ProbaArray coef_probs; + ENTROPY_CONTEXT *a_ctx = ((ENTROPY_CONTEXT *)x->above_context); + ENTROPY_CONTEXT *l_ctx = ((ENTROPY_CONTEXT *)x->left_context); + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int skip_dc = 0; + + qcoeff_ptr = &x->qcoeff[0]; + + if (!x->mode_info_context->mbmi.is_4x4) + { + a = a_ctx + 8; + l = l_ctx + 8; + + coef_probs = fc->coef_probs [1]; + + nonzeros = GetCoeffs(bc, coef_probs, (*a + *l), 0, qcoeff_ptr + 24 * 16); + *a = *l = (nonzeros > 0); + + eobs[24] = nonzeros; + eobtotal += nonzeros - 16; + + coef_probs = fc->coef_probs [0]; + skip_dc = 1; + } + else + { + coef_probs = fc->coef_probs [3]; + skip_dc = 0; + } + + for (i = 0; i < 16; ++i) + { + a = a_ctx + (i&3); + l = l_ctx + ((i&0xc)>>2); + + nonzeros = GetCoeffs(bc, coef_probs, (*a + *l), skip_dc, qcoeff_ptr); + *a = *l = (nonzeros > 0); + + nonzeros += skip_dc; + eobs[i] = nonzeros; + eobtotal += nonzeros; + qcoeff_ptr += 16; + } + + coef_probs = fc->coef_probs [2]; + + a_ctx += 4; + l_ctx += 4; + for (i = 16; i < 24; ++i) + { + a = a_ctx + ((i > 19)<<1) + (i&1); + l = l_ctx + ((i > 19)<<1) + ((i&3)>1); + + nonzeros = GetCoeffs(bc, coef_probs, (*a + *l), 0, qcoeff_ptr); + *a = *l = (nonzeros > 0); + + eobs[i] = nonzeros; + eobtotal += nonzeros; + qcoeff_ptr += 16; + } + + return eobtotal; +} + diff --git a/vp8/decoder/detokenize.h b/vp8/decoder/detokenize.h new file mode 100644 index 0000000..8640bda --- /dev/null +++ b/vp8/decoder/detokenize.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef DETOKENIZE_H +#define DETOKENIZE_H + +#include "onyxd_int.h" + +void vp8_reset_mb_tokens_context(MACROBLOCKD *x); +int vp8_decode_mb_tokens(VP8D_COMP *, MACROBLOCKD *); + +#endif /* DETOKENIZE_H */ diff --git a/vp8/decoder/ec_types.h b/vp8/decoder/ec_types.h new file mode 100644 index 0000000..ccb5ddb --- /dev/null +++ b/vp8/decoder/ec_types.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VP8_DEC_EC_TYPES_H +#define VP8_DEC_EC_TYPES_H + +#define MAX_OVERLAPS 16 + + + +/* The area (pixel area in Q6) the block pointed to by bmi overlaps + * another block with. + */ +typedef struct +{ + int overlap; + union b_mode_info *bmi; +} OVERLAP_NODE; + +/* Structure to keep track of overlapping blocks on a block level. */ +typedef struct +{ + /* TODO(holmer): This array should be exchanged for a linked list */ + OVERLAP_NODE overlaps[MAX_OVERLAPS]; +} B_OVERLAP; + +/* Structure used to hold all the overlaps of a macroblock. The overlaps of a + * macroblock is further divided into block overlaps. + */ +typedef struct +{ + B_OVERLAP overlaps[16]; +} MB_OVERLAP; + +/* Structure for keeping track of motion vectors and which reference frame they + * refer to. Used for motion vector interpolation. + */ +typedef struct +{ + MV mv; + MV_REFERENCE_FRAME ref_frame; +} EC_BLOCK; + +#endif /* VP8_DEC_EC_TYPES_H */ diff --git a/vp8/decoder/error_concealment.c b/vp8/decoder/error_concealment.c new file mode 100644 index 0000000..7750728 --- /dev/null +++ b/vp8/decoder/error_concealment.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "error_concealment.h" +#include "onyxd_int.h" +#include "decodemv.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/findnearmv.h" + +#include + +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define MAX(x,y) (((x)>(y))?(x):(y)) + +#define FLOOR(x,q) ((x) & -(1 << (q))) + +#define NUM_NEIGHBORS 20 + +typedef struct ec_position +{ + int row; + int col; +} EC_POS; + +/* + * Regenerate the table in Matlab with: + * x = meshgrid((1:4), (1:4)); + * y = meshgrid((1:4), (1:4))'; + * W = round((1./(sqrt(x.^2 + y.^2))*2^7)); + * W(1,1) = 0; + */ +static const int weights_q7[5][5] = { + { 0, 128, 64, 43, 32 }, + {128, 91, 57, 40, 31 }, + { 64, 57, 45, 36, 29 }, + { 43, 40, 36, 30, 26 }, + { 32, 31, 29, 26, 23 } +}; + +int vp8_alloc_overlap_lists(VP8D_COMP *pbi) +{ + if (pbi->overlaps != NULL) + { + vpx_free(pbi->overlaps); + pbi->overlaps = NULL; + } + pbi->overlaps = vpx_calloc(pbi->common.mb_rows * pbi->common.mb_cols, + sizeof(MB_OVERLAP)); + if (pbi->overlaps == NULL) + return -1; + vpx_memset(pbi->overlaps, 0, + sizeof(MB_OVERLAP) * pbi->common.mb_rows * pbi->common.mb_cols); + return 0; +} + +void vp8_de_alloc_overlap_lists(VP8D_COMP *pbi) +{ + vpx_free(pbi->overlaps); + pbi->overlaps = NULL; +} + +/* Inserts a new overlap area value to the list of overlaps of a block */ +static void assign_overlap(OVERLAP_NODE* overlaps, + union b_mode_info *bmi, + int overlap) +{ + int i; + if (overlap <= 0) + return; + /* Find and assign to the next empty overlap node in the list of overlaps. + * Empty is defined as bmi == NULL */ + for (i = 0; i < MAX_OVERLAPS; i++) + { + if (overlaps[i].bmi == NULL) + { + overlaps[i].bmi = bmi; + overlaps[i].overlap = overlap; + break; + } + } +} + +/* Calculates the overlap area between two 4x4 squares, where the first + * square has its upper-left corner at (b1_row, b1_col) and the second + * square has its upper-left corner at (b2_row, b2_col). Doesn't + * properly handle squares which do not overlap. + */ +static int block_overlap(int b1_row, int b1_col, int b2_row, int b2_col) +{ + const int int_top = MAX(b1_row, b2_row); // top + const int int_left = MAX(b1_col, b2_col); // left + /* Since each block is 4x4 pixels, adding 4 (Q3) to the left/top edge + * gives us the right/bottom edge. + */ + const int int_right = MIN(b1_col + (4<<3), b2_col + (4<<3)); // right + const int int_bottom = MIN(b1_row + (4<<3), b2_row + (4<<3)); // bottom + return (int_bottom - int_top) * (int_right - int_left); +} + +/* Calculates the overlap area for all blocks in a macroblock at position + * (mb_row, mb_col) in macroblocks, which are being overlapped by a given + * overlapping block at position (new_row, new_col) (in pixels, Q3). The + * first block being overlapped in the macroblock has position (first_blk_row, + * first_blk_col) in blocks relative the upper-left corner of the image. + */ +static void calculate_overlaps_mb(B_OVERLAP *b_overlaps, union b_mode_info *bmi, + int new_row, int new_col, + int mb_row, int mb_col, + int first_blk_row, int first_blk_col) +{ + /* Find the blocks within this MB (defined by mb_row, mb_col) which are + * overlapped by bmi and calculate and assign overlap for each of those + * blocks. */ + + /* Block coordinates relative the upper-left block */ + const int rel_ol_blk_row = first_blk_row - mb_row * 4; + const int rel_ol_blk_col = first_blk_col - mb_col * 4; + /* If the block partly overlaps any previous MB, these coordinates + * can be < 0. We don't want to access blocks in previous MBs. + */ + const int blk_idx = MAX(rel_ol_blk_row,0) * 4 + MAX(rel_ol_blk_col,0); + /* Upper left overlapping block */ + B_OVERLAP *b_ol_ul = &(b_overlaps[blk_idx]); + + /* Calculate and assign overlaps for all blocks in this MB + * which the motion compensated block overlaps + */ + /* Avoid calculating overlaps for blocks in later MBs */ + int end_row = MIN(4 + mb_row * 4 - first_blk_row, 2); + int end_col = MIN(4 + mb_col * 4 - first_blk_col, 2); + int row, col; + + /* Check if new_row and new_col are evenly divisible by 4 (Q3), + * and if so we shouldn't check neighboring blocks + */ + if (new_row >= 0 && (new_row & 0x1F) == 0) + end_row = 1; + if (new_col >= 0 && (new_col & 0x1F) == 0) + end_col = 1; + + /* Check if the overlapping block partly overlaps a previous MB + * and if so, we're overlapping fewer blocks in this MB. + */ + if (new_row < (mb_row*16)<<3) + end_row = 1; + if (new_col < (mb_col*16)<<3) + end_col = 1; + + for (row = 0; row < end_row; ++row) + { + for (col = 0; col < end_col; ++col) + { + /* input in Q3, result in Q6 */ + const int overlap = block_overlap(new_row, new_col, + (((first_blk_row + row) * + 4) << 3), + (((first_blk_col + col) * + 4) << 3)); + assign_overlap(b_ol_ul[row * 4 + col].overlaps, bmi, overlap); + } + } +} + +void vp8_calculate_overlaps(MB_OVERLAP *overlap_ul, + int mb_rows, int mb_cols, + union b_mode_info *bmi, + int b_row, int b_col) +{ + MB_OVERLAP *mb_overlap; + int row, col, rel_row, rel_col; + int new_row, new_col; + int end_row, end_col; + int overlap_b_row, overlap_b_col; + int overlap_mb_row, overlap_mb_col; + + /* mb subpixel position */ + row = (4 * b_row) << 3; /* Q3 */ + col = (4 * b_col) << 3; /* Q3 */ + + /* reverse compensate for motion */ + new_row = row - bmi->mv.as_mv.row; + new_col = col - bmi->mv.as_mv.col; + + if (new_row >= ((16*mb_rows) << 3) || new_col >= ((16*mb_cols) << 3)) + { + /* the new block ended up outside the frame */ + return; + } + + if (new_row <= (-4 << 3) || new_col <= (-4 << 3)) + { + /* outside the frame */ + return; + } + /* overlapping block's position in blocks */ + overlap_b_row = FLOOR(new_row / 4, 3) >> 3; + overlap_b_col = FLOOR(new_col / 4, 3) >> 3; + + /* overlapping block's MB position in MBs + * operations are done in Q3 + */ + overlap_mb_row = FLOOR((overlap_b_row << 3) / 4, 3) >> 3; + overlap_mb_col = FLOOR((overlap_b_col << 3) / 4, 3) >> 3; + + end_row = MIN(mb_rows - overlap_mb_row, 2); + end_col = MIN(mb_cols - overlap_mb_col, 2); + + /* Don't calculate overlap for MBs we don't overlap */ + /* Check if the new block row starts at the last block row of the MB */ + if (abs(new_row - ((16*overlap_mb_row) << 3)) < ((3*4) << 3)) + end_row = 1; + /* Check if the new block col starts at the last block col of the MB */ + if (abs(new_col - ((16*overlap_mb_col) << 3)) < ((3*4) << 3)) + end_col = 1; + + /* find the MB(s) this block is overlapping */ + for (rel_row = 0; rel_row < end_row; ++rel_row) + { + for (rel_col = 0; rel_col < end_col; ++rel_col) + { + if (overlap_mb_row + rel_row < 0 || + overlap_mb_col + rel_col < 0) + continue; + mb_overlap = overlap_ul + (overlap_mb_row + rel_row) * mb_cols + + overlap_mb_col + rel_col; + + calculate_overlaps_mb(mb_overlap->overlaps, bmi, + new_row, new_col, + overlap_mb_row + rel_row, + overlap_mb_col + rel_col, + overlap_b_row + rel_row, + overlap_b_col + rel_col); + } + } +} + +/* Estimates a motion vector given the overlapping blocks' motion vectors. + * Filters out all overlapping blocks which do not refer to the correct + * reference frame type. + */ +static void estimate_mv(const OVERLAP_NODE *overlaps, union b_mode_info *bmi) +{ + int i; + int overlap_sum = 0; + int row_acc = 0; + int col_acc = 0; + + bmi->mv.as_int = 0; + for (i=0; i < MAX_OVERLAPS; ++i) + { + if (overlaps[i].bmi == NULL) + break; + col_acc += overlaps[i].overlap * overlaps[i].bmi->mv.as_mv.col; + row_acc += overlaps[i].overlap * overlaps[i].bmi->mv.as_mv.row; + overlap_sum += overlaps[i].overlap; + } + if (overlap_sum > 0) + { + /* Q9 / Q6 = Q3 */ + bmi->mv.as_mv.col = col_acc / overlap_sum; + bmi->mv.as_mv.row = row_acc / overlap_sum; + } + else + { + bmi->mv.as_mv.col = 0; + bmi->mv.as_mv.row = 0; + } +} + +/* Estimates all motion vectors for a macroblock given the lists of + * overlaps for each block. Decides whether or not the MVs must be clamped. + */ +static void estimate_mb_mvs(const B_OVERLAP *block_overlaps, + MODE_INFO *mi, + int mb_to_left_edge, + int mb_to_right_edge, + int mb_to_top_edge, + int mb_to_bottom_edge) +{ + int row, col; + int non_zero_count = 0; + MV * const filtered_mv = &(mi->mbmi.mv.as_mv); + union b_mode_info * const bmi = mi->bmi; + filtered_mv->col = 0; + filtered_mv->row = 0; + mi->mbmi.need_to_clamp_mvs = 0; + for (row = 0; row < 4; ++row) + { + int this_b_to_top_edge = mb_to_top_edge + ((row*4)<<3); + int this_b_to_bottom_edge = mb_to_bottom_edge - ((row*4)<<3); + for (col = 0; col < 4; ++col) + { + int i = row * 4 + col; + int this_b_to_left_edge = mb_to_left_edge + ((col*4)<<3); + int this_b_to_right_edge = mb_to_right_edge - ((col*4)<<3); + /* Estimate vectors for all blocks which are overlapped by this */ + /* type. Interpolate/extrapolate the rest of the block's MVs */ + estimate_mv(block_overlaps[i].overlaps, &(bmi[i])); + mi->mbmi.need_to_clamp_mvs |= vp8_check_mv_bounds( + &bmi[i].mv, + this_b_to_left_edge, + this_b_to_right_edge, + this_b_to_top_edge, + this_b_to_bottom_edge); + if (bmi[i].mv.as_int != 0) + { + ++non_zero_count; + filtered_mv->col += bmi[i].mv.as_mv.col; + filtered_mv->row += bmi[i].mv.as_mv.row; + } + } + } + if (non_zero_count > 0) + { + filtered_mv->col /= non_zero_count; + filtered_mv->row /= non_zero_count; + } +} + +static void calc_prev_mb_overlaps(MB_OVERLAP *overlaps, MODE_INFO *prev_mi, + int mb_row, int mb_col, + int mb_rows, int mb_cols) +{ + int sub_row; + int sub_col; + for (sub_row = 0; sub_row < 4; ++sub_row) + { + for (sub_col = 0; sub_col < 4; ++sub_col) + { + vp8_calculate_overlaps( + overlaps, mb_rows, mb_cols, + &(prev_mi->bmi[sub_row * 4 + sub_col]), + 4 * mb_row + sub_row, + 4 * mb_col + sub_col); + } + } +} + +/* Estimate all missing motion vectors. This function does the same as the one + * above, but has different input arguments. */ +static void estimate_missing_mvs(MB_OVERLAP *overlaps, + MODE_INFO *mi, MODE_INFO *prev_mi, + int mb_rows, int mb_cols, + unsigned int first_corrupt) +{ + int mb_row, mb_col; + vpx_memset(overlaps, 0, sizeof(MB_OVERLAP) * mb_rows * mb_cols); + /* First calculate the overlaps for all blocks */ + for (mb_row = 0; mb_row < mb_rows; ++mb_row) + { + for (mb_col = 0; mb_col < mb_cols; ++mb_col) + { + /* We're only able to use blocks referring to the last frame + * when extrapolating new vectors. + */ + if (prev_mi->mbmi.ref_frame == LAST_FRAME) + { + calc_prev_mb_overlaps(overlaps, prev_mi, + mb_row, mb_col, + mb_rows, mb_cols); + } + ++prev_mi; + } + ++prev_mi; + } + + mb_row = first_corrupt / mb_cols; + mb_col = first_corrupt - mb_row * mb_cols; + mi += mb_row*(mb_cols + 1) + mb_col; + /* Go through all macroblocks in the current image with missing MVs + * and calculate new MVs using the overlaps. + */ + for (; mb_row < mb_rows; ++mb_row) + { + int mb_to_top_edge = -((mb_row * 16)) << 3; + int mb_to_bottom_edge = ((mb_rows - 1 - mb_row) * 16) << 3; + for (; mb_col < mb_cols; ++mb_col) + { + int mb_to_left_edge = -((mb_col * 16) << 3); + int mb_to_right_edge = ((mb_cols - 1 - mb_col) * 16) << 3; + const B_OVERLAP *block_overlaps = + overlaps[mb_row*mb_cols + mb_col].overlaps; + mi->mbmi.ref_frame = LAST_FRAME; + mi->mbmi.mode = SPLITMV; + mi->mbmi.uv_mode = DC_PRED; + mi->mbmi.partitioning = 3; + mi->mbmi.segment_id = 0; + estimate_mb_mvs(block_overlaps, + mi, + mb_to_left_edge, + mb_to_right_edge, + mb_to_top_edge, + mb_to_bottom_edge); + ++mi; + } + mb_col = 0; + ++mi; + } +} + +void vp8_estimate_missing_mvs(VP8D_COMP *pbi) +{ + VP8_COMMON * const pc = &pbi->common; + estimate_missing_mvs(pbi->overlaps, + pc->mi, pc->prev_mi, + pc->mb_rows, pc->mb_cols, + pbi->mvs_corrupt_from_mb); +} + +static void assign_neighbor(EC_BLOCK *neighbor, MODE_INFO *mi, int block_idx) +{ + assert(mi->mbmi.ref_frame < MAX_REF_FRAMES); + neighbor->ref_frame = mi->mbmi.ref_frame; + neighbor->mv = mi->bmi[block_idx].mv.as_mv; +} + +/* Finds the neighboring blocks of a macroblocks. In the general case + * 20 blocks are found. If a fewer number of blocks are found due to + * image boundaries, those positions in the EC_BLOCK array are left "empty". + * The neighbors are enumerated with the upper-left neighbor as the first + * element, the second element refers to the neighbor to right of the previous + * neighbor, and so on. The last element refers to the neighbor below the first + * neighbor. + */ +static void find_neighboring_blocks(MODE_INFO *mi, + EC_BLOCK *neighbors, + int mb_row, int mb_col, + int mb_rows, int mb_cols, + int mi_stride) +{ + int i = 0; + int j; + if (mb_row > 0) + { + /* upper left */ + if (mb_col > 0) + assign_neighbor(&neighbors[i], mi - mi_stride - 1, 15); + ++i; + /* above */ + for (j = 12; j < 16; ++j, ++i) + assign_neighbor(&neighbors[i], mi - mi_stride, j); + } + else + i += 5; + if (mb_col < mb_cols - 1) + { + /* upper right */ + if (mb_row > 0) + assign_neighbor(&neighbors[i], mi - mi_stride + 1, 12); + ++i; + /* right */ + for (j = 0; j <= 12; j += 4, ++i) + assign_neighbor(&neighbors[i], mi + 1, j); + } + else + i += 5; + if (mb_row < mb_rows - 1) + { + /* lower right */ + if (mb_col < mb_cols - 1) + assign_neighbor(&neighbors[i], mi + mi_stride + 1, 0); + ++i; + /* below */ + for (j = 0; j < 4; ++j, ++i) + assign_neighbor(&neighbors[i], mi + mi_stride, j); + } + else + i += 5; + if (mb_col > 0) + { + /* lower left */ + if (mb_row < mb_rows - 1) + assign_neighbor(&neighbors[i], mi + mi_stride - 1, 4); + ++i; + /* left */ + for (j = 3; j < 16; j += 4, ++i) + { + assign_neighbor(&neighbors[i], mi - 1, j); + } + } + else + i += 5; + assert(i == 20); +} + +/* Interpolates all motion vectors for a macroblock from the neighboring blocks' + * motion vectors. + */ +static void interpolate_mvs(MACROBLOCKD *mb, + EC_BLOCK *neighbors, + MV_REFERENCE_FRAME dom_ref_frame) +{ + int row, col, i; + MODE_INFO * const mi = mb->mode_info_context; + /* Table with the position of the neighboring blocks relative the position + * of the upper left block of the current MB. Starting with the upper left + * neighbor and going to the right. + */ + const EC_POS neigh_pos[NUM_NEIGHBORS] = { + {-1,-1}, {-1,0}, {-1,1}, {-1,2}, {-1,3}, + {-1,4}, {0,4}, {1,4}, {2,4}, {3,4}, + {4,4}, {4,3}, {4,2}, {4,1}, {4,0}, + {4,-1}, {3,-1}, {2,-1}, {1,-1}, {0,-1} + }; + mi->mbmi.need_to_clamp_mvs = 0; + for (row = 0; row < 4; ++row) + { + int mb_to_top_edge = mb->mb_to_top_edge + ((row*4)<<3); + int mb_to_bottom_edge = mb->mb_to_bottom_edge - ((row*4)<<3); + for (col = 0; col < 4; ++col) + { + int mb_to_left_edge = mb->mb_to_left_edge + ((col*4)<<3); + int mb_to_right_edge = mb->mb_to_right_edge - ((col*4)<<3); + int w_sum = 0; + int mv_row_sum = 0; + int mv_col_sum = 0; + int_mv * const mv = &(mi->bmi[row*4 + col].mv); + mv->as_int = 0; + for (i = 0; i < NUM_NEIGHBORS; ++i) + { + /* Calculate the weighted sum of neighboring MVs referring + * to the dominant frame type. + */ + const int w = weights_q7[abs(row - neigh_pos[i].row)] + [abs(col - neigh_pos[i].col)]; + if (neighbors[i].ref_frame != dom_ref_frame) + continue; + w_sum += w; + /* Q7 * Q3 = Q10 */ + mv_row_sum += w*neighbors[i].mv.row; + mv_col_sum += w*neighbors[i].mv.col; + } + if (w_sum > 0) + { + /* Avoid division by zero. + * Normalize with the sum of the coefficients + * Q3 = Q10 / Q7 + */ + mv->as_mv.row = mv_row_sum / w_sum; + mv->as_mv.col = mv_col_sum / w_sum; + mi->mbmi.need_to_clamp_mvs |= vp8_check_mv_bounds( + mv, + mb_to_left_edge, + mb_to_right_edge, + mb_to_top_edge, + mb_to_bottom_edge); + } + } + } +} + +void vp8_interpolate_motion(MACROBLOCKD *mb, + int mb_row, int mb_col, + int mb_rows, int mb_cols, + int mi_stride) +{ + /* Find relevant neighboring blocks */ + EC_BLOCK neighbors[NUM_NEIGHBORS]; + int i; + /* Initialize the array. MAX_REF_FRAMES is interpreted as "doesn't exist" */ + for (i = 0; i < NUM_NEIGHBORS; ++i) + { + neighbors[i].ref_frame = MAX_REF_FRAMES; + neighbors[i].mv.row = neighbors[i].mv.col = 0; + } + find_neighboring_blocks(mb->mode_info_context, + neighbors, + mb_row, mb_col, + mb_rows, mb_cols, + mb->mode_info_stride); + /* Interpolate MVs for the missing blocks from the surrounding + * blocks which refer to the last frame. */ + interpolate_mvs(mb, neighbors, LAST_FRAME); + + mb->mode_info_context->mbmi.ref_frame = LAST_FRAME; + mb->mode_info_context->mbmi.mode = SPLITMV; + mb->mode_info_context->mbmi.uv_mode = DC_PRED; + mb->mode_info_context->mbmi.partitioning = 3; + mb->mode_info_context->mbmi.segment_id = 0; +} + +void vp8_conceal_corrupt_mb(MACROBLOCKD *xd) +{ + /* This macroblock has corrupt residual, use the motion compensated + image (predictor) for concealment */ + + /* The build predictor functions now output directly into the dst buffer, + * so the copies are no longer necessary */ + +} diff --git a/vp8/decoder/error_concealment.h b/vp8/decoder/error_concealment.h new file mode 100644 index 0000000..65ae9d9 --- /dev/null +++ b/vp8/decoder/error_concealment.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef ERROR_CONCEALMENT_H +#define ERROR_CONCEALMENT_H + +#include "onyxd_int.h" +#include "ec_types.h" + +/* Allocate memory for the overlap lists */ +int vp8_alloc_overlap_lists(VP8D_COMP *pbi); + +/* Deallocate the overlap lists */ +void vp8_de_alloc_overlap_lists(VP8D_COMP *pbi); + +/* Estimate all missing motion vectors. */ +void vp8_estimate_missing_mvs(VP8D_COMP *pbi); + +/* Functions for spatial MV interpolation */ + +/* Interpolates all motion vectors for a macroblock mb at position + * (mb_row, mb_col). */ +void vp8_interpolate_motion(MACROBLOCKD *mb, + int mb_row, int mb_col, + int mb_rows, int mb_cols, + int mi_stride); + +/* Conceal a macroblock with corrupt residual. + * Copies the prediction signal to the reconstructed image. + */ +void vp8_conceal_corrupt_mb(MACROBLOCKD *xd); + +#endif diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c new file mode 100644 index 0000000..c59ce25 --- /dev/null +++ b/vp8/decoder/onyxd_if.c @@ -0,0 +1,614 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/onyxc_int.h" +#if CONFIG_POSTPROC +#include "vp8/common/postproc.h" +#endif +#include "vp8/common/onyxd.h" +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/alloccommon.h" +#include "vp8/common/loopfilter.h" +#include "vp8/common/swapyv12buffer.h" +#include "vp8/common/threading.h" +#include "decoderthreading.h" +#include +#include + +#include "vp8/common/quant_common.h" +#include "vpx_scale/vpxscale.h" +#include "vp8/common/systemdependent.h" +#include "vpx_ports/vpx_timer.h" +#include "detokenize.h" +#if CONFIG_ERROR_CONCEALMENT +#include "error_concealment.h" +#endif +#if ARCH_ARM +#include "vpx_ports/arm.h" +#endif + +extern void vp8_init_loop_filter(VP8_COMMON *cm); +extern void vp8cx_init_de_quantizer(VP8D_COMP *pbi); +static int get_free_fb (VP8_COMMON *cm); +static void ref_cnt_fb (int *buf, int *idx, int new_idx); + +struct VP8D_COMP * vp8dx_create_decompressor(VP8D_CONFIG *oxcf) +{ + VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP)); + + if (!pbi) + return NULL; + + vpx_memset(pbi, 0, sizeof(VP8D_COMP)); + + if (setjmp(pbi->common.error.jmp)) + { + pbi->common.error.setjmp = 0; + vp8dx_remove_decompressor(pbi); + return 0; + } + + pbi->common.error.setjmp = 1; + + vp8_create_common(&pbi->common); + + pbi->common.current_video_frame = 0; + pbi->ready_for_new_data = 1; + +#if CONFIG_MULTITHREAD + pbi->max_threads = oxcf->max_threads; + vp8_decoder_create_threads(pbi); +#endif + + /* vp8cx_init_de_quantizer() is first called here. Add check in frame_init_dequantizer() to avoid + * unnecessary calling of vp8cx_init_de_quantizer() for every frame. + */ + vp8cx_init_de_quantizer(pbi); + + vp8_loop_filter_init(&pbi->common); + + pbi->common.error.setjmp = 0; + +#if CONFIG_ERROR_CONCEALMENT + pbi->ec_enabled = oxcf->error_concealment; +#else + pbi->ec_enabled = 0; +#endif + /* Error concealment is activated after a key frame has been + * decoded without errors when error concealment is enabled. + */ + pbi->ec_active = 0; + + pbi->decoded_key_frame = 0; + + pbi->input_fragments = oxcf->input_fragments; + pbi->num_fragments = 0; + + /* Independent partitions is activated when a frame updates the + * token probability table to have equal probabilities over the + * PREV_COEF context. + */ + pbi->independent_partitions = 0; + + return pbi; +} + + +void vp8dx_remove_decompressor(VP8D_COMP *pbi) +{ + if (!pbi) + return; + +#if CONFIG_MULTITHREAD + if (pbi->b_multithreaded_rd) + vp8mt_de_alloc_temp_buffers(pbi, pbi->common.mb_rows); + vp8_decoder_remove_threads(pbi); +#endif +#if CONFIG_ERROR_CONCEALMENT + vp8_de_alloc_overlap_lists(pbi); +#endif + vp8_remove_common(&pbi->common); + vpx_free(pbi->mbc); + vpx_free(pbi); +} + + +vpx_codec_err_t vp8dx_get_reference(VP8D_COMP *pbi, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8_COMMON *cm = &pbi->common; + int ref_fb_idx; + + if (ref_frame_flag == VP8_LAST_FLAG) + ref_fb_idx = cm->lst_fb_idx; + else if (ref_frame_flag == VP8_GOLD_FLAG) + ref_fb_idx = cm->gld_fb_idx; + else if (ref_frame_flag == VP8_ALT_FLAG) + ref_fb_idx = cm->alt_fb_idx; + else{ + vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, + "Invalid reference frame"); + return pbi->common.error.error_code; + } + + if(cm->yv12_fb[ref_fb_idx].y_height != sd->y_height || + cm->yv12_fb[ref_fb_idx].y_width != sd->y_width || + cm->yv12_fb[ref_fb_idx].uv_height != sd->uv_height || + cm->yv12_fb[ref_fb_idx].uv_width != sd->uv_width){ + vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, + "Incorrect buffer dimensions"); + } + else + vp8_yv12_copy_frame(&cm->yv12_fb[ref_fb_idx], sd); + + return pbi->common.error.error_code; +} + + +vpx_codec_err_t vp8dx_set_reference(VP8D_COMP *pbi, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8_COMMON *cm = &pbi->common; + int *ref_fb_ptr = NULL; + int free_fb; + + if (ref_frame_flag == VP8_LAST_FLAG) + ref_fb_ptr = &cm->lst_fb_idx; + else if (ref_frame_flag == VP8_GOLD_FLAG) + ref_fb_ptr = &cm->gld_fb_idx; + else if (ref_frame_flag == VP8_ALT_FLAG) + ref_fb_ptr = &cm->alt_fb_idx; + else{ + vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, + "Invalid reference frame"); + return pbi->common.error.error_code; + } + + if(cm->yv12_fb[*ref_fb_ptr].y_height != sd->y_height || + cm->yv12_fb[*ref_fb_ptr].y_width != sd->y_width || + cm->yv12_fb[*ref_fb_ptr].uv_height != sd->uv_height || + cm->yv12_fb[*ref_fb_ptr].uv_width != sd->uv_width){ + vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, + "Incorrect buffer dimensions"); + } + else{ + /* Find an empty frame buffer. */ + free_fb = get_free_fb(cm); + /* Decrease fb_idx_ref_cnt since it will be increased again in + * ref_cnt_fb() below. */ + cm->fb_idx_ref_cnt[free_fb]--; + + /* Manage the reference counters and copy image. */ + ref_cnt_fb (cm->fb_idx_ref_cnt, ref_fb_ptr, free_fb); + vp8_yv12_copy_frame(sd, &cm->yv12_fb[*ref_fb_ptr]); + } + + return pbi->common.error.error_code; +} + +/*For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us.*/ +#if HAVE_NEON +extern void vp8_push_neon(int64_t *store); +extern void vp8_pop_neon(int64_t *store); +#endif + +static int get_free_fb (VP8_COMMON *cm) +{ + int i; + for (i = 0; i < NUM_YV12_BUFFERS; i++) + if (cm->fb_idx_ref_cnt[i] == 0) + break; + + assert(i < NUM_YV12_BUFFERS); + cm->fb_idx_ref_cnt[i] = 1; + return i; +} + +static void ref_cnt_fb (int *buf, int *idx, int new_idx) +{ + if (buf[*idx] > 0) + buf[*idx]--; + + *idx = new_idx; + + buf[new_idx]++; +} + +/* If any buffer copy / swapping is signalled it should be done here. */ +static int swap_frame_buffers (VP8_COMMON *cm) +{ + int err = 0; + + /* The alternate reference frame or golden frame can be updated + * using the new, last, or golden/alt ref frame. If it + * is updated using the newly decoded frame it is a refresh. + * An update using the last or golden/alt ref frame is a copy. + */ + if (cm->copy_buffer_to_arf) + { + int new_fb = 0; + + if (cm->copy_buffer_to_arf == 1) + new_fb = cm->lst_fb_idx; + else if (cm->copy_buffer_to_arf == 2) + new_fb = cm->gld_fb_idx; + else + err = -1; + + ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->alt_fb_idx, new_fb); + } + + if (cm->copy_buffer_to_gf) + { + int new_fb = 0; + + if (cm->copy_buffer_to_gf == 1) + new_fb = cm->lst_fb_idx; + else if (cm->copy_buffer_to_gf == 2) + new_fb = cm->alt_fb_idx; + else + err = -1; + + ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->gld_fb_idx, new_fb); + } + + if (cm->refresh_golden_frame) + ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->gld_fb_idx, cm->new_fb_idx); + + if (cm->refresh_alt_ref_frame) + ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->alt_fb_idx, cm->new_fb_idx); + + if (cm->refresh_last_frame) + { + ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->lst_fb_idx, cm->new_fb_idx); + + cm->frame_to_show = &cm->yv12_fb[cm->lst_fb_idx]; + } + else + cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx]; + + cm->fb_idx_ref_cnt[cm->new_fb_idx]--; + + return err; +} + +int vp8dx_receive_compressed_data(VP8D_COMP *pbi, unsigned long size, const unsigned char *source, int64_t time_stamp) +{ +#if HAVE_NEON + int64_t dx_store_reg[8]; +#endif + VP8_COMMON *cm = &pbi->common; + int retcode = 0; + + /*if(pbi->ready_for_new_data == 0) + return -1;*/ + + if (pbi == 0) + { + return -1; + } + + pbi->common.error.error_code = VPX_CODEC_OK; + + if (pbi->num_fragments == 0) + { + /* New frame, reset fragment pointers and sizes */ + vpx_memset(pbi->fragments, 0, sizeof(pbi->fragments)); + vpx_memset(pbi->fragment_sizes, 0, sizeof(pbi->fragment_sizes)); + } + if (pbi->input_fragments && !(source == NULL && size == 0)) + { + /* Store a pointer to this fragment and return. We haven't + * received the complete frame yet, so we will wait with decoding. + */ + assert(pbi->num_fragments < MAX_PARTITIONS); + pbi->fragments[pbi->num_fragments] = source; + pbi->fragment_sizes[pbi->num_fragments] = size; + pbi->num_fragments++; + if (pbi->num_fragments > (1 << EIGHT_PARTITION) + 1) + { + pbi->common.error.error_code = VPX_CODEC_UNSUP_BITSTREAM; + pbi->common.error.setjmp = 0; + pbi->num_fragments = 0; + return -1; + } + return 0; + } + + if (!pbi->input_fragments) + { + pbi->fragments[0] = source; + pbi->fragment_sizes[0] = size; + pbi->num_fragments = 1; + } + assert(pbi->common.multi_token_partition <= EIGHT_PARTITION); + if (pbi->num_fragments == 0) + { + pbi->num_fragments = 1; + pbi->fragments[0] = NULL; + pbi->fragment_sizes[0] = 0; + } + + if (!pbi->ec_active && + pbi->num_fragments <= 1 && pbi->fragment_sizes[0] == 0) + { + /* If error concealment is disabled we won't signal missing frames + * to the decoder. + */ + if (cm->fb_idx_ref_cnt[cm->lst_fb_idx] > 1) + { + /* The last reference shares buffer with another reference + * buffer. Move it to its own buffer before setting it as + * corrupt, otherwise we will make multiple buffers corrupt. + */ + const int prev_idx = cm->lst_fb_idx; + cm->fb_idx_ref_cnt[prev_idx]--; + cm->lst_fb_idx = get_free_fb(cm); + vp8_yv12_copy_frame(&cm->yv12_fb[prev_idx], + &cm->yv12_fb[cm->lst_fb_idx]); + } + /* This is used to signal that we are missing frames. + * We do not know if the missing frame(s) was supposed to update + * any of the reference buffers, but we act conservative and + * mark only the last buffer as corrupted. + */ + cm->yv12_fb[cm->lst_fb_idx].corrupted = 1; + + /* Signal that we have no frame to show. */ + cm->show_frame = 0; + + pbi->num_fragments = 0; + + /* Nothing more to do. */ + return 0; + } + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_push_neon(dx_store_reg); + } +#endif + + cm->new_fb_idx = get_free_fb (cm); + + if (setjmp(pbi->common.error.jmp)) + { +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(dx_store_reg); + } +#endif + pbi->common.error.setjmp = 0; + + pbi->num_fragments = 0; + + /* We do not know if the missing frame(s) was supposed to update + * any of the reference buffers, but we act conservative and + * mark only the last buffer as corrupted. + */ + cm->yv12_fb[cm->lst_fb_idx].corrupted = 1; + + if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) + cm->fb_idx_ref_cnt[cm->new_fb_idx]--; + return -1; + } + + pbi->common.error.setjmp = 1; + + retcode = vp8_decode_frame(pbi); + + if (retcode < 0) + { +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(dx_store_reg); + } +#endif + pbi->common.error.error_code = VPX_CODEC_ERROR; + pbi->common.error.setjmp = 0; + pbi->num_fragments = 0; + if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) + cm->fb_idx_ref_cnt[cm->new_fb_idx]--; + return retcode; + } + +#if CONFIG_MULTITHREAD + if (pbi->b_multithreaded_rd && cm->multi_token_partition != ONE_PARTITION) + { + if (swap_frame_buffers (cm)) + { +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(dx_store_reg); + } +#endif + pbi->common.error.error_code = VPX_CODEC_ERROR; + pbi->common.error.setjmp = 0; + pbi->num_fragments = 0; + return -1; + } + } else +#endif + { + if (swap_frame_buffers (cm)) + { +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(dx_store_reg); + } +#endif + pbi->common.error.error_code = VPX_CODEC_ERROR; + pbi->common.error.setjmp = 0; + pbi->num_fragments = 0; + return -1; + } + + if(cm->filter_level) + { + /* Apply the loop filter if appropriate. */ + vp8_loop_filter_frame(cm, &pbi->mb); + } + vp8_yv12_extend_frame_borders(cm->frame_to_show); + } + + + vp8_clear_system_state(); + +#if CONFIG_ERROR_CONCEALMENT + /* swap the mode infos to storage for future error concealment */ + if (pbi->ec_enabled && pbi->common.prev_mi) + { + MODE_INFO* tmp = pbi->common.prev_mi; + int row, col; + pbi->common.prev_mi = pbi->common.mi; + pbi->common.mi = tmp; + + /* Propagate the segment_ids to the next frame */ + for (row = 0; row < pbi->common.mb_rows; ++row) + { + for (col = 0; col < pbi->common.mb_cols; ++col) + { + const int i = row*pbi->common.mode_info_stride + col; + pbi->common.mi[i].mbmi.segment_id = + pbi->common.prev_mi[i].mbmi.segment_id; + } + } + } +#endif + + /*vp8_print_modes_and_motion_vectors( cm->mi, cm->mb_rows,cm->mb_cols, cm->current_video_frame);*/ + + if (cm->show_frame) + cm->current_video_frame++; + + pbi->ready_for_new_data = 0; + pbi->last_time_stamp = time_stamp; + pbi->num_fragments = 0; + +#if 0 + { + int i; + int64_t earliest_time = pbi->dr[0].time_stamp; + int64_t latest_time = pbi->dr[0].time_stamp; + int64_t time_diff = 0; + int bytes = 0; + + pbi->dr[pbi->common.current_video_frame&0xf].size = pbi->bc.pos + pbi->bc2.pos + 4;; + pbi->dr[pbi->common.current_video_frame&0xf].time_stamp = time_stamp; + + for (i = 0; i < 16; i++) + { + + bytes += pbi->dr[i].size; + + if (pbi->dr[i].time_stamp < earliest_time) + earliest_time = pbi->dr[i].time_stamp; + + if (pbi->dr[i].time_stamp > latest_time) + latest_time = pbi->dr[i].time_stamp; + } + + time_diff = latest_time - earliest_time; + + if (time_diff > 0) + { + pbi->common.bitrate = 80000.00 * bytes / time_diff ; + pbi->common.framerate = 160000000.00 / time_diff ; + } + + } +#endif + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(dx_store_reg); + } +#endif + pbi->common.error.setjmp = 0; + return retcode; +} +int vp8dx_get_raw_frame(VP8D_COMP *pbi, YV12_BUFFER_CONFIG *sd, int64_t *time_stamp, int64_t *time_end_stamp, vp8_ppflags_t *flags) +{ + int ret = -1; + + if (pbi->ready_for_new_data == 1) + return ret; + + /* ie no raw frame to show!!! */ + if (pbi->common.show_frame == 0) + return ret; + + pbi->ready_for_new_data = 1; + *time_stamp = pbi->last_time_stamp; + *time_end_stamp = 0; + + sd->clrtype = pbi->common.clr_type; +#if CONFIG_POSTPROC + ret = vp8_post_proc_frame(&pbi->common, sd, flags); +#else + + if (pbi->common.frame_to_show) + { + *sd = *pbi->common.frame_to_show; + sd->y_width = pbi->common.Width; + sd->y_height = pbi->common.Height; + sd->uv_height = pbi->common.Height / 2; + ret = 0; + } + else + { + ret = -1; + } + +#endif /*!CONFIG_POSTPROC*/ + vp8_clear_system_state(); + return ret; +} + + +/* This function as written isn't decoder specific, but the encoder has + * much faster ways of computing this, so it's ok for it to live in a + * decode specific file. + */ +int vp8dx_references_buffer( VP8_COMMON *oci, int ref_frame ) +{ + const MODE_INFO *mi = oci->mi; + int mb_row, mb_col; + + for (mb_row = 0; mb_row < oci->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < oci->mb_cols; mb_col++,mi++) + { + if( mi->mbmi.ref_frame == ref_frame) + return 1; + } + mi++; + } + return 0; + +} diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h new file mode 100644 index 0000000..97cf0dc --- /dev/null +++ b/vp8/decoder/onyxd_int.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_VP8D_INT_H +#define __INC_VP8D_INT_H +#include "vpx_config.h" +#include "vp8/common/onyxd.h" +#include "treereader.h" +#include "vp8/common/onyxc_int.h" +#include "vp8/common/threading.h" + +#if CONFIG_ERROR_CONCEALMENT +#include "ec_types.h" +#endif + +typedef struct +{ + int ithread; + void *ptr1; + void *ptr2; +} DECODETHREAD_DATA; + +typedef struct +{ + MACROBLOCKD mbd; + int mb_row; +} MB_ROW_DEC; + +typedef struct +{ + int64_t time_stamp; + int size; +} DATARATE; + + +typedef struct VP8D_COMP +{ + DECLARE_ALIGNED(16, MACROBLOCKD, mb); + + DECLARE_ALIGNED(16, VP8_COMMON, common); + + vp8_reader bc, bc2; + + VP8D_CONFIG oxcf; + + + const unsigned char *fragments[MAX_PARTITIONS]; + unsigned int fragment_sizes[MAX_PARTITIONS]; + unsigned int num_fragments; + +#if CONFIG_MULTITHREAD + /* variable for threading */ + + volatile int b_multithreaded_rd; + int max_threads; + int current_mb_col_main; + int decoding_thread_count; + int allocated_decoding_thread_count; + + int mt_baseline_filter_level[MAX_MB_SEGMENTS]; + int sync_range; + int *mt_current_mb_col; /* Each row remembers its already decoded column. */ + + unsigned char **mt_yabove_row; /* mb_rows x width */ + unsigned char **mt_uabove_row; + unsigned char **mt_vabove_row; + unsigned char **mt_yleft_col; /* mb_rows x 16 */ + unsigned char **mt_uleft_col; /* mb_rows x 8 */ + unsigned char **mt_vleft_col; /* mb_rows x 8 */ + + MB_ROW_DEC *mb_row_di; + DECODETHREAD_DATA *de_thread_data; + + pthread_t *h_decoding_thread; + sem_t *h_event_start_decoding; + sem_t h_event_end_decoding; + /* end of threading data */ +#endif + + vp8_reader *mbc; + int64_t last_time_stamp; + int ready_for_new_data; + + DATARATE dr[16]; + + vp8_prob prob_intra; + vp8_prob prob_last; + vp8_prob prob_gf; + vp8_prob prob_skip_false; + +#if CONFIG_ERROR_CONCEALMENT + MB_OVERLAP *overlaps; + /* the mb num from which modes and mvs (first partition) are corrupt */ + unsigned int mvs_corrupt_from_mb; +#endif + int ec_enabled; + int ec_active; + int input_fragments; + int decoded_key_frame; + int independent_partitions; + int frame_corrupt_residual; + +} VP8D_COMP; + +int vp8_decode_frame(VP8D_COMP *cpi); + +#if CONFIG_DEBUG +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval" at %s:%d", \ + __FILE__,__LINE__);\ + } while(0) +#else +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval);\ + } while(0) +#endif + +#endif diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c new file mode 100644 index 0000000..47a0349 --- /dev/null +++ b/vp8/decoder/threading.c @@ -0,0 +1,922 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#if !defined(WIN32) && CONFIG_OS_SUPPORT == 1 +# include +#endif +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/threading.h" + +#include "vp8/common/loopfilter.h" +#include "vp8/common/extend.h" +#include "vpx_ports/vpx_timer.h" +#include "detokenize.h" +#include "vp8/common/reconintra4x4.h" +#include "vp8/common/reconinter.h" +#if CONFIG_ERROR_CONCEALMENT +#include "error_concealment.h" +#endif + +extern void vp8_mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd); + +static void setup_decoding_thread_data(VP8D_COMP *pbi, MACROBLOCKD *xd, MB_ROW_DEC *mbrd, int count) +{ + VP8_COMMON *const pc = & pbi->common; + int i; + + for (i = 0; i < count; i++) + { + MACROBLOCKD *mbd = &mbrd[i].mbd; + mbd->subpixel_predict = xd->subpixel_predict; + mbd->subpixel_predict8x4 = xd->subpixel_predict8x4; + mbd->subpixel_predict8x8 = xd->subpixel_predict8x8; + mbd->subpixel_predict16x16 = xd->subpixel_predict16x16; + + mbd->mode_info_context = pc->mi + pc->mode_info_stride * (i + 1); + mbd->mode_info_stride = pc->mode_info_stride; + + mbd->frame_type = pc->frame_type; + mbd->pre = pc->yv12_fb[pc->lst_fb_idx]; + mbd->dst = pc->yv12_fb[pc->new_fb_idx]; + + vp8_setup_block_dptrs(mbd); + vp8_build_block_doffsets(mbd); + mbd->segmentation_enabled = xd->segmentation_enabled; + mbd->mb_segement_abs_delta = xd->mb_segement_abs_delta; + vpx_memcpy(mbd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); + + /*signed char ref_lf_deltas[MAX_REF_LF_DELTAS];*/ + vpx_memcpy(mbd->ref_lf_deltas, xd->ref_lf_deltas, sizeof(xd->ref_lf_deltas)); + /*signed char mode_lf_deltas[MAX_MODE_LF_DELTAS];*/ + vpx_memcpy(mbd->mode_lf_deltas, xd->mode_lf_deltas, sizeof(xd->mode_lf_deltas)); + /*unsigned char mode_ref_lf_delta_enabled; + unsigned char mode_ref_lf_delta_update;*/ + mbd->mode_ref_lf_delta_enabled = xd->mode_ref_lf_delta_enabled; + mbd->mode_ref_lf_delta_update = xd->mode_ref_lf_delta_update; + + mbd->current_bc = &pbi->bc2; + + vpx_memcpy(mbd->dequant_y1_dc, xd->dequant_y1_dc, sizeof(xd->dequant_y1_dc)); + vpx_memcpy(mbd->dequant_y1, xd->dequant_y1, sizeof(xd->dequant_y1)); + vpx_memcpy(mbd->dequant_y2, xd->dequant_y2, sizeof(xd->dequant_y2)); + vpx_memcpy(mbd->dequant_uv, xd->dequant_uv, sizeof(xd->dequant_uv)); + + mbd->fullpixel_mask = 0xffffffff; + if(pc->full_pixel) + mbd->fullpixel_mask = 0xfffffff8; + + } + + for (i=0; i< pc->mb_rows; i++) + pbi->mt_current_mb_col[i]=-1; +} + +static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, unsigned int mb_idx) +{ + MB_PREDICTION_MODE mode; + int i; +#if CONFIG_ERROR_CONCEALMENT + int corruption_detected = 0; +#endif + + if (xd->mode_info_context->mbmi.mb_skip_coeff) + { + vp8_reset_mb_tokens_context(xd); + } + else if (!vp8dx_bool_error(xd->current_bc)) + { + int eobtotal; + eobtotal = vp8_decode_mb_tokens(pbi, xd); + + /* Special case: Force the loopfilter to skip when eobtotal is zero */ + xd->mode_info_context->mbmi.mb_skip_coeff = (eobtotal==0); + } + + mode = xd->mode_info_context->mbmi.mode; + + if (xd->segmentation_enabled) + vp8_mb_init_dequantizer(pbi, xd); + + +#if CONFIG_ERROR_CONCEALMENT + + if(pbi->ec_active) + { + int throw_residual; + /* When we have independent partitions we can apply residual even + * though other partitions within the frame are corrupt. + */ + throw_residual = (!pbi->independent_partitions && + pbi->frame_corrupt_residual); + throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc)); + + if ((mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual)) + { + /* MB with corrupt residuals or corrupt mode/motion vectors. + * Better to use the predictor as reconstruction. + */ + pbi->frame_corrupt_residual = 1; + vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); + vp8_conceal_corrupt_mb(xd); + + + corruption_detected = 1; + + /* force idct to be skipped for B_PRED and use the + * prediction only for reconstruction + * */ + vpx_memset(xd->eobs, 0, 25); + } + } +#endif + + /* do prediction */ + if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) + { + vp8_build_intra_predictors_mbuv_s(xd, + xd->recon_above[1], + xd->recon_above[2], + xd->recon_left[1], + xd->recon_left[2], + xd->recon_left_stride[1], + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride); + + if (mode != B_PRED) + { + vp8_build_intra_predictors_mby_s(xd, + xd->recon_above[0], + xd->recon_left[0], + xd->recon_left_stride[0], + xd->dst.y_buffer, + xd->dst.y_stride); + } + else + { + short *DQC = xd->dequant_y1; + int dst_stride = xd->dst.y_stride; + unsigned char *base_dst = xd->dst.y_buffer; + + /* clear out residual eob info */ + if(xd->mode_info_context->mbmi.mb_skip_coeff) + vpx_memset(xd->eobs, 0, 25); + + intra_prediction_down_copy(xd, xd->recon_above[0] + 16); + + for (i = 0; i < 16; i++) + { + BLOCKD *b = &xd->block[i]; + int b_mode = xd->mode_info_context->bmi[i].as_mode; + unsigned char *yabove; + unsigned char *yleft; + int left_stride; + unsigned char top_left; + + /*Caution: For some b_mode, it needs 8 pixels (4 above + 4 above-right).*/ + if (i < 4 && pbi->common.filter_level) + yabove = xd->recon_above[0] + b->offset; //i*4; + else + yabove = (base_dst - dst_stride) + b->offset; + + if (i%4==0 && pbi->common.filter_level) + { + yleft = xd->recon_left[0] + i; + left_stride = 1; + } + else + { + yleft = (base_dst - 1) + b->offset; + left_stride = dst_stride; + } + + if ((i==4 || i==8 || i==12) && pbi->common.filter_level) + top_left = *(xd->recon_left[0] + i - 1); + else + top_left = yabove[-1]; + + vp8_intra4x4_predict_d_c(yabove, yleft, left_stride, + b_mode, + base_dst + b->offset, dst_stride, + top_left); + + if (xd->eobs[i] ) + { + if (xd->eobs[i] > 1) + { + vp8_dequant_idct_add + (b->qcoeff, DQC, + base_dst + b->offset, dst_stride); + } + else + { + vp8_dc_only_idct_add + (b->qcoeff[0] * DQC[0], + base_dst + b->offset, dst_stride, + base_dst + b->offset, dst_stride); + ((int *)b->qcoeff)[0] = 0; + } + } + } + } + } + else + { + vp8_build_inter_predictors_mb(xd); + } + + +#if CONFIG_ERROR_CONCEALMENT + if (corruption_detected) + { + return; + } +#endif + + if(!xd->mode_info_context->mbmi.mb_skip_coeff) + { + /* dequantization and idct */ + if (mode != B_PRED) + { + short *DQC = xd->dequant_y1; + + if (mode != SPLITMV) + { + BLOCKD *b = &xd->block[24]; + + /* do 2nd order transform on the dc block */ + if (xd->eobs[24] > 1) + { + vp8_dequantize_b(b, xd->dequant_y2); + + vp8_short_inv_walsh4x4(&b->dqcoeff[0], + xd->qcoeff); + ((int *)b->qcoeff)[0] = 0; + ((int *)b->qcoeff)[1] = 0; + ((int *)b->qcoeff)[2] = 0; + ((int *)b->qcoeff)[3] = 0; + ((int *)b->qcoeff)[4] = 0; + ((int *)b->qcoeff)[5] = 0; + ((int *)b->qcoeff)[6] = 0; + ((int *)b->qcoeff)[7] = 0; + } + else + { + b->dqcoeff[0] = b->qcoeff[0] * xd->dequant_y2[0]; + vp8_short_inv_walsh4x4_1(&b->dqcoeff[0], + xd->qcoeff); + ((int *)b->qcoeff)[0] = 0; + } + + /* override the dc dequant constant in order to preserve the + * dc components + */ + DQC = xd->dequant_y1_dc; + } + + vp8_dequant_idct_add_y_block + (xd->qcoeff, DQC, + xd->dst.y_buffer, + xd->dst.y_stride, xd->eobs); + } + + vp8_dequant_idct_add_uv_block + (xd->qcoeff+16*16, xd->dequant_uv, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride, xd->eobs+16); + } +} + +typedef void (*init_current_bc_fn_t)(VP8D_COMP *pbi, MACROBLOCKD *xd, + int start_mb_row, int mb_row, int num_part); + +static void init_current_bc(VP8D_COMP *pbi, MACROBLOCKD *xd, int start_mb_row, + int mb_row, int num_part) +{ + (void) start_mb_row; + + xd->current_bc = &pbi->mbc[mb_row%num_part]; +} + +static void init_current_bc_threads(VP8D_COMP *pbi, MACROBLOCKD *xd, + int start_mb_row, int mb_row, int num_part) +{ + (void) xd; + pbi->mb_row_di[start_mb_row - 1].mb_row = mb_row; + pbi->mb_row_di[start_mb_row - 1].mbd.current_bc = &pbi->mbc[mb_row%num_part]; +} + + +static void decode_mb_rows(VP8D_COMP *pbi, MACROBLOCKD *xd, int start_mb_row, + init_current_bc_fn_t init_current_bc_fn) +{ + volatile int *last_row_current_mb_col = NULL; + int mb_row; + VP8_COMMON *pc = &pbi->common; + int nsync = pbi->sync_range; + int num_part = 1 << pbi->common.multi_token_partition; + + int dst_fb_idx = pc->new_fb_idx; + unsigned char *ref_buffer[MAX_REF_FRAMES][3]; + unsigned char *dst_buffer[3]; + int i; + int ref_fb_index[MAX_REF_FRAMES]; + int ref_fb_corrupted[MAX_REF_FRAMES]; + + ref_fb_corrupted[INTRA_FRAME] = 0; + + ref_fb_index[LAST_FRAME] = pc->lst_fb_idx; + ref_fb_index[GOLDEN_FRAME] = pc->gld_fb_idx; + ref_fb_index[ALTREF_FRAME] = pc->alt_fb_idx; + + for(i = 1; i < MAX_REF_FRAMES; i++) + { + ref_buffer[i][0] = pc->yv12_fb[ref_fb_index[i]].y_buffer; + ref_buffer[i][1] = pc->yv12_fb[ref_fb_index[i]].u_buffer; + ref_buffer[i][2] = pc->yv12_fb[ref_fb_index[i]].v_buffer; + + ref_fb_corrupted[i] = pc->yv12_fb[ref_fb_index[i]].corrupted; + } + + dst_buffer[0] = pc->yv12_fb[dst_fb_idx].y_buffer; + dst_buffer[1] = pc->yv12_fb[dst_fb_idx].u_buffer; + dst_buffer[2] = pc->yv12_fb[dst_fb_idx].v_buffer; + + xd->up_available = (start_mb_row != 0); + + for (mb_row = start_mb_row; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1)) + { + int i; + int recon_yoffset, recon_uvoffset; + int mb_col; + int ref_fb_idx = pc->lst_fb_idx; + int dst_fb_idx = pc->new_fb_idx; + int recon_y_stride = pc->yv12_fb[ref_fb_idx].y_stride; + int recon_uv_stride = pc->yv12_fb[ref_fb_idx].uv_stride; + + int filter_level; + loop_filter_info_n *lfi_n = &pc->lf_info; + + init_current_bc_fn(pbi, xd, start_mb_row, mb_row, num_part); + + if (mb_row > 0) + last_row_current_mb_col = &pbi->mt_current_mb_col[mb_row -1]; + + recon_yoffset = mb_row * recon_y_stride * 16; + recon_uvoffset = mb_row * recon_uv_stride * 8; + + /* reset contexts */ + xd->above_context = pc->above_context; + vpx_memset(xd->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); + + xd->left_available = 0; + + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + + if (pbi->common.filter_level) + { + xd->recon_above[0] = pbi->mt_yabove_row[mb_row] + 0*16 +32; + xd->recon_above[1] = pbi->mt_uabove_row[mb_row] + 0*8 +16; + xd->recon_above[2] = pbi->mt_vabove_row[mb_row] + 0*8 +16; + + xd->recon_left[0] = pbi->mt_yleft_col[mb_row]; + xd->recon_left[1] = pbi->mt_uleft_col[mb_row]; + xd->recon_left[2] = pbi->mt_vleft_col[mb_row]; + + //TODO: move to outside row loop + xd->recon_left_stride[0] = 1; + xd->recon_left_stride[1] = 1; + } + else + { + xd->recon_above[0] = dst_buffer[0] + recon_yoffset; + xd->recon_above[1] = dst_buffer[1] + recon_uvoffset; + xd->recon_above[2] = dst_buffer[2] + recon_uvoffset; + + xd->recon_left[0] = xd->recon_above[0] - 1; + xd->recon_left[1] = xd->recon_above[1] - 1; + xd->recon_left[2] = xd->recon_above[2] - 1; + + xd->recon_above[0] -= xd->dst.y_stride; + xd->recon_above[1] -= xd->dst.uv_stride; + xd->recon_above[2] -= xd->dst.uv_stride; + + //TODO: move to outside row loop + xd->recon_left_stride[0] = xd->dst.y_stride; + xd->recon_left_stride[1] = xd->dst.uv_stride; + } + + for (mb_col = 0; mb_col < pc->mb_cols; mb_col++) + { + if ( mb_row > 0 && (mb_col & (nsync-1)) == 0) + { + while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != pc->mb_cols - 1) + { + x86_pause_hint(); + thread_sleep(0); + } + } + + /* Distance of MB to the various image edges. + * These are specified to 8th pel as they are always + * compared to values that are in 1/8th pel units. + */ + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + + #if CONFIG_ERROR_CONCEALMENT + { + int corrupt_residual = + (!pbi->independent_partitions && + pbi->frame_corrupt_residual) || + vp8dx_bool_error(xd->current_bc); + if (pbi->ec_active && + (xd->mode_info_context->mbmi.ref_frame == + INTRA_FRAME) && + corrupt_residual) + { + /* We have an intra block with corrupt + * coefficients, better to conceal with an inter + * block. + * Interpolate MVs from neighboring MBs + * + * Note that for the first mb with corrupt + * residual in a frame, we might not discover + * that before decoding the residual. That + * happens after this check, and therefore no + * inter concealment will be done. + */ + vp8_interpolate_motion(xd, + mb_row, mb_col, + pc->mb_rows, pc->mb_cols, + pc->mode_info_stride); + } + } + #endif + + + xd->dst.y_buffer = dst_buffer[0] + recon_yoffset; + xd->dst.u_buffer = dst_buffer[1] + recon_uvoffset; + xd->dst.v_buffer = dst_buffer[2] + recon_uvoffset; + + xd->pre.y_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][0] + recon_yoffset; + xd->pre.u_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][1] + recon_uvoffset; + xd->pre.v_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][2] + recon_uvoffset; + + /* propagate errors from reference frames */ + xd->corrupted |= ref_fb_corrupted[xd->mode_info_context->mbmi.ref_frame]; + + decode_macroblock(pbi, xd, 0); + + xd->left_available = 1; + + /* check if the boolean decoder has suffered an error */ + xd->corrupted |= vp8dx_bool_error(xd->current_bc); + + xd->recon_above[0] += 16; + xd->recon_above[1] += 8; + xd->recon_above[2] += 8; + + if (!pbi->common.filter_level) + { + xd->recon_left[0] += 16; + xd->recon_left[1] += 8; + xd->recon_left[2] += 8; + } + + if (pbi->common.filter_level) + { + int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED && + xd->mode_info_context->mbmi.mode != SPLITMV && + xd->mode_info_context->mbmi.mb_skip_coeff); + + const int mode_index = lfi_n->mode_lf_lut[xd->mode_info_context->mbmi.mode]; + const int seg = xd->mode_info_context->mbmi.segment_id; + const int ref_frame = xd->mode_info_context->mbmi.ref_frame; + + filter_level = lfi_n->lvl[seg][ref_frame][mode_index]; + + if( mb_row != pc->mb_rows-1 ) + { + /* Save decoded MB last row data for next-row decoding */ + vpx_memcpy((pbi->mt_yabove_row[mb_row + 1] + 32 + mb_col*16), (xd->dst.y_buffer + 15 * recon_y_stride), 16); + vpx_memcpy((pbi->mt_uabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.u_buffer + 7 * recon_uv_stride), 8); + vpx_memcpy((pbi->mt_vabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.v_buffer + 7 * recon_uv_stride), 8); + } + + /* save left_col for next MB decoding */ + if(mb_col != pc->mb_cols-1) + { + MODE_INFO *next = xd->mode_info_context +1; + + if (next->mbmi.ref_frame == INTRA_FRAME) + { + for (i = 0; i < 16; i++) + pbi->mt_yleft_col[mb_row][i] = xd->dst.y_buffer [i* recon_y_stride + 15]; + for (i = 0; i < 8; i++) + { + pbi->mt_uleft_col[mb_row][i] = xd->dst.u_buffer [i* recon_uv_stride + 7]; + pbi->mt_vleft_col[mb_row][i] = xd->dst.v_buffer [i* recon_uv_stride + 7]; + } + } + } + + /* loopfilter on this macroblock. */ + if (filter_level) + { + if(pc->filter_type == NORMAL_LOOPFILTER) + { + loop_filter_info lfi; + FRAME_TYPE frame_type = pc->frame_type; + const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level]; + lfi.mblim = lfi_n->mblim[filter_level]; + lfi.blim = lfi_n->blim[filter_level]; + lfi.lim = lfi_n->lim[filter_level]; + lfi.hev_thr = lfi_n->hev_thr[hev_index]; + + if (mb_col > 0) + vp8_loop_filter_mbv + (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); + + if (!skip_lf) + vp8_loop_filter_bv + (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_mbh + (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); + + if (!skip_lf) + vp8_loop_filter_bh + (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi); + } + else + { + if (mb_col > 0) + vp8_loop_filter_simple_mbv + (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]); + + if (!skip_lf) + vp8_loop_filter_simple_bv + (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]); + + /* don't apply across umv border */ + if (mb_row > 0) + vp8_loop_filter_simple_mbh + (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]); + + if (!skip_lf) + vp8_loop_filter_simple_bh + (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]); + } + } + + } + + recon_yoffset += 16; + recon_uvoffset += 8; + + ++xd->mode_info_context; /* next mb */ + + xd->above_context++; + + /*pbi->mb_row_di[ithread].current_mb_col = mb_col;*/ + pbi->mt_current_mb_col[mb_row] = mb_col; + } + + /* adjust to the next row of mbs */ + if (pbi->common.filter_level) + { + if(mb_row != pc->mb_rows-1) + { + int lasty = pc->yv12_fb[ref_fb_idx].y_width + VP8BORDERINPIXELS; + int lastuv = (pc->yv12_fb[ref_fb_idx].y_width>>1) + (VP8BORDERINPIXELS>>1); + + for (i = 0; i < 4; i++) + { + pbi->mt_yabove_row[mb_row +1][lasty + i] = pbi->mt_yabove_row[mb_row +1][lasty -1]; + pbi->mt_uabove_row[mb_row +1][lastuv + i] = pbi->mt_uabove_row[mb_row +1][lastuv -1]; + pbi->mt_vabove_row[mb_row +1][lastuv + i] = pbi->mt_vabove_row[mb_row +1][lastuv -1]; + } + } + } else + vp8_extend_mb_row(&pc->yv12_fb[dst_fb_idx], xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8); + + ++xd->mode_info_context; /* skip prediction column */ + xd->up_available = 1; + + /* since we have multithread */ + xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count; + } +} + + +static THREAD_FUNCTION thread_decoding_proc(void *p_data) +{ + int ithread = ((DECODETHREAD_DATA *)p_data)->ithread; + VP8D_COMP *pbi = (VP8D_COMP *)(((DECODETHREAD_DATA *)p_data)->ptr1); + MB_ROW_DEC *mbrd = (MB_ROW_DEC *)(((DECODETHREAD_DATA *)p_data)->ptr2); + ENTROPY_CONTEXT_PLANES mb_row_left_context; + + while (1) + { + if (pbi->b_multithreaded_rd == 0) + break; + + /*if(WaitForSingleObject(pbi->h_event_start_decoding[ithread], INFINITE) == WAIT_OBJECT_0)*/ + if (sem_wait(&pbi->h_event_start_decoding[ithread]) == 0) + { + if (pbi->b_multithreaded_rd == 0) + break; + else + { + MACROBLOCKD *xd = &mbrd->mbd; + + xd->left_context = &mb_row_left_context; + + decode_mb_rows(pbi, xd, ithread+1, init_current_bc_threads); + } + } + + /* add this to each frame */ + if ((mbrd->mb_row == pbi->common.mb_rows-1) || + ((mbrd->mb_row == pbi->common.mb_rows-2) && + (pbi->common.mb_rows % (pbi->decoding_thread_count+1))==1)) + { + /*SetEvent(pbi->h_event_end_decoding);*/ + sem_post(&pbi->h_event_end_decoding); + } + } + + return 0 ; +} + + +void vp8_decoder_create_threads(VP8D_COMP *pbi) +{ + int core_count = 0; + int ithread; + + pbi->b_multithreaded_rd = 0; + pbi->allocated_decoding_thread_count = 0; + + /* limit decoding threads to the max number of token partitions */ + core_count = (pbi->max_threads > 8) ? 8 : pbi->max_threads; + + /* limit decoding threads to the available cores */ + if (core_count > pbi->common.processor_core_count) + core_count = pbi->common.processor_core_count; + + if (core_count > 1) + { + pbi->b_multithreaded_rd = 1; + pbi->decoding_thread_count = core_count - 1; + + CHECK_MEM_ERROR(pbi->h_decoding_thread, vpx_malloc(sizeof(pthread_t) * pbi->decoding_thread_count)); + CHECK_MEM_ERROR(pbi->h_event_start_decoding, vpx_malloc(sizeof(sem_t) * pbi->decoding_thread_count)); + CHECK_MEM_ERROR(pbi->mb_row_di, vpx_memalign(32, sizeof(MB_ROW_DEC) * pbi->decoding_thread_count)); + vpx_memset(pbi->mb_row_di, 0, sizeof(MB_ROW_DEC) * pbi->decoding_thread_count); + CHECK_MEM_ERROR(pbi->de_thread_data, vpx_malloc(sizeof(DECODETHREAD_DATA) * pbi->decoding_thread_count)); + + for (ithread = 0; ithread < pbi->decoding_thread_count; ithread++) + { + sem_init(&pbi->h_event_start_decoding[ithread], 0, 0); + + pbi->de_thread_data[ithread].ithread = ithread; + pbi->de_thread_data[ithread].ptr1 = (void *)pbi; + pbi->de_thread_data[ithread].ptr2 = (void *) &pbi->mb_row_di[ithread]; + + pthread_create(&pbi->h_decoding_thread[ithread], 0, thread_decoding_proc, (&pbi->de_thread_data[ithread])); + } + + sem_init(&pbi->h_event_end_decoding, 0, 0); + + pbi->allocated_decoding_thread_count = pbi->decoding_thread_count; + } +} + + +void vp8mt_de_alloc_temp_buffers(VP8D_COMP *pbi, int mb_rows) +{ + int i; + + if (pbi->b_multithreaded_rd) + { + vpx_free(pbi->mt_current_mb_col); + pbi->mt_current_mb_col = NULL ; + + /* Free above_row buffers. */ + if (pbi->mt_yabove_row) + { + for (i=0; i< mb_rows; i++) + { + vpx_free(pbi->mt_yabove_row[i]); + pbi->mt_yabove_row[i] = NULL ; + } + vpx_free(pbi->mt_yabove_row); + pbi->mt_yabove_row = NULL ; + } + + if (pbi->mt_uabove_row) + { + for (i=0; i< mb_rows; i++) + { + vpx_free(pbi->mt_uabove_row[i]); + pbi->mt_uabove_row[i] = NULL ; + } + vpx_free(pbi->mt_uabove_row); + pbi->mt_uabove_row = NULL ; + } + + if (pbi->mt_vabove_row) + { + for (i=0; i< mb_rows; i++) + { + vpx_free(pbi->mt_vabove_row[i]); + pbi->mt_vabove_row[i] = NULL ; + } + vpx_free(pbi->mt_vabove_row); + pbi->mt_vabove_row = NULL ; + } + + /* Free left_col buffers. */ + if (pbi->mt_yleft_col) + { + for (i=0; i< mb_rows; i++) + { + vpx_free(pbi->mt_yleft_col[i]); + pbi->mt_yleft_col[i] = NULL ; + } + vpx_free(pbi->mt_yleft_col); + pbi->mt_yleft_col = NULL ; + } + + if (pbi->mt_uleft_col) + { + for (i=0; i< mb_rows; i++) + { + vpx_free(pbi->mt_uleft_col[i]); + pbi->mt_uleft_col[i] = NULL ; + } + vpx_free(pbi->mt_uleft_col); + pbi->mt_uleft_col = NULL ; + } + + if (pbi->mt_vleft_col) + { + for (i=0; i< mb_rows; i++) + { + vpx_free(pbi->mt_vleft_col[i]); + pbi->mt_vleft_col[i] = NULL ; + } + vpx_free(pbi->mt_vleft_col); + pbi->mt_vleft_col = NULL ; + } + } +} + + +void vp8mt_alloc_temp_buffers(VP8D_COMP *pbi, int width, int prev_mb_rows) +{ + VP8_COMMON *const pc = & pbi->common; + int i; + int uv_width; + + if (pbi->b_multithreaded_rd) + { + vp8mt_de_alloc_temp_buffers(pbi, prev_mb_rows); + + /* our internal buffers are always multiples of 16 */ + if ((width & 0xf) != 0) + width += 16 - (width & 0xf); + + if (width < 640) pbi->sync_range = 1; + else if (width <= 1280) pbi->sync_range = 8; + else if (width <= 2560) pbi->sync_range =16; + else pbi->sync_range = 32; + + uv_width = width >>1; + + /* Allocate an int for each mb row. */ + CHECK_MEM_ERROR(pbi->mt_current_mb_col, vpx_malloc(sizeof(int) * pc->mb_rows)); + + /* Allocate memory for above_row buffers. */ + CHECK_MEM_ERROR(pbi->mt_yabove_row, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); + for (i=0; i< pc->mb_rows; i++) + CHECK_MEM_ERROR(pbi->mt_yabove_row[i], vpx_memalign(16,sizeof(unsigned char) * (width + (VP8BORDERINPIXELS<<1)))); + + CHECK_MEM_ERROR(pbi->mt_uabove_row, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); + for (i=0; i< pc->mb_rows; i++) + CHECK_MEM_ERROR(pbi->mt_uabove_row[i], vpx_memalign(16,sizeof(unsigned char) * (uv_width + VP8BORDERINPIXELS))); + + CHECK_MEM_ERROR(pbi->mt_vabove_row, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); + for (i=0; i< pc->mb_rows; i++) + CHECK_MEM_ERROR(pbi->mt_vabove_row[i], vpx_memalign(16,sizeof(unsigned char) * (uv_width + VP8BORDERINPIXELS))); + + /* Allocate memory for left_col buffers. */ + CHECK_MEM_ERROR(pbi->mt_yleft_col, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); + for (i=0; i< pc->mb_rows; i++) + CHECK_MEM_ERROR(pbi->mt_yleft_col[i], vpx_calloc(sizeof(unsigned char) * 16, 1)); + + CHECK_MEM_ERROR(pbi->mt_uleft_col, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); + for (i=0; i< pc->mb_rows; i++) + CHECK_MEM_ERROR(pbi->mt_uleft_col[i], vpx_calloc(sizeof(unsigned char) * 8, 1)); + + CHECK_MEM_ERROR(pbi->mt_vleft_col, vpx_malloc(sizeof(unsigned char *) * pc->mb_rows)); + for (i=0; i< pc->mb_rows; i++) + CHECK_MEM_ERROR(pbi->mt_vleft_col[i], vpx_calloc(sizeof(unsigned char) * 8, 1)); + } +} + + +void vp8_decoder_remove_threads(VP8D_COMP *pbi) +{ + /* shutdown MB Decoding thread; */ + if (pbi->b_multithreaded_rd) + { + int i; + + pbi->b_multithreaded_rd = 0; + + /* allow all threads to exit */ + for (i = 0; i < pbi->allocated_decoding_thread_count; i++) + { + sem_post(&pbi->h_event_start_decoding[i]); + pthread_join(pbi->h_decoding_thread[i], NULL); + } + + for (i = 0; i < pbi->allocated_decoding_thread_count; i++) + { + sem_destroy(&pbi->h_event_start_decoding[i]); + } + + sem_destroy(&pbi->h_event_end_decoding); + + vpx_free(pbi->h_decoding_thread); + pbi->h_decoding_thread = NULL; + + vpx_free(pbi->h_event_start_decoding); + pbi->h_event_start_decoding = NULL; + + vpx_free(pbi->mb_row_di); + pbi->mb_row_di = NULL ; + + vpx_free(pbi->de_thread_data); + pbi->de_thread_data = NULL; + } +} + +void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + VP8_COMMON *pc = &pbi->common; + int i; + + int filter_level = pc->filter_level; + + if (filter_level) + { + /* Set above_row buffer to 127 for decoding first MB row */ + vpx_memset(pbi->mt_yabove_row[0] + VP8BORDERINPIXELS-1, 127, pc->yv12_fb[pc->lst_fb_idx].y_width + 5); + vpx_memset(pbi->mt_uabove_row[0] + (VP8BORDERINPIXELS>>1)-1, 127, (pc->yv12_fb[pc->lst_fb_idx].y_width>>1) +5); + vpx_memset(pbi->mt_vabove_row[0] + (VP8BORDERINPIXELS>>1)-1, 127, (pc->yv12_fb[pc->lst_fb_idx].y_width>>1) +5); + + for (i=1; imb_rows; i++) + { + vpx_memset(pbi->mt_yabove_row[i] + VP8BORDERINPIXELS-1, (unsigned char)129, 1); + vpx_memset(pbi->mt_uabove_row[i] + (VP8BORDERINPIXELS>>1)-1, (unsigned char)129, 1); + vpx_memset(pbi->mt_vabove_row[i] + (VP8BORDERINPIXELS>>1)-1, (unsigned char)129, 1); + } + + /* Set left_col to 129 initially */ + for (i=0; imb_rows; i++) + { + vpx_memset(pbi->mt_yleft_col[i], (unsigned char)129, 16); + vpx_memset(pbi->mt_uleft_col[i], (unsigned char)129, 8); + vpx_memset(pbi->mt_vleft_col[i], (unsigned char)129, 8); + } + + /* Initialize the loop filter for this frame. */ + vp8_loop_filter_frame_init(pc, &pbi->mb, filter_level); + } + + setup_decoding_thread_data(pbi, xd, pbi->mb_row_di, pbi->decoding_thread_count); + + for (i = 0; i < pbi->decoding_thread_count; i++) + sem_post(&pbi->h_event_start_decoding[i]); + + decode_mb_rows(pbi, xd, 0, init_current_bc); + + sem_wait(&pbi->h_event_end_decoding); /* add back for each frame */ +} diff --git a/vp8/decoder/treereader.h b/vp8/decoder/treereader.h new file mode 100644 index 0000000..238ff85 --- /dev/null +++ b/vp8/decoder/treereader.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef tree_reader_h +#define tree_reader_h 1 + +#include "vp8/common/treecoder.h" + +#include "dboolhuff.h" + +typedef BOOL_DECODER vp8_reader; + +#define vp8_read vp8dx_decode_bool +#define vp8_read_literal vp8_decode_value +#define vp8_read_bit( R) vp8_read( R, vp8_prob_half) + + +/* Intent of tree data structure is to make decoding trivial. */ + +static int vp8_treed_read( + vp8_reader *const r, /* !!! must return a 0 or 1 !!! */ + vp8_tree t, + const vp8_prob *const p +) +{ + register vp8_tree_index i = 0; + + while ((i = t[ i + vp8_read(r, p[i>>1])]) > 0) ; + + return -i; +} + +#endif /* tree_reader_h */ diff --git a/vp8/encoder/arm/armv5te/boolhuff_armv5te.asm b/vp8/encoder/arm/armv5te/boolhuff_armv5te.asm new file mode 100644 index 0000000..a644a00 --- /dev/null +++ b/vp8/encoder/arm/armv5te/boolhuff_armv5te.asm @@ -0,0 +1,310 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_start_encode| + EXPORT |vp8_encode_bool| + EXPORT |vp8_stop_encode| + EXPORT |vp8_encode_value| + IMPORT |vp8_validate_buffer_arm| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + + ; macro for validating write buffer position + ; needs vp8_writer in r0 + ; start shall not be in r1 + MACRO + VALIDATE_POS $start, $pos + push {r0-r3, r12, lr} ; rest of regs are preserved by subroutine call + ldr r2, [r0, #vp8_writer_buffer_end] + ldr r3, [r0, #vp8_writer_error] + mov r1, $pos + mov r0, $start + bl vp8_validate_buffer_arm + pop {r0-r3, r12, lr} + MEND + +; r0 BOOL_CODER *br +; r1 unsigned char *source +; r2 unsigned char *source_end +|vp8_start_encode| PROC + str r2, [r0, #vp8_writer_buffer_end] + mov r12, #0 + mov r3, #255 + mvn r2, #23 + str r12, [r0, #vp8_writer_lowvalue] + str r3, [r0, #vp8_writer_range] + str r2, [r0, #vp8_writer_count] + str r12, [r0, #vp8_writer_pos] + str r1, [r0, #vp8_writer_buffer] + bx lr + ENDP + +; r0 BOOL_CODER *br +; r1 int bit +; r2 int probability +|vp8_encode_bool| PROC + push {r4-r10, lr} + + mov r4, r2 + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + + sub r7, r5, #1 ; range-1 + + cmp r1, #0 + mul r6, r4, r7 ; ((range-1) * probability) + + mov r7, #1 + add r4, r7, r6, lsr #8 ; 1 + (((range-1) * probability) >> 8) + + addne r2, r2, r4 ; if (bit) lowvalue += split + subne r4, r5, r4 ; if (bit) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r9, #0 + strb r9, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r1, [r7, r4] + cmpge r1, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r9, [r7, r4] ; w->buffer[x] + add r9, r9, #1 + strb r9, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r9, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r1, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r1, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r9, r1 ; validate_buffer at pos + + strb r7, [r9, r4] ; w->buffer[w->pos++] + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + pop {r4-r10, pc} + ENDP + +; r0 BOOL_CODER *br +|vp8_stop_encode| PROC + push {r4-r10, lr} + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + + mov r10, #32 + +stop_encode_loop + sub r7, r5, #1 ; range-1 + + mov r4, r7, lsl #7 ; ((range-1) * 128) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * 128) >> 8) + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero_se ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set_se + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start_se +token_zero_while_loop_se + mov r9, #0 + strb r9, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start_se + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r1, [r7, r4] + cmpge r1, #0xff + beq token_zero_while_loop_se + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r9, [r7, r4] ; w->buffer[x] + add r9, r9, #1 + strb r9, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set_se + rsb r4, r6, #24 ; 24-offset + ldr r9, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r1, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r1, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r9, r1 ; validate_buffer at pos + + strb r7, [r9, r4] ; w->buffer[w->pos++] + +token_count_lt_zero_se + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r10, r10, #1 + bne stop_encode_loop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + pop {r4-r10, pc} + + ENDP + +; r0 BOOL_CODER *br +; r1 int data +; r2 int bits +|vp8_encode_value| PROC + push {r4-r12, lr} + + mov r10, r2 + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + + rsb r4, r10, #32 ; 32-n + + ; v is kept in r1 during the token pack loop + lsl r1, r1, r4 ; r1 = v << 32 - n + +encode_value_loop + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsls r1, r1, #1 ; bit = v >> n + mov r4, r7, lsl #7 ; ((range-1) * 128) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * 128) >> 8) + + addcs r2, r2, r4 ; if (bit) lowvalue += split + subcs r4, r5, r4 ; if (bit) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero_ev ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set_ev + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start_ev +token_zero_while_loop_ev + mov r9, #0 + strb r9, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start_ev + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop_ev + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r9, [r7, r4] ; w->buffer[x] + add r9, r9, #1 + strb r9, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set_ev + rsb r4, r6, #24 ; 24-offset + ldr r9, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r9, r11 ; validate_buffer at pos + + strb r7, [r9, r4] ; w->buffer[w->pos++] + +token_count_lt_zero_ev + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r10, r10, #1 + bne encode_value_loop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + pop {r4-r12, pc} + ENDP + + END diff --git a/vp8/encoder/arm/armv5te/vp8_packtokens_armv5.asm b/vp8/encoder/arm/armv5te/vp8_packtokens_armv5.asm new file mode 100644 index 0000000..a1cd467 --- /dev/null +++ b/vp8/encoder/arm/armv5te/vp8_packtokens_armv5.asm @@ -0,0 +1,317 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8cx_pack_tokens_armv5| + IMPORT |vp8_validate_buffer_arm| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + + + ; macro for validating write buffer position + ; needs vp8_writer in r0 + ; start shall not be in r1 + MACRO + VALIDATE_POS $start, $pos + push {r0-r3, r12, lr} ; rest of regs are preserved by subroutine call + ldr r2, [r0, #vp8_writer_buffer_end] + ldr r3, [r0, #vp8_writer_error] + mov r1, $pos + mov r0, $start + bl vp8_validate_buffer_arm + pop {r0-r3, r12, lr} + MEND + + +; r0 vp8_writer *w +; r1 const TOKENEXTRA *p +; r2 int xcount +; r3 vp8_coef_encodings +; s0 vp8_extra_bits +; s1 vp8_coef_tree +|vp8cx_pack_tokens_armv5| PROC + push {r4-r12, lr} + sub sp, sp, #16 + + ; Add size of xcount * sizeof (TOKENEXTRA) to get stop + ; sizeof (TOKENEXTRA) is 8 + add r2, r1, r2, lsl #3 ; stop = p + xcount*sizeof(TOKENEXTRA) + str r2, [sp, #0] + str r3, [sp, #8] ; save vp8_coef_encodings + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + b check_p_lt_stop + +while_p_lt_stop + ldrb r6, [r1, #tokenextra_token] ; t + ldr r4, [sp, #8] ; vp8_coef_encodings + mov lr, #0 + add r4, r4, r6, lsl #3 ; a = vp8_coef_encodings + t + ldr r9, [r1, #tokenextra_context_tree] ; pp + + ldrb r7, [r1, #tokenextra_skip_eob_node] + + ldr r6, [r4, #vp8_token_value] ; v + ldr r8, [r4, #vp8_token_len] ; n + + ; vp8 specific skip_eob_node + cmp r7, #0 + movne lr, #2 ; i = 2 + subne r8, r8, #1 ; --n + + rsb r4, r8, #32 ; 32-n + ldr r10, [sp, #60] ; vp8_coef_tree + + ; v is kept in r12 during the token pack loop + lsl r12, r6, r4 ; r12 = v << 32 - n + +; loop start +token_loop + ldrb r4, [r9, lr, asr #1] ; pp [i>>1] + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsls r12, r12, #1 ; bb = v >> n + mul r6, r4, r7 ; ((range-1) * pp[i>>1])) + + ; bb can only be 0 or 1. So only execute this statement + ; if bb == 1, otherwise it will act like i + 0 + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = vp8_coef_tree[i+bb] + add r4, r7, r6, lsr #8 ; 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++] + + ; r10 is used earlier in the loop, but r10 is used as + ; temp variable here. So after r10 is used, reload + ; vp8_coef_tree_dcd into r10 + ldr r10, [sp, #60] ; vp8_coef_tree + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r8, r8, #1 ; --n + bne token_loop + + ldrb r6, [r1, #tokenextra_token] ; t + ldr r7, [sp, #56] ; vp8_extra_bits + ; Add t * sizeof (vp8_extra_bit_struct) to get the desired + ; element. Here vp8_extra_bit_struct == 16 + add r12, r7, r6, lsl #4 ; b = vp8_extra_bits + t + + ldr r4, [r12, #vp8_extra_bit_struct_base_val] + cmp r4, #0 + beq skip_extra_bits + +; if( b->base_val) + ldr r8, [r12, #vp8_extra_bit_struct_len] ; L + ldrsh lr, [r1, #tokenextra_extra] ; e = p->Extra + cmp r8, #0 ; if( L) + beq no_extra_bits + + ldr r9, [r12, #vp8_extra_bit_struct_prob] + asr r7, lr, #1 ; v=e>>1 + + ldr r10, [r12, #vp8_extra_bit_struct_tree] + str r10, [sp, #4] ; b->tree + + rsb r4, r8, #32 + lsl r12, r7, r4 + + mov lr, #0 ; i = 0 + +extra_bits_loop + ldrb r4, [r9, lr, asr #1] ; pp[i>>1] + sub r7, r5, #1 ; range-1 + lsls r12, r12, #1 ; v >> n + mul r6, r4, r7 ; (range-1) * pp[i>>1] + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = b->tree[i+bb] + add r4, r7, r6, lsr #8 ; split = 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + clz r6, r4 + sub r6, r6, #24 + + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi extra_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset= shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl extra_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos - 1 + b extra_zero_while_start +extra_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +extra_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq extra_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] + add r10, r10, #1 + strb r10, [r7, r4] +extra_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++]=(lowvalue >> (24-offset)) + ldr r10, [sp, #4] ; b->tree +extra_count_lt_zero + lsl r2, r2, r6 + + subs r8, r8, #1 ; --n + bne extra_bits_loop ; while (n) + +no_extra_bits + ldr lr, [r1, #4] ; e = p->Extra + add r4, r5, #1 ; range + 1 + tst lr, #1 + lsr r4, r4, #1 ; split = (range + 1) >> 1 + addne r2, r2, r4 ; lowvalue += split + subne r4, r5, r4 ; range = range-split + tst r2, #0x80000000 ; lowvalue & 0x80000000 + lsl r5, r4, #1 ; range <<= 1 + beq end_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] + mov r7, #0 + sub r4, r4, #1 + b end_zero_while_start +end_zero_while_loop + strb r7, [r6, r4] + sub r4, r4, #1 ; x-- +end_zero_while_start + cmp r4, #0 + ldrge r6, [r0, #vp8_writer_buffer] + ldrb r12, [r6, r4] + cmpge r12, #0xff + beq end_zero_while_loop + + ldr r6, [r0, #vp8_writer_buffer] + ldrb r7, [r6, r4] + add r7, r7, #1 + strb r7, [r6, r4] +end_high_bit_not_set + adds r3, r3, #1 ; ++count + lsl r2, r2, #1 ; lowvalue <<= 1 + bne end_count_zero + + ldr r4, [r0, #vp8_writer_pos] + mvn r3, #7 + ldr r7, [r0, #vp8_writer_buffer] + lsr r6, r2, #24 ; lowvalue >> 24 + add r12, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r12, [r0, #vp8_writer_pos] + + VALIDATE_POS r7, r12 ; validate_buffer at pos + + strb r6, [r7, r4] +end_count_zero +skip_extra_bits + add r1, r1, #TOKENEXTRA_SZ ; ++p +check_p_lt_stop + ldr r4, [sp, #0] ; stop + cmp r1, r4 ; while( p < stop) + bcc while_p_lt_stop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + add sp, sp, #16 + pop {r4-r12, pc} + ENDP + + END diff --git a/vp8/encoder/arm/armv5te/vp8_packtokens_mbrow_armv5.asm b/vp8/encoder/arm/armv5te/vp8_packtokens_mbrow_armv5.asm new file mode 100644 index 0000000..1fa5e6c --- /dev/null +++ b/vp8/encoder/arm/armv5te/vp8_packtokens_mbrow_armv5.asm @@ -0,0 +1,352 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8cx_pack_mb_row_tokens_armv5| + IMPORT |vp8_validate_buffer_arm| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + + + ; macro for validating write buffer position + ; needs vp8_writer in r0 + ; start shall not be in r1 + MACRO + VALIDATE_POS $start, $pos + push {r0-r3, r12, lr} ; rest of regs are preserved by subroutine call + ldr r2, [r0, #vp8_writer_buffer_end] + ldr r3, [r0, #vp8_writer_error] + mov r1, $pos + mov r0, $start + bl vp8_validate_buffer_arm + pop {r0-r3, r12, lr} + MEND + +; r0 VP8_COMP *cpi +; r1 vp8_writer *w +; r2 vp8_coef_encodings +; r3 vp8_extra_bits +; s0 vp8_coef_tree + +|vp8cx_pack_mb_row_tokens_armv5| PROC + push {r4-r12, lr} + sub sp, sp, #24 + + ; Compute address of cpi->common.mb_rows + ldr r4, _VP8_COMP_common_ + ldr r6, _VP8_COMMON_MBrows_ + add r4, r0, r4 + + ldr r5, [r4, r6] ; load up mb_rows + + str r2, [sp, #20] ; save vp8_coef_encodings + str r5, [sp, #12] ; save mb_rows + str r3, [sp, #8] ; save vp8_extra_bits + + ldr r4, _VP8_COMP_tplist_ + add r4, r0, r4 + ldr r7, [r4, #0] ; dereference cpi->tp_list + + mov r0, r1 ; keep same as other loops + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + +mb_row_loop + + ldr r1, [r7, #tokenlist_start] + ldr r9, [r7, #tokenlist_stop] + str r9, [sp, #0] ; save stop for later comparison + str r7, [sp, #16] ; tokenlist address for next time + + b check_p_lt_stop + + ; actuall work gets done here! + +while_p_lt_stop + ldrb r6, [r1, #tokenextra_token] ; t + ldr r4, [sp, #20] ; vp8_coef_encodings + mov lr, #0 + add r4, r4, r6, lsl #3 ; a = vp8_coef_encodings + t + ldr r9, [r1, #tokenextra_context_tree] ; pp + + ldrb r7, [r1, #tokenextra_skip_eob_node] + + ldr r6, [r4, #vp8_token_value] ; v + ldr r8, [r4, #vp8_token_len] ; n + + ; vp8 specific skip_eob_node + cmp r7, #0 + movne lr, #2 ; i = 2 + subne r8, r8, #1 ; --n + + rsb r4, r8, #32 ; 32-n + ldr r10, [sp, #64] ; vp8_coef_tree + + ; v is kept in r12 during the token pack loop + lsl r12, r6, r4 ; r12 = v << 32 - n + +; loop start +token_loop + ldrb r4, [r9, lr, asr #1] ; pp [i>>1] + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsls r12, r12, #1 ; bb = v >> n + mul r6, r4, r7 ; ((range-1) * pp[i>>1])) + + ; bb can only be 0 or 1. So only execute this statement + ; if bb == 1, otherwise it will act like i + 0 + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = vp8_coef_tree[i+bb] + add r4, r7, r6, lsr #8 ; 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++] + + ; r10 is used earlier in the loop, but r10 is used as + ; temp variable here. So after r10 is used, reload + ; vp8_coef_tree_dcd into r10 + ldr r10, [sp, #64] ; vp8_coef_tree + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r8, r8, #1 ; --n + bne token_loop + + ldrb r6, [r1, #tokenextra_token] ; t + ldr r7, [sp, #8] ; vp8_extra_bits + ; Add t * sizeof (vp8_extra_bit_struct) to get the desired + ; element. Here vp8_extra_bit_struct == 16 + add r12, r7, r6, lsl #4 ; b = vp8_extra_bits + t + + ldr r4, [r12, #vp8_extra_bit_struct_base_val] + cmp r4, #0 + beq skip_extra_bits + +; if( b->base_val) + ldr r8, [r12, #vp8_extra_bit_struct_len] ; L + ldrsh lr, [r1, #tokenextra_extra] ; e = p->Extra + cmp r8, #0 ; if( L) + beq no_extra_bits + + ldr r9, [r12, #vp8_extra_bit_struct_prob] + asr r7, lr, #1 ; v=e>>1 + + ldr r10, [r12, #vp8_extra_bit_struct_tree] + str r10, [sp, #4] ; b->tree + + rsb r4, r8, #32 + lsl r12, r7, r4 + + mov lr, #0 ; i = 0 + +extra_bits_loop + ldrb r4, [r9, lr, asr #1] ; pp[i>>1] + sub r7, r5, #1 ; range-1 + lsls r12, r12, #1 ; v >> n + mul r6, r4, r7 ; (range-1) * pp[i>>1] + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = b->tree[i+bb] + add r4, r7, r6, lsr #8 ; split = 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + clz r6, r4 + sub r6, r6, #24 + + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi extra_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset= shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl extra_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos - 1 + b extra_zero_while_start +extra_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +extra_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq extra_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] + add r10, r10, #1 + strb r10, [r7, r4] +extra_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++]=(lowvalue >> (24-offset)) + ldr r10, [sp, #4] ; b->tree +extra_count_lt_zero + lsl r2, r2, r6 + + subs r8, r8, #1 ; --n + bne extra_bits_loop ; while (n) + +no_extra_bits + ldr lr, [r1, #4] ; e = p->Extra + add r4, r5, #1 ; range + 1 + tst lr, #1 + lsr r4, r4, #1 ; split = (range + 1) >> 1 + addne r2, r2, r4 ; lowvalue += split + subne r4, r5, r4 ; range = range-split + tst r2, #0x80000000 ; lowvalue & 0x80000000 + lsl r5, r4, #1 ; range <<= 1 + beq end_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] + mov r7, #0 + sub r4, r4, #1 + b end_zero_while_start +end_zero_while_loop + strb r7, [r6, r4] + sub r4, r4, #1 ; x-- +end_zero_while_start + cmp r4, #0 + ldrge r6, [r0, #vp8_writer_buffer] + ldrb r12, [r6, r4] + cmpge r12, #0xff + beq end_zero_while_loop + + ldr r6, [r0, #vp8_writer_buffer] + ldrb r7, [r6, r4] + add r7, r7, #1 + strb r7, [r6, r4] +end_high_bit_not_set + adds r3, r3, #1 ; ++count + lsl r2, r2, #1 ; lowvalue <<= 1 + bne end_count_zero + + ldr r4, [r0, #vp8_writer_pos] + mvn r3, #7 + ldr r7, [r0, #vp8_writer_buffer] + lsr r6, r2, #24 ; lowvalue >> 24 + add r12, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r12, [r0, #vp8_writer_pos] + + VALIDATE_POS r7, r12 ; validate_buffer at pos + + strb r6, [r7, r4] +end_count_zero +skip_extra_bits + add r1, r1, #TOKENEXTRA_SZ ; ++p +check_p_lt_stop + ldr r4, [sp, #0] ; stop + cmp r1, r4 ; while( p < stop) + bcc while_p_lt_stop + + ldr r6, [sp, #12] ; mb_rows + ldr r7, [sp, #16] ; tokenlist address + subs r6, r6, #1 + add r7, r7, #TOKENLIST_SZ ; next element in the array + str r6, [sp, #12] + bne mb_row_loop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + add sp, sp, #24 + pop {r4-r12, pc} + ENDP + +_VP8_COMP_common_ + DCD vp8_comp_common +_VP8_COMMON_MBrows_ + DCD vp8_common_mb_rows +_VP8_COMP_tplist_ + DCD vp8_comp_tplist + + END diff --git a/vp8/encoder/arm/armv5te/vp8_packtokens_partitions_armv5.asm b/vp8/encoder/arm/armv5te/vp8_packtokens_partitions_armv5.asm new file mode 100644 index 0000000..90a98fe --- /dev/null +++ b/vp8/encoder/arm/armv5te/vp8_packtokens_partitions_armv5.asm @@ -0,0 +1,471 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8cx_pack_tokens_into_partitions_armv5| + IMPORT |vp8_validate_buffer_arm| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + + ; macro for validating write buffer position + ; needs vp8_writer in r0 + ; start shall not be in r1 + MACRO + VALIDATE_POS $start, $pos + push {r0-r3, r12, lr} ; rest of regs are preserved by subroutine call + ldr r2, [r0, #vp8_writer_buffer_end] + ldr r3, [r0, #vp8_writer_error] + mov r1, $pos + mov r0, $start + bl vp8_validate_buffer_arm + pop {r0-r3, r12, lr} + MEND + +; r0 VP8_COMP *cpi +; r1 unsigned char *cx_data +; r2 const unsigned char *cx_data_end +; r3 int num_part +; s0 vp8_coef_encodings +; s1 vp8_extra_bits, +; s2 const vp8_tree_index * + +|vp8cx_pack_tokens_into_partitions_armv5| PROC + push {r4-r12, lr} + sub sp, sp, #40 + + ; Compute address of cpi->common.mb_rows + ldr r4, _VP8_COMP_common_ + ldr r6, _VP8_COMMON_MBrows_ + add r4, r0, r4 + + ldr r5, [r4, r6] ; load up mb_rows + + str r5, [sp, #36] ; save mb_rows + str r1, [sp, #24] ; save ptr = cx_data + str r3, [sp, #20] ; save num_part + str r2, [sp, #8] ; save cx_data_end + + ldr r4, _VP8_COMP_tplist_ + add r4, r0, r4 + ldr r7, [r4, #0] ; dereference cpi->tp_list + str r7, [sp, #32] ; store start of cpi->tp_list + + ldr r11, _VP8_COMP_bc_ ; load up vp8_writer out of cpi + add r0, r0, r11 + + mov r11, #0 + str r11, [sp, #28] ; i + +numparts_loop + ldr r2, _vp8_writer_sz_ ; load up sizeof(vp8_writer) + add r0, r2 ; bc[i + 1] + + ldr r10, [sp, #24] ; ptr + ldr r5, [sp, #36] ; move mb_rows to the counting section + subs r5, r5, r11 ; move start point with each partition + ; mb_rows starts at i + str r5, [sp, #12] + + ; Reset all of the VP8 Writer data for each partition that + ; is processed. + ; start_encode + + ldr r3, [sp, #8] + str r3, [r0, #vp8_writer_buffer_end] + + mov r2, #0 ; vp8_writer_lowvalue + mov r5, #255 ; vp8_writer_range + mvn r3, #23 ; vp8_writer_count + + str r2, [r0, #vp8_writer_pos] + str r10, [r0, #vp8_writer_buffer] + + ble end_partition ; if (mb_rows <= 0) end partition + +mb_row_loop + + ldr r1, [r7, #tokenlist_start] + ldr r9, [r7, #tokenlist_stop] + str r9, [sp, #0] ; save stop for later comparison + str r7, [sp, #16] ; tokenlist address for next time + + b check_p_lt_stop + + ; actual work gets done here! + +while_p_lt_stop + ldrb r6, [r1, #tokenextra_token] ; t + ldr r4, [sp, #80] ; vp8_coef_encodings + mov lr, #0 + add r4, r4, r6, lsl #3 ; a = vp8_coef_encodings + t + ldr r9, [r1, #tokenextra_context_tree] ; pp + + ldrb r7, [r1, #tokenextra_skip_eob_node] + + ldr r6, [r4, #vp8_token_value] ; v + ldr r8, [r4, #vp8_token_len] ; n + + ; vp8 specific skip_eob_node + cmp r7, #0 + movne lr, #2 ; i = 2 + subne r8, r8, #1 ; --n + + rsb r4, r8, #32 ; 32-n + ldr r10, [sp, #88] ; vp8_coef_tree + + ; v is kept in r12 during the token pack loop + lsl r12, r6, r4 ; r12 = v << 32 - n + +; loop start +token_loop + ldrb r4, [r9, lr, asr #1] ; pp [i>>1] + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsls r12, r12, #1 ; bb = v >> n + mul r6, r4, r7 ; ((range-1) * pp[i>>1])) + + ; bb can only be 0 or 1. So only execute this statement + ; if bb == 1, otherwise it will act like i + 0 + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = vp8_coef_tree[i+bb] + add r4, r7, r6, lsr #8 ; 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++] + + ; r10 is used earlier in the loop, but r10 is used as + ; temp variable here. So after r10 is used, reload + ; vp8_coef_tree_dcd into r10 + ldr r10, [sp, #88] ; vp8_coef_tree + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r8, r8, #1 ; --n + bne token_loop + + ldrb r6, [r1, #tokenextra_token] ; t + ldr r7, [sp, #84] ; vp8_extra_bits + ; Add t * sizeof (vp8_extra_bit_struct) to get the desired + ; element. Here vp8_extra_bit_struct == 16 + add r12, r7, r6, lsl #4 ; b = vp8_extra_bits + t + + ldr r4, [r12, #vp8_extra_bit_struct_base_val] + cmp r4, #0 + beq skip_extra_bits + +; if( b->base_val) + ldr r8, [r12, #vp8_extra_bit_struct_len] ; L + ldrsh lr, [r1, #tokenextra_extra] ; e = p->Extra + cmp r8, #0 ; if( L) + beq no_extra_bits + + ldr r9, [r12, #vp8_extra_bit_struct_prob] + asr r7, lr, #1 ; v=e>>1 + + ldr r10, [r12, #vp8_extra_bit_struct_tree] + str r10, [sp, #4] ; b->tree + + rsb r4, r8, #32 + lsl r12, r7, r4 + + mov lr, #0 ; i = 0 + +extra_bits_loop + ldrb r4, [r9, lr, asr #1] ; pp[i>>1] + sub r7, r5, #1 ; range-1 + lsls r12, r12, #1 ; v >> n + mul r6, r4, r7 ; (range-1) * pp[i>>1] + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = b->tree[i+bb] + add r4, r7, r6, lsr #8 ; split = 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + clz r6, r4 + sub r6, r6, #24 + + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi extra_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset= shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl extra_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos - 1 + b extra_zero_while_start +extra_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +extra_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq extra_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] + add r10, r10, #1 + strb r10, [r7, r4] +extra_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++]=(lowvalue >> (24-offset)) + ldr r10, [sp, #4] ; b->tree +extra_count_lt_zero + lsl r2, r2, r6 + + subs r8, r8, #1 ; --n + bne extra_bits_loop ; while (n) + +no_extra_bits + ldr lr, [r1, #4] ; e = p->Extra + add r4, r5, #1 ; range + 1 + tst lr, #1 + lsr r4, r4, #1 ; split = (range + 1) >> 1 + addne r2, r2, r4 ; lowvalue += split + subne r4, r5, r4 ; range = range-split + tst r2, #0x80000000 ; lowvalue & 0x80000000 + lsl r5, r4, #1 ; range <<= 1 + beq end_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] + mov r7, #0 + sub r4, r4, #1 + b end_zero_while_start +end_zero_while_loop + strb r7, [r6, r4] + sub r4, r4, #1 ; x-- +end_zero_while_start + cmp r4, #0 + ldrge r6, [r0, #vp8_writer_buffer] + ldrb r12, [r6, r4] + cmpge r12, #0xff + beq end_zero_while_loop + + ldr r6, [r0, #vp8_writer_buffer] + ldrb r7, [r6, r4] + add r7, r7, #1 + strb r7, [r6, r4] +end_high_bit_not_set + adds r3, r3, #1 ; ++count + lsl r2, r2, #1 ; lowvalue <<= 1 + bne end_count_zero + + ldr r4, [r0, #vp8_writer_pos] + mvn r3, #7 ; count = -8 + ldr r7, [r0, #vp8_writer_buffer] + lsr r6, r2, #24 ; lowvalue >> 24 + add r12, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r12, [r0, #vp8_writer_pos] + + VALIDATE_POS r7, r12 ; validate_buffer at pos + + strb r6, [r7, r4] +end_count_zero +skip_extra_bits + add r1, r1, #TOKENEXTRA_SZ ; ++p +check_p_lt_stop + ldr r4, [sp, #0] ; stop + cmp r1, r4 ; while( p < stop) + bcc while_p_lt_stop + + ldr r10, [sp, #20] ; num_parts + mov r1, #TOKENLIST_SZ + mul r1, r10, r1 + + ldr r6, [sp, #12] ; mb_rows + ldr r7, [sp, #16] ; tokenlist address + subs r6, r6, r10 + add r7, r7, r1 ; next element in the array + str r6, [sp, #12] + bgt mb_row_loop + +end_partition + mov r12, #32 + +stop_encode_loop + sub r7, r5, #1 ; range-1 + + mov r4, r7, lsl #7 ; ((range-1) * 128) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * 128) >> 8) + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero_se ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set_se + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start_se +token_zero_while_loop_se + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start_se + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop_se + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set_se + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + + VALIDATE_POS r10, r11 ; validate_buffer at pos + + strb r7, [r10, r4] ; w->buffer[w->pos++] + +token_count_lt_zero_se + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r12, r12, #1 + bne stop_encode_loop + + ldr r4, [r0, #vp8_writer_pos] ; w->pos + ldr r12, [sp, #24] ; ptr + add r12, r12, r4 ; ptr += w->pos + str r12, [sp, #24] + + ldr r11, [sp, #28] ; i + ldr r10, [sp, #20] ; num_parts + + add r11, r11, #1 ; i++ + str r11, [sp, #28] + + ldr r7, [sp, #32] ; cpi->tp_list[i] + mov r1, #TOKENLIST_SZ + add r7, r7, r1 ; next element in cpi->tp_list + str r7, [sp, #32] ; cpi->tp_list[i+1] + + cmp r10, r11 + bgt numparts_loop + + add sp, sp, #40 + pop {r4-r12, pc} + ENDP + +_VP8_COMP_common_ + DCD vp8_comp_common +_VP8_COMMON_MBrows_ + DCD vp8_common_mb_rows +_VP8_COMP_tplist_ + DCD vp8_comp_tplist +_VP8_COMP_bc_ + DCD vp8_comp_bc +_vp8_writer_sz_ + DCD vp8_writer_sz + + END diff --git a/vp8/encoder/arm/armv6/vp8_fast_quantize_b_armv6.asm b/vp8/encoder/arm/armv6/vp8_fast_quantize_b_armv6.asm new file mode 100644 index 0000000..d61f5d9 --- /dev/null +++ b/vp8/encoder/arm/armv6/vp8_fast_quantize_b_armv6.asm @@ -0,0 +1,225 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_fast_quantize_b_armv6| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 BLOCK *b +; r1 BLOCKD *d +|vp8_fast_quantize_b_armv6| PROC + stmfd sp!, {r1, r4-r11, lr} + + ldr r3, [r0, #vp8_block_coeff] ; coeff + ldr r4, [r0, #vp8_block_quant_fast] ; quant_fast + ldr r5, [r0, #vp8_block_round] ; round + ldr r6, [r1, #vp8_blockd_qcoeff] ; qcoeff + ldr r7, [r1, #vp8_blockd_dqcoeff] ; dqcoeff + ldr r8, [r1, #vp8_blockd_dequant] ; dequant + + ldr r2, loop_count ; loop_count=0x1000000. 'lsls' instruction + ; is used to update the counter so that + ; it can be used to mark nonzero + ; quantized coefficient pairs. + + mov r1, #0 ; flags for quantized coeffs + + ; PART 1: quantization and dequantization loop +loop + ldr r9, [r3], #4 ; [z1 | z0] + ldr r10, [r5], #4 ; [r1 | r0] + ldr r11, [r4], #4 ; [q1 | q0] + + ssat16 lr, #1, r9 ; [sz1 | sz0] + eor r9, r9, lr ; [z1 ^ sz1 | z0 ^ sz0] + ssub16 r9, r9, lr ; x = (z ^ sz) - sz + sadd16 r9, r9, r10 ; [x1+r1 | x0+r0] + + ldr r12, [r3], #4 ; [z3 | z2] + + smulbb r0, r9, r11 ; [(x0+r0)*q0] + smultt r9, r9, r11 ; [(x1+r1)*q1] + + ldr r10, [r5], #4 ; [r3 | r2] + + ssat16 r11, #1, r12 ; [sz3 | sz2] + eor r12, r12, r11 ; [z3 ^ sz3 | z2 ^ sz2] + pkhtb r0, r9, r0, asr #16 ; [y1 | y0] + ldr r9, [r4], #4 ; [q3 | q2] + ssub16 r12, r12, r11 ; x = (z ^ sz) - sz + + sadd16 r12, r12, r10 ; [x3+r3 | x2+r2] + + eor r0, r0, lr ; [(y1 ^ sz1) | (y0 ^ sz0)] + + smulbb r10, r12, r9 ; [(x2+r2)*q2] + smultt r12, r12, r9 ; [(x3+r3)*q3] + + ssub16 r0, r0, lr ; x = (y ^ sz) - sz + + cmp r0, #0 ; check if zero + orrne r1, r1, r2, lsr #24 ; add flag for nonzero coeffs + + str r0, [r6], #4 ; *qcoeff++ = x + ldr r9, [r8], #4 ; [dq1 | dq0] + + pkhtb r10, r12, r10, asr #16 ; [y3 | y2] + eor r10, r10, r11 ; [(y3 ^ sz3) | (y2 ^ sz2)] + ssub16 r10, r10, r11 ; x = (y ^ sz) - sz + + cmp r10, #0 ; check if zero + orrne r1, r1, r2, lsr #23 ; add flag for nonzero coeffs + + str r10, [r6], #4 ; *qcoeff++ = x + ldr r11, [r8], #4 ; [dq3 | dq2] + + smulbb r12, r0, r9 ; [x0*dq0] + smultt r0, r0, r9 ; [x1*dq1] + + smulbb r9, r10, r11 ; [x2*dq2] + smultt r10, r10, r11 ; [x3*dq3] + + lsls r2, r2, #2 ; update loop counter + strh r12, [r7, #0] ; dqcoeff[0] = [x0*dq0] + strh r0, [r7, #2] ; dqcoeff[1] = [x1*dq1] + strh r9, [r7, #4] ; dqcoeff[2] = [x2*dq2] + strh r10, [r7, #6] ; dqcoeff[3] = [x3*dq3] + add r7, r7, #8 ; dqcoeff += 8 + bne loop + + ; PART 2: check position for eob... + ldr r11, [sp, #0] ; restore BLOCKD pointer + mov lr, #0 ; init eob + cmp r1, #0 ; coeffs after quantization? + ldr r12, [r11, #vp8_blockd_eob] + beq end ; skip eob calculations if all zero + + ldr r0, [r11, #vp8_blockd_qcoeff] + + ; check shortcut for nonzero qcoeffs + tst r1, #0x80 + bne quant_coeff_15_14 + tst r1, #0x20 + bne quant_coeff_13_11 + tst r1, #0x8 + bne quant_coeff_12_7 + tst r1, #0x40 + bne quant_coeff_10_9 + tst r1, #0x10 + bne quant_coeff_8_3 + tst r1, #0x2 + bne quant_coeff_6_5 + tst r1, #0x4 + bne quant_coeff_4_2 + b quant_coeff_1_0 + +quant_coeff_15_14 + ldrh r2, [r0, #30] ; rc=15, i=15 + mov lr, #16 + cmp r2, #0 + bne end + + ldrh r3, [r0, #28] ; rc=14, i=14 + mov lr, #15 + cmp r3, #0 + bne end + +quant_coeff_13_11 + ldrh r2, [r0, #22] ; rc=11, i=13 + mov lr, #14 + cmp r2, #0 + bne end + +quant_coeff_12_7 + ldrh r3, [r0, #14] ; rc=7, i=12 + mov lr, #13 + cmp r3, #0 + bne end + + ldrh r2, [r0, #20] ; rc=10, i=11 + mov lr, #12 + cmp r2, #0 + bne end + +quant_coeff_10_9 + ldrh r3, [r0, #26] ; rc=13, i=10 + mov lr, #11 + cmp r3, #0 + bne end + + ldrh r2, [r0, #24] ; rc=12, i=9 + mov lr, #10 + cmp r2, #0 + bne end + +quant_coeff_8_3 + ldrh r3, [r0, #18] ; rc=9, i=8 + mov lr, #9 + cmp r3, #0 + bne end + + ldrh r2, [r0, #12] ; rc=6, i=7 + mov lr, #8 + cmp r2, #0 + bne end + +quant_coeff_6_5 + ldrh r3, [r0, #6] ; rc=3, i=6 + mov lr, #7 + cmp r3, #0 + bne end + + ldrh r2, [r0, #4] ; rc=2, i=5 + mov lr, #6 + cmp r2, #0 + bne end + +quant_coeff_4_2 + ldrh r3, [r0, #10] ; rc=5, i=4 + mov lr, #5 + cmp r3, #0 + bne end + + ldrh r2, [r0, #16] ; rc=8, i=3 + mov lr, #4 + cmp r2, #0 + bne end + + ldrh r3, [r0, #8] ; rc=4, i=2 + mov lr, #3 + cmp r3, #0 + bne end + +quant_coeff_1_0 + ldrh r2, [r0, #2] ; rc=1, i=1 + mov lr, #2 + cmp r2, #0 + bne end + + mov lr, #1 ; rc=0, i=0 + +end + strb lr, [r12] + ldmfd sp!, {r1, r4-r11, pc} + + ENDP + +loop_count + DCD 0x1000000 + + END + diff --git a/vp8/encoder/arm/armv6/vp8_mse16x16_armv6.asm b/vp8/encoder/arm/armv6/vp8_mse16x16_armv6.asm new file mode 100644 index 0000000..000805d --- /dev/null +++ b/vp8/encoder/arm/armv6/vp8_mse16x16_armv6.asm @@ -0,0 +1,138 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_mse16x16_armv6| + + ARM + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +; +;note: Based on vp8_variance16x16_armv6. In this function, sum is never used. +; So, we can remove this part of calculation. + +|vp8_mse16x16_armv6| PROC + + push {r4-r9, lr} + + pld [r0, r1, lsl #0] + pld [r2, r3, lsl #0] + + mov r12, #16 ; set loop counter to 16 (=block height) + mov r4, #0 ; initialize sse = 0 + +loop + ; 1st 4 pixels + ldr r5, [r0, #0x0] ; load 4 src pixels + ldr r6, [r2, #0x0] ; load 4 ref pixels + + mov lr, #0 ; constant zero + + usub8 r8, r5, r6 ; calculate difference + pld [r0, r1, lsl #1] + sel r7, r8, lr ; select bytes with positive difference + usub8 r9, r6, r5 ; calculate difference with reversed operands + pld [r2, r3, lsl #1] + sel r8, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r5, r7, lr ; calculate sum of positive differences + usad8 r6, r8, lr ; calculate sum of negative differences + orr r8, r8, r7 ; differences of all 4 pixels + + ldr r5, [r0, #0x4] ; load 4 src pixels + + ; calculate sse + uxtb16 r6, r8 ; byte (two pixels) to halfwords + uxtb16 r7, r8, ror #8 ; another two pixels to halfwords + smlad r4, r6, r6, r4 ; dual signed multiply, add and accumulate (1) + + ; 2nd 4 pixels + ldr r6, [r2, #0x4] ; load 4 ref pixels + smlad r4, r7, r7, r4 ; dual signed multiply, add and accumulate (2) + + usub8 r8, r5, r6 ; calculate difference + sel r7, r8, lr ; select bytes with positive difference + usub8 r9, r6, r5 ; calculate difference with reversed operands + sel r8, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r5, r7, lr ; calculate sum of positive differences + usad8 r6, r8, lr ; calculate sum of negative differences + orr r8, r8, r7 ; differences of all 4 pixels + ldr r5, [r0, #0x8] ; load 4 src pixels + ; calculate sse + uxtb16 r6, r8 ; byte (two pixels) to halfwords + uxtb16 r7, r8, ror #8 ; another two pixels to halfwords + smlad r4, r6, r6, r4 ; dual signed multiply, add and accumulate (1) + + ; 3rd 4 pixels + ldr r6, [r2, #0x8] ; load 4 ref pixels + smlad r4, r7, r7, r4 ; dual signed multiply, add and accumulate (2) + + usub8 r8, r5, r6 ; calculate difference + sel r7, r8, lr ; select bytes with positive difference + usub8 r9, r6, r5 ; calculate difference with reversed operands + sel r8, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r5, r7, lr ; calculate sum of positive differences + usad8 r6, r8, lr ; calculate sum of negative differences + orr r8, r8, r7 ; differences of all 4 pixels + + ldr r5, [r0, #0xc] ; load 4 src pixels + + ; calculate sse + uxtb16 r6, r8 ; byte (two pixels) to halfwords + uxtb16 r7, r8, ror #8 ; another two pixels to halfwords + smlad r4, r6, r6, r4 ; dual signed multiply, add and accumulate (1) + + ; 4th 4 pixels + ldr r6, [r2, #0xc] ; load 4 ref pixels + smlad r4, r7, r7, r4 ; dual signed multiply, add and accumulate (2) + + usub8 r8, r5, r6 ; calculate difference + add r0, r0, r1 ; set src_ptr to next row + sel r7, r8, lr ; select bytes with positive difference + usub8 r9, r6, r5 ; calculate difference with reversed operands + add r2, r2, r3 ; set dst_ptr to next row + sel r8, r9, lr ; select bytes with negative difference + + ; calculate partial sums + usad8 r5, r7, lr ; calculate sum of positive differences + usad8 r6, r8, lr ; calculate sum of negative differences + orr r8, r8, r7 ; differences of all 4 pixels + + subs r12, r12, #1 ; next row + + ; calculate sse + uxtb16 r6, r8 ; byte (two pixels) to halfwords + uxtb16 r7, r8, ror #8 ; another two pixels to halfwords + smlad r4, r6, r6, r4 ; dual signed multiply, add and accumulate (1) + smlad r4, r7, r7, r4 ; dual signed multiply, add and accumulate (2) + + bne loop + + ; return stuff + ldr r1, [sp, #28] ; get address of sse + mov r0, r4 ; return sse + str r4, [r1] ; store sse + + pop {r4-r9, pc} + + ENDP + + END diff --git a/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm b/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm new file mode 100644 index 0000000..8034c1d --- /dev/null +++ b/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm @@ -0,0 +1,262 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + EXPORT |vp8_short_fdct4x4_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY +; void vp8_short_fdct4x4_c(short *input, short *output, int pitch) +|vp8_short_fdct4x4_armv6| PROC + + stmfd sp!, {r4 - r12, lr} + + ; PART 1 + + ; coeffs 0-3 + ldrd r4, r5, [r0] ; [i1 | i0] [i3 | i2] + + ldr r10, c7500 + ldr r11, c14500 + ldr r12, c0x22a453a0 ; [2217*4 | 5352*4] + ldr lr, c0x00080008 + ror r5, r5, #16 ; [i2 | i3] + + qadd16 r6, r4, r5 ; [i1+i2 | i0+i3] = [b1 | a1] without shift + qsub16 r7, r4, r5 ; [i1-i2 | i0-i3] = [c1 | d1] without shift + + add r0, r0, r2 ; update input pointer + + qadd16 r7, r7, r7 ; 2*[c1|d1] --> we can use smlad and smlsd + ; with 2217*4 and 5352*4 without losing the + ; sign bit (overflow) + + smuad r4, r6, lr ; o0 = (i1+i2)*8 + (i0+i3)*8 + smusd r5, r6, lr ; o2 = (i1+i2)*8 - (i0+i3)*8 + + smlad r6, r7, r12, r11 ; o1 = (c1 * 2217 + d1 * 5352 + 14500) + smlsdx r7, r7, r12, r10 ; o3 = (d1 * 2217 - c1 * 5352 + 7500) + + ldrd r8, r9, [r0] ; [i5 | i4] [i7 | i6] + + pkhbt r3, r4, r6, lsl #4 ; [o1 | o0], keep in register for PART 2 + pkhbt r6, r5, r7, lsl #4 ; [o3 | o2] + + str r6, [r1, #4] + + ; coeffs 4-7 + ror r9, r9, #16 ; [i6 | i7] + + qadd16 r6, r8, r9 ; [i5+i6 | i4+i7] = [b1 | a1] without shift + qsub16 r7, r8, r9 ; [i5-i6 | i4-i7] = [c1 | d1] without shift + + add r0, r0, r2 ; update input pointer + + qadd16 r7, r7, r7 ; 2x[c1|d1] --> we can use smlad and smlsd + ; with 2217*4 and 5352*4 without losing the + ; sign bit (overflow) + + smuad r9, r6, lr ; o4 = (i5+i6)*8 + (i4+i7)*8 + smusd r8, r6, lr ; o6 = (i5+i6)*8 - (i4+i7)*8 + + smlad r6, r7, r12, r11 ; o5 = (c1 * 2217 + d1 * 5352 + 14500) + smlsdx r7, r7, r12, r10 ; o7 = (d1 * 2217 - c1 * 5352 + 7500) + + ldrd r4, r5, [r0] ; [i9 | i8] [i11 | i10] + + pkhbt r9, r9, r6, lsl #4 ; [o5 | o4], keep in register for PART 2 + pkhbt r6, r8, r7, lsl #4 ; [o7 | o6] + + str r6, [r1, #12] + + ; coeffs 8-11 + ror r5, r5, #16 ; [i10 | i11] + + qadd16 r6, r4, r5 ; [i9+i10 | i8+i11]=[b1 | a1] without shift + qsub16 r7, r4, r5 ; [i9-i10 | i8-i11]=[c1 | d1] without shift + + add r0, r0, r2 ; update input pointer + + qadd16 r7, r7, r7 ; 2x[c1|d1] --> we can use smlad and smlsd + ; with 2217*4 and 5352*4 without losing the + ; sign bit (overflow) + + smuad r2, r6, lr ; o8 = (i9+i10)*8 + (i8+i11)*8 + smusd r8, r6, lr ; o10 = (i9+i10)*8 - (i8+i11)*8 + + smlad r6, r7, r12, r11 ; o9 = (c1 * 2217 + d1 * 5352 + 14500) + smlsdx r7, r7, r12, r10 ; o11 = (d1 * 2217 - c1 * 5352 + 7500) + + ldrd r4, r5, [r0] ; [i13 | i12] [i15 | i14] + + pkhbt r2, r2, r6, lsl #4 ; [o9 | o8], keep in register for PART 2 + pkhbt r6, r8, r7, lsl #4 ; [o11 | o10] + + str r6, [r1, #20] + + ; coeffs 12-15 + ror r5, r5, #16 ; [i14 | i15] + + qadd16 r6, r4, r5 ; [i13+i14 | i12+i15]=[b1|a1] without shift + qsub16 r7, r4, r5 ; [i13-i14 | i12-i15]=[c1|d1] without shift + + qadd16 r7, r7, r7 ; 2x[c1|d1] --> we can use smlad and smlsd + ; with 2217*4 and 5352*4 without losing the + ; sign bit (overflow) + + smuad r4, r6, lr ; o12 = (i13+i14)*8 + (i12+i15)*8 + smusd r5, r6, lr ; o14 = (i13+i14)*8 - (i12+i15)*8 + + smlad r6, r7, r12, r11 ; o13 = (c1 * 2217 + d1 * 5352 + 14500) + smlsdx r7, r7, r12, r10 ; o15 = (d1 * 2217 - c1 * 5352 + 7500) + + pkhbt r0, r4, r6, lsl #4 ; [o13 | o12], keep in register for PART 2 + pkhbt r6, r5, r7, lsl #4 ; [o15 | o14] + + str r6, [r1, #28] + + + ; PART 2 ------------------------------------------------- + ldr r11, c12000 + ldr r10, c51000 + ldr lr, c0x00070007 + + qadd16 r4, r3, r0 ; a1 = [i1+i13 | i0+i12] + qadd16 r5, r9, r2 ; b1 = [i5+i9 | i4+i8] + qsub16 r6, r9, r2 ; c1 = [i5-i9 | i4-i8] + qsub16 r7, r3, r0 ; d1 = [i1-i13 | i0-i12] + + qadd16 r4, r4, lr ; a1 + 7 + + add r0, r11, #0x10000 ; add (d!=0) + + qadd16 r2, r4, r5 ; a1 + b1 + 7 + qsub16 r3, r4, r5 ; a1 - b1 + 7 + + ldr r12, c0x08a914e8 ; [2217 | 5352] + + lsl r8, r2, #16 ; prepare bottom halfword for scaling + asr r2, r2, #4 ; scale top halfword + lsl r9, r3, #16 ; prepare bottom halfword for scaling + asr r3, r3, #4 ; scale top halfword + pkhtb r4, r2, r8, asr #20 ; pack and scale bottom halfword + pkhtb r5, r3, r9, asr #20 ; pack and scale bottom halfword + + smulbt r2, r6, r12 ; [ ------ | c1*2217] + str r4, [r1, #0] ; [ o1 | o0] + smultt r3, r6, r12 ; [c1*2217 | ------ ] + str r5, [r1, #16] ; [ o9 | o8] + + smlabb r8, r7, r12, r2 ; [ ------ | d1*5352] + smlatb r9, r7, r12, r3 ; [d1*5352 | ------ ] + + smulbb r2, r6, r12 ; [ ------ | c1*5352] + smultb r3, r6, r12 ; [c1*5352 | ------ ] + + lsls r6, r7, #16 ; d1 != 0 ? + addeq r8, r8, r11 ; c1_b*2217+d1_b*5352+12000 + (d==0) + addne r8, r8, r0 ; c1_b*2217+d1_b*5352+12000 + (d!=0) + asrs r6, r7, #16 + addeq r9, r9, r11 ; c1_t*2217+d1_t*5352+12000 + (d==0) + addne r9, r9, r0 ; c1_t*2217+d1_t*5352+12000 + (d!=0) + + smlabt r4, r7, r12, r10 ; [ ------ | d1*2217] + 51000 + smlatt r5, r7, r12, r10 ; [d1*2217 | ------ ] + 51000 + + pkhtb r9, r9, r8, asr #16 + + sub r4, r4, r2 + sub r5, r5, r3 + + ldr r3, [r1, #4] ; [i3 | i2] + + pkhtb r5, r5, r4, asr #16 ; [o13|o12] + + str r9, [r1, #8] ; [o5 | 04] + + ldr r9, [r1, #12] ; [i7 | i6] + ldr r8, [r1, #28] ; [i15|i14] + ldr r2, [r1, #20] ; [i11|i10] + str r5, [r1, #24] ; [o13|o12] + + qadd16 r4, r3, r8 ; a1 = [i3+i15 | i2+i14] + qadd16 r5, r9, r2 ; b1 = [i7+i11 | i6+i10] + + qadd16 r4, r4, lr ; a1 + 7 + + qsub16 r6, r9, r2 ; c1 = [i7-i11 | i6-i10] + qadd16 r2, r4, r5 ; a1 + b1 + 7 + qsub16 r7, r3, r8 ; d1 = [i3-i15 | i2-i14] + qsub16 r3, r4, r5 ; a1 - b1 + 7 + + lsl r8, r2, #16 ; prepare bottom halfword for scaling + asr r2, r2, #4 ; scale top halfword + lsl r9, r3, #16 ; prepare bottom halfword for scaling + asr r3, r3, #4 ; scale top halfword + pkhtb r4, r2, r8, asr #20 ; pack and scale bottom halfword + pkhtb r5, r3, r9, asr #20 ; pack and scale bottom halfword + + smulbt r2, r6, r12 ; [ ------ | c1*2217] + str r4, [r1, #4] ; [ o3 | o2] + smultt r3, r6, r12 ; [c1*2217 | ------ ] + str r5, [r1, #20] ; [ o11 | o10] + + smlabb r8, r7, r12, r2 ; [ ------ | d1*5352] + smlatb r9, r7, r12, r3 ; [d1*5352 | ------ ] + + smulbb r2, r6, r12 ; [ ------ | c1*5352] + smultb r3, r6, r12 ; [c1*5352 | ------ ] + + lsls r6, r7, #16 ; d1 != 0 ? + addeq r8, r8, r11 ; c1_b*2217+d1_b*5352+12000 + (d==0) + addne r8, r8, r0 ; c1_b*2217+d1_b*5352+12000 + (d!=0) + + asrs r6, r7, #16 + addeq r9, r9, r11 ; c1_t*2217+d1_t*5352+12000 + (d==0) + addne r9, r9, r0 ; c1_t*2217+d1_t*5352+12000 + (d!=0) + + smlabt r4, r7, r12, r10 ; [ ------ | d1*2217] + 51000 + smlatt r5, r7, r12, r10 ; [d1*2217 | ------ ] + 51000 + + pkhtb r9, r9, r8, asr #16 + + sub r4, r4, r2 + sub r5, r5, r3 + + str r9, [r1, #12] ; [o7 | o6] + pkhtb r5, r5, r4, asr #16 ; [o15|o14] + + str r5, [r1, #28] ; [o15|o14] + + ldmfd sp!, {r4 - r12, pc} + + ENDP + +; Used constants +c7500 + DCD 7500 +c14500 + DCD 14500 +c0x22a453a0 + DCD 0x22a453a0 +c0x00080008 + DCD 0x00080008 +c12000 + DCD 12000 +c51000 + DCD 51000 +c0x00070007 + DCD 0x00070007 +c0x08a914e8 + DCD 0x08a914e8 + + END diff --git a/vp8/encoder/arm/armv6/vp8_subtract_armv6.asm b/vp8/encoder/arm/armv6/vp8_subtract_armv6.asm new file mode 100644 index 0000000..f329f8f --- /dev/null +++ b/vp8/encoder/arm/armv6/vp8_subtract_armv6.asm @@ -0,0 +1,272 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_subtract_mby_armv6| + EXPORT |vp8_subtract_mbuv_armv6| + EXPORT |vp8_subtract_b_armv6| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 BLOCK *be +; r1 BLOCKD *bd +; r2 int pitch +|vp8_subtract_b_armv6| PROC + + stmfd sp!, {r4-r9} + + ldr r4, [r0, #vp8_block_base_src] + ldr r5, [r0, #vp8_block_src] + ldr r6, [r0, #vp8_block_src_diff] + + ldr r3, [r4] + ldr r7, [r0, #vp8_block_src_stride] + add r3, r3, r5 ; src = *base_src + src + ldr r8, [r1, #vp8_blockd_predictor] + + mov r9, #4 ; loop count + +loop_block + + ldr r0, [r3], r7 ; src + ldr r1, [r8], r2 ; pred + + uxtb16 r4, r0 ; [s2 | s0] + uxtb16 r5, r1 ; [p2 | p0] + uxtb16 r0, r0, ror #8 ; [s3 | s1] + uxtb16 r1, r1, ror #8 ; [p3 | p1] + + usub16 r4, r4, r5 ; [d2 | d0] + usub16 r5, r0, r1 ; [d3 | d1] + + subs r9, r9, #1 ; decrement loop counter + + pkhbt r0, r4, r5, lsl #16 ; [d1 | d0] + pkhtb r1, r5, r4, asr #16 ; [d3 | d2] + + str r0, [r6, #0] ; diff + str r1, [r6, #4] ; diff + + add r6, r6, r2, lsl #1 ; update diff pointer + bne loop_block + + ldmfd sp!, {r4-r9} + mov pc, lr + + ENDP + + +; r0 short *diff +; r1 unsigned char *usrc +; r2 unsigned char *vsrc +; r3 int src_stride +; sp unsigned char *upred +; sp unsigned char *vpred +; sp int pred_stride +|vp8_subtract_mbuv_armv6| PROC + + stmfd sp!, {r4-r11} + + add r0, r0, #512 ; set *diff point to Cb + mov r4, #8 ; loop count + ldr r5, [sp, #32] ; upred + ldr r12, [sp, #40] ; pred_stride + + ; Subtract U block +loop_u + ldr r6, [r1] ; usrc (A) + ldr r7, [r5] ; upred (A) + + uxtb16 r8, r6 ; [s2 | s0] (A) + uxtb16 r9, r7 ; [p2 | p0] (A) + uxtb16 r10, r6, ror #8 ; [s3 | s1] (A) + uxtb16 r11, r7, ror #8 ; [p3 | p1] (A) + + usub16 r6, r8, r9 ; [d2 | d0] (A) + usub16 r7, r10, r11 ; [d3 | d1] (A) + + ldr r10, [r1, #4] ; usrc (B) + ldr r11, [r5, #4] ; upred (B) + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (A) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (A) + + str r8, [r0], #4 ; diff (A) + uxtb16 r8, r10 ; [s2 | s0] (B) + str r9, [r0], #4 ; diff (A) + + uxtb16 r9, r11 ; [p2 | p0] (B) + uxtb16 r10, r10, ror #8 ; [s3 | s1] (B) + uxtb16 r11, r11, ror #8 ; [p3 | p1] (B) + + usub16 r6, r8, r9 ; [d2 | d0] (B) + usub16 r7, r10, r11 ; [d3 | d1] (B) + + add r1, r1, r3 ; update usrc pointer + add r5, r5, r12 ; update upred pointer + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (B) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (B) + + str r8, [r0], #4 ; diff (B) + subs r4, r4, #1 ; update loop counter + str r9, [r0], #4 ; diff (B) + + bne loop_u + + ldr r5, [sp, #36] ; vpred + mov r4, #8 ; loop count + + ; Subtract V block +loop_v + ldr r6, [r2] ; vsrc (A) + ldr r7, [r5] ; vpred (A) + + uxtb16 r8, r6 ; [s2 | s0] (A) + uxtb16 r9, r7 ; [p2 | p0] (A) + uxtb16 r10, r6, ror #8 ; [s3 | s1] (A) + uxtb16 r11, r7, ror #8 ; [p3 | p1] (A) + + usub16 r6, r8, r9 ; [d2 | d0] (A) + usub16 r7, r10, r11 ; [d3 | d1] (A) + + ldr r10, [r2, #4] ; vsrc (B) + ldr r11, [r5, #4] ; vpred (B) + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (A) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (A) + + str r8, [r0], #4 ; diff (A) + uxtb16 r8, r10 ; [s2 | s0] (B) + str r9, [r0], #4 ; diff (A) + + uxtb16 r9, r11 ; [p2 | p0] (B) + uxtb16 r10, r10, ror #8 ; [s3 | s1] (B) + uxtb16 r11, r11, ror #8 ; [p3 | p1] (B) + + usub16 r6, r8, r9 ; [d2 | d0] (B) + usub16 r7, r10, r11 ; [d3 | d1] (B) + + add r2, r2, r3 ; update vsrc pointer + add r5, r5, r12 ; update vpred pointer + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (B) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (B) + + str r8, [r0], #4 ; diff (B) + subs r4, r4, #1 ; update loop counter + str r9, [r0], #4 ; diff (B) + + bne loop_v + + ldmfd sp!, {r4-r11} + bx lr + + ENDP + + +; r0 short *diff +; r1 unsigned char *src +; r2 int src_stride +; r3 unsigned char *pred +; sp int pred_stride +|vp8_subtract_mby_armv6| PROC + + stmfd sp!, {r4-r11} + ldr r12, [sp, #32] ; pred_stride + mov r4, #16 +loop + ldr r6, [r1] ; src (A) + ldr r7, [r3] ; pred (A) + + uxtb16 r8, r6 ; [s2 | s0] (A) + uxtb16 r9, r7 ; [p2 | p0] (A) + uxtb16 r10, r6, ror #8 ; [s3 | s1] (A) + uxtb16 r11, r7, ror #8 ; [p3 | p1] (A) + + usub16 r6, r8, r9 ; [d2 | d0] (A) + usub16 r7, r10, r11 ; [d3 | d1] (A) + + ldr r10, [r1, #4] ; src (B) + ldr r11, [r3, #4] ; pred (B) + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (A) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (A) + + str r8, [r0], #4 ; diff (A) + uxtb16 r8, r10 ; [s2 | s0] (B) + str r9, [r0], #4 ; diff (A) + + uxtb16 r9, r11 ; [p2 | p0] (B) + uxtb16 r10, r10, ror #8 ; [s3 | s1] (B) + uxtb16 r11, r11, ror #8 ; [p3 | p1] (B) + + usub16 r6, r8, r9 ; [d2 | d0] (B) + usub16 r7, r10, r11 ; [d3 | d1] (B) + + ldr r10, [r1, #8] ; src (C) + ldr r11, [r3, #8] ; pred (C) + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (B) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (B) + + str r8, [r0], #4 ; diff (B) + uxtb16 r8, r10 ; [s2 | s0] (C) + str r9, [r0], #4 ; diff (B) + + uxtb16 r9, r11 ; [p2 | p0] (C) + uxtb16 r10, r10, ror #8 ; [s3 | s1] (C) + uxtb16 r11, r11, ror #8 ; [p3 | p1] (C) + + usub16 r6, r8, r9 ; [d2 | d0] (C) + usub16 r7, r10, r11 ; [d3 | d1] (C) + + ldr r10, [r1, #12] ; src (D) + ldr r11, [r3, #12] ; pred (D) + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (C) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (C) + + str r8, [r0], #4 ; diff (C) + uxtb16 r8, r10 ; [s2 | s0] (D) + str r9, [r0], #4 ; diff (C) + + uxtb16 r9, r11 ; [p2 | p0] (D) + uxtb16 r10, r10, ror #8 ; [s3 | s1] (D) + uxtb16 r11, r11, ror #8 ; [p3 | p1] (D) + + usub16 r6, r8, r9 ; [d2 | d0] (D) + usub16 r7, r10, r11 ; [d3 | d1] (D) + + add r1, r1, r2 ; update src pointer + add r3, r3, r12 ; update pred pointer + + pkhbt r8, r6, r7, lsl #16 ; [d1 | d0] (D) + pkhtb r9, r7, r6, asr #16 ; [d3 | d2] (D) + + str r8, [r0], #4 ; diff (D) + subs r4, r4, #1 ; update loop counter + str r9, [r0], #4 ; diff (D) + + bne loop + + ldmfd sp!, {r4-r11} + bx lr + + ENDP + + END + diff --git a/vp8/encoder/arm/armv6/walsh_v6.asm b/vp8/encoder/arm/armv6/walsh_v6.asm new file mode 100644 index 0000000..5eaf3f2 --- /dev/null +++ b/vp8/encoder/arm/armv6/walsh_v6.asm @@ -0,0 +1,212 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + EXPORT |vp8_short_walsh4x4_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code + +;short vp8_short_walsh4x4_armv6(short *input, short *output, int pitch) +; r0 short *input, +; r1 short *output, +; r2 int pitch +|vp8_short_walsh4x4_armv6| PROC + + stmdb sp!, {r4 - r11, lr} + + ldrd r4, r5, [r0], r2 + ldr lr, c00040004 + ldrd r6, r7, [r0], r2 + + ; 0-3 + qadd16 r3, r4, r5 ; [d1|a1] [1+3 | 0+2] + qsub16 r4, r4, r5 ; [c1|b1] [1-3 | 0-2] + + ldrd r8, r9, [r0], r2 + ; 4-7 + qadd16 r5, r6, r7 ; [d1|a1] [5+7 | 4+6] + qsub16 r6, r6, r7 ; [c1|b1] [5-7 | 4-6] + + ldrd r10, r11, [r0] + ; 8-11 + qadd16 r7, r8, r9 ; [d1|a1] [9+11 | 8+10] + qsub16 r8, r8, r9 ; [c1|b1] [9-11 | 8-10] + + ; 12-15 + qadd16 r9, r10, r11 ; [d1|a1] [13+15 | 12+14] + qsub16 r10, r10, r11 ; [c1|b1] [13-15 | 12-14] + + + lsls r2, r3, #16 + smuad r11, r3, lr ; A0 = a1<<2 + d1<<2 + addne r11, r11, #1 ; A0 += (a1!=0) + + lsls r2, r7, #16 + smuad r12, r7, lr ; C0 = a1<<2 + d1<<2 + addne r12, r12, #1 ; C0 += (a1!=0) + + add r0, r11, r12 ; a1_0 = A0 + C0 + sub r11, r11, r12 ; b1_0 = A0 - C0 + + lsls r2, r5, #16 + smuad r12, r5, lr ; B0 = a1<<2 + d1<<2 + addne r12, r12, #1 ; B0 += (a1!=0) + + lsls r2, r9, #16 + smuad r2, r9, lr ; D0 = a1<<2 + d1<<2 + addne r2, r2, #1 ; D0 += (a1!=0) + + add lr, r12, r2 ; d1_0 = B0 + D0 + sub r12, r12, r2 ; c1_0 = B0 - D0 + + ; op[0,4,8,12] + adds r2, r0, lr ; a2 = a1_0 + d1_0 + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + subs r0, r0, lr ; d2 = a1_0 - d1_0 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1] ; op[0] + + addmi r0, r0, #1 ; += a2 < 0 + add r0, r0, #3 ; += 3 + ldr lr, c00040004 + mov r0, r0, asr #3 ; >> 3 + strh r0, [r1, #24] ; op[12] + + adds r2, r11, r12 ; b2 = b1_0 + c1_0 + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + subs r0, r11, r12 ; c2 = b1_0 - c1_0 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #8] ; op[4] + + addmi r0, r0, #1 ; += a2 < 0 + add r0, r0, #3 ; += 3 + smusd r3, r3, lr ; A3 = a1<<2 - d1<<2 + smusd r7, r7, lr ; C3 = a1<<2 - d1<<2 + mov r0, r0, asr #3 ; >> 3 + strh r0, [r1, #16] ; op[8] + + + ; op[3,7,11,15] + add r0, r3, r7 ; a1_3 = A3 + C3 + sub r3, r3, r7 ; b1_3 = A3 - C3 + + smusd r5, r5, lr ; B3 = a1<<2 - d1<<2 + smusd r9, r9, lr ; D3 = a1<<2 - d1<<2 + add r7, r5, r9 ; d1_3 = B3 + D3 + sub r5, r5, r9 ; c1_3 = B3 - D3 + + adds r2, r0, r7 ; a2 = a1_3 + d1_3 + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + adds r9, r3, r5 ; b2 = b1_3 + c1_3 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #6] ; op[3] + + addmi r9, r9, #1 ; += a2 < 0 + add r9, r9, #3 ; += 3 + subs r2, r3, r5 ; c2 = b1_3 - c1_3 + mov r9, r9, asr #3 ; >> 3 + strh r9, [r1, #14] ; op[7] + + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + subs r9, r0, r7 ; d2 = a1_3 - d1_3 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #22] ; op[11] + + addmi r9, r9, #1 ; += a2 < 0 + add r9, r9, #3 ; += 3 + smuad r3, r4, lr ; A1 = b1<<2 + c1<<2 + smuad r5, r8, lr ; C1 = b1<<2 + c1<<2 + mov r9, r9, asr #3 ; >> 3 + strh r9, [r1, #30] ; op[15] + + ; op[1,5,9,13] + add r0, r3, r5 ; a1_1 = A1 + C1 + sub r3, r3, r5 ; b1_1 = A1 - C1 + + smuad r7, r6, lr ; B1 = b1<<2 + c1<<2 + smuad r9, r10, lr ; D1 = b1<<2 + c1<<2 + add r5, r7, r9 ; d1_1 = B1 + D1 + sub r7, r7, r9 ; c1_1 = B1 - D1 + + adds r2, r0, r5 ; a2 = a1_1 + d1_1 + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + adds r9, r3, r7 ; b2 = b1_1 + c1_1 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #2] ; op[1] + + addmi r9, r9, #1 ; += a2 < 0 + add r9, r9, #3 ; += 3 + subs r2, r3, r7 ; c2 = b1_1 - c1_1 + mov r9, r9, asr #3 ; >> 3 + strh r9, [r1, #10] ; op[5] + + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + subs r9, r0, r5 ; d2 = a1_1 - d1_1 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #18] ; op[9] + + addmi r9, r9, #1 ; += a2 < 0 + add r9, r9, #3 ; += 3 + smusd r4, r4, lr ; A2 = b1<<2 - c1<<2 + smusd r8, r8, lr ; C2 = b1<<2 - c1<<2 + mov r9, r9, asr #3 ; >> 3 + strh r9, [r1, #26] ; op[13] + + + ; op[2,6,10,14] + add r11, r4, r8 ; a1_2 = A2 + C2 + sub r12, r4, r8 ; b1_2 = A2 - C2 + + smusd r6, r6, lr ; B2 = b1<<2 - c1<<2 + smusd r10, r10, lr ; D2 = b1<<2 - c1<<2 + add r4, r6, r10 ; d1_2 = B2 + D2 + sub r8, r6, r10 ; c1_2 = B2 - D2 + + adds r2, r11, r4 ; a2 = a1_2 + d1_2 + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + adds r9, r12, r8 ; b2 = b1_2 + c1_2 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #4] ; op[2] + + addmi r9, r9, #1 ; += a2 < 0 + add r9, r9, #3 ; += 3 + subs r2, r12, r8 ; c2 = b1_2 - c1_2 + mov r9, r9, asr #3 ; >> 3 + strh r9, [r1, #12] ; op[6] + + addmi r2, r2, #1 ; += a2 < 0 + add r2, r2, #3 ; += 3 + subs r9, r11, r4 ; d2 = a1_2 - d1_2 + mov r2, r2, asr #3 ; >> 3 + strh r2, [r1, #20] ; op[10] + + addmi r9, r9, #1 ; += a2 < 0 + add r9, r9, #3 ; += 3 + mov r9, r9, asr #3 ; >> 3 + strh r9, [r1, #28] ; op[14] + + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_short_walsh4x4_armv6| + +c00040004 + DCD 0x00040004 + + END diff --git a/vp8/encoder/arm/boolhuff_arm.c b/vp8/encoder/arm/boolhuff_arm.c new file mode 100644 index 0000000..17a941b --- /dev/null +++ b/vp8/encoder/arm/boolhuff_arm.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/encoder/boolhuff.h" +#include "vpx/internal/vpx_codec_internal.h" + +const unsigned int vp8_prob_cost[256] = +{ + 2047, 2047, 1791, 1641, 1535, 1452, 1385, 1328, 1279, 1235, 1196, 1161, 1129, 1099, 1072, 1046, + 1023, 1000, 979, 959, 940, 922, 905, 889, 873, 858, 843, 829, 816, 803, 790, 778, + 767, 755, 744, 733, 723, 713, 703, 693, 684, 675, 666, 657, 649, 641, 633, 625, + 617, 609, 602, 594, 587, 580, 573, 567, 560, 553, 547, 541, 534, 528, 522, 516, + 511, 505, 499, 494, 488, 483, 477, 472, 467, 462, 457, 452, 447, 442, 437, 433, + 428, 424, 419, 415, 410, 406, 401, 397, 393, 389, 385, 381, 377, 373, 369, 365, + 361, 357, 353, 349, 346, 342, 338, 335, 331, 328, 324, 321, 317, 314, 311, 307, + 304, 301, 297, 294, 291, 288, 285, 281, 278, 275, 272, 269, 266, 263, 260, 257, + 255, 252, 249, 246, 243, 240, 238, 235, 232, 229, 227, 224, 221, 219, 216, 214, + 211, 208, 206, 203, 201, 198, 196, 194, 191, 189, 186, 184, 181, 179, 177, 174, + 172, 170, 168, 165, 163, 161, 159, 156, 154, 152, 150, 148, 145, 143, 141, 139, + 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, + 105, 103, 101, 99, 97, 95, 93, 92, 90, 88, 86, 84, 82, 81, 79, 77, + 75, 73, 72, 70, 68, 66, 65, 63, 61, 60, 58, 56, 55, 53, 51, 50, + 48, 46, 45, 43, 41, 40, 38, 37, 35, 33, 32, 30, 29, 27, 25, 24, + 22, 21, 19, 18, 16, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1, 1 +}; + +int vp8_validate_buffer_arm(const unsigned char *start, + size_t len, + const unsigned char *end, + struct vpx_internal_error_info *error) +{ + return validate_buffer(start, len, end, error); +} diff --git a/vp8/encoder/arm/dct_arm.c b/vp8/encoder/arm/dct_arm.c new file mode 100644 index 0000000..af0fb27 --- /dev/null +++ b/vp8/encoder/arm/dct_arm.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vpx_config.h" +#include "vpx_rtcd.h" + +#if HAVE_MEDIA + +void vp8_short_fdct8x4_armv6(short *input, short *output, int pitch) +{ + vp8_short_fdct4x4_armv6(input, output, pitch); + vp8_short_fdct4x4_armv6(input + 4, output + 16, pitch); +} + +#endif /* HAVE_MEDIA */ diff --git a/vp8/encoder/arm/neon/fastquantizeb_neon.asm b/vp8/encoder/arm/neon/fastquantizeb_neon.asm new file mode 100644 index 0000000..1430588 --- /dev/null +++ b/vp8/encoder/arm/neon/fastquantizeb_neon.asm @@ -0,0 +1,258 @@ +; +; Copyright (c) 2011 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_fast_quantize_b_neon| + EXPORT |vp8_fast_quantize_b_pair_neon| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=4 + +;vp8_fast_quantize_b_pair_neon(BLOCK *b1, BLOCK *b2, BLOCKD *d1, BLOCKD *d2); +|vp8_fast_quantize_b_pair_neon| PROC + + stmfd sp!, {r4-r9} + vstmdb sp!, {q4-q7} + + ldr r4, [r0, #vp8_block_coeff] + ldr r5, [r0, #vp8_block_quant_fast] + ldr r6, [r0, #vp8_block_round] + + vld1.16 {q0, q1}, [r4@128] ; load z + + ldr r7, [r2, #vp8_blockd_qcoeff] + + vabs.s16 q4, q0 ; calculate x = abs(z) + vabs.s16 q5, q1 + + ;right shift 15 to get sign, all 0 if it is positive, all 1 if it is negative + vshr.s16 q2, q0, #15 ; sz + vshr.s16 q3, q1, #15 + + vld1.s16 {q6, q7}, [r6@128] ; load round_ptr [0-15] + vld1.s16 {q8, q9}, [r5@128] ; load quant_ptr [0-15] + + ldr r4, [r1, #vp8_block_coeff] + + vadd.s16 q4, q6 ; x + Round + vadd.s16 q5, q7 + + vld1.16 {q0, q1}, [r4@128] ; load z2 + + vqdmulh.s16 q4, q8 ; y = ((Round+abs(z)) * Quant) >> 16 + vqdmulh.s16 q5, q9 + + vabs.s16 q10, q0 ; calculate x2 = abs(z_2) + vabs.s16 q11, q1 + vshr.s16 q12, q0, #15 ; sz2 + vshr.s16 q13, q1, #15 + + ;modify data to have its original sign + veor.s16 q4, q2 ; y^sz + veor.s16 q5, q3 + + vadd.s16 q10, q6 ; x2 + Round + vadd.s16 q11, q7 + + ldr r8, [r2, #vp8_blockd_dequant] + + vqdmulh.s16 q10, q8 ; y2 = ((Round+abs(z)) * Quant) >> 16 + vqdmulh.s16 q11, q9 + + vshr.s16 q4, #1 ; right shift 1 after vqdmulh + vshr.s16 q5, #1 + + vld1.s16 {q6, q7}, [r8@128] ;load dequant_ptr[i] + + vsub.s16 q4, q2 ; x1=(y^sz)-sz = (y^sz)-(-1) (2's complement) + vsub.s16 q5, q3 + + vshr.s16 q10, #1 ; right shift 1 after vqdmulh + vshr.s16 q11, #1 + + ldr r9, [r2, #vp8_blockd_dqcoeff] + + veor.s16 q10, q12 ; y2^sz2 + veor.s16 q11, q13 + + vst1.s16 {q4, q5}, [r7] ; store: qcoeff = x1 + + + vsub.s16 q10, q12 ; x2=(y^sz)-sz = (y^sz)-(-1) (2's complement) + vsub.s16 q11, q13 + + ldr r6, [r3, #vp8_blockd_qcoeff] + + vmul.s16 q2, q6, q4 ; x * Dequant + vmul.s16 q3, q7, q5 + + adr r0, inv_zig_zag ; load ptr of inverse zigzag table + + vceq.s16 q8, q8 ; set q8 to all 1 + + vst1.s16 {q10, q11}, [r6] ; store: qcoeff = x2 + + vmul.s16 q12, q6, q10 ; x2 * Dequant + vmul.s16 q13, q7, q11 + + vld1.16 {q6, q7}, [r0@128] ; load inverse scan order + + vtst.16 q14, q4, q8 ; now find eob + vtst.16 q15, q5, q8 ; non-zero element is set to all 1 + + vst1.s16 {q2, q3}, [r9] ; store dqcoeff = x * Dequant + + ldr r7, [r3, #vp8_blockd_dqcoeff] + + vand q0, q6, q14 ; get all valid numbers from scan array + vand q1, q7, q15 + + vst1.s16 {q12, q13}, [r7] ; store dqcoeff = x * Dequant + + vtst.16 q2, q10, q8 ; now find eob + vtst.16 q3, q11, q8 ; non-zero element is set to all 1 + + vmax.u16 q0, q0, q1 ; find maximum value in q0, q1 + + vand q10, q6, q2 ; get all valid numbers from scan array + vand q11, q7, q3 + vmax.u16 q10, q10, q11 ; find maximum value in q10, q11 + + vmax.u16 d0, d0, d1 + vmax.u16 d20, d20, d21 + vmovl.u16 q0, d0 + vmovl.u16 q10, d20 + + vmax.u32 d0, d0, d1 + vmax.u32 d20, d20, d21 + vpmax.u32 d0, d0, d0 + vpmax.u32 d20, d20, d20 + + ldr r4, [r2, #vp8_blockd_eob] + ldr r5, [r3, #vp8_blockd_eob] + + vst1.8 {d0[0]}, [r4] ; store eob + vst1.8 {d20[0]}, [r5] ; store eob + + vldmia sp!, {q4-q7} + ldmfd sp!, {r4-r9} + bx lr + + ENDP + +;void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) +|vp8_fast_quantize_b_neon| PROC + + stmfd sp!, {r4-r7} + + ldr r3, [r0, #vp8_block_coeff] + ldr r4, [r0, #vp8_block_quant_fast] + ldr r5, [r0, #vp8_block_round] + + vld1.16 {q0, q1}, [r3@128] ; load z + vorr.s16 q14, q0, q1 ; check if all zero (step 1) + ldr r6, [r1, #vp8_blockd_qcoeff] + ldr r7, [r1, #vp8_blockd_dqcoeff] + vorr.s16 d28, d28, d29 ; check if all zero (step 2) + + vabs.s16 q12, q0 ; calculate x = abs(z) + vabs.s16 q13, q1 + + ;right shift 15 to get sign, all 0 if it is positive, all 1 if it is negative + vshr.s16 q2, q0, #15 ; sz + vmov r2, r3, d28 ; check if all zero (step 3) + vshr.s16 q3, q1, #15 + + vld1.s16 {q14, q15}, [r5@128]; load round_ptr [0-15] + vld1.s16 {q8, q9}, [r4@128] ; load quant_ptr [0-15] + + vadd.s16 q12, q14 ; x + Round + vadd.s16 q13, q15 + + adr r0, inv_zig_zag ; load ptr of inverse zigzag table + + vqdmulh.s16 q12, q8 ; y = ((Round+abs(z)) * Quant) >> 16 + vqdmulh.s16 q13, q9 + + vld1.16 {q10, q11}, [r0@128]; load inverse scan order + + vceq.s16 q8, q8 ; set q8 to all 1 + + ldr r4, [r1, #vp8_blockd_dequant] + + vshr.s16 q12, #1 ; right shift 1 after vqdmulh + vshr.s16 q13, #1 + + ldr r5, [r1, #vp8_blockd_eob] + + orr r2, r2, r3 ; check if all zero (step 4) + cmp r2, #0 ; check if all zero (step 5) + beq zero_output ; check if all zero (step 6) + + ;modify data to have its original sign + veor.s16 q12, q2 ; y^sz + veor.s16 q13, q3 + + vsub.s16 q12, q2 ; x1=(y^sz)-sz = (y^sz)-(-1) (2's complement) + vsub.s16 q13, q3 + + vld1.s16 {q2, q3}, [r4@128] ; load dequant_ptr[i] + + vtst.16 q14, q12, q8 ; now find eob + vtst.16 q15, q13, q8 ; non-zero element is set to all 1 + + vst1.s16 {q12, q13}, [r6@128]; store: qcoeff = x1 + + vand q10, q10, q14 ; get all valid numbers from scan array + vand q11, q11, q15 + + + vmax.u16 q0, q10, q11 ; find maximum value in q0, q1 + vmax.u16 d0, d0, d1 + vmovl.u16 q0, d0 + + vmul.s16 q2, q12 ; x * Dequant + vmul.s16 q3, q13 + + vmax.u32 d0, d0, d1 + vpmax.u32 d0, d0, d0 + + vst1.s16 {q2, q3}, [r7@128] ; store dqcoeff = x * Dequant + + vst1.8 {d0[0]}, [r5] ; store eob + + ldmfd sp!, {r4-r7} + bx lr + +zero_output + strb r2, [r5] ; store eob + vst1.s16 {q0, q1}, [r6@128] ; qcoeff = 0 + vst1.s16 {q0, q1}, [r7@128] ; dqcoeff = 0 + + ldmfd sp!, {r4-r7} + bx lr + + ENDP + +; default inverse zigzag table is defined in vp8/common/entropy.c + ALIGN 16 ; enable use of @128 bit aligned loads +inv_zig_zag + DCW 0x0001, 0x0002, 0x0006, 0x0007 + DCW 0x0003, 0x0005, 0x0008, 0x000d + DCW 0x0004, 0x0009, 0x000c, 0x000e + DCW 0x000a, 0x000b, 0x000f, 0x0010 + + END + diff --git a/vp8/encoder/arm/neon/picklpf_arm.c b/vp8/encoder/arm/neon/picklpf_arm.c new file mode 100644 index 0000000..ec8071e --- /dev/null +++ b/vp8/encoder/arm/neon/picklpf_arm.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vp8/common/loopfilter.h" +#include "vpx_scale/yv12config.h" + +extern void vp8_memcpy_partial_neon(unsigned char *dst_ptr, + unsigned char *src_ptr, + int sz); + + +void vp8_yv12_copy_partial_frame_neon(YV12_BUFFER_CONFIG *src_ybc, + YV12_BUFFER_CONFIG *dst_ybc) +{ + unsigned char *src_y, *dst_y; + int yheight; + int ystride; + int yoffset; + int linestocopy; + + yheight = src_ybc->y_height; + ystride = src_ybc->y_stride; + + /* number of MB rows to use in partial filtering */ + linestocopy = (yheight >> 4) / PARTIAL_FRAME_FRACTION; + linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */ + + /* Copy extra 4 so that full filter context is available if filtering done + * on the copied partial frame and not original. Partial filter does mb + * filtering for top row also, which can modify3 pixels above. + */ + linestocopy += 4; + /* partial image starts at ~middle of frame (macroblock border) */ + yoffset = ystride * (((yheight >> 5) * 16) - 4); + src_y = src_ybc->y_buffer + yoffset; + dst_y = dst_ybc->y_buffer + yoffset; + + vp8_memcpy_partial_neon(dst_y, src_y, ystride * linestocopy); +} diff --git a/vp8/encoder/arm/neon/shortfdct_neon.asm b/vp8/encoder/arm/neon/shortfdct_neon.asm new file mode 100644 index 0000000..09dd011 --- /dev/null +++ b/vp8/encoder/arm/neon/shortfdct_neon.asm @@ -0,0 +1,221 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_short_fdct4x4_neon| + EXPORT |vp8_short_fdct8x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=4 + + + ALIGN 16 ; enable use of @128 bit aligned loads +coeff + DCW 5352, 5352, 5352, 5352 + DCW 2217, 2217, 2217, 2217 + DCD 14500, 14500, 14500, 14500 + DCD 7500, 7500, 7500, 7500 + DCD 12000, 12000, 12000, 12000 + DCD 51000, 51000, 51000, 51000 + +;void vp8_short_fdct4x4_c(short *input, short *output, int pitch) +|vp8_short_fdct4x4_neon| PROC + + ; Part one + vld1.16 {d0}, [r0@64], r2 + adr r12, coeff + vld1.16 {d1}, [r0@64], r2 + vld1.16 {q8}, [r12@128]! ; d16=5352, d17=2217 + vld1.16 {d2}, [r0@64], r2 + vld1.32 {q9, q10}, [r12@128]! ; q9=14500, q10=7500 + vld1.16 {d3}, [r0@64], r2 + + ; transpose d0=ip[0], d1=ip[1], d2=ip[2], d3=ip[3] + vtrn.32 d0, d2 + vtrn.32 d1, d3 + vld1.32 {q11,q12}, [r12@128] ; q11=12000, q12=51000 + vtrn.16 d0, d1 + vtrn.16 d2, d3 + + vadd.s16 d4, d0, d3 ; a1 = ip[0] + ip[3] + vadd.s16 d5, d1, d2 ; b1 = ip[1] + ip[2] + vsub.s16 d6, d1, d2 ; c1 = ip[1] - ip[2] + vsub.s16 d7, d0, d3 ; d1 = ip[0] - ip[3] + + vshl.s16 q2, q2, #3 ; (a1, b1) << 3 + vshl.s16 q3, q3, #3 ; (c1, d1) << 3 + + vadd.s16 d0, d4, d5 ; op[0] = a1 + b1 + vsub.s16 d2, d4, d5 ; op[2] = a1 - b1 + + vmlal.s16 q9, d7, d16 ; d1*5352 + 14500 + vmlal.s16 q10, d7, d17 ; d1*2217 + 7500 + vmlal.s16 q9, d6, d17 ; c1*2217 + d1*5352 + 14500 + vmlsl.s16 q10, d6, d16 ; d1*2217 - c1*5352 + 7500 + + vshrn.s32 d1, q9, #12 ; op[1] = (c1*2217 + d1*5352 + 14500)>>12 + vshrn.s32 d3, q10, #12 ; op[3] = (d1*2217 - c1*5352 + 7500)>>12 + + + ; Part two + + ; transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12] + vtrn.32 d0, d2 + vtrn.32 d1, d3 + vtrn.16 d0, d1 + vtrn.16 d2, d3 + + vmov.s16 d26, #7 + + vadd.s16 d4, d0, d3 ; a1 = ip[0] + ip[12] + vadd.s16 d5, d1, d2 ; b1 = ip[4] + ip[8] + vsub.s16 d6, d1, d2 ; c1 = ip[4] - ip[8] + vadd.s16 d4, d4, d26 ; a1 + 7 + vsub.s16 d7, d0, d3 ; d1 = ip[0] - ip[12] + + vadd.s16 d0, d4, d5 ; op[0] = a1 + b1 + 7 + vsub.s16 d2, d4, d5 ; op[8] = a1 - b1 + 7 + + vmlal.s16 q11, d7, d16 ; d1*5352 + 12000 + vmlal.s16 q12, d7, d17 ; d1*2217 + 51000 + + vceq.s16 d4, d7, #0 + + vshr.s16 d0, d0, #4 + vshr.s16 d2, d2, #4 + + vmlal.s16 q11, d6, d17 ; c1*2217 + d1*5352 + 12000 + vmlsl.s16 q12, d6, d16 ; d1*2217 - c1*5352 + 51000 + + vmvn.s16 d4, d4 + vshrn.s32 d1, q11, #16 ; op[4] = (c1*2217 + d1*5352 + 12000)>>16 + vsub.s16 d1, d1, d4 ; op[4] += (d1!=0) + vshrn.s32 d3, q12, #16 ; op[12]= (d1*2217 - c1*5352 + 51000)>>16 + + vst1.16 {q0, q1}, [r1@128] + + bx lr + + ENDP + +;void vp8_short_fdct8x4_c(short *input, short *output, int pitch) +|vp8_short_fdct8x4_neon| PROC + + ; Part one + + vld1.16 {q0}, [r0@128], r2 + adr r12, coeff + vld1.16 {q1}, [r0@128], r2 + vld1.16 {q8}, [r12@128]! ; d16=5352, d17=2217 + vld1.16 {q2}, [r0@128], r2 + vld1.32 {q9, q10}, [r12@128]! ; q9=14500, q10=7500 + vld1.16 {q3}, [r0@128], r2 + + ; transpose q0=ip[0], q1=ip[1], q2=ip[2], q3=ip[3] + vtrn.32 q0, q2 ; [A0|B0] + vtrn.32 q1, q3 ; [A1|B1] + vtrn.16 q0, q1 ; [A2|B2] + vtrn.16 q2, q3 ; [A3|B3] + + vadd.s16 q11, q0, q3 ; a1 = ip[0] + ip[3] + vadd.s16 q12, q1, q2 ; b1 = ip[1] + ip[2] + vsub.s16 q13, q1, q2 ; c1 = ip[1] - ip[2] + vsub.s16 q14, q0, q3 ; d1 = ip[0] - ip[3] + + vshl.s16 q11, q11, #3 ; a1 << 3 + vshl.s16 q12, q12, #3 ; b1 << 3 + vshl.s16 q13, q13, #3 ; c1 << 3 + vshl.s16 q14, q14, #3 ; d1 << 3 + + vadd.s16 q0, q11, q12 ; [A0 | B0] = a1 + b1 + vsub.s16 q2, q11, q12 ; [A2 | B2] = a1 - b1 + + vmov.s16 q11, q9 ; 14500 + vmov.s16 q12, q10 ; 7500 + + vmlal.s16 q9, d28, d16 ; A[1] = d1*5352 + 14500 + vmlal.s16 q10, d28, d17 ; A[3] = d1*2217 + 7500 + vmlal.s16 q11, d29, d16 ; B[1] = d1*5352 + 14500 + vmlal.s16 q12, d29, d17 ; B[3] = d1*2217 + 7500 + + vmlal.s16 q9, d26, d17 ; A[1] = c1*2217 + d1*5352 + 14500 + vmlsl.s16 q10, d26, d16 ; A[3] = d1*2217 - c1*5352 + 7500 + vmlal.s16 q11, d27, d17 ; B[1] = c1*2217 + d1*5352 + 14500 + vmlsl.s16 q12, d27, d16 ; B[3] = d1*2217 - c1*5352 + 7500 + + vshrn.s32 d2, q9, #12 ; A[1] = (c1*2217 + d1*5352 + 14500)>>12 + vshrn.s32 d6, q10, #12 ; A[3] = (d1*2217 - c1*5352 + 7500)>>12 + vshrn.s32 d3, q11, #12 ; B[1] = (c1*2217 + d1*5352 + 14500)>>12 + vshrn.s32 d7, q12, #12 ; B[3] = (d1*2217 - c1*5352 + 7500)>>12 + + + ; Part two + vld1.32 {q9,q10}, [r12@128] ; q9=12000, q10=51000 + + ; transpose q0=ip[0], q1=ip[4], q2=ip[8], q3=ip[12] + vtrn.32 q0, q2 ; q0=[A0 | B0] + vtrn.32 q1, q3 ; q1=[A4 | B4] + vtrn.16 q0, q1 ; q2=[A8 | B8] + vtrn.16 q2, q3 ; q3=[A12|B12] + + vmov.s16 q15, #7 + + vadd.s16 q11, q0, q3 ; a1 = ip[0] + ip[12] + vadd.s16 q12, q1, q2 ; b1 = ip[4] + ip[8] + vadd.s16 q11, q11, q15 ; a1 + 7 + vsub.s16 q13, q1, q2 ; c1 = ip[4] - ip[8] + vsub.s16 q14, q0, q3 ; d1 = ip[0] - ip[12] + + vadd.s16 q0, q11, q12 ; a1 + b1 + 7 + vsub.s16 q1, q11, q12 ; a1 - b1 + 7 + + vmov.s16 q11, q9 ; 12000 + vmov.s16 q12, q10 ; 51000 + + vshr.s16 d0, d0, #4 ; A[0] = (a1 + b1 + 7)>>4 + vshr.s16 d4, d1, #4 ; B[0] = (a1 + b1 + 7)>>4 + vshr.s16 d2, d2, #4 ; A[8] = (a1 + b1 + 7)>>4 + vshr.s16 d6, d3, #4 ; B[8] = (a1 + b1 + 7)>>4 + + + vmlal.s16 q9, d28, d16 ; A[4] = d1*5352 + 12000 + vmlal.s16 q10, d28, d17 ; A[12] = d1*2217 + 51000 + vmlal.s16 q11, d29, d16 ; B[4] = d1*5352 + 12000 + vmlal.s16 q12, d29, d17 ; B[12] = d1*2217 + 51000 + + vceq.s16 q14, q14, #0 + + vmlal.s16 q9, d26, d17 ; A[4] = c1*2217 + d1*5352 + 12000 + vmlsl.s16 q10, d26, d16 ; A[12] = d1*2217 - c1*5352 + 51000 + vmlal.s16 q11, d27, d17 ; B[4] = c1*2217 + d1*5352 + 12000 + vmlsl.s16 q12, d27, d16 ; B[12] = d1*2217 - c1*5352 + 51000 + + vmvn.s16 q14, q14 + + vshrn.s32 d1, q9, #16 ; A[4] = (c1*2217 + d1*5352 + 12000)>>16 + vshrn.s32 d3, q10, #16 ; A[12]= (d1*2217 - c1*5352 + 51000)>>16 + vsub.s16 d1, d1, d28 ; A[4] += (d1!=0) + + vshrn.s32 d5, q11, #16 ; B[4] = (c1*2217 + d1*5352 + 12000)>>16 + vshrn.s32 d7, q12, #16 ; B[12]= (d1*2217 - c1*5352 + 51000)>>16 + vsub.s16 d5, d5, d29 ; B[4] += (d1!=0) + + vst1.16 {q0, q1}, [r1@128]! ; block A + vst1.16 {q2, q3}, [r1@128]! ; block B + + bx lr + + ENDP + + END + diff --git a/vp8/encoder/arm/neon/subtract_neon.asm b/vp8/encoder/arm/neon/subtract_neon.asm new file mode 100644 index 0000000..91a328c --- /dev/null +++ b/vp8/encoder/arm/neon/subtract_neon.asm @@ -0,0 +1,199 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + EXPORT |vp8_subtract_b_neon| + EXPORT |vp8_subtract_mby_neon| + EXPORT |vp8_subtract_mbuv_neon| + + INCLUDE asm_enc_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;void vp8_subtract_b_neon(BLOCK *be, BLOCKD *bd, int pitch) +|vp8_subtract_b_neon| PROC + + stmfd sp!, {r4-r7} + + ldr r3, [r0, #vp8_block_base_src] + ldr r4, [r0, #vp8_block_src] + ldr r5, [r0, #vp8_block_src_diff] + ldr r3, [r3] + ldr r6, [r0, #vp8_block_src_stride] + add r3, r3, r4 ; src = *base_src + src + ldr r7, [r1, #vp8_blockd_predictor] + + vld1.8 {d0}, [r3], r6 ;load src + vld1.8 {d1}, [r7], r2 ;load pred + vld1.8 {d2}, [r3], r6 + vld1.8 {d3}, [r7], r2 + vld1.8 {d4}, [r3], r6 + vld1.8 {d5}, [r7], r2 + vld1.8 {d6}, [r3], r6 + vld1.8 {d7}, [r7], r2 + + vsubl.u8 q10, d0, d1 + vsubl.u8 q11, d2, d3 + vsubl.u8 q12, d4, d5 + vsubl.u8 q13, d6, d7 + + mov r2, r2, lsl #1 + + vst1.16 {d20}, [r5], r2 ;store diff + vst1.16 {d22}, [r5], r2 + vst1.16 {d24}, [r5], r2 + vst1.16 {d26}, [r5], r2 + + ldmfd sp!, {r4-r7} + bx lr + + ENDP + + +;========================================== +;void vp8_subtract_mby_neon(short *diff, unsigned char *src, int src_stride +; unsigned char *pred, int pred_stride) +|vp8_subtract_mby_neon| PROC + push {r4-r7} + mov r12, #4 + ldr r4, [sp, #16] ; pred_stride + mov r6, #32 ; "diff" stride x2 + add r5, r0, #16 ; second diff pointer + +subtract_mby_loop + vld1.8 {q0}, [r1], r2 ;load src + vld1.8 {q1}, [r3], r4 ;load pred + vld1.8 {q2}, [r1], r2 + vld1.8 {q3}, [r3], r4 + vld1.8 {q4}, [r1], r2 + vld1.8 {q5}, [r3], r4 + vld1.8 {q6}, [r1], r2 + vld1.8 {q7}, [r3], r4 + + vsubl.u8 q8, d0, d2 + vsubl.u8 q9, d1, d3 + vsubl.u8 q10, d4, d6 + vsubl.u8 q11, d5, d7 + vsubl.u8 q12, d8, d10 + vsubl.u8 q13, d9, d11 + vsubl.u8 q14, d12, d14 + vsubl.u8 q15, d13, d15 + + vst1.16 {q8}, [r0], r6 ;store diff + vst1.16 {q9}, [r5], r6 + vst1.16 {q10}, [r0], r6 + vst1.16 {q11}, [r5], r6 + vst1.16 {q12}, [r0], r6 + vst1.16 {q13}, [r5], r6 + vst1.16 {q14}, [r0], r6 + vst1.16 {q15}, [r5], r6 + + subs r12, r12, #1 + bne subtract_mby_loop + + pop {r4-r7} + bx lr + ENDP + +;================================= +;void vp8_subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, +; int src_stride, unsigned char *upred, +; unsigned char *vpred, int pred_stride) + +|vp8_subtract_mbuv_neon| PROC + push {r4-r7} + ldr r4, [sp, #16] ; upred + ldr r5, [sp, #20] ; vpred + ldr r6, [sp, #24] ; pred_stride + add r0, r0, #512 ; short *udiff = diff + 256; + mov r12, #32 ; "diff" stride x2 + add r7, r0, #16 ; second diff pointer + +;u + vld1.8 {d0}, [r1], r3 ;load usrc + vld1.8 {d1}, [r4], r6 ;load upred + vld1.8 {d2}, [r1], r3 + vld1.8 {d3}, [r4], r6 + vld1.8 {d4}, [r1], r3 + vld1.8 {d5}, [r4], r6 + vld1.8 {d6}, [r1], r3 + vld1.8 {d7}, [r4], r6 + vld1.8 {d8}, [r1], r3 + vld1.8 {d9}, [r4], r6 + vld1.8 {d10}, [r1], r3 + vld1.8 {d11}, [r4], r6 + vld1.8 {d12}, [r1], r3 + vld1.8 {d13}, [r4], r6 + vld1.8 {d14}, [r1], r3 + vld1.8 {d15}, [r4], r6 + + vsubl.u8 q8, d0, d1 + vsubl.u8 q9, d2, d3 + vsubl.u8 q10, d4, d5 + vsubl.u8 q11, d6, d7 + vsubl.u8 q12, d8, d9 + vsubl.u8 q13, d10, d11 + vsubl.u8 q14, d12, d13 + vsubl.u8 q15, d14, d15 + + vst1.16 {q8}, [r0], r12 ;store diff + vst1.16 {q9}, [r7], r12 + vst1.16 {q10}, [r0], r12 + vst1.16 {q11}, [r7], r12 + vst1.16 {q12}, [r0], r12 + vst1.16 {q13}, [r7], r12 + vst1.16 {q14}, [r0], r12 + vst1.16 {q15}, [r7], r12 + +;v + vld1.8 {d0}, [r2], r3 ;load vsrc + vld1.8 {d1}, [r5], r6 ;load vpred + vld1.8 {d2}, [r2], r3 + vld1.8 {d3}, [r5], r6 + vld1.8 {d4}, [r2], r3 + vld1.8 {d5}, [r5], r6 + vld1.8 {d6}, [r2], r3 + vld1.8 {d7}, [r5], r6 + vld1.8 {d8}, [r2], r3 + vld1.8 {d9}, [r5], r6 + vld1.8 {d10}, [r2], r3 + vld1.8 {d11}, [r5], r6 + vld1.8 {d12}, [r2], r3 + vld1.8 {d13}, [r5], r6 + vld1.8 {d14}, [r2], r3 + vld1.8 {d15}, [r5], r6 + + vsubl.u8 q8, d0, d1 + vsubl.u8 q9, d2, d3 + vsubl.u8 q10, d4, d5 + vsubl.u8 q11, d6, d7 + vsubl.u8 q12, d8, d9 + vsubl.u8 q13, d10, d11 + vsubl.u8 q14, d12, d13 + vsubl.u8 q15, d14, d15 + + vst1.16 {q8}, [r0], r12 ;store diff + vst1.16 {q9}, [r7], r12 + vst1.16 {q10}, [r0], r12 + vst1.16 {q11}, [r7], r12 + vst1.16 {q12}, [r0], r12 + vst1.16 {q13}, [r7], r12 + vst1.16 {q14}, [r0], r12 + vst1.16 {q15}, [r7], r12 + + pop {r4-r7} + bx lr + + ENDP + + END diff --git a/vp8/encoder/arm/neon/vp8_memcpy_neon.asm b/vp8/encoder/arm/neon/vp8_memcpy_neon.asm new file mode 100644 index 0000000..5b9f11e --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_memcpy_neon.asm @@ -0,0 +1,70 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_memcpy_partial_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;========================================= +;this is not a full memcpy function!!! +;void vp8_memcpy_partial_neon(unsigned char *dst_ptr, unsigned char *src_ptr, +; int sz); +|vp8_memcpy_partial_neon| PROC + ;pld [r1] ;preload pred data + ;pld [r1, #128] + ;pld [r1, #256] + ;pld [r1, #384] + + mov r12, r2, lsr #8 ;copy 256 bytes data at one time + +memcpy_neon_loop + vld1.8 {q0, q1}, [r1]! ;load src data + subs r12, r12, #1 + vld1.8 {q2, q3}, [r1]! + vst1.8 {q0, q1}, [r0]! ;copy to dst_ptr + vld1.8 {q4, q5}, [r1]! + vst1.8 {q2, q3}, [r0]! + vld1.8 {q6, q7}, [r1]! + vst1.8 {q4, q5}, [r0]! + vld1.8 {q8, q9}, [r1]! + vst1.8 {q6, q7}, [r0]! + vld1.8 {q10, q11}, [r1]! + vst1.8 {q8, q9}, [r0]! + vld1.8 {q12, q13}, [r1]! + vst1.8 {q10, q11}, [r0]! + vld1.8 {q14, q15}, [r1]! + vst1.8 {q12, q13}, [r0]! + vst1.8 {q14, q15}, [r0]! + + ;pld [r1] ;preload pred data -- need to adjust for real device + ;pld [r1, #128] + ;pld [r1, #256] + ;pld [r1, #384] + + bne memcpy_neon_loop + + ands r3, r2, #0xff ;extra copy + beq done_copy_neon_loop + +extra_copy_neon_loop + vld1.8 {q0}, [r1]! ;load src data + subs r3, r3, #16 + vst1.8 {q0}, [r0]! + bne extra_copy_neon_loop + +done_copy_neon_loop + bx lr + ENDP + + END diff --git a/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm b/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm new file mode 100644 index 0000000..55edbf5 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm @@ -0,0 +1,116 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_mse16x16_neon| + EXPORT |vp8_get4x4sse_cs_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;============================ +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +;note: in this function, sum is never used. So, we can remove this part of calculation +;from vp8_variance(). + +|vp8_mse16x16_neon| PROC + vmov.i8 q7, #0 ;q7, q8, q9, q10 - sse + vmov.i8 q8, #0 + vmov.i8 q9, #0 + vmov.i8 q10, #0 + + mov r12, #8 + +mse16x16_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vmlal.s16 q7, d22, d22 + vmlal.s16 q8, d23, d23 + + subs r12, r12, #1 + + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vmlal.s16 q7, d26, d26 + vmlal.s16 q8, d27, d27 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne mse16x16_neon_loop + + vadd.u32 q7, q7, q8 + vadd.u32 q9, q9, q10 + + ldr r12, [sp] ;load *sse from stack + + vadd.u32 q10, q7, q9 + vpaddl.u32 q1, q10 + vadd.u64 d0, d2, d3 + + vst1.32 {d0[0]}, [r12] + vmov.32 r0, d0[0] + + bx lr + + ENDP + + +;============================= +; r0 unsigned char *src_ptr, +; r1 int source_stride, +; r2 unsigned char *ref_ptr, +; r3 int recon_stride +|vp8_get4x4sse_cs_neon| PROC + vld1.8 {d0}, [r0], r1 ;Load up source and reference + vld1.8 {d4}, [r2], r3 + vld1.8 {d1}, [r0], r1 + vld1.8 {d5}, [r2], r3 + vld1.8 {d2}, [r0], r1 + vld1.8 {d6}, [r2], r3 + vld1.8 {d3}, [r0], r1 + vld1.8 {d7}, [r2], r3 + + vsubl.u8 q11, d0, d4 + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vmull.s16 q7, d22, d22 + vmull.s16 q8, d24, d24 + vmull.s16 q9, d26, d26 + vmull.s16 q10, d28, d28 + + vadd.u32 q7, q7, q8 + vadd.u32 q9, q9, q10 + vadd.u32 q9, q7, q9 + + vpaddl.u32 q1, q9 + vadd.u64 d0, d2, d3 + + vmov.32 r0, d0[0] + bx lr + + ENDP + + END diff --git a/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm b/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm new file mode 100644 index 0000000..2226629 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm @@ -0,0 +1,103 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_short_walsh4x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_short_walsh4x4_neon(short *input, short *output, int pitch) +; r0 short *input, +; r1 short *output, +; r2 int pitch +|vp8_short_walsh4x4_neon| PROC + + vld1.16 {d0}, [r0@64], r2 ; load input + vld1.16 {d1}, [r0@64], r2 + vld1.16 {d2}, [r0@64], r2 + vld1.16 {d3}, [r0@64] + + ;First for-loop + ;transpose d0, d1, d2, d3. Then, d0=ip[0], d1=ip[1], d2=ip[2], d3=ip[3] + vtrn.32 d0, d2 + vtrn.32 d1, d3 + + vmov.s32 q15, #3 ; add 3 to all values + + vtrn.16 d0, d1 + vtrn.16 d2, d3 + + vadd.s16 d4, d0, d2 ; ip[0] + ip[2] + vadd.s16 d5, d1, d3 ; ip[1] + ip[3] + vsub.s16 d6, d1, d3 ; ip[1] - ip[3] + vsub.s16 d7, d0, d2 ; ip[0] - ip[2] + + vshl.s16 d4, d4, #2 ; a1 = (ip[0] + ip[2]) << 2 + vshl.s16 d5, d5, #2 ; d1 = (ip[1] + ip[3]) << 2 + vshl.s16 d6, d6, #2 ; c1 = (ip[1] - ip[3]) << 2 + vceq.s16 d16, d4, #0 ; a1 == 0 + vshl.s16 d7, d7, #2 ; b1 = (ip[0] - ip[2]) << 2 + + vadd.s16 d0, d4, d5 ; a1 + d1 + vmvn d16, d16 ; a1 != 0 + vsub.s16 d3, d4, d5 ; op[3] = a1 - d1 + vadd.s16 d1, d7, d6 ; op[1] = b1 + c1 + vsub.s16 d2, d7, d6 ; op[2] = b1 - c1 + vsub.s16 d0, d0, d16 ; op[0] = a1 + d1 + (a1 != 0) + + ;Second for-loop + ;transpose d0, d1, d2, d3, Then, d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12] + vtrn.32 d1, d3 + vtrn.32 d0, d2 + vtrn.16 d2, d3 + vtrn.16 d0, d1 + + vaddl.s16 q8, d0, d2 ; a1 = ip[0]+ip[8] + vaddl.s16 q9, d1, d3 ; d1 = ip[4]+ip[12] + vsubl.s16 q10, d1, d3 ; c1 = ip[4]-ip[12] + vsubl.s16 q11, d0, d2 ; b1 = ip[0]-ip[8] + + vadd.s32 q0, q8, q9 ; a2 = a1 + d1 + vadd.s32 q1, q11, q10 ; b2 = b1 + c1 + vsub.s32 q2, q11, q10 ; c2 = b1 - c1 + vsub.s32 q3, q8, q9 ; d2 = a1 - d1 + + vclt.s32 q8, q0, #0 + vclt.s32 q9, q1, #0 + vclt.s32 q10, q2, #0 + vclt.s32 q11, q3, #0 + + ; subtract -1 (or 0) + vsub.s32 q0, q0, q8 ; a2 += a2 < 0 + vsub.s32 q1, q1, q9 ; b2 += b2 < 0 + vsub.s32 q2, q2, q10 ; c2 += c2 < 0 + vsub.s32 q3, q3, q11 ; d2 += d2 < 0 + + vadd.s32 q8, q0, q15 ; a2 + 3 + vadd.s32 q9, q1, q15 ; b2 + 3 + vadd.s32 q10, q2, q15 ; c2 + 3 + vadd.s32 q11, q3, q15 ; d2 + 3 + + ; vrshrn? would add 1 << 3-1 = 2 + vshrn.s32 d0, q8, #3 + vshrn.s32 d1, q9, #3 + vshrn.s32 d2, q10, #3 + vshrn.s32 d3, q11, #3 + + vst1.16 {q0, q1}, [r1@128] + + bx lr + + ENDP + + END diff --git a/vp8/encoder/arm/quantize_arm.c b/vp8/encoder/arm/quantize_arm.c new file mode 100644 index 0000000..8999e34 --- /dev/null +++ b/vp8/encoder/arm/quantize_arm.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vp8/encoder/block.h" +#include +#include "vpx_mem/vpx_mem.h" +#include "vp8/encoder/quantize.h" +#include "vp8/common/entropy.h" + + +#if HAVE_NEON + +/* vp8_quantize_mbX functions here differs from corresponding ones in + * quantize.c only by using quantize_b_pair function pointer instead of + * the regular quantize_b function pointer */ +void vp8_quantize_mby_neon(MACROBLOCK *x) +{ + int i; + int has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + + for (i = 0; i < 16; i+=2) + x->quantize_b_pair(&x->block[i], &x->block[i+1], + &x->e_mbd.block[i], &x->e_mbd.block[i+1]); + + if(has_2nd_order) + x->quantize_b(&x->block[24], &x->e_mbd.block[24]); +} + +void vp8_quantize_mb_neon(MACROBLOCK *x) +{ + int i; + int has_2nd_order=(x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + + for (i = 0; i < 24; i+=2) + x->quantize_b_pair(&x->block[i], &x->block[i+1], + &x->e_mbd.block[i], &x->e_mbd.block[i+1]); + + if (has_2nd_order) + x->quantize_b(&x->block[24], &x->e_mbd.block[24]); +} + + +void vp8_quantize_mbuv_neon(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i+=2) + x->quantize_b_pair(&x->block[i], &x->block[i+1], + &x->e_mbd.block[i], &x->e_mbd.block[i+1]); +} + +#endif /* HAVE_NEON */ diff --git a/vp8/encoder/asm_enc_offsets.c b/vp8/encoder/asm_enc_offsets.c new file mode 100644 index 0000000..a4169b3 --- /dev/null +++ b/vp8/encoder/asm_enc_offsets.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_ports/asm_offsets.h" +#include "vpx_config.h" +#include "block.h" +#include "vp8/common/blockd.h" +#include "onyx_int.h" +#include "treewriter.h" +#include "tokenize.h" + +BEGIN + +/* regular quantize */ +DEFINE(vp8_block_coeff, offsetof(BLOCK, coeff)); +DEFINE(vp8_block_zbin, offsetof(BLOCK, zbin)); +DEFINE(vp8_block_round, offsetof(BLOCK, round)); +DEFINE(vp8_block_quant, offsetof(BLOCK, quant)); +DEFINE(vp8_block_quant_fast, offsetof(BLOCK, quant_fast)); +DEFINE(vp8_block_zbin_extra, offsetof(BLOCK, zbin_extra)); +DEFINE(vp8_block_zrun_zbin_boost, offsetof(BLOCK, zrun_zbin_boost)); +DEFINE(vp8_block_quant_shift, offsetof(BLOCK, quant_shift)); + +DEFINE(vp8_blockd_qcoeff, offsetof(BLOCKD, qcoeff)); +DEFINE(vp8_blockd_dequant, offsetof(BLOCKD, dequant)); +DEFINE(vp8_blockd_dqcoeff, offsetof(BLOCKD, dqcoeff)); +DEFINE(vp8_blockd_eob, offsetof(BLOCKD, eob)); + +/* subtract */ +DEFINE(vp8_block_base_src, offsetof(BLOCK, base_src)); +DEFINE(vp8_block_src, offsetof(BLOCK, src)); +DEFINE(vp8_block_src_diff, offsetof(BLOCK, src_diff)); +DEFINE(vp8_block_src_stride, offsetof(BLOCK, src_stride)); + +DEFINE(vp8_blockd_predictor, offsetof(BLOCKD, predictor)); + +/* pack tokens */ +DEFINE(vp8_writer_lowvalue, offsetof(vp8_writer, lowvalue)); +DEFINE(vp8_writer_range, offsetof(vp8_writer, range)); +DEFINE(vp8_writer_count, offsetof(vp8_writer, count)); +DEFINE(vp8_writer_pos, offsetof(vp8_writer, pos)); +DEFINE(vp8_writer_buffer, offsetof(vp8_writer, buffer)); +DEFINE(vp8_writer_buffer_end, offsetof(vp8_writer, buffer_end)); +DEFINE(vp8_writer_error, offsetof(vp8_writer, error)); + +DEFINE(tokenextra_token, offsetof(TOKENEXTRA, Token)); +DEFINE(tokenextra_extra, offsetof(TOKENEXTRA, Extra)); +DEFINE(tokenextra_context_tree, offsetof(TOKENEXTRA, context_tree)); +DEFINE(tokenextra_skip_eob_node, offsetof(TOKENEXTRA, skip_eob_node)); +DEFINE(TOKENEXTRA_SZ, sizeof(TOKENEXTRA)); + +DEFINE(vp8_extra_bit_struct_sz, sizeof(vp8_extra_bit_struct)); + +DEFINE(vp8_token_value, offsetof(vp8_token, value)); +DEFINE(vp8_token_len, offsetof(vp8_token, Len)); + +DEFINE(vp8_extra_bit_struct_tree, offsetof(vp8_extra_bit_struct, tree)); +DEFINE(vp8_extra_bit_struct_prob, offsetof(vp8_extra_bit_struct, prob)); +DEFINE(vp8_extra_bit_struct_len, offsetof(vp8_extra_bit_struct, Len)); +DEFINE(vp8_extra_bit_struct_base_val, offsetof(vp8_extra_bit_struct, base_val)); + +DEFINE(vp8_comp_tplist, offsetof(VP8_COMP, tplist)); +DEFINE(vp8_comp_common, offsetof(VP8_COMP, common)); +DEFINE(vp8_comp_bc , offsetof(VP8_COMP, bc)); +DEFINE(vp8_writer_sz , sizeof(vp8_writer)); + +DEFINE(tokenlist_start, offsetof(TOKENLIST, start)); +DEFINE(tokenlist_stop, offsetof(TOKENLIST, stop)); +DEFINE(TOKENLIST_SZ, sizeof(TOKENLIST)); + +DEFINE(vp8_common_mb_rows, offsetof(VP8_COMMON, mb_rows)); + +END + +/* add asserts for any offset that is not supported by assembly code + * add asserts for any size that is not supported by assembly code + + * These are used in vp8cx_pack_tokens. They are hard coded so if their sizes + * change they will have to be adjusted. + */ + +#if HAVE_EDSP +ct_assert(TOKENEXTRA_SZ, sizeof(TOKENEXTRA) == 8) +ct_assert(vp8_extra_bit_struct_sz, sizeof(vp8_extra_bit_struct) == 16) +#endif diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c new file mode 100644 index 0000000..3824294 --- /dev/null +++ b/vp8/encoder/bitstream.c @@ -0,0 +1,1734 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/header.h" +#include "encodemv.h" +#include "vp8/common/entropymode.h" +#include "vp8/common/findnearmv.h" +#include "mcomp.h" +#include "vp8/common/systemdependent.h" +#include +#include +#include +#include "vp8/common/pragmas.h" +#include "vpx/vpx_encoder.h" +#include "vpx_mem/vpx_mem.h" +#include "bitstream.h" + +#include "defaultcoefcounts.h" +#include "vp8/common/common.h" + +const int vp8cx_base_skip_false_prob[128] = +{ + 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, 248, 244, 240, 236, 232, 229, 225, + 221, 217, 213, 208, 204, 199, 194, 190, + 187, 183, 179, 175, 172, 168, 164, 160, + 157, 153, 149, 145, 142, 138, 134, 130, + 127, 124, 120, 117, 114, 110, 107, 104, + 101, 98, 95, 92, 89, 86, 83, 80, + 77, 74, 71, 68, 65, 62, 59, 56, + 53, 50, 47, 44, 41, 38, 35, 32, + 30, 28, 26, 24, 22, 20, 18, 16, +}; + +#if defined(SECTIONBITS_OUTPUT) +unsigned __int64 Sectionbits[500]; +#endif + +#ifdef ENTROPY_STATS +int intra_mode_stats[10][10][10]; +static unsigned int tree_update_hist [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] [2]; +extern unsigned int active_section; +#endif + +#ifdef MODE_STATS +int count_mb_seg[4] = { 0, 0, 0, 0 }; +#endif + + +static void update_mode( + vp8_writer *const w, + int n, + vp8_token tok [/* n */], + vp8_tree tree, + vp8_prob Pnew [/* n-1 */], + vp8_prob Pcur [/* n-1 */], + unsigned int bct [/* n-1 */] [2], + const unsigned int num_events[/* n */] +) +{ + unsigned int new_b = 0, old_b = 0; + int i = 0; + + vp8_tree_probs_from_distribution( + n--, tok, tree, + Pnew, bct, num_events, + 256, 1 + ); + + do + { + new_b += vp8_cost_branch(bct[i], Pnew[i]); + old_b += vp8_cost_branch(bct[i], Pcur[i]); + } + while (++i < n); + + if (new_b + (n << 8) < old_b) + { + int i = 0; + + vp8_write_bit(w, 1); + + do + { + const vp8_prob p = Pnew[i]; + + vp8_write_literal(w, Pcur[i] = p ? p : 1, 8); + } + while (++i < n); + } + else + vp8_write_bit(w, 0); +} + +static void update_mbintra_mode_probs(VP8_COMP *cpi) +{ + VP8_COMMON *const x = & cpi->common; + + vp8_writer *const w = cpi->bc; + + { + vp8_prob Pnew [VP8_YMODES-1]; + unsigned int bct [VP8_YMODES-1] [2]; + + update_mode( + w, VP8_YMODES, vp8_ymode_encodings, vp8_ymode_tree, + Pnew, x->fc.ymode_prob, bct, (unsigned int *)cpi->ymode_count + ); + } + { + vp8_prob Pnew [VP8_UV_MODES-1]; + unsigned int bct [VP8_UV_MODES-1] [2]; + + update_mode( + w, VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, + Pnew, x->fc.uv_mode_prob, bct, (unsigned int *)cpi->uv_mode_count + ); + } +} + +static void write_ymode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_ymode_tree, p, vp8_ymode_encodings + m); +} + +static void kfwrite_ymode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_kf_ymode_tree, p, vp8_kf_ymode_encodings + m); +} + +static void write_uv_mode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_uv_mode_tree, p, vp8_uv_mode_encodings + m); +} + + +static void write_bmode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_bmode_tree, p, vp8_bmode_encodings + m); +} + +static void write_split(vp8_writer *bc, int x) +{ + vp8_write_token( + bc, vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + x + ); +} + +void vp8_pack_tokens_c(vp8_writer *w, const TOKENEXTRA *p, int xcount) +{ + const TOKENEXTRA *stop = p + xcount; + unsigned int split; + unsigned int shift; + int count = w->count; + unsigned int range = w->range; + unsigned int lowvalue = w->lowvalue; + + while (p < stop) + { + const int t = p->Token; + const vp8_token *a = vp8_coef_encodings + t; + const vp8_extra_bit_struct *b = vp8_extra_bits + t; + int i = 0; + const unsigned char *pp = p->context_tree; + int v = a->value; + int n = a->Len; + + if (p->skip_eob_node) + { + n--; + i = 2; + } + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = vp8_coef_tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = vp8_norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + validate_buffer(w->buffer + w->pos, + 1, + w->buffer_end, + w->error); + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + + + if (b->base_val) + { + const int e = p->Extra, L = b->Len; + + if (L) + { + const unsigned char *pp = b->prob; + int v = e >> 1; + int n = L; /* number of bits in v, assumed nonzero */ + int i = 0; + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = b->tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = vp8_norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + validate_buffer(w->buffer + w->pos, + 1, + w->buffer_end, + w->error); + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + } + + + { + + split = (range + 1) >> 1; + + if (e & 1) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + range <<= 1; + + if ((lowvalue & 0x80000000)) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + + } + + lowvalue <<= 1; + + if (!++count) + { + count = -8; + + validate_buffer(w->buffer + w->pos, + 1, + w->buffer_end, + w->error); + + w->buffer[w->pos++] = (lowvalue >> 24); + lowvalue &= 0xffffff; + } + } + + } + + ++p; + } + + w->count = count; + w->lowvalue = lowvalue; + w->range = range; + +} + +static void write_partition_size(unsigned char *cx_data, int size) +{ + signed char csize; + + csize = size & 0xff; + *cx_data = csize; + csize = (size >> 8) & 0xff; + *(cx_data + 1) = csize; + csize = (size >> 16) & 0xff; + *(cx_data + 2) = csize; + +} + +static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data, + unsigned char * cx_data_end, + int num_part) +{ + + int i; + unsigned char *ptr = cx_data; + unsigned char *ptr_end = cx_data_end; + vp8_writer * w; + + for (i = 0; i < num_part; i++) + { + int mb_row; + + w = cpi->bc + i + 1; + + vp8_start_encode(w, ptr, ptr_end); + + for (mb_row = i; mb_row < cpi->common.mb_rows; mb_row += num_part) + { + const TOKENEXTRA *p = cpi->tplist[mb_row].start; + const TOKENEXTRA *stop = cpi->tplist[mb_row].stop; + int tokens = stop - p; + + vp8_pack_tokens_c(w, p, tokens); + } + + vp8_stop_encode(w); + ptr += w->pos; + } +} + + +static void pack_mb_row_tokens_c(VP8_COMP *cpi, vp8_writer *w) +{ + int mb_row; + + for (mb_row = 0; mb_row < cpi->common.mb_rows; mb_row++) + { + const TOKENEXTRA *p = cpi->tplist[mb_row].start; + const TOKENEXTRA *stop = cpi->tplist[mb_row].stop; + int tokens = stop - p; + + vp8_pack_tokens_c(w, p, tokens); + } + +} + +static void write_mv_ref +( + vp8_writer *w, MB_PREDICTION_MODE m, const vp8_prob *p +) +{ +#if CONFIG_DEBUG + assert(NEARESTMV <= m && m <= SPLITMV); +#endif + vp8_write_token(w, vp8_mv_ref_tree, p, + vp8_mv_ref_encoding_array - NEARESTMV + m); +} + +static void write_sub_mv_ref +( + vp8_writer *w, B_PREDICTION_MODE m, const vp8_prob *p +) +{ +#if CONFIG_DEBUG + assert(LEFT4X4 <= m && m <= NEW4X4); +#endif + vp8_write_token(w, vp8_sub_mv_ref_tree, p, + vp8_sub_mv_ref_encoding_array - LEFT4X4 + m); +} + +static void write_mv +( + vp8_writer *w, const MV *mv, const int_mv *ref, const MV_CONTEXT *mvc +) +{ + MV e; + e.row = mv->row - ref->as_mv.row; + e.col = mv->col - ref->as_mv.col; + + vp8_encode_motion_vector(w, &e, mvc); +} + +static void write_mb_features(vp8_writer *w, const MB_MODE_INFO *mi, const MACROBLOCKD *x) +{ + // Encode the MB segment id. + if (x->segmentation_enabled && x->update_mb_segmentation_map) + { + switch (mi->segment_id) + { + case 0: + vp8_write(w, 0, x->mb_segment_tree_probs[0]); + vp8_write(w, 0, x->mb_segment_tree_probs[1]); + break; + case 1: + vp8_write(w, 0, x->mb_segment_tree_probs[0]); + vp8_write(w, 1, x->mb_segment_tree_probs[1]); + break; + case 2: + vp8_write(w, 1, x->mb_segment_tree_probs[0]); + vp8_write(w, 0, x->mb_segment_tree_probs[2]); + break; + case 3: + vp8_write(w, 1, x->mb_segment_tree_probs[0]); + vp8_write(w, 1, x->mb_segment_tree_probs[2]); + break; + + // TRAP.. This should not happen + default: + vp8_write(w, 0, x->mb_segment_tree_probs[0]); + vp8_write(w, 0, x->mb_segment_tree_probs[1]); + break; + } + } +} +void vp8_convert_rfct_to_prob(VP8_COMP *const cpi) +{ + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + // Calculate the probabilities used to code the ref frame based on useage + if (!(cpi->prob_intra_coded = rf_intra * 255 / (rf_intra + rf_inter))) + cpi->prob_intra_coded = 1; + + cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + if (!cpi->prob_last_coded) + cpi->prob_last_coded = 1; + + cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + if (!cpi->prob_gf_coded) + cpi->prob_gf_coded = 1; + +} + +static void pack_inter_mode_mvs(VP8_COMP *const cpi) +{ + VP8_COMMON *const pc = & cpi->common; + vp8_writer *const w = cpi->bc; + const MV_CONTEXT *mvc = pc->fc.mvc; + + + MODE_INFO *m = pc->mi; + const int mis = pc->mode_info_stride; + int mb_row = -1; + + int prob_skip_false = 0; + + cpi->mb.partition_info = cpi->mb.pi; + + vp8_convert_rfct_to_prob(cpi); + +#ifdef ENTROPY_STATS + active_section = 1; +#endif + + if (pc->mb_no_coeff_skip) + { + int total_mbs = pc->mb_rows * pc->mb_cols; + + prob_skip_false = (total_mbs - cpi->skip_true_count ) * 256 / total_mbs; + + if (prob_skip_false <= 1) + prob_skip_false = 1; + + if (prob_skip_false > 255) + prob_skip_false = 255; + + cpi->prob_skip_false = prob_skip_false; + vp8_write_literal(w, prob_skip_false, 8); + } + + vp8_write_literal(w, cpi->prob_intra_coded, 8); + vp8_write_literal(w, cpi->prob_last_coded, 8); + vp8_write_literal(w, cpi->prob_gf_coded, 8); + + update_mbintra_mode_probs(cpi); + + vp8_write_mvprobs(cpi); + + while (++mb_row < pc->mb_rows) + { + int mb_col = -1; + + while (++mb_col < pc->mb_cols) + { + const MB_MODE_INFO *const mi = & m->mbmi; + const MV_REFERENCE_FRAME rf = mi->ref_frame; + const MB_PREDICTION_MODE mode = mi->mode; + + MACROBLOCKD *xd = &cpi->mb.e_mbd; + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to MV values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + +#ifdef ENTROPY_STATS + active_section = 9; +#endif + + if (cpi->mb.e_mbd.update_mb_segmentation_map) + write_mb_features(w, mi, &cpi->mb.e_mbd); + + if (pc->mb_no_coeff_skip) + vp8_encode_bool(w, m->mbmi.mb_skip_coeff, prob_skip_false); + + if (rf == INTRA_FRAME) + { + vp8_write(w, 0, cpi->prob_intra_coded); +#ifdef ENTROPY_STATS + active_section = 6; +#endif + write_ymode(w, mode, pc->fc.ymode_prob); + + if (mode == B_PRED) + { + int j = 0; + + do + write_bmode(w, m->bmi[j].as_mode, pc->fc.bmode_prob); + while (++j < 16); + } + + write_uv_mode(w, mi->uv_mode, pc->fc.uv_mode_prob); + } + else /* inter coded */ + { + int_mv best_mv; + vp8_prob mv_ref_p [VP8_MVREFS-1]; + + vp8_write(w, 1, cpi->prob_intra_coded); + + if (rf == LAST_FRAME) + vp8_write(w, 0, cpi->prob_last_coded); + else + { + vp8_write(w, 1, cpi->prob_last_coded); + vp8_write(w, (rf == GOLDEN_FRAME) ? 0 : 1, cpi->prob_gf_coded); + } + + { + int_mv n1, n2; + int ct[4]; + + vp8_find_near_mvs(xd, m, &n1, &n2, &best_mv, ct, rf, cpi->common.ref_frame_sign_bias); + vp8_clamp_mv2(&best_mv, xd); + + vp8_mv_ref_probs(mv_ref_p, ct); + +#ifdef ENTROPY_STATS + accum_mv_refs(mode, ct); +#endif + + } + +#ifdef ENTROPY_STATS + active_section = 3; +#endif + + write_mv_ref(w, mode, mv_ref_p); + + switch (mode) /* new, split require MVs */ + { + case NEWMV: + +#ifdef ENTROPY_STATS + active_section = 5; +#endif + + write_mv(w, &mi->mv.as_mv, &best_mv, mvc); + break; + + case SPLITMV: + { + int j = 0; + +#ifdef MODE_STATS + ++count_mb_seg [mi->partitioning]; +#endif + + write_split(w, mi->partitioning); + + do + { + B_PREDICTION_MODE blockmode; + int_mv blockmv; + const int *const L = vp8_mbsplits [mi->partitioning]; + int k = -1; /* first block in subset j */ + int mv_contz; + int_mv leftmv, abovemv; + + blockmode = cpi->mb.partition_info->bmi[j].mode; + blockmv = cpi->mb.partition_info->bmi[j].mv; +#if CONFIG_DEBUG + while (j != L[++k]) + if (k >= 16) + assert(0); +#else + while (j != L[++k]); +#endif + leftmv.as_int = left_block_mv(m, k); + abovemv.as_int = above_block_mv(m, k, mis); + mv_contz = vp8_mv_cont(&leftmv, &abovemv); + + write_sub_mv_ref(w, blockmode, vp8_sub_mv_ref_prob2 [mv_contz]); + + if (blockmode == NEW4X4) + { +#ifdef ENTROPY_STATS + active_section = 11; +#endif + write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *) mvc); + } + } + while (++j < cpi->mb.partition_info->count); + } + break; + default: + break; + } + } + + ++m; + cpi->mb.partition_info++; + } + + ++m; /* skip L prediction border */ + cpi->mb.partition_info++; + } +} + + +static void write_kfmodes(VP8_COMP *cpi) +{ + vp8_writer *const bc = cpi->bc; + const VP8_COMMON *const c = & cpi->common; + /* const */ + MODE_INFO *m = c->mi; + + int mb_row = -1; + int prob_skip_false = 0; + + if (c->mb_no_coeff_skip) + { + int total_mbs = c->mb_rows * c->mb_cols; + + prob_skip_false = (total_mbs - cpi->skip_true_count ) * 256 / total_mbs; + + if (prob_skip_false <= 1) + prob_skip_false = 1; + + if (prob_skip_false >= 255) + prob_skip_false = 255; + + cpi->prob_skip_false = prob_skip_false; + vp8_write_literal(bc, prob_skip_false, 8); + } + + while (++mb_row < c->mb_rows) + { + int mb_col = -1; + + while (++mb_col < c->mb_cols) + { + const int ym = m->mbmi.mode; + + if (cpi->mb.e_mbd.update_mb_segmentation_map) + write_mb_features(bc, &m->mbmi, &cpi->mb.e_mbd); + + if (c->mb_no_coeff_skip) + vp8_encode_bool(bc, m->mbmi.mb_skip_coeff, prob_skip_false); + + kfwrite_ymode(bc, ym, c->kf_ymode_prob); + + if (ym == B_PRED) + { + const int mis = c->mode_info_stride; + int i = 0; + + do + { + const B_PREDICTION_MODE A = above_block_mode(m, i, mis); + const B_PREDICTION_MODE L = left_block_mode(m, i); + const int bm = m->bmi[i].as_mode; + +#ifdef ENTROPY_STATS + ++intra_mode_stats [A] [L] [bm]; +#endif + + write_bmode(bc, bm, c->kf_bmode_prob [A] [L]); + } + while (++i < 16); + } + + write_uv_mode(bc, (m++)->mbmi.uv_mode, c->kf_uv_mode_prob); + } + + m++; // skip L prediction border + } +} + +#if 0 +/* This function is used for debugging probability trees. */ +static void print_prob_tree(vp8_prob + coef_probs[BLOCK_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS][ENTROPY_NODES]) +{ + /* print coef probability tree */ + int i,j,k,l; + FILE* f = fopen("enc_tree_probs.txt", "a"); + fprintf(f, "{\n"); + for (i = 0; i < BLOCK_TYPES; i++) + { + fprintf(f, " {\n"); + for (j = 0; j < COEF_BANDS; j++) + { + fprintf(f, " {\n"); + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + { + fprintf(f, " {"); + for (l = 0; l < ENTROPY_NODES; l++) + { + fprintf(f, "%3u, ", + (unsigned int)(coef_probs [i][j][k][l])); + } + fprintf(f, " }\n"); + } + fprintf(f, " }\n"); + } + fprintf(f, " }\n"); + } + fprintf(f, "}\n"); + fclose(f); +} +#endif + +static void sum_probs_over_prev_coef_context( + const unsigned int probs[PREV_COEF_CONTEXTS][MAX_ENTROPY_TOKENS], + unsigned int* out) +{ + int i, j; + for (i=0; i < MAX_ENTROPY_TOKENS; ++i) + { + for (j=0; j < PREV_COEF_CONTEXTS; ++j) + { + const unsigned int tmp = out[i]; + out[i] += probs[j][i]; + /* check for wrap */ + if (out[i] < tmp) + out[i] = UINT_MAX; + } + } +} + +static int prob_update_savings(const unsigned int *ct, + const vp8_prob oldp, const vp8_prob newp, + const vp8_prob upd) +{ + const int old_b = vp8_cost_branch(ct, oldp); + const int new_b = vp8_cost_branch(ct, newp); + const int update_b = 8 + + ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8); + + return old_b - new_b - update_b; +} + +static int independent_coef_context_savings(VP8_COMP *cpi) +{ + int savings = 0; + int i = 0; + do + { + int j = 0; + do + { + int k = 0; + unsigned int prev_coef_count_sum[MAX_ENTROPY_TOKENS] = {0}; + int prev_coef_savings[MAX_ENTROPY_TOKENS] = {0}; + const unsigned int (*probs)[MAX_ENTROPY_TOKENS]; + /* Calculate new probabilities given the constraint that + * they must be equal over the prev coef contexts + */ + + probs = (const unsigned int (*)[MAX_ENTROPY_TOKENS]) + cpi->coef_counts[i][j]; + + /* Reset to default probabilities at key frames */ + if (cpi->common.frame_type == KEY_FRAME) + probs = default_coef_counts[i][j]; + + sum_probs_over_prev_coef_context(probs, prev_coef_count_sum); + + do + { + /* at every context */ + + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + + int t = 0; /* token/prob index */ + + vp8_tree_probs_from_distribution( + MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + cpi->frame_coef_probs[i][j][k], + cpi->frame_branch_ct [i][j][k], + prev_coef_count_sum, + 256, 1); + + do + { + const unsigned int *ct = cpi->frame_branch_ct [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; + const vp8_prob oldp = cpi->common.fc.coef_probs [i][j][k][t]; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + const int s = prob_update_savings(ct, oldp, newp, upd); + + if (cpi->common.frame_type != KEY_FRAME || + (cpi->common.frame_type == KEY_FRAME && newp != oldp)) + prev_coef_savings[t] += s; + } + while (++t < ENTROPY_NODES); + } + while (++k < PREV_COEF_CONTEXTS); + k = 0; + do + { + /* We only update probabilities if we can save bits, except + * for key frames where we have to update all probabilities + * to get the equal probabilities across the prev coef + * contexts. + */ + if (prev_coef_savings[k] > 0 || + cpi->common.frame_type == KEY_FRAME) + savings += prev_coef_savings[k]; + } + while (++k < ENTROPY_NODES); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + return savings; +} + +static int default_coef_context_savings(VP8_COMP *cpi) +{ + int savings = 0; + int i = 0; + do + { + int j = 0; + do + { + int k = 0; + do + { + /* at every context */ + + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + + int t = 0; /* token/prob index */ + + vp8_tree_probs_from_distribution( + MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + cpi->frame_coef_probs [i][j][k], + cpi->frame_branch_ct [i][j][k], + cpi->coef_counts [i][j][k], + 256, 1 + ); + + do + { + const unsigned int *ct = cpi->frame_branch_ct [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; + const vp8_prob oldp = cpi->common.fc.coef_probs [i][j][k][t]; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + const int s = prob_update_savings(ct, oldp, newp, upd); + + if (s > 0) + { + savings += s; + } + } + while (++t < ENTROPY_NODES); + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + return savings; +} + +void vp8_calc_ref_frame_costs(int *ref_frame_cost, + int prob_intra, + int prob_last, + int prob_garf + ) +{ + ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(prob_intra); + ref_frame_cost[LAST_FRAME] = vp8_cost_one(prob_intra) + + vp8_cost_zero(prob_last); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(prob_intra) + + vp8_cost_one(prob_last) + + vp8_cost_zero(prob_garf); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(prob_intra) + + vp8_cost_one(prob_last) + + vp8_cost_one(prob_garf); + +} + +int vp8_estimate_entropy_savings(VP8_COMP *cpi) +{ + int savings = 0; + + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + int new_intra, new_last, new_garf, oldtotal, newtotal; + int ref_frame_cost[MAX_REF_FRAMES]; + + vp8_clear_system_state(); //__asm emms; + + if (cpi->common.frame_type != KEY_FRAME) + { + if (!(new_intra = rf_intra * 255 / (rf_intra + rf_inter))) + new_intra = 1; + + new_last = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + new_garf = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + + vp8_calc_ref_frame_costs(ref_frame_cost,new_intra,new_last,new_garf); + + newtotal = + rfct[INTRA_FRAME] * ref_frame_cost[INTRA_FRAME] + + rfct[LAST_FRAME] * ref_frame_cost[LAST_FRAME] + + rfct[GOLDEN_FRAME] * ref_frame_cost[GOLDEN_FRAME] + + rfct[ALTREF_FRAME] * ref_frame_cost[ALTREF_FRAME]; + + + // old costs + vp8_calc_ref_frame_costs(ref_frame_cost,cpi->prob_intra_coded, + cpi->prob_last_coded,cpi->prob_gf_coded); + + oldtotal = + rfct[INTRA_FRAME] * ref_frame_cost[INTRA_FRAME] + + rfct[LAST_FRAME] * ref_frame_cost[LAST_FRAME] + + rfct[GOLDEN_FRAME] * ref_frame_cost[GOLDEN_FRAME] + + rfct[ALTREF_FRAME] * ref_frame_cost[ALTREF_FRAME]; + + savings += (oldtotal - newtotal) / 256; + } + + + if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) + savings += independent_coef_context_savings(cpi); + else + savings += default_coef_context_savings(cpi); + + + return savings; +} + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING +int vp8_update_coef_context(VP8_COMP *cpi) +{ + int savings = 0; + + + if (cpi->common.frame_type == KEY_FRAME) + { + /* Reset to default counts/probabilities at key frames */ + vp8_copy(cpi->coef_counts, default_coef_counts); + } + + if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) + savings += independent_coef_context_savings(cpi); + else + savings += default_coef_context_savings(cpi); + + return savings; +} +#endif + +void vp8_update_coef_probs(VP8_COMP *cpi) +{ + int i = 0; +#if !(CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + vp8_writer *const w = cpi->bc; +#endif + int savings = 0; + + vp8_clear_system_state(); //__asm emms; + + do + { + int j = 0; + + do + { + int k = 0; + int prev_coef_savings[ENTROPY_NODES] = {0}; + if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) + { + for (k = 0; k < PREV_COEF_CONTEXTS; ++k) + { + int t; /* token/prob index */ + for (t = 0; t < ENTROPY_NODES; ++t) + { + const unsigned int *ct = cpi->frame_branch_ct [i][j] + [k][t]; + const vp8_prob newp = cpi->frame_coef_probs[i][j][k][t]; + const vp8_prob oldp = cpi->common.fc.coef_probs[i][j] + [k][t]; + const vp8_prob upd = vp8_coef_update_probs[i][j][k][t]; + + prev_coef_savings[t] += + prob_update_savings(ct, oldp, newp, upd); + } + } + k = 0; + } + do + { + //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here. + /* at every context */ + + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [ENTROPY_NODES]; + //unsigned int branch_ct [ENTROPY_NODES] [2]; + + int t = 0; /* token/prob index */ + + //vp8_tree_probs_from_distribution( + // MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree, + // new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k], + // 256, 1 + // ); + + do + { + const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; + + vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + + int s = prev_coef_savings[t]; + int u = 0; + + if (!(cpi->oxcf.error_resilient_mode & + VPX_ERROR_RESILIENT_PARTITIONS)) + { + s = prob_update_savings( + cpi->frame_branch_ct [i][j][k][t], + *Pold, newp, upd); + } + + if (s > 0) + u = 1; + + /* Force updates on key frames if the new is different, + * so that we can be sure we end up with equal probabilities + * over the prev coef contexts. + */ + if ((cpi->oxcf.error_resilient_mode & + VPX_ERROR_RESILIENT_PARTITIONS) && + cpi->common.frame_type == KEY_FRAME && newp != *Pold) + u = 1; + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + cpi->update_probs[i][j][k][t] = u; +#else + vp8_write(w, u, upd); +#endif + + +#ifdef ENTROPY_STATS + ++ tree_update_hist [i][j][k][t] [u]; +#endif + + if (u) + { + /* send/use new probability */ + + *Pold = newp; +#if !(CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + vp8_write_literal(w, newp, 8); +#endif + + savings += s; + + } + + } + while (++t < ENTROPY_NODES); + + /* Accum token counts for generation of default statistics */ +#ifdef ENTROPY_STATS + t = 0; + + do + { + context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t]; + } + while (++t < MAX_ENTROPY_TOKENS); + +#endif + + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + +} + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING +static void pack_coef_probs(VP8_COMP *cpi) +{ + int i = 0; + vp8_writer *const w = cpi->bc; + + do + { + int j = 0; + + do + { + int k = 0; + + do + { + int t = 0; /* token/prob index */ + + do + { + const vp8_prob newp = cpi->common.fc.coef_probs [i][j][k][t]; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + + const char u = cpi->update_probs[i][j][k][t] ; + + vp8_write(w, u, upd); + + if (u) + { + /* send/use new probability */ + vp8_write_literal(w, newp, 8); + } + } + while (++t < ENTROPY_NODES); + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); +} +#endif + +#ifdef PACKET_TESTING +FILE *vpxlogc = 0; +#endif + +static void put_delta_q(vp8_writer *bc, int delta_q) +{ + if (delta_q != 0) + { + vp8_write_bit(bc, 1); + vp8_write_literal(bc, abs(delta_q), 4); + + if (delta_q < 0) + vp8_write_bit(bc, 1); + else + vp8_write_bit(bc, 0); + } + else + vp8_write_bit(bc, 0); +} + +void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned char * dest_end, unsigned long *size) +{ + int i, j; + VP8_HEADER oh; + VP8_COMMON *const pc = & cpi->common; + vp8_writer *const bc = cpi->bc; + MACROBLOCKD *const xd = & cpi->mb.e_mbd; + int extra_bytes_packed = 0; + + unsigned char *cx_data = dest; + unsigned char *cx_data_end = dest_end; + const int *mb_feature_data_bits; + + oh.show_frame = (int) pc->show_frame; + oh.type = (int)pc->frame_type; + oh.version = pc->version; + oh.first_partition_length_in_bytes = 0; + + mb_feature_data_bits = vp8_mb_feature_data_bits; + + bc[0].error = &pc->error; + + validate_buffer(cx_data, 3, cx_data_end, &cpi->common.error); + cx_data += 3; + +#if defined(SECTIONBITS_OUTPUT) + Sectionbits[active_section = 1] += sizeof(VP8_HEADER) * 8 * 256; +#endif + + //vp8_kf_default_bmode_probs() is called in vp8_setup_key_frame() once for each + //K frame before encode frame. pc->kf_bmode_prob doesn't get changed anywhere + //else. No need to call it again here. --yw + //vp8_kf_default_bmode_probs( pc->kf_bmode_prob); + + // every keyframe send startcode, width, height, scale factor, clamp and color type + if (oh.type == KEY_FRAME) + { + int v; + + validate_buffer(cx_data, 7, cx_data_end, &cpi->common.error); + + // Start / synch code + cx_data[0] = 0x9D; + cx_data[1] = 0x01; + cx_data[2] = 0x2a; + + v = (pc->horiz_scale << 14) | pc->Width; + cx_data[3] = v; + cx_data[4] = v >> 8; + + v = (pc->vert_scale << 14) | pc->Height; + cx_data[5] = v; + cx_data[6] = v >> 8; + + + extra_bytes_packed = 7; + cx_data += extra_bytes_packed ; + + vp8_start_encode(bc, cx_data, cx_data_end); + + // signal clr type + vp8_write_bit(bc, pc->clr_type); + vp8_write_bit(bc, pc->clamp_type); + + } + else + vp8_start_encode(bc, cx_data, cx_data_end); + + + // Signal whether or not Segmentation is enabled + vp8_write_bit(bc, xd->segmentation_enabled); + + // Indicate which features are enabled + if (xd->segmentation_enabled) + { + // Signal whether or not the segmentation map is being updated. + vp8_write_bit(bc, xd->update_mb_segmentation_map); + vp8_write_bit(bc, xd->update_mb_segmentation_data); + + if (xd->update_mb_segmentation_data) + { + signed char Data; + + vp8_write_bit(bc, xd->mb_segement_abs_delta); + + // For each segmentation feature (Quant and loop filter level) + for (i = 0; i < MB_LVL_MAX; i++) + { + // For each of the segments + for (j = 0; j < MAX_MB_SEGMENTS; j++) + { + Data = xd->segment_feature_data[i][j]; + + // Frame level data + if (Data) + { + vp8_write_bit(bc, 1); + + if (Data < 0) + { + Data = - Data; + vp8_write_literal(bc, Data, mb_feature_data_bits[i]); + vp8_write_bit(bc, 1); + } + else + { + vp8_write_literal(bc, Data, mb_feature_data_bits[i]); + vp8_write_bit(bc, 0); + } + } + else + vp8_write_bit(bc, 0); + } + } + } + + if (xd->update_mb_segmentation_map) + { + // Write the probs used to decode the segment id for each macro block. + for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) + { + int Data = xd->mb_segment_tree_probs[i]; + + if (Data != 255) + { + vp8_write_bit(bc, 1); + vp8_write_literal(bc, Data, 8); + } + else + vp8_write_bit(bc, 0); + } + } + } + + // Code to determine whether or not to update the scan order. + vp8_write_bit(bc, pc->filter_type); + vp8_write_literal(bc, pc->filter_level, 6); + vp8_write_literal(bc, pc->sharpness_level, 3); + + // Write out loop filter deltas applied at the MB level based on mode or ref frame (if they are enabled). + vp8_write_bit(bc, xd->mode_ref_lf_delta_enabled); + + if (xd->mode_ref_lf_delta_enabled) + { + // Do the deltas need to be updated + int send_update = xd->mode_ref_lf_delta_update + || cpi->oxcf.error_resilient_mode; + + vp8_write_bit(bc, send_update); + if (send_update) + { + int Data; + + // Send update + for (i = 0; i < MAX_REF_LF_DELTAS; i++) + { + Data = xd->ref_lf_deltas[i]; + + // Frame level data + if (xd->ref_lf_deltas[i] != xd->last_ref_lf_deltas[i] + || cpi->oxcf.error_resilient_mode) + { + xd->last_ref_lf_deltas[i] = xd->ref_lf_deltas[i]; + vp8_write_bit(bc, 1); + + if (Data > 0) + { + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 0); // sign + } + else + { + Data = -Data; + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 1); // sign + } + } + else + vp8_write_bit(bc, 0); + } + + // Send update + for (i = 0; i < MAX_MODE_LF_DELTAS; i++) + { + Data = xd->mode_lf_deltas[i]; + + if (xd->mode_lf_deltas[i] != xd->last_mode_lf_deltas[i] + || cpi->oxcf.error_resilient_mode) + { + xd->last_mode_lf_deltas[i] = xd->mode_lf_deltas[i]; + vp8_write_bit(bc, 1); + + if (Data > 0) + { + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 0); // sign + } + else + { + Data = -Data; + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 1); // sign + } + } + else + vp8_write_bit(bc, 0); + } + } + } + + //signal here is multi token partition is enabled + vp8_write_literal(bc, pc->multi_token_partition, 2); + + // Frame Qbaseline quantizer index + vp8_write_literal(bc, pc->base_qindex, 7); + + // Transmit Dc, Second order and Uv quantizer delta information + put_delta_q(bc, pc->y1dc_delta_q); + put_delta_q(bc, pc->y2dc_delta_q); + put_delta_q(bc, pc->y2ac_delta_q); + put_delta_q(bc, pc->uvdc_delta_q); + put_delta_q(bc, pc->uvac_delta_q); + + // When there is a key frame all reference buffers are updated using the new key frame + if (pc->frame_type != KEY_FRAME) + { + // Should the GF or ARF be updated using the transmitted frame or buffer + vp8_write_bit(bc, pc->refresh_golden_frame); + vp8_write_bit(bc, pc->refresh_alt_ref_frame); + + // If not being updated from current frame should either GF or ARF be updated from another buffer + if (!pc->refresh_golden_frame) + vp8_write_literal(bc, pc->copy_buffer_to_gf, 2); + + if (!pc->refresh_alt_ref_frame) + vp8_write_literal(bc, pc->copy_buffer_to_arf, 2); + + // Indicate reference frame sign bias for Golden and ARF frames (always 0 for last frame buffer) + vp8_write_bit(bc, pc->ref_frame_sign_bias[GOLDEN_FRAME]); + vp8_write_bit(bc, pc->ref_frame_sign_bias[ALTREF_FRAME]); + } + +#if !(CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) + { + if (pc->frame_type == KEY_FRAME) + pc->refresh_entropy_probs = 1; + else + pc->refresh_entropy_probs = 0; + } +#endif + + vp8_write_bit(bc, pc->refresh_entropy_probs); + + if (pc->frame_type != KEY_FRAME) + vp8_write_bit(bc, pc->refresh_last_frame); + +#ifdef ENTROPY_STATS + + if (pc->frame_type == INTER_FRAME) + active_section = 0; + else + active_section = 7; + +#endif + + vp8_clear_system_state(); //__asm emms; + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + pack_coef_probs(cpi); +#else + if (pc->refresh_entropy_probs == 0) + { + // save a copy for later refresh + vpx_memcpy(&cpi->common.lfc, &cpi->common.fc, sizeof(cpi->common.fc)); + } + + vp8_update_coef_probs(cpi); +#endif + +#ifdef ENTROPY_STATS + active_section = 2; +#endif + + // Write out the mb_no_coeff_skip flag + vp8_write_bit(bc, pc->mb_no_coeff_skip); + + if (pc->frame_type == KEY_FRAME) + { + write_kfmodes(cpi); + +#ifdef ENTROPY_STATS + active_section = 8; +#endif + } + else + { + pack_inter_mode_mvs(cpi); + +#ifdef ENTROPY_STATS + active_section = 1; +#endif + } + + vp8_stop_encode(bc); + + cx_data += bc->pos; + + oh.first_partition_length_in_bytes = cpi->bc->pos; + + /* update frame tag */ + { + int v = (oh.first_partition_length_in_bytes << 5) | + (oh.show_frame << 4) | + (oh.version << 1) | + oh.type; + + dest[0] = v; + dest[1] = v >> 8; + dest[2] = v >> 16; + } + + *size = VP8_HEADER_SIZE + extra_bytes_packed + cpi->bc->pos; + + cpi->partition_sz[0] = *size; + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + { + const int num_part = (1 << pc->multi_token_partition); + unsigned char * dp = cpi->partition_d[0] + cpi->partition_sz[0]; + + if (num_part > 1) + { + /* write token part sizes (all but last) if more than 1 */ + validate_buffer(dp, 3 * (num_part - 1), cpi->partition_d_end[0], + &pc->error); + + cpi->partition_sz[0] += 3*(num_part-1); + + for(i = 1; i < num_part; i++) + { + write_partition_size(dp, cpi->partition_sz[i]); + dp += 3; + } + } + + if (!cpi->output_partition) + { + /* concatenate partition buffers */ + for(i = 0; i < num_part; i++) + { + vpx_memmove(dp, cpi->partition_d[i+1], cpi->partition_sz[i+1]); + cpi->partition_d[i+1] = dp; + dp += cpi->partition_sz[i+1]; + } + } + + /* update total size */ + *size = 0; + for(i = 0; i < num_part+1; i++) + { + *size += cpi->partition_sz[i]; + } + } +#else + if (pc->multi_token_partition != ONE_PARTITION) + { + int num_part = 1 << pc->multi_token_partition; + + /* partition size table at the end of first partition */ + cpi->partition_sz[0] += 3 * (num_part - 1); + *size += 3 * (num_part - 1); + + validate_buffer(cx_data, 3 * (num_part - 1), cx_data_end, + &pc->error); + + for(i = 1; i < num_part + 1; i++) + { + cpi->bc[i].error = &pc->error; + } + + pack_tokens_into_partitions(cpi, cx_data + 3 * (num_part - 1), + cx_data_end, num_part); + + for(i = 1; i < num_part; i++) + { + cpi->partition_sz[i] = cpi->bc[i].pos; + write_partition_size(cx_data, cpi->partition_sz[i]); + cx_data += 3; + *size += cpi->partition_sz[i]; /* add to total */ + } + + /* add last partition to total size */ + cpi->partition_sz[i] = cpi->bc[i].pos; + *size += cpi->partition_sz[i]; + } + else + { + bc[1].error = &pc->error; + + vp8_start_encode(&cpi->bc[1], cx_data, cx_data_end); + +#if CONFIG_MULTITHREAD + if (cpi->b_multi_threaded) + pack_mb_row_tokens(cpi, &cpi->bc[1]); + else +#endif + pack_tokens(&cpi->bc[1], cpi->tok, cpi->tok_count); + + vp8_stop_encode(&cpi->bc[1]); + + *size += cpi->bc[1].pos; + cpi->partition_sz[1] = cpi->bc[1].pos; + } +#endif +} + +#ifdef ENTROPY_STATS +void print_tree_update_probs() +{ + int i, j, k, l; + FILE *f = fopen("context.c", "a"); + int Sum; + fprintf(f, "\n/* Update probabilities for token entropy tree. */\n\n"); + fprintf(f, "const vp8_prob tree_update_probs[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] = {\n"); + + for (i = 0; i < BLOCK_TYPES; i++) + { + fprintf(f, " { \n"); + + for (j = 0; j < COEF_BANDS; j++) + { + fprintf(f, " {\n"); + + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + { + fprintf(f, " {"); + + for (l = 0; l < ENTROPY_NODES; l++) + { + Sum = tree_update_hist[i][j][k][l][0] + tree_update_hist[i][j][k][l][1]; + + if (Sum > 0) + { + if (((tree_update_hist[i][j][k][l][0] * 255) / Sum) > 0) + fprintf(f, "%3ld, ", (tree_update_hist[i][j][k][l][0] * 255) / Sum); + else + fprintf(f, "%3ld, ", 1); + } + else + fprintf(f, "%3ld, ", 128); + } + + fprintf(f, "},\n"); + } + + fprintf(f, " },\n"); + } + + fprintf(f, " },\n"); + } + + fprintf(f, "};\n"); + fclose(f); +} +#endif diff --git a/vp8/encoder/bitstream.h b/vp8/encoder/bitstream.h new file mode 100644 index 0000000..455a94f --- /dev/null +++ b/vp8/encoder/bitstream.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_BITSTREAM_H +#define __INC_BITSTREAM_H + +#if HAVE_EDSP +void vp8cx_pack_tokens_armv5(vp8_writer *w, const TOKENEXTRA *p, int xcount, + const vp8_token *, + const vp8_extra_bit_struct *, + const vp8_tree_index *); +void vp8cx_pack_tokens_into_partitions_armv5(VP8_COMP *, + unsigned char * cx_data, + const unsigned char *cx_data_end, + int num_parts, + const vp8_token *, + const vp8_extra_bit_struct *, + const vp8_tree_index *); +void vp8cx_pack_mb_row_tokens_armv5(VP8_COMP *cpi, vp8_writer *w, + const vp8_token *, + const vp8_extra_bit_struct *, + const vp8_tree_index *); +# define pack_tokens(a,b,c) \ + vp8cx_pack_tokens_armv5(a,b,c,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) +# define pack_tokens_into_partitions(a,b,c,d) \ + vp8cx_pack_tokens_into_partitions_armv5(a,b,c,d,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) +# define pack_mb_row_tokens(a,b) \ + vp8cx_pack_mb_row_tokens_armv5(a,b,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) +#else + +void vp8_pack_tokens_c(vp8_writer *w, const TOKENEXTRA *p, int xcount); + +# define pack_tokens(a,b,c) vp8_pack_tokens_c(a,b,c) +# define pack_tokens_into_partitions(a,b,c,d) pack_tokens_into_partitions_c(a,b,c,d) +# define pack_mb_row_tokens(a,b) pack_mb_row_tokens_c(a,b) +#endif + +#endif diff --git a/vp8/encoder/block.h b/vp8/encoder/block.h new file mode 100644 index 0000000..6165d04 --- /dev/null +++ b/vp8/encoder/block.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_BLOCK_H +#define __INC_BLOCK_H + +#include "vp8/common/onyx.h" +#include "vp8/common/blockd.h" +#include "vp8/common/entropymv.h" +#include "vp8/common/entropy.h" +#include "vpx_ports/mem.h" + +// motion search site +typedef struct +{ + MV mv; + int offset; +} search_site; + +typedef struct block +{ + // 16 Y blocks, 4 U blocks, 4 V blocks each with 16 entries + short *src_diff; + short *coeff; + + // 16 Y blocks, 4 U blocks, 4 V blocks each with 16 entries + short *quant; + short *quant_fast; + unsigned char *quant_shift; + short *zbin; + short *zrun_zbin_boost; + short *round; + + // Zbin Over Quant value + short zbin_extra; + + unsigned char **base_src; + int src; + int src_stride; +} BLOCK; + +typedef struct +{ + int count; + struct + { + B_PREDICTION_MODE mode; + int_mv mv; + } bmi[16]; +} PARTITION_INFO; + +typedef struct macroblock +{ + DECLARE_ALIGNED(16, short, src_diff[400]); // 16x16 Y 8x8 U 8x8 V 4x4 2nd Y + DECLARE_ALIGNED(16, short, coeff[400]); // 16x16 Y 8x8 U 8x8 V 4x4 2nd Y + DECLARE_ALIGNED(16, unsigned char, thismb[256]); + + unsigned char *thismb_ptr; + // 16 Y blocks, 4 U blocks, 4 V blocks, 1 DC 2nd order block each with 16 entries + BLOCK block[25]; + + YV12_BUFFER_CONFIG src; + + MACROBLOCKD e_mbd; + PARTITION_INFO *partition_info; /* work pointer */ + PARTITION_INFO *pi; /* Corresponds to upper left visible macroblock */ + PARTITION_INFO *pip; /* Base of allocated array */ + + int ref_frame_cost[MAX_REF_FRAMES]; + + search_site *ss; + int ss_count; + int searches_per_step; + + int errorperbit; + int sadperbit16; + int sadperbit4; + int rddiv; + int rdmult; + unsigned int * mb_activity_ptr; + int * mb_norm_activity_ptr; + signed int act_zbin_adj; + signed int last_act_zbin_adj; + + int mvcosts[2][MVvals+1]; + int *mvcost[2]; + int mvsadcosts[2][MVfpvals+1]; + int *mvsadcost[2]; + int mbmode_cost[2][MB_MODE_COUNT]; + int intra_uv_mode_cost[2][MB_MODE_COUNT]; + unsigned int bmode_costs[10][10][10]; + unsigned int inter_bmode_costs[B_MODE_COUNT]; + + // These define limits to motion vector components to prevent them from extending outside the UMV borders + int mv_col_min; + int mv_col_max; + int mv_row_min; + int mv_row_max; + + int skip; + + int encode_breakout; + + //char * gf_active_ptr; + signed char *gf_active_ptr; + + unsigned char *active_ptr; + MV_CONTEXT *mvc; + + unsigned int token_costs[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; + int optimize; + int q_index; + + void (*short_fdct4x4)(short *input, short *output, int pitch); + void (*short_fdct8x4)(short *input, short *output, int pitch); + void (*short_walsh4x4)(short *input, short *output, int pitch); + void (*quantize_b)(BLOCK *b, BLOCKD *d); + void (*quantize_b_pair)(BLOCK *b1, BLOCK *b2, BLOCKD *d0, BLOCKD *d1); + +} MACROBLOCK; + + +#endif diff --git a/vp8/encoder/boolhuff.c b/vp8/encoder/boolhuff.c new file mode 100644 index 0000000..74770a2 --- /dev/null +++ b/vp8/encoder/boolhuff.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "boolhuff.h" + +#if defined(SECTIONBITS_OUTPUT) +unsigned __int64 Sectionbits[500]; + +#endif + +#ifdef ENTROPY_STATS +unsigned int active_section = 0; +#endif + +const unsigned int vp8_prob_cost[256] = +{ + 2047, 2047, 1791, 1641, 1535, 1452, 1385, 1328, 1279, 1235, 1196, 1161, 1129, 1099, 1072, 1046, + 1023, 1000, 979, 959, 940, 922, 905, 889, 873, 858, 843, 829, 816, 803, 790, 778, + 767, 755, 744, 733, 723, 713, 703, 693, 684, 675, 666, 657, 649, 641, 633, 625, + 617, 609, 602, 594, 587, 580, 573, 567, 560, 553, 547, 541, 534, 528, 522, 516, + 511, 505, 499, 494, 488, 483, 477, 472, 467, 462, 457, 452, 447, 442, 437, 433, + 428, 424, 419, 415, 410, 406, 401, 397, 393, 389, 385, 381, 377, 373, 369, 365, + 361, 357, 353, 349, 346, 342, 338, 335, 331, 328, 324, 321, 317, 314, 311, 307, + 304, 301, 297, 294, 291, 288, 285, 281, 278, 275, 272, 269, 266, 263, 260, 257, + 255, 252, 249, 246, 243, 240, 238, 235, 232, 229, 227, 224, 221, 219, 216, 214, + 211, 208, 206, 203, 201, 198, 196, 194, 191, 189, 186, 184, 181, 179, 177, 174, + 172, 170, 168, 165, 163, 161, 159, 156, 154, 152, 150, 148, 145, 143, 141, 139, + 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, + 105, 103, 101, 99, 97, 95, 93, 92, 90, 88, 86, 84, 82, 81, 79, 77, + 75, 73, 72, 70, 68, 66, 65, 63, 61, 60, 58, 56, 55, 53, 51, 50, + 48, 46, 45, 43, 41, 40, 38, 37, 35, 33, 32, 30, 29, 27, 25, 24, + 22, 21, 19, 18, 16, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1, 1 +}; + +void vp8_start_encode(BOOL_CODER *br, unsigned char *source, unsigned char *source_end) +{ + + br->lowvalue = 0; + br->range = 255; + br->count = -24; + br->buffer = source; + br->buffer_end = source_end; + br->pos = 0; +} + +void vp8_stop_encode(BOOL_CODER *br) +{ + int i; + + for (i = 0; i < 32; i++) + vp8_encode_bool(br, 0, 128); +} + + +void vp8_encode_value(BOOL_CODER *br, int data, int bits) +{ + int bit; + + for (bit = bits - 1; bit >= 0; bit--) + vp8_encode_bool(br, (1 & (data >> bit)), 0x80); + +} diff --git a/vp8/encoder/boolhuff.h b/vp8/encoder/boolhuff.h new file mode 100644 index 0000000..fb6cbaf --- /dev/null +++ b/vp8/encoder/boolhuff.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : boolhuff.h +* +* Description : Bool Coder header file. +* +****************************************************************************/ +#ifndef __INC_BOOLHUFF_H +#define __INC_BOOLHUFF_H + +#include "vpx_ports/mem.h" +#include "vpx/internal/vpx_codec_internal.h" + +typedef struct +{ + unsigned int lowvalue; + unsigned int range; + int count; + unsigned int pos; + unsigned char *buffer; + unsigned char *buffer_end; + struct vpx_internal_error_info *error; + + // Variables used to track bit costs without outputing to the bitstream + unsigned int measure_cost; + unsigned long bit_counter; +} BOOL_CODER; + +extern void vp8_start_encode(BOOL_CODER *bc, unsigned char *buffer, unsigned char *buffer_end); + +extern void vp8_encode_value(BOOL_CODER *br, int data, int bits); +extern void vp8_stop_encode(BOOL_CODER *bc); +extern const unsigned int vp8_prob_cost[256]; + + +DECLARE_ALIGNED(16, extern const unsigned char, vp8_norm[256]); + +static int validate_buffer(const unsigned char *start, + size_t len, + const unsigned char *end, + struct vpx_internal_error_info *error) +{ + if (start + len > start && start + len < end) + return 1; + else + vpx_internal_error(error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet or corrupt partition "); + + return 0; +} +static void vp8_encode_bool(BOOL_CODER *br, int bit, int probability) +{ + unsigned int split; + int count = br->count; + unsigned int range = br->range; + unsigned int lowvalue = br->lowvalue; + register unsigned int shift; + +#ifdef ENTROPY_STATS +#if defined(SECTIONBITS_OUTPUT) + + if (bit) + Sectionbits[active_section] += vp8_prob_cost[255-probability]; + else + Sectionbits[active_section] += vp8_prob_cost[probability]; + +#endif +#endif + + split = 1 + (((range - 1) * probability) >> 8); + + range = split; + + if (bit) + { + lowvalue += split; + range = br->range - split; + } + + shift = vp8_norm[range]; + + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = br->pos - 1; + + while (x >= 0 && br->buffer[x] == 0xff) + { + br->buffer[x] = (unsigned char)0; + x--; + } + + br->buffer[x] += 1; + } + + validate_buffer(br->buffer + br->pos, 1, br->buffer_end, br->error); + br->buffer[br->pos++] = (lowvalue >> (24 - offset)); + + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + br->count = count; + br->lowvalue = lowvalue; + br->range = range; +} + +#endif diff --git a/vp8/encoder/dct.c b/vp8/encoder/dct.c new file mode 100644 index 0000000..b5a11ae --- /dev/null +++ b/vp8/encoder/dct.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include + +void vp8_short_fdct4x4_c(short *input, short *output, int pitch) +{ + int i; + int a1, b1, c1, d1; + short *ip = input; + short *op = output; + + for (i = 0; i < 4; i++) + { + a1 = ((ip[0] + ip[3])<<3); + b1 = ((ip[1] + ip[2])<<3); + c1 = ((ip[1] - ip[2])<<3); + d1 = ((ip[0] - ip[3])<<3); + + op[0] = a1 + b1; + op[2] = a1 - b1; + + op[1] = (c1 * 2217 + d1 * 5352 + 14500)>>12; + op[3] = (d1 * 2217 - c1 * 5352 + 7500)>>12; + + ip += pitch / 2; + op += 4; + + } + ip = output; + op = output; + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[12]; + b1 = ip[4] + ip[8]; + c1 = ip[4] - ip[8]; + d1 = ip[0] - ip[12]; + + op[0] = ( a1 + b1 + 7)>>4; + op[8] = ( a1 - b1 + 7)>>4; + + op[4] =((c1 * 2217 + d1 * 5352 + 12000)>>16) + (d1!=0); + op[12] = (d1 * 2217 - c1 * 5352 + 51000)>>16; + + ip++; + op++; + } +} + +void vp8_short_fdct8x4_c(short *input, short *output, int pitch) +{ + vp8_short_fdct4x4_c(input, output, pitch); + vp8_short_fdct4x4_c(input + 4, output + 16, pitch); +} + +void vp8_short_walsh4x4_c(short *input, short *output, int pitch) +{ + int i; + int a1, b1, c1, d1; + int a2, b2, c2, d2; + short *ip = input; + short *op = output; + + + for (i = 0; i < 4; i++) + { + a1 = ((ip[0] + ip[2])<<2); + d1 = ((ip[1] + ip[3])<<2); + c1 = ((ip[1] - ip[3])<<2); + b1 = ((ip[0] - ip[2])<<2); + + op[0] = a1 + d1 + (a1!=0); + op[1] = b1 + c1; + op[2] = b1 - c1; + op[3] = a1 - d1; + ip += pitch / 2; + op += 4; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[8]; + d1 = ip[4] + ip[12]; + c1 = ip[4] - ip[12]; + b1 = ip[0] - ip[8]; + + a2 = a1 + d1; + b2 = b1 + c1; + c2 = b1 - c1; + d2 = a1 - d1; + + a2 += a2<0; + b2 += b2<0; + c2 += c2<0; + d2 += d2<0; + + op[0] = (a2+3) >> 3; + op[4] = (b2+3) >> 3; + op[8] = (c2+3) >> 3; + op[12]= (d2+3) >> 3; + + ip++; + op++; + } +} diff --git a/vp8/encoder/dct_value_cost.h b/vp8/encoder/dct_value_cost.h new file mode 100644 index 0000000..e892765 --- /dev/null +++ b/vp8/encoder/dct_value_cost.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* Generated file, included by tokenize.c */ +/* Values generated by fill_value_tokens() */ + +static const short dct_value_cost[2048*2] = +{ + 8285, 8277, 8267, 8259, 8253, 8245, 8226, 8218, 8212, 8204, 8194, 8186, + 8180, 8172, 8150, 8142, 8136, 8128, 8118, 8110, 8104, 8096, 8077, 8069, + 8063, 8055, 8045, 8037, 8031, 8023, 7997, 7989, 7983, 7975, 7965, 7957, + 7951, 7943, 7924, 7916, 7910, 7902, 7892, 7884, 7878, 7870, 7848, 7840, + 7834, 7826, 7816, 7808, 7802, 7794, 7775, 7767, 7761, 7753, 7743, 7735, + 7729, 7721, 7923, 7915, 7909, 7901, 7891, 7883, 7877, 7869, 7850, 7842, + 7836, 7828, 7818, 7810, 7804, 7796, 7774, 7766, 7760, 7752, 7742, 7734, + 7728, 7720, 7701, 7693, 7687, 7679, 7669, 7661, 7655, 7647, 7621, 7613, + 7607, 7599, 7589, 7581, 7575, 7567, 7548, 7540, 7534, 7526, 7516, 7508, + 7502, 7494, 7472, 7464, 7458, 7450, 7440, 7432, 7426, 7418, 7399, 7391, + 7385, 7377, 7367, 7359, 7353, 7345, 7479, 7471, 7465, 7457, 7447, 7439, + 7433, 7425, 7406, 7398, 7392, 7384, 7374, 7366, 7360, 7352, 7330, 7322, + 7316, 7308, 7298, 7290, 7284, 7276, 7257, 7249, 7243, 7235, 7225, 7217, + 7211, 7203, 7177, 7169, 7163, 7155, 7145, 7137, 7131, 7123, 7104, 7096, + 7090, 7082, 7072, 7064, 7058, 7050, 7028, 7020, 7014, 7006, 6996, 6988, + 6982, 6974, 6955, 6947, 6941, 6933, 6923, 6915, 6909, 6901, 7632, 7624, + 7618, 7610, 7600, 7592, 7586, 7578, 7559, 7551, 7545, 7537, 7527, 7519, + 7513, 7505, 7483, 7475, 7469, 7461, 7451, 7443, 7437, 7429, 7410, 7402, + 7396, 7388, 7378, 7370, 7364, 7356, 7330, 7322, 7316, 7308, 7298, 7290, + 7284, 7276, 7257, 7249, 7243, 7235, 7225, 7217, 7211, 7203, 7181, 7173, + 7167, 7159, 7149, 7141, 7135, 7127, 7108, 7100, 7094, 7086, 7076, 7068, + 7062, 7054, 7188, 7180, 7174, 7166, 7156, 7148, 7142, 7134, 7115, 7107, + 7101, 7093, 7083, 7075, 7069, 7061, 7039, 7031, 7025, 7017, 7007, 6999, + 6993, 6985, 6966, 6958, 6952, 6944, 6934, 6926, 6920, 6912, 6886, 6878, + 6872, 6864, 6854, 6846, 6840, 6832, 6813, 6805, 6799, 6791, 6781, 6773, + 6767, 6759, 6737, 6729, 6723, 6715, 6705, 6697, 6691, 6683, 6664, 6656, + 6650, 6642, 6632, 6624, 6618, 6610, 6812, 6804, 6798, 6790, 6780, 6772, + 6766, 6758, 6739, 6731, 6725, 6717, 6707, 6699, 6693, 6685, 6663, 6655, + 6649, 6641, 6631, 6623, 6617, 6609, 6590, 6582, 6576, 6568, 6558, 6550, + 6544, 6536, 6510, 6502, 6496, 6488, 6478, 6470, 6464, 6456, 6437, 6429, + 6423, 6415, 6405, 6397, 6391, 6383, 6361, 6353, 6347, 6339, 6329, 6321, + 6315, 6307, 6288, 6280, 6274, 6266, 6256, 6248, 6242, 6234, 6368, 6360, + 6354, 6346, 6336, 6328, 6322, 6314, 6295, 6287, 6281, 6273, 6263, 6255, + 6249, 6241, 6219, 6211, 6205, 6197, 6187, 6179, 6173, 6165, 6146, 6138, + 6132, 6124, 6114, 6106, 6100, 6092, 6066, 6058, 6052, 6044, 6034, 6026, + 6020, 6012, 5993, 5985, 5979, 5971, 5961, 5953, 5947, 5939, 5917, 5909, + 5903, 5895, 5885, 5877, 5871, 5863, 5844, 5836, 5830, 5822, 5812, 5804, + 5798, 5790, 6697, 6689, 6683, 6675, 6665, 6657, 6651, 6643, 6624, 6616, + 6610, 6602, 6592, 6584, 6578, 6570, 6548, 6540, 6534, 6526, 6516, 6508, + 6502, 6494, 6475, 6467, 6461, 6453, 6443, 6435, 6429, 6421, 6395, 6387, + 6381, 6373, 6363, 6355, 6349, 6341, 6322, 6314, 6308, 6300, 6290, 6282, + 6276, 6268, 6246, 6238, 6232, 6224, 6214, 6206, 6200, 6192, 6173, 6165, + 6159, 6151, 6141, 6133, 6127, 6119, 6253, 6245, 6239, 6231, 6221, 6213, + 6207, 6199, 6180, 6172, 6166, 6158, 6148, 6140, 6134, 6126, 6104, 6096, + 6090, 6082, 6072, 6064, 6058, 6050, 6031, 6023, 6017, 6009, 5999, 5991, + 5985, 5977, 5951, 5943, 5937, 5929, 5919, 5911, 5905, 5897, 5878, 5870, + 5864, 5856, 5846, 5838, 5832, 5824, 5802, 5794, 5788, 5780, 5770, 5762, + 5756, 5748, 5729, 5721, 5715, 5707, 5697, 5689, 5683, 5675, 5877, 5869, + 5863, 5855, 5845, 5837, 5831, 5823, 5804, 5796, 5790, 5782, 5772, 5764, + 5758, 5750, 5728, 5720, 5714, 5706, 5696, 5688, 5682, 5674, 5655, 5647, + 5641, 5633, 5623, 5615, 5609, 5601, 5575, 5567, 5561, 5553, 5543, 5535, + 5529, 5521, 5502, 5494, 5488, 5480, 5470, 5462, 5456, 5448, 5426, 5418, + 5412, 5404, 5394, 5386, 5380, 5372, 5353, 5345, 5339, 5331, 5321, 5313, + 5307, 5299, 5433, 5425, 5419, 5411, 5401, 5393, 5387, 5379, 5360, 5352, + 5346, 5338, 5328, 5320, 5314, 5306, 5284, 5276, 5270, 5262, 5252, 5244, + 5238, 5230, 5211, 5203, 5197, 5189, 5179, 5171, 5165, 5157, 5131, 5123, + 5117, 5109, 5099, 5091, 5085, 5077, 5058, 5050, 5044, 5036, 5026, 5018, + 5012, 5004, 4982, 4974, 4968, 4960, 4950, 4942, 4936, 4928, 4909, 4901, + 4895, 4887, 4877, 4869, 4863, 4855, 5586, 5578, 5572, 5564, 5554, 5546, + 5540, 5532, 5513, 5505, 5499, 5491, 5481, 5473, 5467, 5459, 5437, 5429, + 5423, 5415, 5405, 5397, 5391, 5383, 5364, 5356, 5350, 5342, 5332, 5324, + 5318, 5310, 5284, 5276, 5270, 5262, 5252, 5244, 5238, 5230, 5211, 5203, + 5197, 5189, 5179, 5171, 5165, 5157, 5135, 5127, 5121, 5113, 5103, 5095, + 5089, 5081, 5062, 5054, 5048, 5040, 5030, 5022, 5016, 5008, 5142, 5134, + 5128, 5120, 5110, 5102, 5096, 5088, 5069, 5061, 5055, 5047, 5037, 5029, + 5023, 5015, 4993, 4985, 4979, 4971, 4961, 4953, 4947, 4939, 4920, 4912, + 4906, 4898, 4888, 4880, 4874, 4866, 4840, 4832, 4826, 4818, 4808, 4800, + 4794, 4786, 4767, 4759, 4753, 4745, 4735, 4727, 4721, 4713, 4691, 4683, + 4677, 4669, 4659, 4651, 4645, 4637, 4618, 4610, 4604, 4596, 4586, 4578, + 4572, 4564, 4766, 4758, 4752, 4744, 4734, 4726, 4720, 4712, 4693, 4685, + 4679, 4671, 4661, 4653, 4647, 4639, 4617, 4609, 4603, 4595, 4585, 4577, + 4571, 4563, 4544, 4536, 4530, 4522, 4512, 4504, 4498, 4490, 4464, 4456, + 4450, 4442, 4432, 4424, 4418, 4410, 4391, 4383, 4377, 4369, 4359, 4351, + 4345, 4337, 4315, 4307, 4301, 4293, 4283, 4275, 4269, 4261, 4242, 4234, + 4228, 4220, 4210, 4202, 4196, 4188, 4322, 4314, 4308, 4300, 4290, 4282, + 4276, 4268, 4249, 4241, 4235, 4227, 4217, 4209, 4203, 4195, 4173, 4165, + 4159, 4151, 4141, 4133, 4127, 4119, 4100, 4092, 4086, 4078, 4068, 4060, + 4054, 4046, 4020, 4012, 4006, 3998, 3988, 3980, 3974, 3966, 3947, 3939, + 3933, 3925, 3915, 3907, 3901, 3893, 3871, 3863, 3857, 3849, 3839, 3831, + 3825, 3817, 3798, 3790, 3784, 3776, 3766, 3758, 3752, 3744, 6697, 6689, + 6683, 6675, 6665, 6657, 6651, 6643, 6624, 6616, 6610, 6602, 6592, 6584, + 6578, 6570, 6548, 6540, 6534, 6526, 6516, 6508, 6502, 6494, 6475, 6467, + 6461, 6453, 6443, 6435, 6429, 6421, 6395, 6387, 6381, 6373, 6363, 6355, + 6349, 6341, 6322, 6314, 6308, 6300, 6290, 6282, 6276, 6268, 6246, 6238, + 6232, 6224, 6214, 6206, 6200, 6192, 6173, 6165, 6159, 6151, 6141, 6133, + 6127, 6119, 6253, 6245, 6239, 6231, 6221, 6213, 6207, 6199, 6180, 6172, + 6166, 6158, 6148, 6140, 6134, 6126, 6104, 6096, 6090, 6082, 6072, 6064, + 6058, 6050, 6031, 6023, 6017, 6009, 5999, 5991, 5985, 5977, 5951, 5943, + 5937, 5929, 5919, 5911, 5905, 5897, 5878, 5870, 5864, 5856, 5846, 5838, + 5832, 5824, 5802, 5794, 5788, 5780, 5770, 5762, 5756, 5748, 5729, 5721, + 5715, 5707, 5697, 5689, 5683, 5675, 5877, 5869, 5863, 5855, 5845, 5837, + 5831, 5823, 5804, 5796, 5790, 5782, 5772, 5764, 5758, 5750, 5728, 5720, + 5714, 5706, 5696, 5688, 5682, 5674, 5655, 5647, 5641, 5633, 5623, 5615, + 5609, 5601, 5575, 5567, 5561, 5553, 5543, 5535, 5529, 5521, 5502, 5494, + 5488, 5480, 5470, 5462, 5456, 5448, 5426, 5418, 5412, 5404, 5394, 5386, + 5380, 5372, 5353, 5345, 5339, 5331, 5321, 5313, 5307, 5299, 5433, 5425, + 5419, 5411, 5401, 5393, 5387, 5379, 5360, 5352, 5346, 5338, 5328, 5320, + 5314, 5306, 5284, 5276, 5270, 5262, 5252, 5244, 5238, 5230, 5211, 5203, + 5197, 5189, 5179, 5171, 5165, 5157, 5131, 5123, 5117, 5109, 5099, 5091, + 5085, 5077, 5058, 5050, 5044, 5036, 5026, 5018, 5012, 5004, 4982, 4974, + 4968, 4960, 4950, 4942, 4936, 4928, 4909, 4901, 4895, 4887, 4877, 4869, + 4863, 4855, 5586, 5578, 5572, 5564, 5554, 5546, 5540, 5532, 5513, 5505, + 5499, 5491, 5481, 5473, 5467, 5459, 5437, 5429, 5423, 5415, 5405, 5397, + 5391, 5383, 5364, 5356, 5350, 5342, 5332, 5324, 5318, 5310, 5284, 5276, + 5270, 5262, 5252, 5244, 5238, 5230, 5211, 5203, 5197, 5189, 5179, 5171, + 5165, 5157, 5135, 5127, 5121, 5113, 5103, 5095, 5089, 5081, 5062, 5054, + 5048, 5040, 5030, 5022, 5016, 5008, 5142, 5134, 5128, 5120, 5110, 5102, + 5096, 5088, 5069, 5061, 5055, 5047, 5037, 5029, 5023, 5015, 4993, 4985, + 4979, 4971, 4961, 4953, 4947, 4939, 4920, 4912, 4906, 4898, 4888, 4880, + 4874, 4866, 4840, 4832, 4826, 4818, 4808, 4800, 4794, 4786, 4767, 4759, + 4753, 4745, 4735, 4727, 4721, 4713, 4691, 4683, 4677, 4669, 4659, 4651, + 4645, 4637, 4618, 4610, 4604, 4596, 4586, 4578, 4572, 4564, 4766, 4758, + 4752, 4744, 4734, 4726, 4720, 4712, 4693, 4685, 4679, 4671, 4661, 4653, + 4647, 4639, 4617, 4609, 4603, 4595, 4585, 4577, 4571, 4563, 4544, 4536, + 4530, 4522, 4512, 4504, 4498, 4490, 4464, 4456, 4450, 4442, 4432, 4424, + 4418, 4410, 4391, 4383, 4377, 4369, 4359, 4351, 4345, 4337, 4315, 4307, + 4301, 4293, 4283, 4275, 4269, 4261, 4242, 4234, 4228, 4220, 4210, 4202, + 4196, 4188, 4322, 4314, 4308, 4300, 4290, 4282, 4276, 4268, 4249, 4241, + 4235, 4227, 4217, 4209, 4203, 4195, 4173, 4165, 4159, 4151, 4141, 4133, + 4127, 4119, 4100, 4092, 4086, 4078, 4068, 4060, 4054, 4046, 4020, 4012, + 4006, 3998, 3988, 3980, 3974, 3966, 3947, 3939, 3933, 3925, 3915, 3907, + 3901, 3893, 3871, 3863, 3857, 3849, 3839, 3831, 3825, 3817, 3798, 3790, + 3784, 3776, 3766, 3758, 3752, 3744, 4651, 4643, 4637, 4629, 4619, 4611, + 4605, 4597, 4578, 4570, 4564, 4556, 4546, 4538, 4532, 4524, 4502, 4494, + 4488, 4480, 4470, 4462, 4456, 4448, 4429, 4421, 4415, 4407, 4397, 4389, + 4383, 4375, 4349, 4341, 4335, 4327, 4317, 4309, 4303, 4295, 4276, 4268, + 4262, 4254, 4244, 4236, 4230, 4222, 4200, 4192, 4186, 4178, 4168, 4160, + 4154, 4146, 4127, 4119, 4113, 4105, 4095, 4087, 4081, 4073, 4207, 4199, + 4193, 4185, 4175, 4167, 4161, 4153, 4134, 4126, 4120, 4112, 4102, 4094, + 4088, 4080, 4058, 4050, 4044, 4036, 4026, 4018, 4012, 4004, 3985, 3977, + 3971, 3963, 3953, 3945, 3939, 3931, 3905, 3897, 3891, 3883, 3873, 3865, + 3859, 3851, 3832, 3824, 3818, 3810, 3800, 3792, 3786, 3778, 3756, 3748, + 3742, 3734, 3724, 3716, 3710, 3702, 3683, 3675, 3669, 3661, 3651, 3643, + 3637, 3629, 3831, 3823, 3817, 3809, 3799, 3791, 3785, 3777, 3758, 3750, + 3744, 3736, 3726, 3718, 3712, 3704, 3682, 3674, 3668, 3660, 3650, 3642, + 3636, 3628, 3609, 3601, 3595, 3587, 3577, 3569, 3563, 3555, 3529, 3521, + 3515, 3507, 3497, 3489, 3483, 3475, 3456, 3448, 3442, 3434, 3424, 3416, + 3410, 3402, 3380, 3372, 3366, 3358, 3348, 3340, 3334, 3326, 3307, 3299, + 3293, 3285, 3275, 3267, 3261, 3253, 3387, 3379, 3373, 3365, 3355, 3347, + 3341, 3333, 3314, 3306, 3300, 3292, 3282, 3274, 3268, 3260, 3238, 3230, + 3224, 3216, 3206, 3198, 3192, 3184, 3165, 3157, 3151, 3143, 3133, 3125, + 3119, 3111, 3085, 3077, 3071, 3063, 3053, 3045, 3039, 3031, 3012, 3004, + 2998, 2990, 2980, 2972, 2966, 2958, 2936, 2928, 2922, 2914, 2904, 2896, + 2890, 2882, 2863, 2855, 2849, 2841, 2831, 2823, 2817, 2809, 3540, 3532, + 3526, 3518, 3508, 3500, 3494, 3486, 3467, 3459, 3453, 3445, 3435, 3427, + 3421, 3413, 3391, 3383, 3377, 3369, 3359, 3351, 3345, 3337, 3318, 3310, + 3304, 3296, 3286, 3278, 3272, 3264, 3238, 3230, 3224, 3216, 3206, 3198, + 3192, 3184, 3165, 3157, 3151, 3143, 3133, 3125, 3119, 3111, 3089, 3081, + 3075, 3067, 3057, 3049, 3043, 3035, 3016, 3008, 3002, 2994, 2984, 2976, + 2970, 2962, 3096, 3088, 3082, 3074, 3064, 3056, 3050, 3042, 3023, 3015, + 3009, 3001, 2991, 2983, 2977, 2969, 2947, 2939, 2933, 2925, 2915, 2907, + 2901, 2893, 2874, 2866, 2860, 2852, 2842, 2834, 2828, 2820, 2794, 2786, + 2780, 2772, 2762, 2754, 2748, 2740, 2721, 2713, 2707, 2699, 2689, 2681, + 2675, 2667, 2645, 2637, 2631, 2623, 2613, 2605, 2599, 2591, 2572, 2564, + 2558, 2550, 2540, 2532, 2526, 2518, 2720, 2712, 2706, 2698, 2688, 2680, + 2674, 2666, 2647, 2639, 2633, 2625, 2615, 2607, 2601, 2593, 2571, 2563, + 2557, 2549, 2539, 2531, 2525, 2517, 2498, 2490, 2484, 2476, 2466, 2458, + 2452, 2444, 2418, 2410, 2404, 2396, 2386, 2378, 2372, 2364, 2345, 2337, + 2331, 2323, 2313, 2305, 2299, 2291, 2269, 2261, 2255, 2247, 2237, 2229, + 2223, 2215, 2196, 2188, 2182, 2174, 2164, 2156, 2150, 2142, 2276, 2268, + 2262, 2254, 2244, 2236, 2230, 2222, 2203, 2195, 2189, 2181, 2171, 2163, + 2157, 2149, 2127, 2119, 2113, 2105, 2095, 2087, 2081, 2073, 2054, 2046, + 2040, 2032, 2022, 2014, 2008, 2000, 1974, 1966, 1960, 1952, 1942, 1934, + 1928, 1920, 1901, 1893, 1887, 1879, 1869, 1861, 1855, 1847, 1825, 1817, + 1811, 1803, 1793, 1785, 1779, 1771, 1752, 1744, 1738, 1730, 1720, 1712, + 1706, 1698, 1897, 1883, 1860, 1846, 1819, 1805, 1782, 1768, 1723, 1709, + 1686, 1672, 1645, 1631, 1608, 1594, 1574, 1560, 1537, 1523, 1496, 1482, + 1459, 1445, 1400, 1386, 1363, 1349, 1322, 1308, 1285, 1271, 1608, 1565, + 1535, 1492, 1446, 1403, 1373, 1330, 1312, 1269, 1239, 1196, 1150, 1107, + 1077, 1034, 1291, 1218, 1171, 1098, 1015, 942, 895, 822, 953, 850, + 729, 626, 618, 431, 257, 257, 257, 257, 0, 255, 255, 255, + 255, 429, 616, 624, 727, 848, 951, 820, 893, 940, 1013, 1096, + 1169, 1216, 1289, 1032, 1075, 1105, 1148, 1194, 1237, 1267, 1310, 1328, + 1371, 1401, 1444, 1490, 1533, 1563, 1606, 1269, 1283, 1306, 1320, 1347, + 1361, 1384, 1398, 1443, 1457, 1480, 1494, 1521, 1535, 1558, 1572, 1592, + 1606, 1629, 1643, 1670, 1684, 1707, 1721, 1766, 1780, 1803, 1817, 1844, + 1858, 1881, 1895, 1696, 1704, 1710, 1718, 1728, 1736, 1742, 1750, 1769, + 1777, 1783, 1791, 1801, 1809, 1815, 1823, 1845, 1853, 1859, 1867, 1877, + 1885, 1891, 1899, 1918, 1926, 1932, 1940, 1950, 1958, 1964, 1972, 1998, + 2006, 2012, 2020, 2030, 2038, 2044, 2052, 2071, 2079, 2085, 2093, 2103, + 2111, 2117, 2125, 2147, 2155, 2161, 2169, 2179, 2187, 2193, 2201, 2220, + 2228, 2234, 2242, 2252, 2260, 2266, 2274, 2140, 2148, 2154, 2162, 2172, + 2180, 2186, 2194, 2213, 2221, 2227, 2235, 2245, 2253, 2259, 2267, 2289, + 2297, 2303, 2311, 2321, 2329, 2335, 2343, 2362, 2370, 2376, 2384, 2394, + 2402, 2408, 2416, 2442, 2450, 2456, 2464, 2474, 2482, 2488, 2496, 2515, + 2523, 2529, 2537, 2547, 2555, 2561, 2569, 2591, 2599, 2605, 2613, 2623, + 2631, 2637, 2645, 2664, 2672, 2678, 2686, 2696, 2704, 2710, 2718, 2516, + 2524, 2530, 2538, 2548, 2556, 2562, 2570, 2589, 2597, 2603, 2611, 2621, + 2629, 2635, 2643, 2665, 2673, 2679, 2687, 2697, 2705, 2711, 2719, 2738, + 2746, 2752, 2760, 2770, 2778, 2784, 2792, 2818, 2826, 2832, 2840, 2850, + 2858, 2864, 2872, 2891, 2899, 2905, 2913, 2923, 2931, 2937, 2945, 2967, + 2975, 2981, 2989, 2999, 3007, 3013, 3021, 3040, 3048, 3054, 3062, 3072, + 3080, 3086, 3094, 2960, 2968, 2974, 2982, 2992, 3000, 3006, 3014, 3033, + 3041, 3047, 3055, 3065, 3073, 3079, 3087, 3109, 3117, 3123, 3131, 3141, + 3149, 3155, 3163, 3182, 3190, 3196, 3204, 3214, 3222, 3228, 3236, 3262, + 3270, 3276, 3284, 3294, 3302, 3308, 3316, 3335, 3343, 3349, 3357, 3367, + 3375, 3381, 3389, 3411, 3419, 3425, 3433, 3443, 3451, 3457, 3465, 3484, + 3492, 3498, 3506, 3516, 3524, 3530, 3538, 2807, 2815, 2821, 2829, 2839, + 2847, 2853, 2861, 2880, 2888, 2894, 2902, 2912, 2920, 2926, 2934, 2956, + 2964, 2970, 2978, 2988, 2996, 3002, 3010, 3029, 3037, 3043, 3051, 3061, + 3069, 3075, 3083, 3109, 3117, 3123, 3131, 3141, 3149, 3155, 3163, 3182, + 3190, 3196, 3204, 3214, 3222, 3228, 3236, 3258, 3266, 3272, 3280, 3290, + 3298, 3304, 3312, 3331, 3339, 3345, 3353, 3363, 3371, 3377, 3385, 3251, + 3259, 3265, 3273, 3283, 3291, 3297, 3305, 3324, 3332, 3338, 3346, 3356, + 3364, 3370, 3378, 3400, 3408, 3414, 3422, 3432, 3440, 3446, 3454, 3473, + 3481, 3487, 3495, 3505, 3513, 3519, 3527, 3553, 3561, 3567, 3575, 3585, + 3593, 3599, 3607, 3626, 3634, 3640, 3648, 3658, 3666, 3672, 3680, 3702, + 3710, 3716, 3724, 3734, 3742, 3748, 3756, 3775, 3783, 3789, 3797, 3807, + 3815, 3821, 3829, 3627, 3635, 3641, 3649, 3659, 3667, 3673, 3681, 3700, + 3708, 3714, 3722, 3732, 3740, 3746, 3754, 3776, 3784, 3790, 3798, 3808, + 3816, 3822, 3830, 3849, 3857, 3863, 3871, 3881, 3889, 3895, 3903, 3929, + 3937, 3943, 3951, 3961, 3969, 3975, 3983, 4002, 4010, 4016, 4024, 4034, + 4042, 4048, 4056, 4078, 4086, 4092, 4100, 4110, 4118, 4124, 4132, 4151, + 4159, 4165, 4173, 4183, 4191, 4197, 4205, 4071, 4079, 4085, 4093, 4103, + 4111, 4117, 4125, 4144, 4152, 4158, 4166, 4176, 4184, 4190, 4198, 4220, + 4228, 4234, 4242, 4252, 4260, 4266, 4274, 4293, 4301, 4307, 4315, 4325, + 4333, 4339, 4347, 4373, 4381, 4387, 4395, 4405, 4413, 4419, 4427, 4446, + 4454, 4460, 4468, 4478, 4486, 4492, 4500, 4522, 4530, 4536, 4544, 4554, + 4562, 4568, 4576, 4595, 4603, 4609, 4617, 4627, 4635, 4641, 4649, 3742, + 3750, 3756, 3764, 3774, 3782, 3788, 3796, 3815, 3823, 3829, 3837, 3847, + 3855, 3861, 3869, 3891, 3899, 3905, 3913, 3923, 3931, 3937, 3945, 3964, + 3972, 3978, 3986, 3996, 4004, 4010, 4018, 4044, 4052, 4058, 4066, 4076, + 4084, 4090, 4098, 4117, 4125, 4131, 4139, 4149, 4157, 4163, 4171, 4193, + 4201, 4207, 4215, 4225, 4233, 4239, 4247, 4266, 4274, 4280, 4288, 4298, + 4306, 4312, 4320, 4186, 4194, 4200, 4208, 4218, 4226, 4232, 4240, 4259, + 4267, 4273, 4281, 4291, 4299, 4305, 4313, 4335, 4343, 4349, 4357, 4367, + 4375, 4381, 4389, 4408, 4416, 4422, 4430, 4440, 4448, 4454, 4462, 4488, + 4496, 4502, 4510, 4520, 4528, 4534, 4542, 4561, 4569, 4575, 4583, 4593, + 4601, 4607, 4615, 4637, 4645, 4651, 4659, 4669, 4677, 4683, 4691, 4710, + 4718, 4724, 4732, 4742, 4750, 4756, 4764, 4562, 4570, 4576, 4584, 4594, + 4602, 4608, 4616, 4635, 4643, 4649, 4657, 4667, 4675, 4681, 4689, 4711, + 4719, 4725, 4733, 4743, 4751, 4757, 4765, 4784, 4792, 4798, 4806, 4816, + 4824, 4830, 4838, 4864, 4872, 4878, 4886, 4896, 4904, 4910, 4918, 4937, + 4945, 4951, 4959, 4969, 4977, 4983, 4991, 5013, 5021, 5027, 5035, 5045, + 5053, 5059, 5067, 5086, 5094, 5100, 5108, 5118, 5126, 5132, 5140, 5006, + 5014, 5020, 5028, 5038, 5046, 5052, 5060, 5079, 5087, 5093, 5101, 5111, + 5119, 5125, 5133, 5155, 5163, 5169, 5177, 5187, 5195, 5201, 5209, 5228, + 5236, 5242, 5250, 5260, 5268, 5274, 5282, 5308, 5316, 5322, 5330, 5340, + 5348, 5354, 5362, 5381, 5389, 5395, 5403, 5413, 5421, 5427, 5435, 5457, + 5465, 5471, 5479, 5489, 5497, 5503, 5511, 5530, 5538, 5544, 5552, 5562, + 5570, 5576, 5584, 4853, 4861, 4867, 4875, 4885, 4893, 4899, 4907, 4926, + 4934, 4940, 4948, 4958, 4966, 4972, 4980, 5002, 5010, 5016, 5024, 5034, + 5042, 5048, 5056, 5075, 5083, 5089, 5097, 5107, 5115, 5121, 5129, 5155, + 5163, 5169, 5177, 5187, 5195, 5201, 5209, 5228, 5236, 5242, 5250, 5260, + 5268, 5274, 5282, 5304, 5312, 5318, 5326, 5336, 5344, 5350, 5358, 5377, + 5385, 5391, 5399, 5409, 5417, 5423, 5431, 5297, 5305, 5311, 5319, 5329, + 5337, 5343, 5351, 5370, 5378, 5384, 5392, 5402, 5410, 5416, 5424, 5446, + 5454, 5460, 5468, 5478, 5486, 5492, 5500, 5519, 5527, 5533, 5541, 5551, + 5559, 5565, 5573, 5599, 5607, 5613, 5621, 5631, 5639, 5645, 5653, 5672, + 5680, 5686, 5694, 5704, 5712, 5718, 5726, 5748, 5756, 5762, 5770, 5780, + 5788, 5794, 5802, 5821, 5829, 5835, 5843, 5853, 5861, 5867, 5875, 5673, + 5681, 5687, 5695, 5705, 5713, 5719, 5727, 5746, 5754, 5760, 5768, 5778, + 5786, 5792, 5800, 5822, 5830, 5836, 5844, 5854, 5862, 5868, 5876, 5895, + 5903, 5909, 5917, 5927, 5935, 5941, 5949, 5975, 5983, 5989, 5997, 6007, + 6015, 6021, 6029, 6048, 6056, 6062, 6070, 6080, 6088, 6094, 6102, 6124, + 6132, 6138, 6146, 6156, 6164, 6170, 6178, 6197, 6205, 6211, 6219, 6229, + 6237, 6243, 6251, 6117, 6125, 6131, 6139, 6149, 6157, 6163, 6171, 6190, + 6198, 6204, 6212, 6222, 6230, 6236, 6244, 6266, 6274, 6280, 6288, 6298, + 6306, 6312, 6320, 6339, 6347, 6353, 6361, 6371, 6379, 6385, 6393, 6419, + 6427, 6433, 6441, 6451, 6459, 6465, 6473, 6492, 6500, 6506, 6514, 6524, + 6532, 6538, 6546, 6568, 6576, 6582, 6590, 6600, 6608, 6614, 6622, 6641, + 6649, 6655, 6663, 6673, 6681, 6687, 6695, 3742, 3750, 3756, 3764, 3774, + 3782, 3788, 3796, 3815, 3823, 3829, 3837, 3847, 3855, 3861, 3869, 3891, + 3899, 3905, 3913, 3923, 3931, 3937, 3945, 3964, 3972, 3978, 3986, 3996, + 4004, 4010, 4018, 4044, 4052, 4058, 4066, 4076, 4084, 4090, 4098, 4117, + 4125, 4131, 4139, 4149, 4157, 4163, 4171, 4193, 4201, 4207, 4215, 4225, + 4233, 4239, 4247, 4266, 4274, 4280, 4288, 4298, 4306, 4312, 4320, 4186, + 4194, 4200, 4208, 4218, 4226, 4232, 4240, 4259, 4267, 4273, 4281, 4291, + 4299, 4305, 4313, 4335, 4343, 4349, 4357, 4367, 4375, 4381, 4389, 4408, + 4416, 4422, 4430, 4440, 4448, 4454, 4462, 4488, 4496, 4502, 4510, 4520, + 4528, 4534, 4542, 4561, 4569, 4575, 4583, 4593, 4601, 4607, 4615, 4637, + 4645, 4651, 4659, 4669, 4677, 4683, 4691, 4710, 4718, 4724, 4732, 4742, + 4750, 4756, 4764, 4562, 4570, 4576, 4584, 4594, 4602, 4608, 4616, 4635, + 4643, 4649, 4657, 4667, 4675, 4681, 4689, 4711, 4719, 4725, 4733, 4743, + 4751, 4757, 4765, 4784, 4792, 4798, 4806, 4816, 4824, 4830, 4838, 4864, + 4872, 4878, 4886, 4896, 4904, 4910, 4918, 4937, 4945, 4951, 4959, 4969, + 4977, 4983, 4991, 5013, 5021, 5027, 5035, 5045, 5053, 5059, 5067, 5086, + 5094, 5100, 5108, 5118, 5126, 5132, 5140, 5006, 5014, 5020, 5028, 5038, + 5046, 5052, 5060, 5079, 5087, 5093, 5101, 5111, 5119, 5125, 5133, 5155, + 5163, 5169, 5177, 5187, 5195, 5201, 5209, 5228, 5236, 5242, 5250, 5260, + 5268, 5274, 5282, 5308, 5316, 5322, 5330, 5340, 5348, 5354, 5362, 5381, + 5389, 5395, 5403, 5413, 5421, 5427, 5435, 5457, 5465, 5471, 5479, 5489, + 5497, 5503, 5511, 5530, 5538, 5544, 5552, 5562, 5570, 5576, 5584, 4853, + 4861, 4867, 4875, 4885, 4893, 4899, 4907, 4926, 4934, 4940, 4948, 4958, + 4966, 4972, 4980, 5002, 5010, 5016, 5024, 5034, 5042, 5048, 5056, 5075, + 5083, 5089, 5097, 5107, 5115, 5121, 5129, 5155, 5163, 5169, 5177, 5187, + 5195, 5201, 5209, 5228, 5236, 5242, 5250, 5260, 5268, 5274, 5282, 5304, + 5312, 5318, 5326, 5336, 5344, 5350, 5358, 5377, 5385, 5391, 5399, 5409, + 5417, 5423, 5431, 5297, 5305, 5311, 5319, 5329, 5337, 5343, 5351, 5370, + 5378, 5384, 5392, 5402, 5410, 5416, 5424, 5446, 5454, 5460, 5468, 5478, + 5486, 5492, 5500, 5519, 5527, 5533, 5541, 5551, 5559, 5565, 5573, 5599, + 5607, 5613, 5621, 5631, 5639, 5645, 5653, 5672, 5680, 5686, 5694, 5704, + 5712, 5718, 5726, 5748, 5756, 5762, 5770, 5780, 5788, 5794, 5802, 5821, + 5829, 5835, 5843, 5853, 5861, 5867, 5875, 5673, 5681, 5687, 5695, 5705, + 5713, 5719, 5727, 5746, 5754, 5760, 5768, 5778, 5786, 5792, 5800, 5822, + 5830, 5836, 5844, 5854, 5862, 5868, 5876, 5895, 5903, 5909, 5917, 5927, + 5935, 5941, 5949, 5975, 5983, 5989, 5997, 6007, 6015, 6021, 6029, 6048, + 6056, 6062, 6070, 6080, 6088, 6094, 6102, 6124, 6132, 6138, 6146, 6156, + 6164, 6170, 6178, 6197, 6205, 6211, 6219, 6229, 6237, 6243, 6251, 6117, + 6125, 6131, 6139, 6149, 6157, 6163, 6171, 6190, 6198, 6204, 6212, 6222, + 6230, 6236, 6244, 6266, 6274, 6280, 6288, 6298, 6306, 6312, 6320, 6339, + 6347, 6353, 6361, 6371, 6379, 6385, 6393, 6419, 6427, 6433, 6441, 6451, + 6459, 6465, 6473, 6492, 6500, 6506, 6514, 6524, 6532, 6538, 6546, 6568, + 6576, 6582, 6590, 6600, 6608, 6614, 6622, 6641, 6649, 6655, 6663, 6673, + 6681, 6687, 6695, 5788, 5796, 5802, 5810, 5820, 5828, 5834, 5842, 5861, + 5869, 5875, 5883, 5893, 5901, 5907, 5915, 5937, 5945, 5951, 5959, 5969, + 5977, 5983, 5991, 6010, 6018, 6024, 6032, 6042, 6050, 6056, 6064, 6090, + 6098, 6104, 6112, 6122, 6130, 6136, 6144, 6163, 6171, 6177, 6185, 6195, + 6203, 6209, 6217, 6239, 6247, 6253, 6261, 6271, 6279, 6285, 6293, 6312, + 6320, 6326, 6334, 6344, 6352, 6358, 6366, 6232, 6240, 6246, 6254, 6264, + 6272, 6278, 6286, 6305, 6313, 6319, 6327, 6337, 6345, 6351, 6359, 6381, + 6389, 6395, 6403, 6413, 6421, 6427, 6435, 6454, 6462, 6468, 6476, 6486, + 6494, 6500, 6508, 6534, 6542, 6548, 6556, 6566, 6574, 6580, 6588, 6607, + 6615, 6621, 6629, 6639, 6647, 6653, 6661, 6683, 6691, 6697, 6705, 6715, + 6723, 6729, 6737, 6756, 6764, 6770, 6778, 6788, 6796, 6802, 6810, 6608, + 6616, 6622, 6630, 6640, 6648, 6654, 6662, 6681, 6689, 6695, 6703, 6713, + 6721, 6727, 6735, 6757, 6765, 6771, 6779, 6789, 6797, 6803, 6811, 6830, + 6838, 6844, 6852, 6862, 6870, 6876, 6884, 6910, 6918, 6924, 6932, 6942, + 6950, 6956, 6964, 6983, 6991, 6997, 7005, 7015, 7023, 7029, 7037, 7059, + 7067, 7073, 7081, 7091, 7099, 7105, 7113, 7132, 7140, 7146, 7154, 7164, + 7172, 7178, 7186, 7052, 7060, 7066, 7074, 7084, 7092, 7098, 7106, 7125, + 7133, 7139, 7147, 7157, 7165, 7171, 7179, 7201, 7209, 7215, 7223, 7233, + 7241, 7247, 7255, 7274, 7282, 7288, 7296, 7306, 7314, 7320, 7328, 7354, + 7362, 7368, 7376, 7386, 7394, 7400, 7408, 7427, 7435, 7441, 7449, 7459, + 7467, 7473, 7481, 7503, 7511, 7517, 7525, 7535, 7543, 7549, 7557, 7576, + 7584, 7590, 7598, 7608, 7616, 7622, 7630, 6899, 6907, 6913, 6921, 6931, + 6939, 6945, 6953, 6972, 6980, 6986, 6994, 7004, 7012, 7018, 7026, 7048, + 7056, 7062, 7070, 7080, 7088, 7094, 7102, 7121, 7129, 7135, 7143, 7153, + 7161, 7167, 7175, 7201, 7209, 7215, 7223, 7233, 7241, 7247, 7255, 7274, + 7282, 7288, 7296, 7306, 7314, 7320, 7328, 7350, 7358, 7364, 7372, 7382, + 7390, 7396, 7404, 7423, 7431, 7437, 7445, 7455, 7463, 7469, 7477, 7343, + 7351, 7357, 7365, 7375, 7383, 7389, 7397, 7416, 7424, 7430, 7438, 7448, + 7456, 7462, 7470, 7492, 7500, 7506, 7514, 7524, 7532, 7538, 7546, 7565, + 7573, 7579, 7587, 7597, 7605, 7611, 7619, 7645, 7653, 7659, 7667, 7677, + 7685, 7691, 7699, 7718, 7726, 7732, 7740, 7750, 7758, 7764, 7772, 7794, + 7802, 7808, 7816, 7826, 7834, 7840, 7848, 7867, 7875, 7881, 7889, 7899, + 7907, 7913, 7921, 7719, 7727, 7733, 7741, 7751, 7759, 7765, 7773, 7792, + 7800, 7806, 7814, 7824, 7832, 7838, 7846, 7868, 7876, 7882, 7890, 7900, + 7908, 7914, 7922, 7941, 7949, 7955, 7963, 7973, 7981, 7987, 7995, 8021, + 8029, 8035, 8043, 8053, 8061, 8067, 8075, 8094, 8102, 8108, 8116, 8126, + 8134, 8140, 8148, 8170, 8178, 8184, 8192, 8202, 8210, 8216, 8224, 8243, + 8251, 8257, 8265, 8275 +}; diff --git a/vp8/encoder/dct_value_tokens.h b/vp8/encoder/dct_value_tokens.h new file mode 100644 index 0000000..ef08eed --- /dev/null +++ b/vp8/encoder/dct_value_tokens.h @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* Generated file, included by tokenize.c */ +/* Values generated by fill_value_tokens() */ + +static const TOKENVALUE dct_value_tokens[2048*2] = +{ + {10, 3963}, {10, 3961}, {10, 3959}, {10, 3957}, {10, 3955}, {10, 3953}, + {10, 3951}, {10, 3949}, {10, 3947}, {10, 3945}, {10, 3943}, {10, 3941}, + {10, 3939}, {10, 3937}, {10, 3935}, {10, 3933}, {10, 3931}, {10, 3929}, + {10, 3927}, {10, 3925}, {10, 3923}, {10, 3921}, {10, 3919}, {10, 3917}, + {10, 3915}, {10, 3913}, {10, 3911}, {10, 3909}, {10, 3907}, {10, 3905}, + {10, 3903}, {10, 3901}, {10, 3899}, {10, 3897}, {10, 3895}, {10, 3893}, + {10, 3891}, {10, 3889}, {10, 3887}, {10, 3885}, {10, 3883}, {10, 3881}, + {10, 3879}, {10, 3877}, {10, 3875}, {10, 3873}, {10, 3871}, {10, 3869}, + {10, 3867}, {10, 3865}, {10, 3863}, {10, 3861}, {10, 3859}, {10, 3857}, + {10, 3855}, {10, 3853}, {10, 3851}, {10, 3849}, {10, 3847}, {10, 3845}, + {10, 3843}, {10, 3841}, {10, 3839}, {10, 3837}, {10, 3835}, {10, 3833}, + {10, 3831}, {10, 3829}, {10, 3827}, {10, 3825}, {10, 3823}, {10, 3821}, + {10, 3819}, {10, 3817}, {10, 3815}, {10, 3813}, {10, 3811}, {10, 3809}, + {10, 3807}, {10, 3805}, {10, 3803}, {10, 3801}, {10, 3799}, {10, 3797}, + {10, 3795}, {10, 3793}, {10, 3791}, {10, 3789}, {10, 3787}, {10, 3785}, + {10, 3783}, {10, 3781}, {10, 3779}, {10, 3777}, {10, 3775}, {10, 3773}, + {10, 3771}, {10, 3769}, {10, 3767}, {10, 3765}, {10, 3763}, {10, 3761}, + {10, 3759}, {10, 3757}, {10, 3755}, {10, 3753}, {10, 3751}, {10, 3749}, + {10, 3747}, {10, 3745}, {10, 3743}, {10, 3741}, {10, 3739}, {10, 3737}, + {10, 3735}, {10, 3733}, {10, 3731}, {10, 3729}, {10, 3727}, {10, 3725}, + {10, 3723}, {10, 3721}, {10, 3719}, {10, 3717}, {10, 3715}, {10, 3713}, + {10, 3711}, {10, 3709}, {10, 3707}, {10, 3705}, {10, 3703}, {10, 3701}, + {10, 3699}, {10, 3697}, {10, 3695}, {10, 3693}, {10, 3691}, {10, 3689}, + {10, 3687}, {10, 3685}, {10, 3683}, {10, 3681}, {10, 3679}, {10, 3677}, + {10, 3675}, {10, 3673}, {10, 3671}, {10, 3669}, {10, 3667}, {10, 3665}, + {10, 3663}, {10, 3661}, {10, 3659}, {10, 3657}, {10, 3655}, {10, 3653}, + {10, 3651}, {10, 3649}, {10, 3647}, {10, 3645}, {10, 3643}, {10, 3641}, + {10, 3639}, {10, 3637}, {10, 3635}, {10, 3633}, {10, 3631}, {10, 3629}, + {10, 3627}, {10, 3625}, {10, 3623}, {10, 3621}, {10, 3619}, {10, 3617}, + {10, 3615}, {10, 3613}, {10, 3611}, {10, 3609}, {10, 3607}, {10, 3605}, + {10, 3603}, {10, 3601}, {10, 3599}, {10, 3597}, {10, 3595}, {10, 3593}, + {10, 3591}, {10, 3589}, {10, 3587}, {10, 3585}, {10, 3583}, {10, 3581}, + {10, 3579}, {10, 3577}, {10, 3575}, {10, 3573}, {10, 3571}, {10, 3569}, + {10, 3567}, {10, 3565}, {10, 3563}, {10, 3561}, {10, 3559}, {10, 3557}, + {10, 3555}, {10, 3553}, {10, 3551}, {10, 3549}, {10, 3547}, {10, 3545}, + {10, 3543}, {10, 3541}, {10, 3539}, {10, 3537}, {10, 3535}, {10, 3533}, + {10, 3531}, {10, 3529}, {10, 3527}, {10, 3525}, {10, 3523}, {10, 3521}, + {10, 3519}, {10, 3517}, {10, 3515}, {10, 3513}, {10, 3511}, {10, 3509}, + {10, 3507}, {10, 3505}, {10, 3503}, {10, 3501}, {10, 3499}, {10, 3497}, + {10, 3495}, {10, 3493}, {10, 3491}, {10, 3489}, {10, 3487}, {10, 3485}, + {10, 3483}, {10, 3481}, {10, 3479}, {10, 3477}, {10, 3475}, {10, 3473}, + {10, 3471}, {10, 3469}, {10, 3467}, {10, 3465}, {10, 3463}, {10, 3461}, + {10, 3459}, {10, 3457}, {10, 3455}, {10, 3453}, {10, 3451}, {10, 3449}, + {10, 3447}, {10, 3445}, {10, 3443}, {10, 3441}, {10, 3439}, {10, 3437}, + {10, 3435}, {10, 3433}, {10, 3431}, {10, 3429}, {10, 3427}, {10, 3425}, + {10, 3423}, {10, 3421}, {10, 3419}, {10, 3417}, {10, 3415}, {10, 3413}, + {10, 3411}, {10, 3409}, {10, 3407}, {10, 3405}, {10, 3403}, {10, 3401}, + {10, 3399}, {10, 3397}, {10, 3395}, {10, 3393}, {10, 3391}, {10, 3389}, + {10, 3387}, {10, 3385}, {10, 3383}, {10, 3381}, {10, 3379}, {10, 3377}, + {10, 3375}, {10, 3373}, {10, 3371}, {10, 3369}, {10, 3367}, {10, 3365}, + {10, 3363}, {10, 3361}, {10, 3359}, {10, 3357}, {10, 3355}, {10, 3353}, + {10, 3351}, {10, 3349}, {10, 3347}, {10, 3345}, {10, 3343}, {10, 3341}, + {10, 3339}, {10, 3337}, {10, 3335}, {10, 3333}, {10, 3331}, {10, 3329}, + {10, 3327}, {10, 3325}, {10, 3323}, {10, 3321}, {10, 3319}, {10, 3317}, + {10, 3315}, {10, 3313}, {10, 3311}, {10, 3309}, {10, 3307}, {10, 3305}, + {10, 3303}, {10, 3301}, {10, 3299}, {10, 3297}, {10, 3295}, {10, 3293}, + {10, 3291}, {10, 3289}, {10, 3287}, {10, 3285}, {10, 3283}, {10, 3281}, + {10, 3279}, {10, 3277}, {10, 3275}, {10, 3273}, {10, 3271}, {10, 3269}, + {10, 3267}, {10, 3265}, {10, 3263}, {10, 3261}, {10, 3259}, {10, 3257}, + {10, 3255}, {10, 3253}, {10, 3251}, {10, 3249}, {10, 3247}, {10, 3245}, + {10, 3243}, {10, 3241}, {10, 3239}, {10, 3237}, {10, 3235}, {10, 3233}, + {10, 3231}, {10, 3229}, {10, 3227}, {10, 3225}, {10, 3223}, {10, 3221}, + {10, 3219}, {10, 3217}, {10, 3215}, {10, 3213}, {10, 3211}, {10, 3209}, + {10, 3207}, {10, 3205}, {10, 3203}, {10, 3201}, {10, 3199}, {10, 3197}, + {10, 3195}, {10, 3193}, {10, 3191}, {10, 3189}, {10, 3187}, {10, 3185}, + {10, 3183}, {10, 3181}, {10, 3179}, {10, 3177}, {10, 3175}, {10, 3173}, + {10, 3171}, {10, 3169}, {10, 3167}, {10, 3165}, {10, 3163}, {10, 3161}, + {10, 3159}, {10, 3157}, {10, 3155}, {10, 3153}, {10, 3151}, {10, 3149}, + {10, 3147}, {10, 3145}, {10, 3143}, {10, 3141}, {10, 3139}, {10, 3137}, + {10, 3135}, {10, 3133}, {10, 3131}, {10, 3129}, {10, 3127}, {10, 3125}, + {10, 3123}, {10, 3121}, {10, 3119}, {10, 3117}, {10, 3115}, {10, 3113}, + {10, 3111}, {10, 3109}, {10, 3107}, {10, 3105}, {10, 3103}, {10, 3101}, + {10, 3099}, {10, 3097}, {10, 3095}, {10, 3093}, {10, 3091}, {10, 3089}, + {10, 3087}, {10, 3085}, {10, 3083}, {10, 3081}, {10, 3079}, {10, 3077}, + {10, 3075}, {10, 3073}, {10, 3071}, {10, 3069}, {10, 3067}, {10, 3065}, + {10, 3063}, {10, 3061}, {10, 3059}, {10, 3057}, {10, 3055}, {10, 3053}, + {10, 3051}, {10, 3049}, {10, 3047}, {10, 3045}, {10, 3043}, {10, 3041}, + {10, 3039}, {10, 3037}, {10, 3035}, {10, 3033}, {10, 3031}, {10, 3029}, + {10, 3027}, {10, 3025}, {10, 3023}, {10, 3021}, {10, 3019}, {10, 3017}, + {10, 3015}, {10, 3013}, {10, 3011}, {10, 3009}, {10, 3007}, {10, 3005}, + {10, 3003}, {10, 3001}, {10, 2999}, {10, 2997}, {10, 2995}, {10, 2993}, + {10, 2991}, {10, 2989}, {10, 2987}, {10, 2985}, {10, 2983}, {10, 2981}, + {10, 2979}, {10, 2977}, {10, 2975}, {10, 2973}, {10, 2971}, {10, 2969}, + {10, 2967}, {10, 2965}, {10, 2963}, {10, 2961}, {10, 2959}, {10, 2957}, + {10, 2955}, {10, 2953}, {10, 2951}, {10, 2949}, {10, 2947}, {10, 2945}, + {10, 2943}, {10, 2941}, {10, 2939}, {10, 2937}, {10, 2935}, {10, 2933}, + {10, 2931}, {10, 2929}, {10, 2927}, {10, 2925}, {10, 2923}, {10, 2921}, + {10, 2919}, {10, 2917}, {10, 2915}, {10, 2913}, {10, 2911}, {10, 2909}, + {10, 2907}, {10, 2905}, {10, 2903}, {10, 2901}, {10, 2899}, {10, 2897}, + {10, 2895}, {10, 2893}, {10, 2891}, {10, 2889}, {10, 2887}, {10, 2885}, + {10, 2883}, {10, 2881}, {10, 2879}, {10, 2877}, {10, 2875}, {10, 2873}, + {10, 2871}, {10, 2869}, {10, 2867}, {10, 2865}, {10, 2863}, {10, 2861}, + {10, 2859}, {10, 2857}, {10, 2855}, {10, 2853}, {10, 2851}, {10, 2849}, + {10, 2847}, {10, 2845}, {10, 2843}, {10, 2841}, {10, 2839}, {10, 2837}, + {10, 2835}, {10, 2833}, {10, 2831}, {10, 2829}, {10, 2827}, {10, 2825}, + {10, 2823}, {10, 2821}, {10, 2819}, {10, 2817}, {10, 2815}, {10, 2813}, + {10, 2811}, {10, 2809}, {10, 2807}, {10, 2805}, {10, 2803}, {10, 2801}, + {10, 2799}, {10, 2797}, {10, 2795}, {10, 2793}, {10, 2791}, {10, 2789}, + {10, 2787}, {10, 2785}, {10, 2783}, {10, 2781}, {10, 2779}, {10, 2777}, + {10, 2775}, {10, 2773}, {10, 2771}, {10, 2769}, {10, 2767}, {10, 2765}, + {10, 2763}, {10, 2761}, {10, 2759}, {10, 2757}, {10, 2755}, {10, 2753}, + {10, 2751}, {10, 2749}, {10, 2747}, {10, 2745}, {10, 2743}, {10, 2741}, + {10, 2739}, {10, 2737}, {10, 2735}, {10, 2733}, {10, 2731}, {10, 2729}, + {10, 2727}, {10, 2725}, {10, 2723}, {10, 2721}, {10, 2719}, {10, 2717}, + {10, 2715}, {10, 2713}, {10, 2711}, {10, 2709}, {10, 2707}, {10, 2705}, + {10, 2703}, {10, 2701}, {10, 2699}, {10, 2697}, {10, 2695}, {10, 2693}, + {10, 2691}, {10, 2689}, {10, 2687}, {10, 2685}, {10, 2683}, {10, 2681}, + {10, 2679}, {10, 2677}, {10, 2675}, {10, 2673}, {10, 2671}, {10, 2669}, + {10, 2667}, {10, 2665}, {10, 2663}, {10, 2661}, {10, 2659}, {10, 2657}, + {10, 2655}, {10, 2653}, {10, 2651}, {10, 2649}, {10, 2647}, {10, 2645}, + {10, 2643}, {10, 2641}, {10, 2639}, {10, 2637}, {10, 2635}, {10, 2633}, + {10, 2631}, {10, 2629}, {10, 2627}, {10, 2625}, {10, 2623}, {10, 2621}, + {10, 2619}, {10, 2617}, {10, 2615}, {10, 2613}, {10, 2611}, {10, 2609}, + {10, 2607}, {10, 2605}, {10, 2603}, {10, 2601}, {10, 2599}, {10, 2597}, + {10, 2595}, {10, 2593}, {10, 2591}, {10, 2589}, {10, 2587}, {10, 2585}, + {10, 2583}, {10, 2581}, {10, 2579}, {10, 2577}, {10, 2575}, {10, 2573}, + {10, 2571}, {10, 2569}, {10, 2567}, {10, 2565}, {10, 2563}, {10, 2561}, + {10, 2559}, {10, 2557}, {10, 2555}, {10, 2553}, {10, 2551}, {10, 2549}, + {10, 2547}, {10, 2545}, {10, 2543}, {10, 2541}, {10, 2539}, {10, 2537}, + {10, 2535}, {10, 2533}, {10, 2531}, {10, 2529}, {10, 2527}, {10, 2525}, + {10, 2523}, {10, 2521}, {10, 2519}, {10, 2517}, {10, 2515}, {10, 2513}, + {10, 2511}, {10, 2509}, {10, 2507}, {10, 2505}, {10, 2503}, {10, 2501}, + {10, 2499}, {10, 2497}, {10, 2495}, {10, 2493}, {10, 2491}, {10, 2489}, + {10, 2487}, {10, 2485}, {10, 2483}, {10, 2481}, {10, 2479}, {10, 2477}, + {10, 2475}, {10, 2473}, {10, 2471}, {10, 2469}, {10, 2467}, {10, 2465}, + {10, 2463}, {10, 2461}, {10, 2459}, {10, 2457}, {10, 2455}, {10, 2453}, + {10, 2451}, {10, 2449}, {10, 2447}, {10, 2445}, {10, 2443}, {10, 2441}, + {10, 2439}, {10, 2437}, {10, 2435}, {10, 2433}, {10, 2431}, {10, 2429}, + {10, 2427}, {10, 2425}, {10, 2423}, {10, 2421}, {10, 2419}, {10, 2417}, + {10, 2415}, {10, 2413}, {10, 2411}, {10, 2409}, {10, 2407}, {10, 2405}, + {10, 2403}, {10, 2401}, {10, 2399}, {10, 2397}, {10, 2395}, {10, 2393}, + {10, 2391}, {10, 2389}, {10, 2387}, {10, 2385}, {10, 2383}, {10, 2381}, + {10, 2379}, {10, 2377}, {10, 2375}, {10, 2373}, {10, 2371}, {10, 2369}, + {10, 2367}, {10, 2365}, {10, 2363}, {10, 2361}, {10, 2359}, {10, 2357}, + {10, 2355}, {10, 2353}, {10, 2351}, {10, 2349}, {10, 2347}, {10, 2345}, + {10, 2343}, {10, 2341}, {10, 2339}, {10, 2337}, {10, 2335}, {10, 2333}, + {10, 2331}, {10, 2329}, {10, 2327}, {10, 2325}, {10, 2323}, {10, 2321}, + {10, 2319}, {10, 2317}, {10, 2315}, {10, 2313}, {10, 2311}, {10, 2309}, + {10, 2307}, {10, 2305}, {10, 2303}, {10, 2301}, {10, 2299}, {10, 2297}, + {10, 2295}, {10, 2293}, {10, 2291}, {10, 2289}, {10, 2287}, {10, 2285}, + {10, 2283}, {10, 2281}, {10, 2279}, {10, 2277}, {10, 2275}, {10, 2273}, + {10, 2271}, {10, 2269}, {10, 2267}, {10, 2265}, {10, 2263}, {10, 2261}, + {10, 2259}, {10, 2257}, {10, 2255}, {10, 2253}, {10, 2251}, {10, 2249}, + {10, 2247}, {10, 2245}, {10, 2243}, {10, 2241}, {10, 2239}, {10, 2237}, + {10, 2235}, {10, 2233}, {10, 2231}, {10, 2229}, {10, 2227}, {10, 2225}, + {10, 2223}, {10, 2221}, {10, 2219}, {10, 2217}, {10, 2215}, {10, 2213}, + {10, 2211}, {10, 2209}, {10, 2207}, {10, 2205}, {10, 2203}, {10, 2201}, + {10, 2199}, {10, 2197}, {10, 2195}, {10, 2193}, {10, 2191}, {10, 2189}, + {10, 2187}, {10, 2185}, {10, 2183}, {10, 2181}, {10, 2179}, {10, 2177}, + {10, 2175}, {10, 2173}, {10, 2171}, {10, 2169}, {10, 2167}, {10, 2165}, + {10, 2163}, {10, 2161}, {10, 2159}, {10, 2157}, {10, 2155}, {10, 2153}, + {10, 2151}, {10, 2149}, {10, 2147}, {10, 2145}, {10, 2143}, {10, 2141}, + {10, 2139}, {10, 2137}, {10, 2135}, {10, 2133}, {10, 2131}, {10, 2129}, + {10, 2127}, {10, 2125}, {10, 2123}, {10, 2121}, {10, 2119}, {10, 2117}, + {10, 2115}, {10, 2113}, {10, 2111}, {10, 2109}, {10, 2107}, {10, 2105}, + {10, 2103}, {10, 2101}, {10, 2099}, {10, 2097}, {10, 2095}, {10, 2093}, + {10, 2091}, {10, 2089}, {10, 2087}, {10, 2085}, {10, 2083}, {10, 2081}, + {10, 2079}, {10, 2077}, {10, 2075}, {10, 2073}, {10, 2071}, {10, 2069}, + {10, 2067}, {10, 2065}, {10, 2063}, {10, 2061}, {10, 2059}, {10, 2057}, + {10, 2055}, {10, 2053}, {10, 2051}, {10, 2049}, {10, 2047}, {10, 2045}, + {10, 2043}, {10, 2041}, {10, 2039}, {10, 2037}, {10, 2035}, {10, 2033}, + {10, 2031}, {10, 2029}, {10, 2027}, {10, 2025}, {10, 2023}, {10, 2021}, + {10, 2019}, {10, 2017}, {10, 2015}, {10, 2013}, {10, 2011}, {10, 2009}, + {10, 2007}, {10, 2005}, {10, 2003}, {10, 2001}, {10, 1999}, {10, 1997}, + {10, 1995}, {10, 1993}, {10, 1991}, {10, 1989}, {10, 1987}, {10, 1985}, + {10, 1983}, {10, 1981}, {10, 1979}, {10, 1977}, {10, 1975}, {10, 1973}, + {10, 1971}, {10, 1969}, {10, 1967}, {10, 1965}, {10, 1963}, {10, 1961}, + {10, 1959}, {10, 1957}, {10, 1955}, {10, 1953}, {10, 1951}, {10, 1949}, + {10, 1947}, {10, 1945}, {10, 1943}, {10, 1941}, {10, 1939}, {10, 1937}, + {10, 1935}, {10, 1933}, {10, 1931}, {10, 1929}, {10, 1927}, {10, 1925}, + {10, 1923}, {10, 1921}, {10, 1919}, {10, 1917}, {10, 1915}, {10, 1913}, + {10, 1911}, {10, 1909}, {10, 1907}, {10, 1905}, {10, 1903}, {10, 1901}, + {10, 1899}, {10, 1897}, {10, 1895}, {10, 1893}, {10, 1891}, {10, 1889}, + {10, 1887}, {10, 1885}, {10, 1883}, {10, 1881}, {10, 1879}, {10, 1877}, + {10, 1875}, {10, 1873}, {10, 1871}, {10, 1869}, {10, 1867}, {10, 1865}, + {10, 1863}, {10, 1861}, {10, 1859}, {10, 1857}, {10, 1855}, {10, 1853}, + {10, 1851}, {10, 1849}, {10, 1847}, {10, 1845}, {10, 1843}, {10, 1841}, + {10, 1839}, {10, 1837}, {10, 1835}, {10, 1833}, {10, 1831}, {10, 1829}, + {10, 1827}, {10, 1825}, {10, 1823}, {10, 1821}, {10, 1819}, {10, 1817}, + {10, 1815}, {10, 1813}, {10, 1811}, {10, 1809}, {10, 1807}, {10, 1805}, + {10, 1803}, {10, 1801}, {10, 1799}, {10, 1797}, {10, 1795}, {10, 1793}, + {10, 1791}, {10, 1789}, {10, 1787}, {10, 1785}, {10, 1783}, {10, 1781}, + {10, 1779}, {10, 1777}, {10, 1775}, {10, 1773}, {10, 1771}, {10, 1769}, + {10, 1767}, {10, 1765}, {10, 1763}, {10, 1761}, {10, 1759}, {10, 1757}, + {10, 1755}, {10, 1753}, {10, 1751}, {10, 1749}, {10, 1747}, {10, 1745}, + {10, 1743}, {10, 1741}, {10, 1739}, {10, 1737}, {10, 1735}, {10, 1733}, + {10, 1731}, {10, 1729}, {10, 1727}, {10, 1725}, {10, 1723}, {10, 1721}, + {10, 1719}, {10, 1717}, {10, 1715}, {10, 1713}, {10, 1711}, {10, 1709}, + {10, 1707}, {10, 1705}, {10, 1703}, {10, 1701}, {10, 1699}, {10, 1697}, + {10, 1695}, {10, 1693}, {10, 1691}, {10, 1689}, {10, 1687}, {10, 1685}, + {10, 1683}, {10, 1681}, {10, 1679}, {10, 1677}, {10, 1675}, {10, 1673}, + {10, 1671}, {10, 1669}, {10, 1667}, {10, 1665}, {10, 1663}, {10, 1661}, + {10, 1659}, {10, 1657}, {10, 1655}, {10, 1653}, {10, 1651}, {10, 1649}, + {10, 1647}, {10, 1645}, {10, 1643}, {10, 1641}, {10, 1639}, {10, 1637}, + {10, 1635}, {10, 1633}, {10, 1631}, {10, 1629}, {10, 1627}, {10, 1625}, + {10, 1623}, {10, 1621}, {10, 1619}, {10, 1617}, {10, 1615}, {10, 1613}, + {10, 1611}, {10, 1609}, {10, 1607}, {10, 1605}, {10, 1603}, {10, 1601}, + {10, 1599}, {10, 1597}, {10, 1595}, {10, 1593}, {10, 1591}, {10, 1589}, + {10, 1587}, {10, 1585}, {10, 1583}, {10, 1581}, {10, 1579}, {10, 1577}, + {10, 1575}, {10, 1573}, {10, 1571}, {10, 1569}, {10, 1567}, {10, 1565}, + {10, 1563}, {10, 1561}, {10, 1559}, {10, 1557}, {10, 1555}, {10, 1553}, + {10, 1551}, {10, 1549}, {10, 1547}, {10, 1545}, {10, 1543}, {10, 1541}, + {10, 1539}, {10, 1537}, {10, 1535}, {10, 1533}, {10, 1531}, {10, 1529}, + {10, 1527}, {10, 1525}, {10, 1523}, {10, 1521}, {10, 1519}, {10, 1517}, + {10, 1515}, {10, 1513}, {10, 1511}, {10, 1509}, {10, 1507}, {10, 1505}, + {10, 1503}, {10, 1501}, {10, 1499}, {10, 1497}, {10, 1495}, {10, 1493}, + {10, 1491}, {10, 1489}, {10, 1487}, {10, 1485}, {10, 1483}, {10, 1481}, + {10, 1479}, {10, 1477}, {10, 1475}, {10, 1473}, {10, 1471}, {10, 1469}, + {10, 1467}, {10, 1465}, {10, 1463}, {10, 1461}, {10, 1459}, {10, 1457}, + {10, 1455}, {10, 1453}, {10, 1451}, {10, 1449}, {10, 1447}, {10, 1445}, + {10, 1443}, {10, 1441}, {10, 1439}, {10, 1437}, {10, 1435}, {10, 1433}, + {10, 1431}, {10, 1429}, {10, 1427}, {10, 1425}, {10, 1423}, {10, 1421}, + {10, 1419}, {10, 1417}, {10, 1415}, {10, 1413}, {10, 1411}, {10, 1409}, + {10, 1407}, {10, 1405}, {10, 1403}, {10, 1401}, {10, 1399}, {10, 1397}, + {10, 1395}, {10, 1393}, {10, 1391}, {10, 1389}, {10, 1387}, {10, 1385}, + {10, 1383}, {10, 1381}, {10, 1379}, {10, 1377}, {10, 1375}, {10, 1373}, + {10, 1371}, {10, 1369}, {10, 1367}, {10, 1365}, {10, 1363}, {10, 1361}, + {10, 1359}, {10, 1357}, {10, 1355}, {10, 1353}, {10, 1351}, {10, 1349}, + {10, 1347}, {10, 1345}, {10, 1343}, {10, 1341}, {10, 1339}, {10, 1337}, + {10, 1335}, {10, 1333}, {10, 1331}, {10, 1329}, {10, 1327}, {10, 1325}, + {10, 1323}, {10, 1321}, {10, 1319}, {10, 1317}, {10, 1315}, {10, 1313}, + {10, 1311}, {10, 1309}, {10, 1307}, {10, 1305}, {10, 1303}, {10, 1301}, + {10, 1299}, {10, 1297}, {10, 1295}, {10, 1293}, {10, 1291}, {10, 1289}, + {10, 1287}, {10, 1285}, {10, 1283}, {10, 1281}, {10, 1279}, {10, 1277}, + {10, 1275}, {10, 1273}, {10, 1271}, {10, 1269}, {10, 1267}, {10, 1265}, + {10, 1263}, {10, 1261}, {10, 1259}, {10, 1257}, {10, 1255}, {10, 1253}, + {10, 1251}, {10, 1249}, {10, 1247}, {10, 1245}, {10, 1243}, {10, 1241}, + {10, 1239}, {10, 1237}, {10, 1235}, {10, 1233}, {10, 1231}, {10, 1229}, + {10, 1227}, {10, 1225}, {10, 1223}, {10, 1221}, {10, 1219}, {10, 1217}, + {10, 1215}, {10, 1213}, {10, 1211}, {10, 1209}, {10, 1207}, {10, 1205}, + {10, 1203}, {10, 1201}, {10, 1199}, {10, 1197}, {10, 1195}, {10, 1193}, + {10, 1191}, {10, 1189}, {10, 1187}, {10, 1185}, {10, 1183}, {10, 1181}, + {10, 1179}, {10, 1177}, {10, 1175}, {10, 1173}, {10, 1171}, {10, 1169}, + {10, 1167}, {10, 1165}, {10, 1163}, {10, 1161}, {10, 1159}, {10, 1157}, + {10, 1155}, {10, 1153}, {10, 1151}, {10, 1149}, {10, 1147}, {10, 1145}, + {10, 1143}, {10, 1141}, {10, 1139}, {10, 1137}, {10, 1135}, {10, 1133}, + {10, 1131}, {10, 1129}, {10, 1127}, {10, 1125}, {10, 1123}, {10, 1121}, + {10, 1119}, {10, 1117}, {10, 1115}, {10, 1113}, {10, 1111}, {10, 1109}, + {10, 1107}, {10, 1105}, {10, 1103}, {10, 1101}, {10, 1099}, {10, 1097}, + {10, 1095}, {10, 1093}, {10, 1091}, {10, 1089}, {10, 1087}, {10, 1085}, + {10, 1083}, {10, 1081}, {10, 1079}, {10, 1077}, {10, 1075}, {10, 1073}, + {10, 1071}, {10, 1069}, {10, 1067}, {10, 1065}, {10, 1063}, {10, 1061}, + {10, 1059}, {10, 1057}, {10, 1055}, {10, 1053}, {10, 1051}, {10, 1049}, + {10, 1047}, {10, 1045}, {10, 1043}, {10, 1041}, {10, 1039}, {10, 1037}, + {10, 1035}, {10, 1033}, {10, 1031}, {10, 1029}, {10, 1027}, {10, 1025}, + {10, 1023}, {10, 1021}, {10, 1019}, {10, 1017}, {10, 1015}, {10, 1013}, + {10, 1011}, {10, 1009}, {10, 1007}, {10, 1005}, {10, 1003}, {10, 1001}, + {10, 999}, {10, 997}, {10, 995}, {10, 993}, {10, 991}, {10, 989}, + {10, 987}, {10, 985}, {10, 983}, {10, 981}, {10, 979}, {10, 977}, + {10, 975}, {10, 973}, {10, 971}, {10, 969}, {10, 967}, {10, 965}, + {10, 963}, {10, 961}, {10, 959}, {10, 957}, {10, 955}, {10, 953}, + {10, 951}, {10, 949}, {10, 947}, {10, 945}, {10, 943}, {10, 941}, + {10, 939}, {10, 937}, {10, 935}, {10, 933}, {10, 931}, {10, 929}, + {10, 927}, {10, 925}, {10, 923}, {10, 921}, {10, 919}, {10, 917}, + {10, 915}, {10, 913}, {10, 911}, {10, 909}, {10, 907}, {10, 905}, + {10, 903}, {10, 901}, {10, 899}, {10, 897}, {10, 895}, {10, 893}, + {10, 891}, {10, 889}, {10, 887}, {10, 885}, {10, 883}, {10, 881}, + {10, 879}, {10, 877}, {10, 875}, {10, 873}, {10, 871}, {10, 869}, + {10, 867}, {10, 865}, {10, 863}, {10, 861}, {10, 859}, {10, 857}, + {10, 855}, {10, 853}, {10, 851}, {10, 849}, {10, 847}, {10, 845}, + {10, 843}, {10, 841}, {10, 839}, {10, 837}, {10, 835}, {10, 833}, + {10, 831}, {10, 829}, {10, 827}, {10, 825}, {10, 823}, {10, 821}, + {10, 819}, {10, 817}, {10, 815}, {10, 813}, {10, 811}, {10, 809}, + {10, 807}, {10, 805}, {10, 803}, {10, 801}, {10, 799}, {10, 797}, + {10, 795}, {10, 793}, {10, 791}, {10, 789}, {10, 787}, {10, 785}, + {10, 783}, {10, 781}, {10, 779}, {10, 777}, {10, 775}, {10, 773}, + {10, 771}, {10, 769}, {10, 767}, {10, 765}, {10, 763}, {10, 761}, + {10, 759}, {10, 757}, {10, 755}, {10, 753}, {10, 751}, {10, 749}, + {10, 747}, {10, 745}, {10, 743}, {10, 741}, {10, 739}, {10, 737}, + {10, 735}, {10, 733}, {10, 731}, {10, 729}, {10, 727}, {10, 725}, + {10, 723}, {10, 721}, {10, 719}, {10, 717}, {10, 715}, {10, 713}, + {10, 711}, {10, 709}, {10, 707}, {10, 705}, {10, 703}, {10, 701}, + {10, 699}, {10, 697}, {10, 695}, {10, 693}, {10, 691}, {10, 689}, + {10, 687}, {10, 685}, {10, 683}, {10, 681}, {10, 679}, {10, 677}, + {10, 675}, {10, 673}, {10, 671}, {10, 669}, {10, 667}, {10, 665}, + {10, 663}, {10, 661}, {10, 659}, {10, 657}, {10, 655}, {10, 653}, + {10, 651}, {10, 649}, {10, 647}, {10, 645}, {10, 643}, {10, 641}, + {10, 639}, {10, 637}, {10, 635}, {10, 633}, {10, 631}, {10, 629}, + {10, 627}, {10, 625}, {10, 623}, {10, 621}, {10, 619}, {10, 617}, + {10, 615}, {10, 613}, {10, 611}, {10, 609}, {10, 607}, {10, 605}, + {10, 603}, {10, 601}, {10, 599}, {10, 597}, {10, 595}, {10, 593}, + {10, 591}, {10, 589}, {10, 587}, {10, 585}, {10, 583}, {10, 581}, + {10, 579}, {10, 577}, {10, 575}, {10, 573}, {10, 571}, {10, 569}, + {10, 567}, {10, 565}, {10, 563}, {10, 561}, {10, 559}, {10, 557}, + {10, 555}, {10, 553}, {10, 551}, {10, 549}, {10, 547}, {10, 545}, + {10, 543}, {10, 541}, {10, 539}, {10, 537}, {10, 535}, {10, 533}, + {10, 531}, {10, 529}, {10, 527}, {10, 525}, {10, 523}, {10, 521}, + {10, 519}, {10, 517}, {10, 515}, {10, 513}, {10, 511}, {10, 509}, + {10, 507}, {10, 505}, {10, 503}, {10, 501}, {10, 499}, {10, 497}, + {10, 495}, {10, 493}, {10, 491}, {10, 489}, {10, 487}, {10, 485}, + {10, 483}, {10, 481}, {10, 479}, {10, 477}, {10, 475}, {10, 473}, + {10, 471}, {10, 469}, {10, 467}, {10, 465}, {10, 463}, {10, 461}, + {10, 459}, {10, 457}, {10, 455}, {10, 453}, {10, 451}, {10, 449}, + {10, 447}, {10, 445}, {10, 443}, {10, 441}, {10, 439}, {10, 437}, + {10, 435}, {10, 433}, {10, 431}, {10, 429}, {10, 427}, {10, 425}, + {10, 423}, {10, 421}, {10, 419}, {10, 417}, {10, 415}, {10, 413}, + {10, 411}, {10, 409}, {10, 407}, {10, 405}, {10, 403}, {10, 401}, + {10, 399}, {10, 397}, {10, 395}, {10, 393}, {10, 391}, {10, 389}, + {10, 387}, {10, 385}, {10, 383}, {10, 381}, {10, 379}, {10, 377}, + {10, 375}, {10, 373}, {10, 371}, {10, 369}, {10, 367}, {10, 365}, + {10, 363}, {10, 361}, {10, 359}, {10, 357}, {10, 355}, {10, 353}, + {10, 351}, {10, 349}, {10, 347}, {10, 345}, {10, 343}, {10, 341}, + {10, 339}, {10, 337}, {10, 335}, {10, 333}, {10, 331}, {10, 329}, + {10, 327}, {10, 325}, {10, 323}, {10, 321}, {10, 319}, {10, 317}, + {10, 315}, {10, 313}, {10, 311}, {10, 309}, {10, 307}, {10, 305}, + {10, 303}, {10, 301}, {10, 299}, {10, 297}, {10, 295}, {10, 293}, + {10, 291}, {10, 289}, {10, 287}, {10, 285}, {10, 283}, {10, 281}, + {10, 279}, {10, 277}, {10, 275}, {10, 273}, {10, 271}, {10, 269}, + {10, 267}, {10, 265}, {10, 263}, {10, 261}, {10, 259}, {10, 257}, + {10, 255}, {10, 253}, {10, 251}, {10, 249}, {10, 247}, {10, 245}, + {10, 243}, {10, 241}, {10, 239}, {10, 237}, {10, 235}, {10, 233}, + {10, 231}, {10, 229}, {10, 227}, {10, 225}, {10, 223}, {10, 221}, + {10, 219}, {10, 217}, {10, 215}, {10, 213}, {10, 211}, {10, 209}, + {10, 207}, {10, 205}, {10, 203}, {10, 201}, {10, 199}, {10, 197}, + {10, 195}, {10, 193}, {10, 191}, {10, 189}, {10, 187}, {10, 185}, + {10, 183}, {10, 181}, {10, 179}, {10, 177}, {10, 175}, {10, 173}, + {10, 171}, {10, 169}, {10, 167}, {10, 165}, {10, 163}, {10, 161}, + {10, 159}, {10, 157}, {10, 155}, {10, 153}, {10, 151}, {10, 149}, + {10, 147}, {10, 145}, {10, 143}, {10, 141}, {10, 139}, {10, 137}, + {10, 135}, {10, 133}, {10, 131}, {10, 129}, {10, 127}, {10, 125}, + {10, 123}, {10, 121}, {10, 119}, {10, 117}, {10, 115}, {10, 113}, + {10, 111}, {10, 109}, {10, 107}, {10, 105}, {10, 103}, {10, 101}, + {10, 99}, {10, 97}, {10, 95}, {10, 93}, {10, 91}, {10, 89}, + {10, 87}, {10, 85}, {10, 83}, {10, 81}, {10, 79}, {10, 77}, + {10, 75}, {10, 73}, {10, 71}, {10, 69}, {10, 67}, {10, 65}, + {10, 63}, {10, 61}, {10, 59}, {10, 57}, {10, 55}, {10, 53}, + {10, 51}, {10, 49}, {10, 47}, {10, 45}, {10, 43}, {10, 41}, + {10, 39}, {10, 37}, {10, 35}, {10, 33}, {10, 31}, {10, 29}, + {10, 27}, {10, 25}, {10, 23}, {10, 21}, {10, 19}, {10, 17}, + {10, 15}, {10, 13}, {10, 11}, {10, 9}, {10, 7}, {10, 5}, + {10, 3}, {10, 1}, {9, 63}, {9, 61}, {9, 59}, {9, 57}, + {9, 55}, {9, 53}, {9, 51}, {9, 49}, {9, 47}, {9, 45}, + {9, 43}, {9, 41}, {9, 39}, {9, 37}, {9, 35}, {9, 33}, + {9, 31}, {9, 29}, {9, 27}, {9, 25}, {9, 23}, {9, 21}, + {9, 19}, {9, 17}, {9, 15}, {9, 13}, {9, 11}, {9, 9}, + {9, 7}, {9, 5}, {9, 3}, {9, 1}, {8, 31}, {8, 29}, + {8, 27}, {8, 25}, {8, 23}, {8, 21}, {8, 19}, {8, 17}, + {8, 15}, {8, 13}, {8, 11}, {8, 9}, {8, 7}, {8, 5}, + {8, 3}, {8, 1}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, + {7, 7}, {7, 5}, {7, 3}, {7, 1}, {6, 7}, {6, 5}, + {6, 3}, {6, 1}, {5, 3}, {5, 1}, {4, 1}, {3, 1}, + {2, 1}, {1, 1}, {0, 0}, {1, 0}, {2, 0}, {3, 0}, + {4, 0}, {5, 0}, {5, 2}, {6, 0}, {6, 2}, {6, 4}, + {6, 6}, {7, 0}, {7, 2}, {7, 4}, {7, 6}, {7, 8}, + {7, 10}, {7, 12}, {7, 14}, {8, 0}, {8, 2}, {8, 4}, + {8, 6}, {8, 8}, {8, 10}, {8, 12}, {8, 14}, {8, 16}, + {8, 18}, {8, 20}, {8, 22}, {8, 24}, {8, 26}, {8, 28}, + {8, 30}, {9, 0}, {9, 2}, {9, 4}, {9, 6}, {9, 8}, + {9, 10}, {9, 12}, {9, 14}, {9, 16}, {9, 18}, {9, 20}, + {9, 22}, {9, 24}, {9, 26}, {9, 28}, {9, 30}, {9, 32}, + {9, 34}, {9, 36}, {9, 38}, {9, 40}, {9, 42}, {9, 44}, + {9, 46}, {9, 48}, {9, 50}, {9, 52}, {9, 54}, {9, 56}, + {9, 58}, {9, 60}, {9, 62}, {10, 0}, {10, 2}, {10, 4}, + {10, 6}, {10, 8}, {10, 10}, {10, 12}, {10, 14}, {10, 16}, + {10, 18}, {10, 20}, {10, 22}, {10, 24}, {10, 26}, {10, 28}, + {10, 30}, {10, 32}, {10, 34}, {10, 36}, {10, 38}, {10, 40}, + {10, 42}, {10, 44}, {10, 46}, {10, 48}, {10, 50}, {10, 52}, + {10, 54}, {10, 56}, {10, 58}, {10, 60}, {10, 62}, {10, 64}, + {10, 66}, {10, 68}, {10, 70}, {10, 72}, {10, 74}, {10, 76}, + {10, 78}, {10, 80}, {10, 82}, {10, 84}, {10, 86}, {10, 88}, + {10, 90}, {10, 92}, {10, 94}, {10, 96}, {10, 98}, {10, 100}, + {10, 102}, {10, 104}, {10, 106}, {10, 108}, {10, 110}, {10, 112}, + {10, 114}, {10, 116}, {10, 118}, {10, 120}, {10, 122}, {10, 124}, + {10, 126}, {10, 128}, {10, 130}, {10, 132}, {10, 134}, {10, 136}, + {10, 138}, {10, 140}, {10, 142}, {10, 144}, {10, 146}, {10, 148}, + {10, 150}, {10, 152}, {10, 154}, {10, 156}, {10, 158}, {10, 160}, + {10, 162}, {10, 164}, {10, 166}, {10, 168}, {10, 170}, {10, 172}, + {10, 174}, {10, 176}, {10, 178}, {10, 180}, {10, 182}, {10, 184}, + {10, 186}, {10, 188}, {10, 190}, {10, 192}, {10, 194}, {10, 196}, + {10, 198}, {10, 200}, {10, 202}, {10, 204}, {10, 206}, {10, 208}, + {10, 210}, {10, 212}, {10, 214}, {10, 216}, {10, 218}, {10, 220}, + {10, 222}, {10, 224}, {10, 226}, {10, 228}, {10, 230}, {10, 232}, + {10, 234}, {10, 236}, {10, 238}, {10, 240}, {10, 242}, {10, 244}, + {10, 246}, {10, 248}, {10, 250}, {10, 252}, {10, 254}, {10, 256}, + {10, 258}, {10, 260}, {10, 262}, {10, 264}, {10, 266}, {10, 268}, + {10, 270}, {10, 272}, {10, 274}, {10, 276}, {10, 278}, {10, 280}, + {10, 282}, {10, 284}, {10, 286}, {10, 288}, {10, 290}, {10, 292}, + {10, 294}, {10, 296}, {10, 298}, {10, 300}, {10, 302}, {10, 304}, + {10, 306}, {10, 308}, {10, 310}, {10, 312}, {10, 314}, {10, 316}, + {10, 318}, {10, 320}, {10, 322}, {10, 324}, {10, 326}, {10, 328}, + {10, 330}, {10, 332}, {10, 334}, {10, 336}, {10, 338}, {10, 340}, + {10, 342}, {10, 344}, {10, 346}, {10, 348}, {10, 350}, {10, 352}, + {10, 354}, {10, 356}, {10, 358}, {10, 360}, {10, 362}, {10, 364}, + {10, 366}, {10, 368}, {10, 370}, {10, 372}, {10, 374}, {10, 376}, + {10, 378}, {10, 380}, {10, 382}, {10, 384}, {10, 386}, {10, 388}, + {10, 390}, {10, 392}, {10, 394}, {10, 396}, {10, 398}, {10, 400}, + {10, 402}, {10, 404}, {10, 406}, {10, 408}, {10, 410}, {10, 412}, + {10, 414}, {10, 416}, {10, 418}, {10, 420}, {10, 422}, {10, 424}, + {10, 426}, {10, 428}, {10, 430}, {10, 432}, {10, 434}, {10, 436}, + {10, 438}, {10, 440}, {10, 442}, {10, 444}, {10, 446}, {10, 448}, + {10, 450}, {10, 452}, {10, 454}, {10, 456}, {10, 458}, {10, 460}, + {10, 462}, {10, 464}, {10, 466}, {10, 468}, {10, 470}, {10, 472}, + {10, 474}, {10, 476}, {10, 478}, {10, 480}, {10, 482}, {10, 484}, + {10, 486}, {10, 488}, {10, 490}, {10, 492}, {10, 494}, {10, 496}, + {10, 498}, {10, 500}, {10, 502}, {10, 504}, {10, 506}, {10, 508}, + {10, 510}, {10, 512}, {10, 514}, {10, 516}, {10, 518}, {10, 520}, + {10, 522}, {10, 524}, {10, 526}, {10, 528}, {10, 530}, {10, 532}, + {10, 534}, {10, 536}, {10, 538}, {10, 540}, {10, 542}, {10, 544}, + {10, 546}, {10, 548}, {10, 550}, {10, 552}, {10, 554}, {10, 556}, + {10, 558}, {10, 560}, {10, 562}, {10, 564}, {10, 566}, {10, 568}, + {10, 570}, {10, 572}, {10, 574}, {10, 576}, {10, 578}, {10, 580}, + {10, 582}, {10, 584}, {10, 586}, {10, 588}, {10, 590}, {10, 592}, + {10, 594}, {10, 596}, {10, 598}, {10, 600}, {10, 602}, {10, 604}, + {10, 606}, {10, 608}, {10, 610}, {10, 612}, {10, 614}, {10, 616}, + {10, 618}, {10, 620}, {10, 622}, {10, 624}, {10, 626}, {10, 628}, + {10, 630}, {10, 632}, {10, 634}, {10, 636}, {10, 638}, {10, 640}, + {10, 642}, {10, 644}, {10, 646}, {10, 648}, {10, 650}, {10, 652}, + {10, 654}, {10, 656}, {10, 658}, {10, 660}, {10, 662}, {10, 664}, + {10, 666}, {10, 668}, {10, 670}, {10, 672}, {10, 674}, {10, 676}, + {10, 678}, {10, 680}, {10, 682}, {10, 684}, {10, 686}, {10, 688}, + {10, 690}, {10, 692}, {10, 694}, {10, 696}, {10, 698}, {10, 700}, + {10, 702}, {10, 704}, {10, 706}, {10, 708}, {10, 710}, {10, 712}, + {10, 714}, {10, 716}, {10, 718}, {10, 720}, {10, 722}, {10, 724}, + {10, 726}, {10, 728}, {10, 730}, {10, 732}, {10, 734}, {10, 736}, + {10, 738}, {10, 740}, {10, 742}, {10, 744}, {10, 746}, {10, 748}, + {10, 750}, {10, 752}, {10, 754}, {10, 756}, {10, 758}, {10, 760}, + {10, 762}, {10, 764}, {10, 766}, {10, 768}, {10, 770}, {10, 772}, + {10, 774}, {10, 776}, {10, 778}, {10, 780}, {10, 782}, {10, 784}, + {10, 786}, {10, 788}, {10, 790}, {10, 792}, {10, 794}, {10, 796}, + {10, 798}, {10, 800}, {10, 802}, {10, 804}, {10, 806}, {10, 808}, + {10, 810}, {10, 812}, {10, 814}, {10, 816}, {10, 818}, {10, 820}, + {10, 822}, {10, 824}, {10, 826}, {10, 828}, {10, 830}, {10, 832}, + {10, 834}, {10, 836}, {10, 838}, {10, 840}, {10, 842}, {10, 844}, + {10, 846}, {10, 848}, {10, 850}, {10, 852}, {10, 854}, {10, 856}, + {10, 858}, {10, 860}, {10, 862}, {10, 864}, {10, 866}, {10, 868}, + {10, 870}, {10, 872}, {10, 874}, {10, 876}, {10, 878}, {10, 880}, + {10, 882}, {10, 884}, {10, 886}, {10, 888}, {10, 890}, {10, 892}, + {10, 894}, {10, 896}, {10, 898}, {10, 900}, {10, 902}, {10, 904}, + {10, 906}, {10, 908}, {10, 910}, {10, 912}, {10, 914}, {10, 916}, + {10, 918}, {10, 920}, {10, 922}, {10, 924}, {10, 926}, {10, 928}, + {10, 930}, {10, 932}, {10, 934}, {10, 936}, {10, 938}, {10, 940}, + {10, 942}, {10, 944}, {10, 946}, {10, 948}, {10, 950}, {10, 952}, + {10, 954}, {10, 956}, {10, 958}, {10, 960}, {10, 962}, {10, 964}, + {10, 966}, {10, 968}, {10, 970}, {10, 972}, {10, 974}, {10, 976}, + {10, 978}, {10, 980}, {10, 982}, {10, 984}, {10, 986}, {10, 988}, + {10, 990}, {10, 992}, {10, 994}, {10, 996}, {10, 998}, {10, 1000}, + {10, 1002}, {10, 1004}, {10, 1006}, {10, 1008}, {10, 1010}, {10, 1012}, + {10, 1014}, {10, 1016}, {10, 1018}, {10, 1020}, {10, 1022}, {10, 1024}, + {10, 1026}, {10, 1028}, {10, 1030}, {10, 1032}, {10, 1034}, {10, 1036}, + {10, 1038}, {10, 1040}, {10, 1042}, {10, 1044}, {10, 1046}, {10, 1048}, + {10, 1050}, {10, 1052}, {10, 1054}, {10, 1056}, {10, 1058}, {10, 1060}, + {10, 1062}, {10, 1064}, {10, 1066}, {10, 1068}, {10, 1070}, {10, 1072}, + {10, 1074}, {10, 1076}, {10, 1078}, {10, 1080}, {10, 1082}, {10, 1084}, + {10, 1086}, {10, 1088}, {10, 1090}, {10, 1092}, {10, 1094}, {10, 1096}, + {10, 1098}, {10, 1100}, {10, 1102}, {10, 1104}, {10, 1106}, {10, 1108}, + {10, 1110}, {10, 1112}, {10, 1114}, {10, 1116}, {10, 1118}, {10, 1120}, + {10, 1122}, {10, 1124}, {10, 1126}, {10, 1128}, {10, 1130}, {10, 1132}, + {10, 1134}, {10, 1136}, {10, 1138}, {10, 1140}, {10, 1142}, {10, 1144}, + {10, 1146}, {10, 1148}, {10, 1150}, {10, 1152}, {10, 1154}, {10, 1156}, + {10, 1158}, {10, 1160}, {10, 1162}, {10, 1164}, {10, 1166}, {10, 1168}, + {10, 1170}, {10, 1172}, {10, 1174}, {10, 1176}, {10, 1178}, {10, 1180}, + {10, 1182}, {10, 1184}, {10, 1186}, {10, 1188}, {10, 1190}, {10, 1192}, + {10, 1194}, {10, 1196}, {10, 1198}, {10, 1200}, {10, 1202}, {10, 1204}, + {10, 1206}, {10, 1208}, {10, 1210}, {10, 1212}, {10, 1214}, {10, 1216}, + {10, 1218}, {10, 1220}, {10, 1222}, {10, 1224}, {10, 1226}, {10, 1228}, + {10, 1230}, {10, 1232}, {10, 1234}, {10, 1236}, {10, 1238}, {10, 1240}, + {10, 1242}, {10, 1244}, {10, 1246}, {10, 1248}, {10, 1250}, {10, 1252}, + {10, 1254}, {10, 1256}, {10, 1258}, {10, 1260}, {10, 1262}, {10, 1264}, + {10, 1266}, {10, 1268}, {10, 1270}, {10, 1272}, {10, 1274}, {10, 1276}, + {10, 1278}, {10, 1280}, {10, 1282}, {10, 1284}, {10, 1286}, {10, 1288}, + {10, 1290}, {10, 1292}, {10, 1294}, {10, 1296}, {10, 1298}, {10, 1300}, + {10, 1302}, {10, 1304}, {10, 1306}, {10, 1308}, {10, 1310}, {10, 1312}, + {10, 1314}, {10, 1316}, {10, 1318}, {10, 1320}, {10, 1322}, {10, 1324}, + {10, 1326}, {10, 1328}, {10, 1330}, {10, 1332}, {10, 1334}, {10, 1336}, + {10, 1338}, {10, 1340}, {10, 1342}, {10, 1344}, {10, 1346}, {10, 1348}, + {10, 1350}, {10, 1352}, {10, 1354}, {10, 1356}, {10, 1358}, {10, 1360}, + {10, 1362}, {10, 1364}, {10, 1366}, {10, 1368}, {10, 1370}, {10, 1372}, + {10, 1374}, {10, 1376}, {10, 1378}, {10, 1380}, {10, 1382}, {10, 1384}, + {10, 1386}, {10, 1388}, {10, 1390}, {10, 1392}, {10, 1394}, {10, 1396}, + {10, 1398}, {10, 1400}, {10, 1402}, {10, 1404}, {10, 1406}, {10, 1408}, + {10, 1410}, {10, 1412}, {10, 1414}, {10, 1416}, {10, 1418}, {10, 1420}, + {10, 1422}, {10, 1424}, {10, 1426}, {10, 1428}, {10, 1430}, {10, 1432}, + {10, 1434}, {10, 1436}, {10, 1438}, {10, 1440}, {10, 1442}, {10, 1444}, + {10, 1446}, {10, 1448}, {10, 1450}, {10, 1452}, {10, 1454}, {10, 1456}, + {10, 1458}, {10, 1460}, {10, 1462}, {10, 1464}, {10, 1466}, {10, 1468}, + {10, 1470}, {10, 1472}, {10, 1474}, {10, 1476}, {10, 1478}, {10, 1480}, + {10, 1482}, {10, 1484}, {10, 1486}, {10, 1488}, {10, 1490}, {10, 1492}, + {10, 1494}, {10, 1496}, {10, 1498}, {10, 1500}, {10, 1502}, {10, 1504}, + {10, 1506}, {10, 1508}, {10, 1510}, {10, 1512}, {10, 1514}, {10, 1516}, + {10, 1518}, {10, 1520}, {10, 1522}, {10, 1524}, {10, 1526}, {10, 1528}, + {10, 1530}, {10, 1532}, {10, 1534}, {10, 1536}, {10, 1538}, {10, 1540}, + {10, 1542}, {10, 1544}, {10, 1546}, {10, 1548}, {10, 1550}, {10, 1552}, + {10, 1554}, {10, 1556}, {10, 1558}, {10, 1560}, {10, 1562}, {10, 1564}, + {10, 1566}, {10, 1568}, {10, 1570}, {10, 1572}, {10, 1574}, {10, 1576}, + {10, 1578}, {10, 1580}, {10, 1582}, {10, 1584}, {10, 1586}, {10, 1588}, + {10, 1590}, {10, 1592}, {10, 1594}, {10, 1596}, {10, 1598}, {10, 1600}, + {10, 1602}, {10, 1604}, {10, 1606}, {10, 1608}, {10, 1610}, {10, 1612}, + {10, 1614}, {10, 1616}, {10, 1618}, {10, 1620}, {10, 1622}, {10, 1624}, + {10, 1626}, {10, 1628}, {10, 1630}, {10, 1632}, {10, 1634}, {10, 1636}, + {10, 1638}, {10, 1640}, {10, 1642}, {10, 1644}, {10, 1646}, {10, 1648}, + {10, 1650}, {10, 1652}, {10, 1654}, {10, 1656}, {10, 1658}, {10, 1660}, + {10, 1662}, {10, 1664}, {10, 1666}, {10, 1668}, {10, 1670}, {10, 1672}, + {10, 1674}, {10, 1676}, {10, 1678}, {10, 1680}, {10, 1682}, {10, 1684}, + {10, 1686}, {10, 1688}, {10, 1690}, {10, 1692}, {10, 1694}, {10, 1696}, + {10, 1698}, {10, 1700}, {10, 1702}, {10, 1704}, {10, 1706}, {10, 1708}, + {10, 1710}, {10, 1712}, {10, 1714}, {10, 1716}, {10, 1718}, {10, 1720}, + {10, 1722}, {10, 1724}, {10, 1726}, {10, 1728}, {10, 1730}, {10, 1732}, + {10, 1734}, {10, 1736}, {10, 1738}, {10, 1740}, {10, 1742}, {10, 1744}, + {10, 1746}, {10, 1748}, {10, 1750}, {10, 1752}, {10, 1754}, {10, 1756}, + {10, 1758}, {10, 1760}, {10, 1762}, {10, 1764}, {10, 1766}, {10, 1768}, + {10, 1770}, {10, 1772}, {10, 1774}, {10, 1776}, {10, 1778}, {10, 1780}, + {10, 1782}, {10, 1784}, {10, 1786}, {10, 1788}, {10, 1790}, {10, 1792}, + {10, 1794}, {10, 1796}, {10, 1798}, {10, 1800}, {10, 1802}, {10, 1804}, + {10, 1806}, {10, 1808}, {10, 1810}, {10, 1812}, {10, 1814}, {10, 1816}, + {10, 1818}, {10, 1820}, {10, 1822}, {10, 1824}, {10, 1826}, {10, 1828}, + {10, 1830}, {10, 1832}, {10, 1834}, {10, 1836}, {10, 1838}, {10, 1840}, + {10, 1842}, {10, 1844}, {10, 1846}, {10, 1848}, {10, 1850}, {10, 1852}, + {10, 1854}, {10, 1856}, {10, 1858}, {10, 1860}, {10, 1862}, {10, 1864}, + {10, 1866}, {10, 1868}, {10, 1870}, {10, 1872}, {10, 1874}, {10, 1876}, + {10, 1878}, {10, 1880}, {10, 1882}, {10, 1884}, {10, 1886}, {10, 1888}, + {10, 1890}, {10, 1892}, {10, 1894}, {10, 1896}, {10, 1898}, {10, 1900}, + {10, 1902}, {10, 1904}, {10, 1906}, {10, 1908}, {10, 1910}, {10, 1912}, + {10, 1914}, {10, 1916}, {10, 1918}, {10, 1920}, {10, 1922}, {10, 1924}, + {10, 1926}, {10, 1928}, {10, 1930}, {10, 1932}, {10, 1934}, {10, 1936}, + {10, 1938}, {10, 1940}, {10, 1942}, {10, 1944}, {10, 1946}, {10, 1948}, + {10, 1950}, {10, 1952}, {10, 1954}, {10, 1956}, {10, 1958}, {10, 1960}, + {10, 1962}, {10, 1964}, {10, 1966}, {10, 1968}, {10, 1970}, {10, 1972}, + {10, 1974}, {10, 1976}, {10, 1978}, {10, 1980}, {10, 1982}, {10, 1984}, + {10, 1986}, {10, 1988}, {10, 1990}, {10, 1992}, {10, 1994}, {10, 1996}, + {10, 1998}, {10, 2000}, {10, 2002}, {10, 2004}, {10, 2006}, {10, 2008}, + {10, 2010}, {10, 2012}, {10, 2014}, {10, 2016}, {10, 2018}, {10, 2020}, + {10, 2022}, {10, 2024}, {10, 2026}, {10, 2028}, {10, 2030}, {10, 2032}, + {10, 2034}, {10, 2036}, {10, 2038}, {10, 2040}, {10, 2042}, {10, 2044}, + {10, 2046}, {10, 2048}, {10, 2050}, {10, 2052}, {10, 2054}, {10, 2056}, + {10, 2058}, {10, 2060}, {10, 2062}, {10, 2064}, {10, 2066}, {10, 2068}, + {10, 2070}, {10, 2072}, {10, 2074}, {10, 2076}, {10, 2078}, {10, 2080}, + {10, 2082}, {10, 2084}, {10, 2086}, {10, 2088}, {10, 2090}, {10, 2092}, + {10, 2094}, {10, 2096}, {10, 2098}, {10, 2100}, {10, 2102}, {10, 2104}, + {10, 2106}, {10, 2108}, {10, 2110}, {10, 2112}, {10, 2114}, {10, 2116}, + {10, 2118}, {10, 2120}, {10, 2122}, {10, 2124}, {10, 2126}, {10, 2128}, + {10, 2130}, {10, 2132}, {10, 2134}, {10, 2136}, {10, 2138}, {10, 2140}, + {10, 2142}, {10, 2144}, {10, 2146}, {10, 2148}, {10, 2150}, {10, 2152}, + {10, 2154}, {10, 2156}, {10, 2158}, {10, 2160}, {10, 2162}, {10, 2164}, + {10, 2166}, {10, 2168}, {10, 2170}, {10, 2172}, {10, 2174}, {10, 2176}, + {10, 2178}, {10, 2180}, {10, 2182}, {10, 2184}, {10, 2186}, {10, 2188}, + {10, 2190}, {10, 2192}, {10, 2194}, {10, 2196}, {10, 2198}, {10, 2200}, + {10, 2202}, {10, 2204}, {10, 2206}, {10, 2208}, {10, 2210}, {10, 2212}, + {10, 2214}, {10, 2216}, {10, 2218}, {10, 2220}, {10, 2222}, {10, 2224}, + {10, 2226}, {10, 2228}, {10, 2230}, {10, 2232}, {10, 2234}, {10, 2236}, + {10, 2238}, {10, 2240}, {10, 2242}, {10, 2244}, {10, 2246}, {10, 2248}, + {10, 2250}, {10, 2252}, {10, 2254}, {10, 2256}, {10, 2258}, {10, 2260}, + {10, 2262}, {10, 2264}, {10, 2266}, {10, 2268}, {10, 2270}, {10, 2272}, + {10, 2274}, {10, 2276}, {10, 2278}, {10, 2280}, {10, 2282}, {10, 2284}, + {10, 2286}, {10, 2288}, {10, 2290}, {10, 2292}, {10, 2294}, {10, 2296}, + {10, 2298}, {10, 2300}, {10, 2302}, {10, 2304}, {10, 2306}, {10, 2308}, + {10, 2310}, {10, 2312}, {10, 2314}, {10, 2316}, {10, 2318}, {10, 2320}, + {10, 2322}, {10, 2324}, {10, 2326}, {10, 2328}, {10, 2330}, {10, 2332}, + {10, 2334}, {10, 2336}, {10, 2338}, {10, 2340}, {10, 2342}, {10, 2344}, + {10, 2346}, {10, 2348}, {10, 2350}, {10, 2352}, {10, 2354}, {10, 2356}, + {10, 2358}, {10, 2360}, {10, 2362}, {10, 2364}, {10, 2366}, {10, 2368}, + {10, 2370}, {10, 2372}, {10, 2374}, {10, 2376}, {10, 2378}, {10, 2380}, + {10, 2382}, {10, 2384}, {10, 2386}, {10, 2388}, {10, 2390}, {10, 2392}, + {10, 2394}, {10, 2396}, {10, 2398}, {10, 2400}, {10, 2402}, {10, 2404}, + {10, 2406}, {10, 2408}, {10, 2410}, {10, 2412}, {10, 2414}, {10, 2416}, + {10, 2418}, {10, 2420}, {10, 2422}, {10, 2424}, {10, 2426}, {10, 2428}, + {10, 2430}, {10, 2432}, {10, 2434}, {10, 2436}, {10, 2438}, {10, 2440}, + {10, 2442}, {10, 2444}, {10, 2446}, {10, 2448}, {10, 2450}, {10, 2452}, + {10, 2454}, {10, 2456}, {10, 2458}, {10, 2460}, {10, 2462}, {10, 2464}, + {10, 2466}, {10, 2468}, {10, 2470}, {10, 2472}, {10, 2474}, {10, 2476}, + {10, 2478}, {10, 2480}, {10, 2482}, {10, 2484}, {10, 2486}, {10, 2488}, + {10, 2490}, {10, 2492}, {10, 2494}, {10, 2496}, {10, 2498}, {10, 2500}, + {10, 2502}, {10, 2504}, {10, 2506}, {10, 2508}, {10, 2510}, {10, 2512}, + {10, 2514}, {10, 2516}, {10, 2518}, {10, 2520}, {10, 2522}, {10, 2524}, + {10, 2526}, {10, 2528}, {10, 2530}, {10, 2532}, {10, 2534}, {10, 2536}, + {10, 2538}, {10, 2540}, {10, 2542}, {10, 2544}, {10, 2546}, {10, 2548}, + {10, 2550}, {10, 2552}, {10, 2554}, {10, 2556}, {10, 2558}, {10, 2560}, + {10, 2562}, {10, 2564}, {10, 2566}, {10, 2568}, {10, 2570}, {10, 2572}, + {10, 2574}, {10, 2576}, {10, 2578}, {10, 2580}, {10, 2582}, {10, 2584}, + {10, 2586}, {10, 2588}, {10, 2590}, {10, 2592}, {10, 2594}, {10, 2596}, + {10, 2598}, {10, 2600}, {10, 2602}, {10, 2604}, {10, 2606}, {10, 2608}, + {10, 2610}, {10, 2612}, {10, 2614}, {10, 2616}, {10, 2618}, {10, 2620}, + {10, 2622}, {10, 2624}, {10, 2626}, {10, 2628}, {10, 2630}, {10, 2632}, + {10, 2634}, {10, 2636}, {10, 2638}, {10, 2640}, {10, 2642}, {10, 2644}, + {10, 2646}, {10, 2648}, {10, 2650}, {10, 2652}, {10, 2654}, {10, 2656}, + {10, 2658}, {10, 2660}, {10, 2662}, {10, 2664}, {10, 2666}, {10, 2668}, + {10, 2670}, {10, 2672}, {10, 2674}, {10, 2676}, {10, 2678}, {10, 2680}, + {10, 2682}, {10, 2684}, {10, 2686}, {10, 2688}, {10, 2690}, {10, 2692}, + {10, 2694}, {10, 2696}, {10, 2698}, {10, 2700}, {10, 2702}, {10, 2704}, + {10, 2706}, {10, 2708}, {10, 2710}, {10, 2712}, {10, 2714}, {10, 2716}, + {10, 2718}, {10, 2720}, {10, 2722}, {10, 2724}, {10, 2726}, {10, 2728}, + {10, 2730}, {10, 2732}, {10, 2734}, {10, 2736}, {10, 2738}, {10, 2740}, + {10, 2742}, {10, 2744}, {10, 2746}, {10, 2748}, {10, 2750}, {10, 2752}, + {10, 2754}, {10, 2756}, {10, 2758}, {10, 2760}, {10, 2762}, {10, 2764}, + {10, 2766}, {10, 2768}, {10, 2770}, {10, 2772}, {10, 2774}, {10, 2776}, + {10, 2778}, {10, 2780}, {10, 2782}, {10, 2784}, {10, 2786}, {10, 2788}, + {10, 2790}, {10, 2792}, {10, 2794}, {10, 2796}, {10, 2798}, {10, 2800}, + {10, 2802}, {10, 2804}, {10, 2806}, {10, 2808}, {10, 2810}, {10, 2812}, + {10, 2814}, {10, 2816}, {10, 2818}, {10, 2820}, {10, 2822}, {10, 2824}, + {10, 2826}, {10, 2828}, {10, 2830}, {10, 2832}, {10, 2834}, {10, 2836}, + {10, 2838}, {10, 2840}, {10, 2842}, {10, 2844}, {10, 2846}, {10, 2848}, + {10, 2850}, {10, 2852}, {10, 2854}, {10, 2856}, {10, 2858}, {10, 2860}, + {10, 2862}, {10, 2864}, {10, 2866}, {10, 2868}, {10, 2870}, {10, 2872}, + {10, 2874}, {10, 2876}, {10, 2878}, {10, 2880}, {10, 2882}, {10, 2884}, + {10, 2886}, {10, 2888}, {10, 2890}, {10, 2892}, {10, 2894}, {10, 2896}, + {10, 2898}, {10, 2900}, {10, 2902}, {10, 2904}, {10, 2906}, {10, 2908}, + {10, 2910}, {10, 2912}, {10, 2914}, {10, 2916}, {10, 2918}, {10, 2920}, + {10, 2922}, {10, 2924}, {10, 2926}, {10, 2928}, {10, 2930}, {10, 2932}, + {10, 2934}, {10, 2936}, {10, 2938}, {10, 2940}, {10, 2942}, {10, 2944}, + {10, 2946}, {10, 2948}, {10, 2950}, {10, 2952}, {10, 2954}, {10, 2956}, + {10, 2958}, {10, 2960}, {10, 2962}, {10, 2964}, {10, 2966}, {10, 2968}, + {10, 2970}, {10, 2972}, {10, 2974}, {10, 2976}, {10, 2978}, {10, 2980}, + {10, 2982}, {10, 2984}, {10, 2986}, {10, 2988}, {10, 2990}, {10, 2992}, + {10, 2994}, {10, 2996}, {10, 2998}, {10, 3000}, {10, 3002}, {10, 3004}, + {10, 3006}, {10, 3008}, {10, 3010}, {10, 3012}, {10, 3014}, {10, 3016}, + {10, 3018}, {10, 3020}, {10, 3022}, {10, 3024}, {10, 3026}, {10, 3028}, + {10, 3030}, {10, 3032}, {10, 3034}, {10, 3036}, {10, 3038}, {10, 3040}, + {10, 3042}, {10, 3044}, {10, 3046}, {10, 3048}, {10, 3050}, {10, 3052}, + {10, 3054}, {10, 3056}, {10, 3058}, {10, 3060}, {10, 3062}, {10, 3064}, + {10, 3066}, {10, 3068}, {10, 3070}, {10, 3072}, {10, 3074}, {10, 3076}, + {10, 3078}, {10, 3080}, {10, 3082}, {10, 3084}, {10, 3086}, {10, 3088}, + {10, 3090}, {10, 3092}, {10, 3094}, {10, 3096}, {10, 3098}, {10, 3100}, + {10, 3102}, {10, 3104}, {10, 3106}, {10, 3108}, {10, 3110}, {10, 3112}, + {10, 3114}, {10, 3116}, {10, 3118}, {10, 3120}, {10, 3122}, {10, 3124}, + {10, 3126}, {10, 3128}, {10, 3130}, {10, 3132}, {10, 3134}, {10, 3136}, + {10, 3138}, {10, 3140}, {10, 3142}, {10, 3144}, {10, 3146}, {10, 3148}, + {10, 3150}, {10, 3152}, {10, 3154}, {10, 3156}, {10, 3158}, {10, 3160}, + {10, 3162}, {10, 3164}, {10, 3166}, {10, 3168}, {10, 3170}, {10, 3172}, + {10, 3174}, {10, 3176}, {10, 3178}, {10, 3180}, {10, 3182}, {10, 3184}, + {10, 3186}, {10, 3188}, {10, 3190}, {10, 3192}, {10, 3194}, {10, 3196}, + {10, 3198}, {10, 3200}, {10, 3202}, {10, 3204}, {10, 3206}, {10, 3208}, + {10, 3210}, {10, 3212}, {10, 3214}, {10, 3216}, {10, 3218}, {10, 3220}, + {10, 3222}, {10, 3224}, {10, 3226}, {10, 3228}, {10, 3230}, {10, 3232}, + {10, 3234}, {10, 3236}, {10, 3238}, {10, 3240}, {10, 3242}, {10, 3244}, + {10, 3246}, {10, 3248}, {10, 3250}, {10, 3252}, {10, 3254}, {10, 3256}, + {10, 3258}, {10, 3260}, {10, 3262}, {10, 3264}, {10, 3266}, {10, 3268}, + {10, 3270}, {10, 3272}, {10, 3274}, {10, 3276}, {10, 3278}, {10, 3280}, + {10, 3282}, {10, 3284}, {10, 3286}, {10, 3288}, {10, 3290}, {10, 3292}, + {10, 3294}, {10, 3296}, {10, 3298}, {10, 3300}, {10, 3302}, {10, 3304}, + {10, 3306}, {10, 3308}, {10, 3310}, {10, 3312}, {10, 3314}, {10, 3316}, + {10, 3318}, {10, 3320}, {10, 3322}, {10, 3324}, {10, 3326}, {10, 3328}, + {10, 3330}, {10, 3332}, {10, 3334}, {10, 3336}, {10, 3338}, {10, 3340}, + {10, 3342}, {10, 3344}, {10, 3346}, {10, 3348}, {10, 3350}, {10, 3352}, + {10, 3354}, {10, 3356}, {10, 3358}, {10, 3360}, {10, 3362}, {10, 3364}, + {10, 3366}, {10, 3368}, {10, 3370}, {10, 3372}, {10, 3374}, {10, 3376}, + {10, 3378}, {10, 3380}, {10, 3382}, {10, 3384}, {10, 3386}, {10, 3388}, + {10, 3390}, {10, 3392}, {10, 3394}, {10, 3396}, {10, 3398}, {10, 3400}, + {10, 3402}, {10, 3404}, {10, 3406}, {10, 3408}, {10, 3410}, {10, 3412}, + {10, 3414}, {10, 3416}, {10, 3418}, {10, 3420}, {10, 3422}, {10, 3424}, + {10, 3426}, {10, 3428}, {10, 3430}, {10, 3432}, {10, 3434}, {10, 3436}, + {10, 3438}, {10, 3440}, {10, 3442}, {10, 3444}, {10, 3446}, {10, 3448}, + {10, 3450}, {10, 3452}, {10, 3454}, {10, 3456}, {10, 3458}, {10, 3460}, + {10, 3462}, {10, 3464}, {10, 3466}, {10, 3468}, {10, 3470}, {10, 3472}, + {10, 3474}, {10, 3476}, {10, 3478}, {10, 3480}, {10, 3482}, {10, 3484}, + {10, 3486}, {10, 3488}, {10, 3490}, {10, 3492}, {10, 3494}, {10, 3496}, + {10, 3498}, {10, 3500}, {10, 3502}, {10, 3504}, {10, 3506}, {10, 3508}, + {10, 3510}, {10, 3512}, {10, 3514}, {10, 3516}, {10, 3518}, {10, 3520}, + {10, 3522}, {10, 3524}, {10, 3526}, {10, 3528}, {10, 3530}, {10, 3532}, + {10, 3534}, {10, 3536}, {10, 3538}, {10, 3540}, {10, 3542}, {10, 3544}, + {10, 3546}, {10, 3548}, {10, 3550}, {10, 3552}, {10, 3554}, {10, 3556}, + {10, 3558}, {10, 3560}, {10, 3562}, {10, 3564}, {10, 3566}, {10, 3568}, + {10, 3570}, {10, 3572}, {10, 3574}, {10, 3576}, {10, 3578}, {10, 3580}, + {10, 3582}, {10, 3584}, {10, 3586}, {10, 3588}, {10, 3590}, {10, 3592}, + {10, 3594}, {10, 3596}, {10, 3598}, {10, 3600}, {10, 3602}, {10, 3604}, + {10, 3606}, {10, 3608}, {10, 3610}, {10, 3612}, {10, 3614}, {10, 3616}, + {10, 3618}, {10, 3620}, {10, 3622}, {10, 3624}, {10, 3626}, {10, 3628}, + {10, 3630}, {10, 3632}, {10, 3634}, {10, 3636}, {10, 3638}, {10, 3640}, + {10, 3642}, {10, 3644}, {10, 3646}, {10, 3648}, {10, 3650}, {10, 3652}, + {10, 3654}, {10, 3656}, {10, 3658}, {10, 3660}, {10, 3662}, {10, 3664}, + {10, 3666}, {10, 3668}, {10, 3670}, {10, 3672}, {10, 3674}, {10, 3676}, + {10, 3678}, {10, 3680}, {10, 3682}, {10, 3684}, {10, 3686}, {10, 3688}, + {10, 3690}, {10, 3692}, {10, 3694}, {10, 3696}, {10, 3698}, {10, 3700}, + {10, 3702}, {10, 3704}, {10, 3706}, {10, 3708}, {10, 3710}, {10, 3712}, + {10, 3714}, {10, 3716}, {10, 3718}, {10, 3720}, {10, 3722}, {10, 3724}, + {10, 3726}, {10, 3728}, {10, 3730}, {10, 3732}, {10, 3734}, {10, 3736}, + {10, 3738}, {10, 3740}, {10, 3742}, {10, 3744}, {10, 3746}, {10, 3748}, + {10, 3750}, {10, 3752}, {10, 3754}, {10, 3756}, {10, 3758}, {10, 3760}, + {10, 3762}, {10, 3764}, {10, 3766}, {10, 3768}, {10, 3770}, {10, 3772}, + {10, 3774}, {10, 3776}, {10, 3778}, {10, 3780}, {10, 3782}, {10, 3784}, + {10, 3786}, {10, 3788}, {10, 3790}, {10, 3792}, {10, 3794}, {10, 3796}, + {10, 3798}, {10, 3800}, {10, 3802}, {10, 3804}, {10, 3806}, {10, 3808}, + {10, 3810}, {10, 3812}, {10, 3814}, {10, 3816}, {10, 3818}, {10, 3820}, + {10, 3822}, {10, 3824}, {10, 3826}, {10, 3828}, {10, 3830}, {10, 3832}, + {10, 3834}, {10, 3836}, {10, 3838}, {10, 3840}, {10, 3842}, {10, 3844}, + {10, 3846}, {10, 3848}, {10, 3850}, {10, 3852}, {10, 3854}, {10, 3856}, + {10, 3858}, {10, 3860}, {10, 3862}, {10, 3864}, {10, 3866}, {10, 3868}, + {10, 3870}, {10, 3872}, {10, 3874}, {10, 3876}, {10, 3878}, {10, 3880}, + {10, 3882}, {10, 3884}, {10, 3886}, {10, 3888}, {10, 3890}, {10, 3892}, + {10, 3894}, {10, 3896}, {10, 3898}, {10, 3900}, {10, 3902}, {10, 3904}, + {10, 3906}, {10, 3908}, {10, 3910}, {10, 3912}, {10, 3914}, {10, 3916}, + {10, 3918}, {10, 3920}, {10, 3922}, {10, 3924}, {10, 3926}, {10, 3928}, + {10, 3930}, {10, 3932}, {10, 3934}, {10, 3936}, {10, 3938}, {10, 3940}, + {10, 3942}, {10, 3944}, {10, 3946}, {10, 3948}, {10, 3950}, {10, 3952}, + {10, 3954}, {10, 3956}, {10, 3958}, {10, 3960} +}; diff --git a/vp8/encoder/defaultcoefcounts.h b/vp8/encoder/defaultcoefcounts.h new file mode 100644 index 0000000..2c0f3dd --- /dev/null +++ b/vp8/encoder/defaultcoefcounts.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* Generated file, included by entropy.c */ + +static const unsigned int default_coef_counts[BLOCK_TYPES] + [COEF_BANDS] + [PREV_COEF_CONTEXTS] + [MAX_ENTROPY_TOKENS] = +{ + + { + /* Block Type ( 0 ) */ + { + /* Coeff Band ( 0 ) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + { + /* Coeff Band ( 1 ) */ + {30190, 26544, 225, 24, 4, 0, 0, 0, 0, 0, 0, 4171593,}, + {26846, 25157, 1241, 130, 26, 6, 1, 0, 0, 0, 0, 149987,}, + {10484, 9538, 1006, 160, 36, 18, 0, 0, 0, 0, 0, 15104,}, + }, + { + /* Coeff Band ( 2 ) */ + {25842, 40456, 1126, 83, 11, 2, 0, 0, 0, 0, 0, 0,}, + {9338, 8010, 512, 73, 7, 3, 2, 0, 0, 0, 0, 43294,}, + {1047, 751, 149, 31, 13, 6, 1, 0, 0, 0, 0, 879,}, + }, + { + /* Coeff Band ( 3 ) */ + {26136, 9826, 252, 13, 0, 0, 0, 0, 0, 0, 0, 0,}, + {8134, 5574, 191, 14, 2, 0, 0, 0, 0, 0, 0, 35302,}, + { 605, 677, 116, 9, 1, 0, 0, 0, 0, 0, 0, 611,}, + }, + { + /* Coeff Band ( 4 ) */ + {10263, 15463, 283, 17, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2773, 2191, 128, 9, 2, 2, 0, 0, 0, 0, 0, 10073,}, + { 134, 125, 32, 4, 0, 2, 0, 0, 0, 0, 0, 50,}, + }, + { + /* Coeff Band ( 5 ) */ + {10483, 2663, 23, 1, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2137, 1251, 27, 1, 1, 0, 0, 0, 0, 0, 0, 14362,}, + { 116, 156, 14, 2, 1, 0, 0, 0, 0, 0, 0, 190,}, + }, + { + /* Coeff Band ( 6 ) */ + {40977, 27614, 412, 28, 0, 0, 0, 0, 0, 0, 0, 0,}, + {6113, 5213, 261, 22, 3, 0, 0, 0, 0, 0, 0, 26164,}, + { 382, 312, 50, 14, 2, 0, 0, 0, 0, 0, 0, 345,}, + }, + { + /* Coeff Band ( 7 ) */ + { 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,}, + }, + }, + { + /* Block Type ( 1 ) */ + { + /* Coeff Band ( 0 ) */ + {3268, 19382, 1043, 250, 93, 82, 49, 26, 17, 8, 25, 82289,}, + {8758, 32110, 5436, 1832, 827, 668, 420, 153, 24, 0, 3, 52914,}, + {9337, 23725, 8487, 3954, 2107, 1836, 1069, 399, 59, 0, 0, 18620,}, + }, + { + /* Coeff Band ( 1 ) */ + {12419, 8420, 452, 62, 9, 1, 0, 0, 0, 0, 0, 0,}, + {11715, 8705, 693, 92, 15, 7, 2, 0, 0, 0, 0, 53988,}, + {7603, 8585, 2306, 778, 270, 145, 39, 5, 0, 0, 0, 9136,}, + }, + { + /* Coeff Band ( 2 ) */ + {15938, 14335, 1207, 184, 55, 13, 4, 1, 0, 0, 0, 0,}, + {7415, 6829, 1138, 244, 71, 26, 7, 0, 0, 0, 0, 9980,}, + {1580, 1824, 655, 241, 89, 46, 10, 2, 0, 0, 0, 429,}, + }, + { + /* Coeff Band ( 3 ) */ + {19453, 5260, 201, 19, 0, 0, 0, 0, 0, 0, 0, 0,}, + {9173, 3758, 213, 22, 1, 1, 0, 0, 0, 0, 0, 9820,}, + {1689, 1277, 276, 51, 17, 4, 0, 0, 0, 0, 0, 679,}, + }, + { + /* Coeff Band ( 4 ) */ + {12076, 10667, 620, 85, 19, 9, 5, 0, 0, 0, 0, 0,}, + {4665, 3625, 423, 55, 19, 9, 0, 0, 0, 0, 0, 5127,}, + { 415, 440, 143, 34, 20, 7, 2, 0, 0, 0, 0, 101,}, + }, + { + /* Coeff Band ( 5 ) */ + {12183, 4846, 115, 11, 1, 0, 0, 0, 0, 0, 0, 0,}, + {4226, 3149, 177, 21, 2, 0, 0, 0, 0, 0, 0, 7157,}, + { 375, 621, 189, 51, 11, 4, 1, 0, 0, 0, 0, 198,}, + }, + { + /* Coeff Band ( 6 ) */ + {61658, 37743, 1203, 94, 10, 3, 0, 0, 0, 0, 0, 0,}, + {15514, 11563, 903, 111, 14, 5, 0, 0, 0, 0, 0, 25195,}, + { 929, 1077, 291, 78, 14, 7, 1, 0, 0, 0, 0, 507,}, + }, + { + /* Coeff Band ( 7 ) */ + { 0, 990, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 412, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1641,}, + { 0, 18, 7, 1, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + }, + { + /* Block Type ( 2 ) */ + { + /* Coeff Band ( 0 ) */ + { 953, 24519, 628, 120, 28, 12, 4, 0, 0, 0, 0, 2248798,}, + {1525, 25654, 2647, 617, 239, 143, 42, 5, 0, 0, 0, 66837,}, + {1180, 11011, 3001, 1237, 532, 448, 239, 54, 5, 0, 0, 7122,}, + }, + { + /* Coeff Band ( 1 ) */ + {1356, 2220, 67, 10, 4, 1, 0, 0, 0, 0, 0, 0,}, + {1450, 2544, 102, 18, 4, 3, 0, 0, 0, 0, 0, 57063,}, + {1182, 2110, 470, 130, 41, 21, 0, 0, 0, 0, 0, 6047,}, + }, + { + /* Coeff Band ( 2 ) */ + { 370, 3378, 200, 30, 5, 4, 1, 0, 0, 0, 0, 0,}, + { 293, 1006, 131, 29, 11, 0, 0, 0, 0, 0, 0, 5404,}, + { 114, 387, 98, 23, 4, 8, 1, 0, 0, 0, 0, 236,}, + }, + { + /* Coeff Band ( 3 ) */ + { 579, 194, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 395, 213, 5, 1, 0, 0, 0, 0, 0, 0, 0, 4157,}, + { 119, 122, 4, 0, 0, 0, 0, 0, 0, 0, 0, 300,}, + }, + { + /* Coeff Band ( 4 ) */ + { 38, 557, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 21, 114, 12, 1, 0, 0, 0, 0, 0, 0, 0, 427,}, + { 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,}, + }, + { + /* Coeff Band ( 5 ) */ + { 52, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 652,}, + { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + { + /* Coeff Band ( 6 ) */ + { 640, 569, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 25, 77, 2, 0, 0, 0, 0, 0, 0, 0, 0, 517,}, + { 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,}, + }, + { + /* Coeff Band ( 7 ) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + }, + { + /* Block Type ( 3 ) */ + { + /* Coeff Band ( 0 ) */ + {2506, 20161, 2707, 767, 261, 178, 107, 30, 14, 3, 0, 100694,}, + {8806, 36478, 8817, 3268, 1280, 850, 401, 114, 42, 0, 0, 58572,}, + {11003, 27214, 11798, 5716, 2482, 2072, 1048, 175, 32, 0, 0, 19284,}, + }, + { + /* Coeff Band ( 1 ) */ + {9738, 11313, 959, 205, 70, 18, 11, 1, 0, 0, 0, 0,}, + {12628, 15085, 1507, 273, 52, 19, 9, 0, 0, 0, 0, 54280,}, + {10701, 15846, 5561, 1926, 813, 570, 249, 36, 0, 0, 0, 6460,}, + }, + { + /* Coeff Band ( 2 ) */ + {6781, 22539, 2784, 634, 182, 123, 20, 4, 0, 0, 0, 0,}, + {6263, 11544, 2649, 790, 259, 168, 27, 5, 0, 0, 0, 20539,}, + {3109, 4075, 2031, 896, 457, 386, 158, 29, 0, 0, 0, 1138,}, + }, + { + /* Coeff Band ( 3 ) */ + {11515, 4079, 465, 73, 5, 14, 2, 0, 0, 0, 0, 0,}, + {9361, 5834, 650, 96, 24, 8, 4, 0, 0, 0, 0, 22181,}, + {4343, 3974, 1360, 415, 132, 96, 14, 1, 0, 0, 0, 1267,}, + }, + { + /* Coeff Band ( 4 ) */ + {4787, 9297, 823, 168, 44, 12, 4, 0, 0, 0, 0, 0,}, + {3619, 4472, 719, 198, 60, 31, 3, 0, 0, 0, 0, 8401,}, + {1157, 1175, 483, 182, 88, 31, 8, 0, 0, 0, 0, 268,}, + }, + { + /* Coeff Band ( 5 ) */ + {8299, 1226, 32, 5, 1, 0, 0, 0, 0, 0, 0, 0,}, + {3502, 1568, 57, 4, 1, 1, 0, 0, 0, 0, 0, 9811,}, + {1055, 1070, 166, 29, 6, 1, 0, 0, 0, 0, 0, 527,}, + }, + { + /* Coeff Band ( 6 ) */ + {27414, 27927, 1989, 347, 69, 26, 0, 0, 0, 0, 0, 0,}, + {5876, 10074, 1574, 341, 91, 24, 4, 0, 0, 0, 0, 21954,}, + {1571, 2171, 778, 324, 124, 65, 16, 0, 0, 0, 0, 979,}, + }, + { + /* Coeff Band ( 7 ) */ + { 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459,}, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,}, + }, + }, +}; diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c new file mode 100644 index 0000000..09ed9dd --- /dev/null +++ b/vp8/encoder/denoising.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "denoising.h" + +#include "vp8/common/reconinter.h" +#include "vpx/vpx_integer.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_rtcd.h" + +static const unsigned int NOISE_MOTION_THRESHOLD = 20*20; +static const unsigned int NOISE_DIFF2_THRESHOLD = 75; +// SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming var(noise) ~= 100. +static const unsigned int SSE_DIFF_THRESHOLD = 16*16*20; +static const unsigned int SSE_THRESHOLD = 16*16*40; + +static uint8_t blend(uint8_t state, uint8_t sample, uint8_t factor_q8) +{ + return (uint8_t)( + (((uint16_t)factor_q8 * ((uint16_t)state) + // Q8 + (uint16_t)(256 - factor_q8) * ((uint16_t)sample)) + 128) // Q8 + >> 8); +} + +static unsigned int denoiser_motion_compensate(YV12_BUFFER_CONFIG* src, + YV12_BUFFER_CONFIG* dst, + MACROBLOCK* x, + unsigned int best_sse, + unsigned int zero_mv_sse, + int recon_yoffset, + int recon_uvoffset) +{ + MACROBLOCKD filter_xd = x->e_mbd; + int mv_col; + int mv_row; + int sse_diff = zero_mv_sse - best_sse; + // Compensate the running average. + filter_xd.pre.y_buffer = src->y_buffer + recon_yoffset; + filter_xd.pre.u_buffer = src->u_buffer + recon_uvoffset; + filter_xd.pre.v_buffer = src->v_buffer + recon_uvoffset; + // Write the compensated running average to the destination buffer. + filter_xd.dst.y_buffer = dst->y_buffer + recon_yoffset; + filter_xd.dst.u_buffer = dst->u_buffer + recon_uvoffset; + filter_xd.dst.v_buffer = dst->v_buffer + recon_uvoffset; + // Use the best MV for the compensation. + filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME; + filter_xd.mode_info_context->mbmi.mode = filter_xd.best_sse_inter_mode; + filter_xd.mode_info_context->mbmi.mv = filter_xd.best_sse_mv; + filter_xd.mode_info_context->mbmi.need_to_clamp_mvs = + filter_xd.need_to_clamp_best_mvs; + mv_col = filter_xd.best_sse_mv.as_mv.col; + mv_row = filter_xd.best_sse_mv.as_mv.row; + if (filter_xd.mode_info_context->mbmi.mode <= B_PRED || + (mv_row*mv_row + mv_col*mv_col <= NOISE_MOTION_THRESHOLD && + sse_diff < SSE_DIFF_THRESHOLD)) + { + // Handle intra blocks as referring to last frame with zero motion and + // let the absolute pixel difference affect the filter factor. + // Also consider small amount of motion as being random walk due to noise, + // if it doesn't mean that we get a much bigger error. + // Note that any changes to the mode info only affects the denoising. + filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME; + filter_xd.mode_info_context->mbmi.mode = ZEROMV; + filter_xd.mode_info_context->mbmi.mv.as_int = 0; + x->e_mbd.best_sse_inter_mode = ZEROMV; + x->e_mbd.best_sse_mv.as_int = 0; + best_sse = zero_mv_sse; + } + if (!x->skip) + { + vp8_build_inter_predictors_mb(&filter_xd); + } + else + { + vp8_build_inter16x16_predictors_mb(&filter_xd, + filter_xd.dst.y_buffer, + filter_xd.dst.u_buffer, + filter_xd.dst.v_buffer, + filter_xd.dst.y_stride, + filter_xd.dst.uv_stride); + } + return best_sse; +} + +static void denoiser_filter(YV12_BUFFER_CONFIG* mc_running_avg, + YV12_BUFFER_CONFIG* running_avg, + MACROBLOCK* signal, + unsigned int motion_magnitude2, + int y_offset, + int uv_offset) +{ + unsigned char* sig = signal->thismb; + int sig_stride = 16; + unsigned char* mc_running_avg_y = mc_running_avg->y_buffer + y_offset; + int mc_avg_y_stride = mc_running_avg->y_stride; + unsigned char* running_avg_y = running_avg->y_buffer + y_offset; + int avg_y_stride = running_avg->y_stride; + int r, c; + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + int diff; + int absdiff = 0; + unsigned int filter_coefficient; + absdiff = sig[c] - mc_running_avg_y[c]; + absdiff = absdiff > 0 ? absdiff : -absdiff; + assert(absdiff >= 0 && absdiff < 256); + filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3)); + // Allow some additional filtering of static blocks, or blocks with very + // small motion vectors. + filter_coefficient += filter_coefficient / (3 + (motion_magnitude2 >> 3)); + filter_coefficient = filter_coefficient > 255 ? 255 : filter_coefficient; + + running_avg_y[c] = blend(mc_running_avg_y[c], sig[c], filter_coefficient); + diff = sig[c] - running_avg_y[c]; + + if (diff * diff < NOISE_DIFF2_THRESHOLD) + { + // Replace with mean to suppress the noise. + sig[c] = running_avg_y[c]; + } + else + { + // Replace the filter state with the signal since the change in this + // pixel isn't classified as noise. + running_avg_y[c] = sig[c]; + } + } + sig += sig_stride; + mc_running_avg_y += mc_avg_y_stride; + running_avg_y += avg_y_stride; + } +} + +int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height) +{ + assert(denoiser); + denoiser->yv12_running_avg.flags = 0; + if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg), width, + height, VP8BORDERINPIXELS) < 0) + { + vp8_denoiser_free(denoiser); + return 1; + } + denoiser->yv12_mc_running_avg.flags = 0; + if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width, + height, VP8BORDERINPIXELS) < 0) + { + vp8_denoiser_free(denoiser); + return 1; + } + vpx_memset(denoiser->yv12_running_avg.buffer_alloc, 0, + denoiser->yv12_running_avg.frame_size); + vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0, + denoiser->yv12_mc_running_avg.frame_size); + return 0; +} + +void vp8_denoiser_free(VP8_DENOISER *denoiser) +{ + assert(denoiser); + vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg); + vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg); +} + +void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, + MACROBLOCK *x, + unsigned int best_sse, + unsigned int zero_mv_sse, + int recon_yoffset, + int recon_uvoffset) { + int mv_row; + int mv_col; + unsigned int motion_magnitude2; + // Motion compensate the running average. + best_sse = denoiser_motion_compensate(&denoiser->yv12_running_avg, + &denoiser->yv12_mc_running_avg, + x, + best_sse, + zero_mv_sse, + recon_yoffset, + recon_uvoffset); + + mv_row = x->e_mbd.best_sse_mv.as_mv.row; + mv_col = x->e_mbd.best_sse_mv.as_mv.col; + motion_magnitude2 = mv_row*mv_row + mv_col*mv_col; + if (best_sse > SSE_THRESHOLD || + motion_magnitude2 > 8 * NOISE_MOTION_THRESHOLD) + { + // No filtering of this block since it differs too much from the predictor, + // or the motion vector magnitude is considered too big. + vp8_copy_mem16x16(x->thismb, 16, + denoiser->yv12_running_avg.y_buffer + recon_yoffset, + denoiser->yv12_running_avg.y_stride); + return; + } + // Filter. + denoiser_filter(&denoiser->yv12_mc_running_avg, + &denoiser->yv12_running_avg, + x, + motion_magnitude2, + recon_yoffset, + recon_uvoffset); +} diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h new file mode 100644 index 0000000..343531b --- /dev/null +++ b/vp8/encoder/denoising.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VP8_ENCODER_DENOISING_H_ +#define VP8_ENCODER_DENOISING_H_ + +#include "block.h" + +typedef struct vp8_denoiser +{ + YV12_BUFFER_CONFIG yv12_running_avg; + YV12_BUFFER_CONFIG yv12_mc_running_avg; +} VP8_DENOISER; + +int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height); + +void vp8_denoiser_free(VP8_DENOISER *denoiser); + +void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, + MACROBLOCK *x, + unsigned int best_sse, + unsigned int zero_mv_sse, + int recon_yoffset, + int recon_uvoffset); + +#endif // VP8_ENCODER_DENOISING_H_ diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c new file mode 100644 index 0000000..8233873 --- /dev/null +++ b/vp8/encoder/encodeframe.c @@ -0,0 +1,1352 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "encodemb.h" +#include "encodemv.h" +#include "vp8/common/common.h" +#include "onyx_int.h" +#include "vp8/common/extend.h" +#include "vp8/common/entropymode.h" +#include "vp8/common/quant_common.h" +#include "segmentation.h" +#include "vp8/common/setupintrarecon.h" +#include "encodeintra.h" +#include "vp8/common/reconinter.h" +#include "rdopt.h" +#include "pickinter.h" +#include "vp8/common/findnearmv.h" +#include +#include +#include "vp8/common/invtrans.h" +#include "vpx_ports/vpx_timer.h" +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING +#include "bitstream.h" +#endif +#include "encodeframe.h" + +extern void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; +extern void vp8_calc_ref_frame_costs(int *ref_frame_cost, + int prob_intra, + int prob_last, + int prob_garf + ); +extern void vp8_convert_rfct_to_prob(VP8_COMP *const cpi); +extern void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex); +extern void vp8_auto_select_speed(VP8_COMP *cpi); +extern void vp8cx_init_mbrthread_data(VP8_COMP *cpi, + MACROBLOCK *x, + MB_ROW_COMP *mbr_ei, + int mb_row, + int count); +static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x ); + +#ifdef MODE_STATS +unsigned int inter_y_modes[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int inter_uv_modes[4] = {0, 0, 0, 0}; +unsigned int inter_b_modes[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int y_modes[5] = {0, 0, 0, 0, 0}; +unsigned int uv_modes[4] = {0, 0, 0, 0}; +unsigned int b_modes[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#endif + + +/* activity_avg must be positive, or flat regions could get a zero weight + * (infinite lambda), which confounds analysis. + * This also avoids the need for divide by zero checks in + * vp8_activity_masking(). + */ +#define VP8_ACTIVITY_AVG_MIN (64) + +/* This is used as a reference when computing the source variance for the + * purposes of activity masking. + * Eventually this should be replaced by custom no-reference routines, + * which will be faster. + */ +static const unsigned char VP8_VAR_OFFS[16]= +{ + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 +}; + + +// Original activity measure from Tim T's code. +static unsigned int tt_activity_measure( VP8_COMP *cpi, MACROBLOCK *x ) +{ + unsigned int act; + unsigned int sse; + /* TODO: This could also be done over smaller areas (8x8), but that would + * require extensive changes elsewhere, as lambda is assumed to be fixed + * over an entire MB in most of the code. + * Another option is to compute four 8x8 variances, and pick a single + * lambda using a non-linear combination (e.g., the smallest, or second + * smallest, etc.). + */ + act = vp8_variance16x16(x->src.y_buffer, + x->src.y_stride, VP8_VAR_OFFS, 0, &sse); + act = act<<4; + + /* If the region is flat, lower the activity some more. */ + if (act < 8<<12) + act = act < 5<<12 ? act : 5<<12; + + return act; +} + +// Stub for alternative experimental activity measures. +static unsigned int alt_activity_measure( VP8_COMP *cpi, + MACROBLOCK *x, int use_dc_pred ) +{ + return vp8_encode_intra(cpi,x, use_dc_pred); +} + + +// Measure the activity of the current macroblock +// What we measure here is TBD so abstracted to this function +#define ALT_ACT_MEASURE 1 +static unsigned int mb_activity_measure( VP8_COMP *cpi, MACROBLOCK *x, + int mb_row, int mb_col) +{ + unsigned int mb_activity; + + if ( ALT_ACT_MEASURE ) + { + int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); + + // Or use and alternative. + mb_activity = alt_activity_measure( cpi, x, use_dc_pred ); + } + else + { + // Original activity measure from Tim T's code. + mb_activity = tt_activity_measure( cpi, x ); + } + + if ( mb_activity < VP8_ACTIVITY_AVG_MIN ) + mb_activity = VP8_ACTIVITY_AVG_MIN; + + return mb_activity; +} + +// Calculate an "average" mb activity value for the frame +#define ACT_MEDIAN 0 +static void calc_av_activity( VP8_COMP *cpi, int64_t activity_sum ) +{ +#if ACT_MEDIAN + // Find median: Simple n^2 algorithm for experimentation + { + unsigned int median; + unsigned int i,j; + unsigned int * sortlist; + unsigned int tmp; + + // Create a list to sort to + CHECK_MEM_ERROR(sortlist, + vpx_calloc(sizeof(unsigned int), + cpi->common.MBs)); + + // Copy map to sort list + vpx_memcpy( sortlist, cpi->mb_activity_map, + sizeof(unsigned int) * cpi->common.MBs ); + + + // Ripple each value down to its correct position + for ( i = 1; i < cpi->common.MBs; i ++ ) + { + for ( j = i; j > 0; j -- ) + { + if ( sortlist[j] < sortlist[j-1] ) + { + // Swap values + tmp = sortlist[j-1]; + sortlist[j-1] = sortlist[j]; + sortlist[j] = tmp; + } + else + break; + } + } + + // Even number MBs so estimate median as mean of two either side. + median = ( 1 + sortlist[cpi->common.MBs >> 1] + + sortlist[(cpi->common.MBs >> 1) + 1] ) >> 1; + + cpi->activity_avg = median; + + vpx_free(sortlist); + } +#else + // Simple mean for now + cpi->activity_avg = (unsigned int)(activity_sum/cpi->common.MBs); +#endif + + if (cpi->activity_avg < VP8_ACTIVITY_AVG_MIN) + cpi->activity_avg = VP8_ACTIVITY_AVG_MIN; + + // Experimental code: return fixed value normalized for several clips + if ( ALT_ACT_MEASURE ) + cpi->activity_avg = 100000; +} + +#define USE_ACT_INDEX 0 +#define OUTPUT_NORM_ACT_STATS 0 + +#if USE_ACT_INDEX +// Calculate and activity index for each mb +static void calc_activity_index( VP8_COMP *cpi, MACROBLOCK *x ) +{ + VP8_COMMON *const cm = & cpi->common; + int mb_row, mb_col; + + int64_t act; + int64_t a; + int64_t b; + +#if OUTPUT_NORM_ACT_STATS + FILE *f = fopen("norm_act.stt", "a"); + fprintf(f, "\n%12d\n", cpi->activity_avg ); +#endif + + // Reset pointers to start of activity map + x->mb_activity_ptr = cpi->mb_activity_map; + + // Calculate normalized mb activity number. + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + // Read activity from the map + act = *(x->mb_activity_ptr); + + // Calculate a normalized activity number + a = act + 4*cpi->activity_avg; + b = 4*act + cpi->activity_avg; + + if ( b >= a ) + *(x->activity_ptr) = (int)((b + (a>>1))/a) - 1; + else + *(x->activity_ptr) = 1 - (int)((a + (b>>1))/b); + +#if OUTPUT_NORM_ACT_STATS + fprintf(f, " %6d", *(x->mb_activity_ptr)); +#endif + // Increment activity map pointers + x->mb_activity_ptr++; + } + +#if OUTPUT_NORM_ACT_STATS + fprintf(f, "\n"); +#endif + + } + +#if OUTPUT_NORM_ACT_STATS + fclose(f); +#endif + +} +#endif + +// Loop through all MBs. Note activity of each, average activity and +// calculate a normalized activity for each +static void build_activity_map( VP8_COMP *cpi ) +{ + MACROBLOCK *const x = & cpi->mb; + MACROBLOCKD *xd = &x->e_mbd; + VP8_COMMON *const cm = & cpi->common; + +#if ALT_ACT_MEASURE + YV12_BUFFER_CONFIG *new_yv12 = &cm->yv12_fb[cm->new_fb_idx]; + int recon_yoffset; + int recon_y_stride = new_yv12->y_stride; +#endif + + int mb_row, mb_col; + unsigned int mb_activity; + int64_t activity_sum = 0; + + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { +#if ALT_ACT_MEASURE + // reset above block coeffs + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); +#endif + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { +#if ALT_ACT_MEASURE + xd->dst.y_buffer = new_yv12->y_buffer + recon_yoffset; + xd->left_available = (mb_col != 0); + recon_yoffset += 16; +#endif + //Copy current mb to a buffer + vp8_copy_mem16x16(x->src.y_buffer, x->src.y_stride, x->thismb, 16); + + // measure activity + mb_activity = mb_activity_measure( cpi, x, mb_row, mb_col ); + + // Keep frame sum + activity_sum += mb_activity; + + // Store MB level activity details. + *x->mb_activity_ptr = mb_activity; + + // Increment activity map pointer + x->mb_activity_ptr++; + + // adjust to the next column of source macroblocks + x->src.y_buffer += 16; + } + + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; + +#if ALT_ACT_MEASURE + //extend the recon for intra prediction + vp8_extend_mb_row(new_yv12, xd->dst.y_buffer + 16, + xd->dst.u_buffer + 8, xd->dst.v_buffer + 8); +#endif + + } + + // Calculate an "average" MB activity + calc_av_activity(cpi, activity_sum); + +#if USE_ACT_INDEX + // Calculate an activity index number of each mb + calc_activity_index( cpi, x ); +#endif + +} + +// Macroblock activity masking +void vp8_activity_masking(VP8_COMP *cpi, MACROBLOCK *x) +{ +#if USE_ACT_INDEX + x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2); + x->errorperbit = x->rdmult * 100 /(110 * x->rddiv); + x->errorperbit += (x->errorperbit==0); +#else + int64_t a; + int64_t b; + int64_t act = *(x->mb_activity_ptr); + + // Apply the masking to the RD multiplier. + a = act + (2*cpi->activity_avg); + b = (2*act) + cpi->activity_avg; + + x->rdmult = (unsigned int)(((int64_t)x->rdmult*b + (a>>1))/a); + x->errorperbit = x->rdmult * 100 /(110 * x->rddiv); + x->errorperbit += (x->errorperbit==0); +#endif + + // Activity based Zbin adjustment + adjust_act_zbin(cpi, x); +} + +static +void encode_mb_row(VP8_COMP *cpi, + VP8_COMMON *cm, + int mb_row, + MACROBLOCK *x, + MACROBLOCKD *xd, + TOKENEXTRA **tp, + int *segment_counts, + int *totalrate) +{ + int recon_yoffset, recon_uvoffset; + int mb_col; + int ref_fb_idx = cm->lst_fb_idx; + int dst_fb_idx = cm->new_fb_idx; + int recon_y_stride = cm->yv12_fb[ref_fb_idx].y_stride; + int recon_uv_stride = cm->yv12_fb[ref_fb_idx].uv_stride; + int map_index = (mb_row * cpi->common.mb_cols); + +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + const int num_part = (1 << cm->multi_token_partition); + TOKENEXTRA * tp_start = cpi->tok; + vp8_writer *w; +#endif + +#if CONFIG_MULTITHREAD + const int nsync = cpi->mt_sync_range; + const int rightmost_col = cm->mb_cols + nsync; + volatile const int *last_row_current_mb_col; + volatile int *current_mb_col = &cpi->mt_current_mb_col[mb_row]; + + if ((cpi->b_multi_threaded != 0) && (mb_row != 0)) + last_row_current_mb_col = &cpi->mt_current_mb_col[mb_row - 1]; + else + last_row_current_mb_col = &rightmost_col; +#endif + +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + if(num_part > 1) + w= &cpi->bc[1 + (mb_row % num_part)]; + else + w = &cpi->bc[1]; +#endif + + // reset above block coeffs + xd->above_context = cm->above_context; + + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); + recon_uvoffset = (mb_row * recon_uv_stride * 8); + + cpi->tplist[mb_row].start = *tp; + //printf("Main mb_row = %d\n", mb_row); + + // Distance of Mb to the top & bottom edges, specified in 1/8th pel + // units as they are always compared to values that are in 1/8th pel units + xd->mb_to_top_edge = -((mb_row * 16) << 3); + xd->mb_to_bottom_edge = ((cm->mb_rows - 1 - mb_row) * 16) << 3; + + // Set up limit values for vertical motion vector components + // to prevent them extending beyond the UMV borders + x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + + (VP8BORDERINPIXELS - 16); + + // Set the mb activity pointer to the start of the row. + x->mb_activity_ptr = &cpi->mb_activity_map[map_index]; + + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + *tp = cpi->tok; +#endif + // Distance of Mb to the left & right edges, specified in + // 1/8th pel units as they are always compared to values + // that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((cm->mb_cols - 1 - mb_col) * 16) << 3; + + // Set up limit values for horizontal motion vector components + // to prevent them extending beyond the UMV borders + x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + + (VP8BORDERINPIXELS - 16); + + xd->dst.y_buffer = cm->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset; + xd->dst.u_buffer = cm->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset; + xd->dst.v_buffer = cm->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset; + xd->left_available = (mb_col != 0); + + x->rddiv = cpi->RDDIV; + x->rdmult = cpi->RDMULT; + + //Copy current mb to a buffer + vp8_copy_mem16x16(x->src.y_buffer, x->src.y_stride, x->thismb, 16); + +#if CONFIG_MULTITHREAD + if (cpi->b_multi_threaded != 0) + { + *current_mb_col = mb_col - 1; // set previous MB done + + if ((mb_col & (nsync - 1)) == 0) + { + while (mb_col > (*last_row_current_mb_col - nsync)) + { + x86_pause_hint(); + thread_sleep(0); + } + } + } +#endif + + if(cpi->oxcf.tuning == VP8_TUNE_SSIM) + vp8_activity_masking(cpi, x); + + // Is segmentation enabled + // MB level adjustment to quantizer + if (xd->segmentation_enabled) + { + // Code to set segment id in xd->mbmi.segment_id for current MB (with range checking) + if (cpi->segmentation_map[map_index+mb_col] <= 3) + xd->mode_info_context->mbmi.segment_id = cpi->segmentation_map[map_index+mb_col]; + else + xd->mode_info_context->mbmi.segment_id = 0; + + vp8cx_mb_init_quantizer(cpi, x, 1); + } + else + xd->mode_info_context->mbmi.segment_id = 0; // Set to Segment 0 by default + + x->active_ptr = cpi->active_map + map_index + mb_col; + + if (cm->frame_type == KEY_FRAME) + { + *totalrate += vp8cx_encode_intra_macroblock(cpi, x, tp); +#ifdef MODE_STATS + y_modes[xd->mbmi.mode] ++; +#endif + } + else + { + *totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset, mb_row, mb_col); + +#ifdef MODE_STATS + inter_y_modes[xd->mbmi.mode] ++; + + if (xd->mbmi.mode == SPLITMV) + { + int b; + + for (b = 0; b < xd->mbmi.partition_count; b++) + { + inter_b_modes[x->partition->bmi[b].mode] ++; + } + } + +#endif + + // Count of last ref frame 0,0 usage + if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)) + cpi->inter_zz_count ++; + + // Special case code for cyclic refresh + // If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode + // during vp8cx_encode_inter_macroblock()) back into the global segmentation map + if ((cpi->current_layer == 0) && + (cpi->cyclic_refresh_mode_enabled && xd->segmentation_enabled)) + { + cpi->segmentation_map[map_index+mb_col] = xd->mode_info_context->mbmi.segment_id; + + // If the block has been refreshed mark it as clean (the magnitude of the -ve influences how long it will be before we consider another refresh): + // Else if it was coded (last frame 0,0) and has not already been refreshed then mark it as a candidate for cleanup next time (marked 0) + // else mark it as dirty (1). + if (xd->mode_info_context->mbmi.segment_id) + cpi->cyclic_refresh_map[map_index+mb_col] = -1; + else if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)) + { + if (cpi->cyclic_refresh_map[map_index+mb_col] == 1) + cpi->cyclic_refresh_map[map_index+mb_col] = 0; + } + else + cpi->cyclic_refresh_map[map_index+mb_col] = 1; + + } + } + + cpi->tplist[mb_row].stop = *tp; + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + /* pack tokens for this MB */ + { + int tok_count = *tp - tp_start; + pack_tokens(w, tp_start, tok_count); + } +#endif + // Increment pointer into gf usage flags structure. + x->gf_active_ptr++; + + // Increment the activity mask pointers. + x->mb_activity_ptr++; + + // adjust to the next column of macroblocks + x->src.y_buffer += 16; + x->src.u_buffer += 8; + x->src.v_buffer += 8; + + recon_yoffset += 16; + recon_uvoffset += 8; + + // Keep track of segment usage + segment_counts[xd->mode_info_context->mbmi.segment_id] ++; + + // skip to next mb + xd->mode_info_context++; + x->partition_info++; + xd->above_context++; + } + + //extend the recon for intra prediction + vp8_extend_mb_row( &cm->yv12_fb[dst_fb_idx], + xd->dst.y_buffer + 16, + xd->dst.u_buffer + 8, + xd->dst.v_buffer + 8); + +#if CONFIG_MULTITHREAD + if (cpi->b_multi_threaded != 0) + *current_mb_col = rightmost_col; +#endif + + // this is to account for the border + xd->mode_info_context++; + x->partition_info++; +} + +static void init_encode_frame_mb_context(VP8_COMP *cpi) +{ + MACROBLOCK *const x = & cpi->mb; + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + + // GF active flags data structure + x->gf_active_ptr = (signed char *)cpi->gf_active_flags; + + // Activity map pointer + x->mb_activity_ptr = cpi->mb_activity_map; + + x->act_zbin_adj = 0; + + x->partition_info = x->pi; + + xd->mode_info_context = cm->mi; + xd->mode_info_stride = cm->mode_info_stride; + + xd->frame_type = cm->frame_type; + + // reset intra mode contexts + if (cm->frame_type == KEY_FRAME) + vp8_init_mbmode_probs(cm); + + // Copy data over into macro block data structures. + x->src = * cpi->Source; + xd->pre = cm->yv12_fb[cm->lst_fb_idx]; + xd->dst = cm->yv12_fb[cm->new_fb_idx]; + + // set up frame for intra coded blocks + vp8_setup_intra_recon(&cm->yv12_fb[cm->new_fb_idx]); + + vp8_build_block_offsets(x); + + vp8_setup_block_dptrs(&x->e_mbd); + + vp8_setup_block_ptrs(x); + + xd->mode_info_context->mbmi.mode = DC_PRED; + xd->mode_info_context->mbmi.uv_mode = DC_PRED; + + xd->left_context = &cm->left_context; + + vp8_zero(cpi->count_mb_ref_frame_usage) + vp8_zero(cpi->ymode_count) + vp8_zero(cpi->uv_mode_count) + + x->mvc = cm->fc.mvc; + + vpx_memset(cm->above_context, 0, + sizeof(ENTROPY_CONTEXT_PLANES) * cm->mb_cols); + + // Special case treatment when GF and ARF are not sensible options for reference + if (cpi->ref_frame_flags == VP8_LAST_FLAG) + vp8_calc_ref_frame_costs(x->ref_frame_cost, + cpi->prob_intra_coded,255,128); + else if ((cpi->oxcf.number_of_layers > 1) && + (cpi->ref_frame_flags == VP8_GOLD_FLAG)) + vp8_calc_ref_frame_costs(x->ref_frame_cost, + cpi->prob_intra_coded,1,255); + else if ((cpi->oxcf.number_of_layers > 1) && + (cpi->ref_frame_flags == VP8_ALT_FLAG)) + vp8_calc_ref_frame_costs(x->ref_frame_cost, + cpi->prob_intra_coded,1,1); + else + vp8_calc_ref_frame_costs(x->ref_frame_cost, + cpi->prob_intra_coded, + cpi->prob_last_coded, + cpi->prob_gf_coded); + + xd->fullpixel_mask = 0xffffffff; + if(cm->full_pixel) + xd->fullpixel_mask = 0xfffffff8; +} + +void vp8_encode_frame(VP8_COMP *cpi) +{ + int mb_row; + MACROBLOCK *const x = & cpi->mb; + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + TOKENEXTRA *tp = cpi->tok; + int segment_counts[MAX_MB_SEGMENTS]; + int totalrate; +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + BOOL_CODER * bc = &cpi->bc[1]; // bc[0] is for control partition + const int num_part = (1 << cm->multi_token_partition); +#endif + + vpx_memset(segment_counts, 0, sizeof(segment_counts)); + totalrate = 0; + + if (cpi->compressor_speed == 2) + { + if (cpi->oxcf.cpu_used < 0) + cpi->Speed = -(cpi->oxcf.cpu_used); + else + vp8_auto_select_speed(cpi); + } + + // Functions setup for all frame types so we can use MC in AltRef + if (cm->mcomp_filter_type == SIXTAP) + { + xd->subpixel_predict = vp8_sixtap_predict4x4; + xd->subpixel_predict8x4 = vp8_sixtap_predict8x4; + xd->subpixel_predict8x8 = vp8_sixtap_predict8x8; + xd->subpixel_predict16x16 = vp8_sixtap_predict16x16; + } + else + { + xd->subpixel_predict = vp8_bilinear_predict4x4; + xd->subpixel_predict8x4 = vp8_bilinear_predict8x4; + xd->subpixel_predict8x8 = vp8_bilinear_predict8x8; + xd->subpixel_predict16x16 = vp8_bilinear_predict16x16; + } + + // Reset frame count of inter 0,0 motion vector usage. + cpi->inter_zz_count = 0; + + cpi->prediction_error = 0; + cpi->intra_error = 0; + cpi->skip_true_count = 0; + cpi->tok_count = 0; + +#if 0 + // Experimental code + cpi->frame_distortion = 0; + cpi->last_mb_distortion = 0; +#endif + + xd->mode_info_context = cm->mi; + + vp8_zero(cpi->MVcount); + + vp8_zero(cpi->coef_counts); + + vp8cx_frame_init_quantizer(cpi); + + vp8_initialize_rd_consts(cpi, + vp8_dc_quant(cm->base_qindex, cm->y1dc_delta_q)); + + vp8cx_initialize_me_consts(cpi, cm->base_qindex); + + if(cpi->oxcf.tuning == VP8_TUNE_SSIM) + { + // Initialize encode frame context. + init_encode_frame_mb_context(cpi); + + // Build a frame level activity map + build_activity_map(cpi); + } + + // re-init encode frame context. + init_encode_frame_mb_context(cpi); + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + { + int i; + for(i = 0; i < num_part; i++) + { + vp8_start_encode(&bc[i], cpi->partition_d[i + 1], + cpi->partition_d_end[i + 1]); + bc[i].error = &cm->error; + } + } + +#endif + + { + struct vpx_usec_timer emr_timer; + vpx_usec_timer_start(&emr_timer); + +#if CONFIG_MULTITHREAD + if (cpi->b_multi_threaded) + { + int i; + + vp8cx_init_mbrthread_data(cpi, x, cpi->mb_row_ei, 1, cpi->encoding_thread_count); + + for (i = 0; i < cm->mb_rows; i++) + cpi->mt_current_mb_col[i] = -1; + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + sem_post(&cpi->h_event_start_encoding[i]); + } + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row += (cpi->encoding_thread_count + 1)) + { + vp8_zero(cm->left_context) + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + tp = cpi->tok; +#else + tp = cpi->tok + mb_row * (cm->mb_cols * 16 * 24); +#endif + + encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride * (cpi->encoding_thread_count + 1) - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + + xd->mode_info_context += xd->mode_info_stride * cpi->encoding_thread_count; + x->partition_info += xd->mode_info_stride * cpi->encoding_thread_count; + x->gf_active_ptr += cm->mb_cols * cpi->encoding_thread_count; + + if(mb_row == cm->mb_rows - 1) + { + sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */ + } + } + + sem_wait(&cpi->h_event_end_encoding); /* wait for other threads to finish */ + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++) + { + cpi->tok_count += cpi->tplist[mb_row].stop - cpi->tplist[mb_row].start; + } + + if (xd->segmentation_enabled) + { + int i, j; + + if (xd->segmentation_enabled) + { + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + for (j = 0; j < 4; j++) + segment_counts[j] += cpi->mb_row_ei[i].segment_counts[j]; + } + } + } + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + totalrate += cpi->mb_row_ei[i].totalrate; + } + + } + else +#endif + { + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + vp8_zero(cm->left_context) + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + tp = cpi->tok; +#endif + + encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + } + + cpi->tok_count = tp - cpi->tok; + } + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + { + int i; + for(i = 0; i < num_part; i++) + { + vp8_stop_encode(&bc[i]); + cpi->partition_sz[i+1] = bc[i].pos; + } + } +#endif + + vpx_usec_timer_mark(&emr_timer); + cpi->time_encode_mb_row += vpx_usec_timer_elapsed(&emr_timer); + } + + + // Work out the segment probabilities if segmentation is enabled + if (xd->segmentation_enabled) + { + int tot_count; + int i; + + // Set to defaults + vpx_memset(xd->mb_segment_tree_probs, 255 , sizeof(xd->mb_segment_tree_probs)); + + tot_count = segment_counts[0] + segment_counts[1] + segment_counts[2] + segment_counts[3]; + + if (tot_count) + { + xd->mb_segment_tree_probs[0] = ((segment_counts[0] + segment_counts[1]) * 255) / tot_count; + + tot_count = segment_counts[0] + segment_counts[1]; + + if (tot_count > 0) + { + xd->mb_segment_tree_probs[1] = (segment_counts[0] * 255) / tot_count; + } + + tot_count = segment_counts[2] + segment_counts[3]; + + if (tot_count > 0) + xd->mb_segment_tree_probs[2] = (segment_counts[2] * 255) / tot_count; + + // Zero probabilities not allowed + for (i = 0; i < MB_FEATURE_TREE_PROBS; i ++) + { + if (xd->mb_segment_tree_probs[i] == 0) + xd->mb_segment_tree_probs[i] = 1; + } + } + } + + // 256 rate units to the bit + cpi->projected_frame_size = totalrate >> 8; // projected_frame_size in units of BYTES + + // Make a note of the percentage MBs coded Intra. + if (cm->frame_type == KEY_FRAME) + { + cpi->this_frame_percent_intra = 100; + } + else + { + int tot_modes; + + tot_modes = cpi->count_mb_ref_frame_usage[INTRA_FRAME] + + cpi->count_mb_ref_frame_usage[LAST_FRAME] + + cpi->count_mb_ref_frame_usage[GOLDEN_FRAME] + + cpi->count_mb_ref_frame_usage[ALTREF_FRAME]; + + if (tot_modes) + cpi->this_frame_percent_intra = cpi->count_mb_ref_frame_usage[INTRA_FRAME] * 100 / tot_modes; + + } + +#if 0 + { + int cnt = 0; + int flag[2] = {0, 0}; + + for (cnt = 0; cnt < MVPcount; cnt++) + { + if (cm->fc.pre_mvc[0][cnt] != cm->fc.mvc[0][cnt]) + { + flag[0] = 1; + vpx_memcpy(cm->fc.pre_mvc[0], cm->fc.mvc[0], MVPcount); + break; + } + } + + for (cnt = 0; cnt < MVPcount; cnt++) + { + if (cm->fc.pre_mvc[1][cnt] != cm->fc.mvc[1][cnt]) + { + flag[1] = 1; + vpx_memcpy(cm->fc.pre_mvc[1], cm->fc.mvc[1], MVPcount); + break; + } + } + + if (flag[0] || flag[1]) + vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) cm->fc.mvc, flag); + } +#endif + +#if ! CONFIG_REALTIME_ONLY + // Adjust the projected reference frame usage probability numbers to reflect + // what we have just seen. This may be useful when we make multiple iterations + // of the recode loop rather than continuing to use values from the previous frame. + if ((cm->frame_type != KEY_FRAME) && ((cpi->oxcf.number_of_layers > 1) || + (!cm->refresh_alt_ref_frame && !cm->refresh_golden_frame))) + { + vp8_convert_rfct_to_prob(cpi); + } +#endif +} +void vp8_setup_block_ptrs(MACROBLOCK *x) +{ + int r, c; + int i; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + x->block[r*4+c].src_diff = x->src_diff + r * 4 * 16 + c * 4; + } + } + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[16 + r*2+c].src_diff = x->src_diff + 256 + r * 4 * 8 + c * 4; + } + } + + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[20 + r*2+c].src_diff = x->src_diff + 320 + r * 4 * 8 + c * 4; + } + } + + x->block[24].src_diff = x->src_diff + 384; + + + for (i = 0; i < 25; i++) + { + x->block[i].coeff = x->coeff + i * 16; + } +} + +void vp8_build_block_offsets(MACROBLOCK *x) +{ + int block = 0; + int br, bc; + + vp8_build_block_doffsets(&x->e_mbd); + + // y blocks + x->thismb_ptr = &x->thismb[0]; + for (br = 0; br < 4; br++) + { + for (bc = 0; bc < 4; bc++) + { + BLOCK *this_block = &x->block[block]; + //this_block->base_src = &x->src.y_buffer; + //this_block->src_stride = x->src.y_stride; + //this_block->src = 4 * br * this_block->src_stride + 4 * bc; + this_block->base_src = &x->thismb_ptr; + this_block->src_stride = 16; + this_block->src = 4 * br * 16 + 4 * bc; + ++block; + } + } + + // u blocks + for (br = 0; br < 2; br++) + { + for (bc = 0; bc < 2; bc++) + { + BLOCK *this_block = &x->block[block]; + this_block->base_src = &x->src.u_buffer; + this_block->src_stride = x->src.uv_stride; + this_block->src = 4 * br * this_block->src_stride + 4 * bc; + ++block; + } + } + + // v blocks + for (br = 0; br < 2; br++) + { + for (bc = 0; bc < 2; bc++) + { + BLOCK *this_block = &x->block[block]; + this_block->base_src = &x->src.v_buffer; + this_block->src_stride = x->src.uv_stride; + this_block->src = 4 * br * this_block->src_stride + 4 * bc; + ++block; + } + } +} + +static void sum_intra_stats(VP8_COMP *cpi, MACROBLOCK *x) +{ + const MACROBLOCKD *xd = & x->e_mbd; + const MB_PREDICTION_MODE m = xd->mode_info_context->mbmi.mode; + const MB_PREDICTION_MODE uvm = xd->mode_info_context->mbmi.uv_mode; + +#ifdef MODE_STATS + const int is_key = cpi->common.frame_type == KEY_FRAME; + + ++ (is_key ? uv_modes : inter_uv_modes)[uvm]; + + if (m == B_PRED) + { + unsigned int *const bct = is_key ? b_modes : inter_b_modes; + + int b = 0; + + do + { + ++ bct[xd->block[b].bmi.mode]; + } + while (++b < 16); + } + +#endif + + ++cpi->ymode_count[m]; + ++cpi->uv_mode_count[uvm]; + +} + +// Experimental stub function to create a per MB zbin adjustment based on +// some previously calculated measure of MB activity. +static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x ) +{ +#if USE_ACT_INDEX + x->act_zbin_adj = *(x->mb_activity_ptr); +#else + int64_t a; + int64_t b; + int64_t act = *(x->mb_activity_ptr); + + // Apply the masking to the RD multiplier. + a = act + 4*cpi->activity_avg; + b = 4*act + cpi->activity_avg; + + if ( act > cpi->activity_avg ) + x->act_zbin_adj = (int)(((int64_t)b + (a>>1))/a) - 1; + else + x->act_zbin_adj = 1 - (int)(((int64_t)a + (b>>1))/b); +#endif +} + +int vp8cx_encode_intra_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) +{ + MACROBLOCKD *xd = &x->e_mbd; + int rate; + + if (cpi->sf.RD && cpi->compressor_speed != 2) + vp8_rd_pick_intra_mode(cpi, x, &rate); + else + vp8_pick_intra_mode(cpi, x, &rate); + + if(cpi->oxcf.tuning == VP8_TUNE_SSIM) + { + adjust_act_zbin( cpi, x ); + vp8_update_zbin_extra(cpi, x); + } + + if (x->e_mbd.mode_info_context->mbmi.mode == B_PRED) + vp8_encode_intra4x4mby(x); + else + vp8_encode_intra16x16mby(x); + + vp8_encode_intra16x16mbuv(x); + + sum_intra_stats(cpi, x); + + vp8_tokenize_mb(cpi, &x->e_mbd, t); + + if (xd->mode_info_context->mbmi.mode != B_PRED) + vp8_inverse_transform_mby(xd); + + vp8_dequant_idct_add_uv_block + (xd->qcoeff+16*16, xd->dequant_uv, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride, xd->eobs+16); + return rate; +} +#ifdef SPEEDSTATS +extern int cnt_pm; +#endif + +extern void vp8_fix_contexts(MACROBLOCKD *x); + +int vp8cx_encode_inter_macroblock +( + VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, + int recon_yoffset, int recon_uvoffset, + int mb_row, int mb_col +) +{ + MACROBLOCKD *const xd = &x->e_mbd; + int intra_error = 0; + int rate; + int distortion; + + x->skip = 0; + + if (xd->segmentation_enabled) + x->encode_breakout = cpi->segment_encode_breakout[xd->mode_info_context->mbmi.segment_id]; + else + x->encode_breakout = cpi->oxcf.encode_breakout; + +#if CONFIG_TEMPORAL_DENOISING + // Reset the best sse mode/mv for each macroblock. + x->e_mbd.best_sse_inter_mode = 0; + x->e_mbd.best_sse_mv.as_int = 0; + x->e_mbd.need_to_clamp_best_mvs = 0; +#endif + + if (cpi->sf.RD) + { + int zbin_mode_boost_enabled = cpi->zbin_mode_boost_enabled; + + /* Are we using the fast quantizer for the mode selection? */ + if(cpi->sf.use_fastquant_for_pick) + { + cpi->mb.quantize_b = vp8_fast_quantize_b; + cpi->mb.quantize_b_pair = vp8_fast_quantize_b_pair; + + /* the fast quantizer does not use zbin_extra, so + * do not recalculate */ + cpi->zbin_mode_boost_enabled = 0; + } + vp8_rd_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, + &distortion, &intra_error); + + /* switch back to the regular quantizer for the encode */ + if (cpi->sf.improved_quant) + { + cpi->mb.quantize_b = vp8_regular_quantize_b; + cpi->mb.quantize_b_pair = vp8_regular_quantize_b_pair; + } + + /* restore cpi->zbin_mode_boost_enabled */ + cpi->zbin_mode_boost_enabled = zbin_mode_boost_enabled; + + } + else + { + vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, + &distortion, &intra_error, mb_row, mb_col); + } + + cpi->prediction_error += distortion; + cpi->intra_error += intra_error; + + if(cpi->oxcf.tuning == VP8_TUNE_SSIM) + { + // Adjust the zbin based on this MB rate. + adjust_act_zbin( cpi, x ); + } + +#if 0 + // Experimental RD code + cpi->frame_distortion += distortion; + cpi->last_mb_distortion = distortion; +#endif + + // MB level adjutment to quantizer setup + if (xd->segmentation_enabled) + { + // If cyclic update enabled + if (cpi->current_layer == 0 && cpi->cyclic_refresh_mode_enabled) + { + // Clear segment_id back to 0 if not coded (last frame 0,0) + if ((xd->mode_info_context->mbmi.segment_id == 1) && + ((xd->mode_info_context->mbmi.ref_frame != LAST_FRAME) || (xd->mode_info_context->mbmi.mode != ZEROMV))) + { + xd->mode_info_context->mbmi.segment_id = 0; + + /* segment_id changed, so update */ + vp8cx_mb_init_quantizer(cpi, x, 1); + } + } + } + + { + // Experimental code. Special case for gf and arf zeromv modes. + // Increase zbin size to supress noise + cpi->zbin_mode_boost = 0; + if (cpi->zbin_mode_boost_enabled) + { + if ( xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME ) + { + if (xd->mode_info_context->mbmi.mode == ZEROMV) + { + if (xd->mode_info_context->mbmi.ref_frame != LAST_FRAME) + cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST; + else + cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST; + } + else if (xd->mode_info_context->mbmi.mode == SPLITMV) + cpi->zbin_mode_boost = 0; + else + cpi->zbin_mode_boost = MV_ZBIN_BOOST; + } + } + + /* The fast quantizer doesn't use zbin_extra, only do so with + * the regular quantizer. */ + if (cpi->sf.improved_quant) + vp8_update_zbin_extra(cpi, x); + } + + cpi->count_mb_ref_frame_usage[xd->mode_info_context->mbmi.ref_frame] ++; + + if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) + { + vp8_encode_intra16x16mbuv(x); + + if (xd->mode_info_context->mbmi.mode == B_PRED) + { + vp8_encode_intra4x4mby(x); + } + else + { + vp8_encode_intra16x16mby(x); + } + + sum_intra_stats(cpi, x); + } + else + { + int ref_fb_idx; + + if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME) + ref_fb_idx = cpi->common.lst_fb_idx; + else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME) + ref_fb_idx = cpi->common.gld_fb_idx; + else + ref_fb_idx = cpi->common.alt_fb_idx; + + xd->pre.y_buffer = cpi->common.yv12_fb[ref_fb_idx].y_buffer + recon_yoffset; + xd->pre.u_buffer = cpi->common.yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset; + xd->pre.v_buffer = cpi->common.yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset; + + if (!x->skip) + { + vp8_encode_inter16x16(x); + } + else + vp8_build_inter16x16_predictors_mb(xd, xd->dst.y_buffer, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.y_stride, xd->dst.uv_stride); + + } + + if (!x->skip) + { + vp8_tokenize_mb(cpi, xd, t); + + if (xd->mode_info_context->mbmi.mode != B_PRED) + vp8_inverse_transform_mby(xd); + + vp8_dequant_idct_add_uv_block + (xd->qcoeff+16*16, xd->dequant_uv, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride, xd->eobs+16); + } + else + { + /* always set mb_skip_coeff as it is needed by the loopfilter */ + xd->mode_info_context->mbmi.mb_skip_coeff = 1; + + if (cpi->common.mb_no_coeff_skip) + { + cpi->skip_true_count ++; + vp8_fix_contexts(xd); + } + else + { + vp8_stuff_mb(cpi, xd, t); + } + } + + return rate; +} diff --git a/vp8/encoder/encodeframe.h b/vp8/encoder/encodeframe.h new file mode 100644 index 0000000..4dd6ba0 --- /dev/null +++ b/vp8/encoder/encodeframe.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef ENCODEFRAME_H +#define ENCODEFRAME_H +extern void vp8_activity_masking(VP8_COMP *cpi, MACROBLOCK *x); + +extern void vp8_build_block_offsets(MACROBLOCK *x); + +extern void vp8_setup_block_ptrs(MACROBLOCK *x); + +extern void vp8_encode_frame(VP8_COMP *cpi); + +extern int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, + TOKENEXTRA **t, + int recon_yoffset, int recon_uvoffset, + int mb_row, int mb_col); + +extern int vp8cx_encode_intra_macroblock(VP8_COMP *cpi, MACROBLOCK *x, + TOKENEXTRA **t); +#endif diff --git a/vp8/encoder/encodeintra.c b/vp8/encoder/encodeintra.c new file mode 100644 index 0000000..1f445b7 --- /dev/null +++ b/vp8/encoder/encodeintra.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "quantize.h" +#include "vp8/common/reconintra4x4.h" +#include "encodemb.h" +#include "vp8/common/invtrans.h" +#include "encodeintra.h" + + +int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_dc_pred) +{ + + int i; + int intra_pred_var = 0; + (void) cpi; + + if (use_dc_pred) + { + x->e_mbd.mode_info_context->mbmi.mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + + vp8_encode_intra16x16mby(x); + + vp8_inverse_transform_mby(&x->e_mbd); + } + else + { + for (i = 0; i < 16; i++) + { + x->e_mbd.block[i].bmi.as_mode = B_DC_PRED; + vp8_encode_intra4x4block(x, i); + } + } + + intra_pred_var = vp8_get_mb_ss(x->src_diff); + + return intra_pred_var; +} + +void vp8_encode_intra4x4block(MACROBLOCK *x, int ib) +{ + BLOCKD *b = &x->e_mbd.block[ib]; + BLOCK *be = &x->block[ib]; + int dst_stride = x->e_mbd.dst.y_stride; + unsigned char *base_dst = x->e_mbd.dst.y_buffer; + + vp8_intra4x4_predict(base_dst + b->offset, dst_stride, + b->bmi.as_mode, b->predictor, 16); + + vp8_subtract_b(be, b, 16); + + x->short_fdct4x4(be->src_diff, be->coeff, 32); + + x->quantize_b(be, b); + + if (*b->eob > 1) + { + vp8_short_idct4x4llm(b->dqcoeff, + b->predictor, 16, base_dst + b->offset, dst_stride); + } + else + { + vp8_dc_only_idct_add + (b->dqcoeff[0], b->predictor, 16, base_dst + b->offset, + dst_stride); + } +} + +void vp8_encode_intra4x4mby(MACROBLOCK *mb) +{ + int i; + + MACROBLOCKD *xd = &mb->e_mbd; + intra_prediction_down_copy(xd, xd->dst.y_buffer - xd->dst.y_stride + 16); + + for (i = 0; i < 16; i++) + vp8_encode_intra4x4block(mb, i); + return; +} + +void vp8_encode_intra16x16mby(MACROBLOCK *x) +{ + BLOCK *b = &x->block[0]; + MACROBLOCKD *xd = &x->e_mbd; + + vp8_build_intra_predictors_mby_s(xd, + xd->dst.y_buffer - xd->dst.y_stride, + xd->dst.y_buffer - 1, + xd->dst.y_stride, + xd->dst.y_buffer, + xd->dst.y_stride); + + vp8_subtract_mby(x->src_diff, *(b->base_src), + b->src_stride, xd->dst.y_buffer, xd->dst.y_stride); + + vp8_transform_intra_mby(x); + + vp8_quantize_mby(x); + + if (x->optimize) + vp8_optimize_mby(x); +} + +void vp8_encode_intra16x16mbuv(MACROBLOCK *x) +{ + MACROBLOCKD *xd = &x->e_mbd; + + vp8_build_intra_predictors_mbuv_s(xd, xd->dst.u_buffer - xd->dst.uv_stride, + xd->dst.v_buffer - xd->dst.uv_stride, + xd->dst.u_buffer - 1, + xd->dst.v_buffer - 1, + xd->dst.uv_stride, + xd->dst.u_buffer, xd->dst.v_buffer, + xd->dst.uv_stride); + + vp8_subtract_mbuv(x->src_diff, x->src.u_buffer, + x->src.v_buffer, x->src.uv_stride, xd->dst.u_buffer, + xd->dst.v_buffer, xd->dst.uv_stride); + + vp8_transform_mbuv(x); + + vp8_quantize_mbuv(x); + + if (x->optimize) + vp8_optimize_mbuv(x); +} diff --git a/vp8/encoder/encodeintra.h b/vp8/encoder/encodeintra.h new file mode 100644 index 0000000..be2141f --- /dev/null +++ b/vp8/encoder/encodeintra.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef _ENCODEINTRA_H_ +#define _ENCODEINTRA_H_ +#include "onyx_int.h" + +int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_dc_pred); +void vp8_encode_intra16x16mby(MACROBLOCK *x); +void vp8_encode_intra16x16mbuv(MACROBLOCK *x); +void vp8_encode_intra4x4mby(MACROBLOCK *mb); +void vp8_encode_intra4x4block(MACROBLOCK *x, int ib); +#endif diff --git a/vp8/encoder/encodemb.c b/vp8/encoder/encodemb.c new file mode 100644 index 0000000..f89e4f7 --- /dev/null +++ b/vp8/encoder/encodemb.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "encodemb.h" +#include "vp8/common/reconinter.h" +#include "quantize.h" +#include "tokenize.h" +#include "vp8/common/invtrans.h" +#include "vpx_mem/vpx_mem.h" +#include "rdopt.h" + +void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *src_ptr = (*(be->base_src) + be->src); + short *diff_ptr = be->src_diff; + unsigned char *pred_ptr = bd->predictor; + int src_stride = be->src_stride; + + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + diff_ptr[c] = src_ptr[c] - pred_ptr[c]; + } + + diff_ptr += pitch; + pred_ptr += pitch; + src_ptr += src_stride; + } +} + +void vp8_subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, + int src_stride, unsigned char *upred, + unsigned char *vpred, int pred_stride) +{ + short *udiff = diff + 256; + short *vdiff = diff + 320; + + int r, c; + + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + udiff[c] = usrc[c] - upred[c]; + } + + udiff += 8; + upred += pred_stride; + usrc += src_stride; + } + + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + vdiff[c] = vsrc[c] - vpred[c]; + } + + vdiff += 8; + vpred += pred_stride; + vsrc += src_stride; + } +} + +void vp8_subtract_mby_c(short *diff, unsigned char *src, int src_stride, + unsigned char *pred, int pred_stride) +{ + int r, c; + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + diff[c] = src[c] - pred[c]; + } + + diff += 16; + pred += pred_stride; + src += src_stride; + } +} + +static void vp8_subtract_mb(MACROBLOCK *x) +{ + BLOCK *b = &x->block[0]; + + vp8_subtract_mby(x->src_diff, *(b->base_src), + b->src_stride, x->e_mbd.dst.y_buffer, x->e_mbd.dst.y_stride); + vp8_subtract_mbuv(x->src_diff, x->src.u_buffer, + x->src.v_buffer, x->src.uv_stride, x->e_mbd.dst.u_buffer, + x->e_mbd.dst.v_buffer, x->e_mbd.dst.uv_stride); +} + +static void build_dcblock(MACROBLOCK *x) +{ + short *src_diff_ptr = &x->src_diff[384]; + int i; + + for (i = 0; i < 16; i++) + { + src_diff_ptr[i] = x->coeff[i * 16]; + } +} + +void vp8_transform_mbuv(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i += 2) + { + x->short_fdct8x4(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 16); + } +} + + +void vp8_transform_intra_mby(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->short_fdct8x4(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + build_dcblock(x); + + // do 2nd order transform on the dc block + x->short_walsh4x4(&x->block[24].src_diff[0], + &x->block[24].coeff[0], 8); + +} + + +static void transform_mb(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->short_fdct8x4(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + if (x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + build_dcblock(x); + + for (i = 16; i < 24; i += 2) + { + x->short_fdct8x4(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 16); + } + + // do 2nd order transform on the dc block + if (x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + x->short_walsh4x4(&x->block[24].src_diff[0], + &x->block[24].coeff[0], 8); + +} + + +static void transform_mby(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->short_fdct8x4(&x->block[i].src_diff[0], + &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + if (x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) + { + build_dcblock(x); + x->short_walsh4x4(&x->block[24].src_diff[0], + &x->block[24].coeff[0], 8); + } +} + + + +#define RDTRUNC(RM,DM,R,D) ( (128+(R)*(RM)) & 0xFF ) + +typedef struct vp8_token_state vp8_token_state; + +struct vp8_token_state{ + int rate; + int error; + signed char next; + signed char token; + short qc; +}; + +// TODO: experiments to find optimal multiple numbers +#define Y1_RD_MULT 4 +#define UV_RD_MULT 2 +#define Y2_RD_MULT 16 + +static const int plane_rd_mult[4]= +{ + Y1_RD_MULT, + Y2_RD_MULT, + UV_RD_MULT, + Y1_RD_MULT +}; + +static void optimize_b(MACROBLOCK *mb, int ib, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + BLOCK *b; + BLOCKD *d; + vp8_token_state tokens[17][2]; + unsigned best_mask[2]; + const short *dequant_ptr; + const short *coeff_ptr; + short *qcoeff_ptr; + short *dqcoeff_ptr; + int eob; + int i0; + int rc; + int x; + int sz = 0; + int next; + int rdmult; + int rddiv; + int final_eob; + int rd_cost0; + int rd_cost1; + int rate0; + int rate1; + int error0; + int error1; + int t0; + int t1; + int best; + int band; + int pt; + int i; + int err_mult = plane_rd_mult[type]; + + b = &mb->block[ib]; + d = &mb->e_mbd.block[ib]; + + /* Enable this to test the effect of RDO as a replacement for the dynamic + * zero bin instead of an augmentation of it. + */ +#if 0 + vp8_strict_quantize_b(b, d); +#endif + + dequant_ptr = d->dequant; + coeff_ptr = b->coeff; + qcoeff_ptr = d->qcoeff; + dqcoeff_ptr = d->dqcoeff; + i0 = !type; + eob = *d->eob; + + /* Now set up a Viterbi trellis to evaluate alternative roundings. */ + rdmult = mb->rdmult * err_mult; + if(mb->e_mbd.mode_info_context->mbmi.ref_frame==INTRA_FRAME) + rdmult = (rdmult * 9)>>4; + + rddiv = mb->rddiv; + best_mask[0] = best_mask[1] = 0; + /* Initialize the sentinel node of the trellis. */ + tokens[eob][0].rate = 0; + tokens[eob][0].error = 0; + tokens[eob][0].next = 16; + tokens[eob][0].token = DCT_EOB_TOKEN; + tokens[eob][0].qc = 0; + *(tokens[eob] + 1) = *(tokens[eob] + 0); + next = eob; + for (i = eob; i-- > i0;) + { + int base_bits; + int d2; + int dx; + + rc = vp8_default_zig_zag1d[i]; + x = qcoeff_ptr[rc]; + /* Only add a trellis state for non-zero coefficients. */ + if (x) + { + int shortcut=0; + error0 = tokens[next][0].error; + error1 = tokens[next][1].error; + /* Evaluate the first possibility for this state. */ + rate0 = tokens[next][0].rate; + rate1 = tokens[next][1].rate; + t0 = (vp8_dct_value_tokens_ptr + x)->Token; + /* Consider both possible successor states. */ + if (next < 16) + { + band = vp8_coef_bands[i + 1]; + pt = vp8_prev_token_class[t0]; + rate0 += + mb->token_costs[type][band][pt][tokens[next][0].token]; + rate1 += + mb->token_costs[type][band][pt][tokens[next][1].token]; + } + rd_cost0 = RDCOST(rdmult, rddiv, rate0, error0); + rd_cost1 = RDCOST(rdmult, rddiv, rate1, error1); + if (rd_cost0 == rd_cost1) + { + rd_cost0 = RDTRUNC(rdmult, rddiv, rate0, error0); + rd_cost1 = RDTRUNC(rdmult, rddiv, rate1, error1); + } + /* And pick the best. */ + best = rd_cost1 < rd_cost0; + base_bits = *(vp8_dct_value_cost_ptr + x); + dx = dqcoeff_ptr[rc] - coeff_ptr[rc]; + d2 = dx*dx; + tokens[i][0].rate = base_bits + (best ? rate1 : rate0); + tokens[i][0].error = d2 + (best ? error1 : error0); + tokens[i][0].next = next; + tokens[i][0].token = t0; + tokens[i][0].qc = x; + best_mask[0] |= best << i; + /* Evaluate the second possibility for this state. */ + rate0 = tokens[next][0].rate; + rate1 = tokens[next][1].rate; + + if((abs(x)*dequant_ptr[rc]>abs(coeff_ptr[rc])) && + (abs(x)*dequant_ptr[rc]Token; + } + if (next < 16) + { + band = vp8_coef_bands[i + 1]; + if(t0!=DCT_EOB_TOKEN) + { + pt = vp8_prev_token_class[t0]; + rate0 += mb->token_costs[type][band][pt][ + tokens[next][0].token]; + } + if(t1!=DCT_EOB_TOKEN) + { + pt = vp8_prev_token_class[t1]; + rate1 += mb->token_costs[type][band][pt][ + tokens[next][1].token]; + } + } + + rd_cost0 = RDCOST(rdmult, rddiv, rate0, error0); + rd_cost1 = RDCOST(rdmult, rddiv, rate1, error1); + if (rd_cost0 == rd_cost1) + { + rd_cost0 = RDTRUNC(rdmult, rddiv, rate0, error0); + rd_cost1 = RDTRUNC(rdmult, rddiv, rate1, error1); + } + /* And pick the best. */ + best = rd_cost1 < rd_cost0; + base_bits = *(vp8_dct_value_cost_ptr + x); + + if(shortcut) + { + dx -= (dequant_ptr[rc] + sz) ^ sz; + d2 = dx*dx; + } + tokens[i][1].rate = base_bits + (best ? rate1 : rate0); + tokens[i][1].error = d2 + (best ? error1 : error0); + tokens[i][1].next = next; + tokens[i][1].token =best?t1:t0; + tokens[i][1].qc = x; + best_mask[1] |= best << i; + /* Finally, make this the new head of the trellis. */ + next = i; + } + /* There's no choice to make for a zero coefficient, so we don't + * add a new trellis node, but we do need to update the costs. + */ + else + { + band = vp8_coef_bands[i + 1]; + t0 = tokens[next][0].token; + t1 = tokens[next][1].token; + /* Update the cost of each path if we're past the EOB token. */ + if (t0 != DCT_EOB_TOKEN) + { + tokens[next][0].rate += mb->token_costs[type][band][0][t0]; + tokens[next][0].token = ZERO_TOKEN; + } + if (t1 != DCT_EOB_TOKEN) + { + tokens[next][1].rate += mb->token_costs[type][band][0][t1]; + tokens[next][1].token = ZERO_TOKEN; + } + /* Don't update next, because we didn't add a new node. */ + } + } + + /* Now pick the best path through the whole trellis. */ + band = vp8_coef_bands[i + 1]; + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + rate0 = tokens[next][0].rate; + rate1 = tokens[next][1].rate; + error0 = tokens[next][0].error; + error1 = tokens[next][1].error; + t0 = tokens[next][0].token; + t1 = tokens[next][1].token; + rate0 += mb->token_costs[type][band][pt][t0]; + rate1 += mb->token_costs[type][band][pt][t1]; + rd_cost0 = RDCOST(rdmult, rddiv, rate0, error0); + rd_cost1 = RDCOST(rdmult, rddiv, rate1, error1); + if (rd_cost0 == rd_cost1) + { + rd_cost0 = RDTRUNC(rdmult, rddiv, rate0, error0); + rd_cost1 = RDTRUNC(rdmult, rddiv, rate1, error1); + } + best = rd_cost1 < rd_cost0; + final_eob = i0 - 1; + for (i = next; i < eob; i = next) + { + x = tokens[i][best].qc; + if (x) + final_eob = i; + rc = vp8_default_zig_zag1d[i]; + qcoeff_ptr[rc] = x; + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; + next = tokens[i][best].next; + best = (best_mask[best] >> i) & 1; + } + final_eob++; + + *a = *l = (final_eob != !type); + *d->eob = (char)final_eob; +} +static void check_reset_2nd_coeffs(MACROBLOCKD *x, int type, + ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int sum=0; + int i; + BLOCKD *bd = &x->block[24]; + + if(bd->dequant[0]>=35 && bd->dequant[1]>=35) + return; + + for(i=0;i<(*bd->eob);i++) + { + int coef = bd->dqcoeff[vp8_default_zig_zag1d[i]]; + sum+= (coef>=0)?coef:-coef; + if(sum>=35) + return; + } + /************************************************************************** + our inverse hadamard transform effectively is weighted sum of all 16 inputs + with weight either 1 or -1. It has a last stage scaling of (sum+3)>>3. And + dc only idct is (dc+4)>>3. So if all the sums are between -35 and 29, the + output after inverse wht and idct will be all zero. A sum of absolute value + smaller than 35 guarantees all 16 different (+1/-1) weighted sums in wht + fall between -35 and +35. + **************************************************************************/ + if(sum < 35) + { + for(i=0;i<(*bd->eob);i++) + { + int rc = vp8_default_zig_zag1d[i]; + bd->qcoeff[rc]=0; + bd->dqcoeff[rc]=0; + } + *bd->eob = 0; + *a = *l = (*bd->eob != !type); + } +} + +static void optimize_mb(MACROBLOCK *x) +{ + int b; + int type; + int has_2nd_order; + + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + type = has_2nd_order ? PLANE_TYPE_Y_NO_DC : PLANE_TYPE_Y_WITH_DC; + + for (b = 0; b < 16; b++) + { + optimize_b(x, b, type, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + } + + for (b = 16; b < 24; b++) + { + optimize_b(x, b, PLANE_TYPE_UV, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + } + + if (has_2nd_order) + { + b=24; + optimize_b(x, b, PLANE_TYPE_Y2, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + check_reset_2nd_coeffs(&x->e_mbd, PLANE_TYPE_Y2, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + } +} + + +void vp8_optimize_mby(MACROBLOCK *x) +{ + int b; + int type; + int has_2nd_order; + + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + if (!x->e_mbd.above_context) + return; + + if (!x->e_mbd.left_context) + return; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + type = has_2nd_order ? PLANE_TYPE_Y_NO_DC : PLANE_TYPE_Y_WITH_DC; + + for (b = 0; b < 16; b++) + { + optimize_b(x, b, type, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + } + + + if (has_2nd_order) + { + b=24; + optimize_b(x, b, PLANE_TYPE_Y2, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + check_reset_2nd_coeffs(&x->e_mbd, PLANE_TYPE_Y2, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + } +} + +void vp8_optimize_mbuv(MACROBLOCK *x) +{ + int b; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + if (!x->e_mbd.above_context) + return; + + if (!x->e_mbd.left_context) + return; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + for (b = 16; b < 24; b++) + { + optimize_b(x, b, PLANE_TYPE_UV, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + } +} + +void vp8_encode_inter16x16(MACROBLOCK *x) +{ + vp8_build_inter_predictors_mb(&x->e_mbd); + + vp8_subtract_mb(x); + + transform_mb(x); + + vp8_quantize_mb(x); + + if (x->optimize) + optimize_mb(x); +} + +/* this funciton is used by first pass only */ +void vp8_encode_inter16x16y(MACROBLOCK *x) +{ + BLOCK *b = &x->block[0]; + + vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.dst.y_buffer, + x->e_mbd.dst.y_stride); + + vp8_subtract_mby(x->src_diff, *(b->base_src), + b->src_stride, x->e_mbd.dst.y_buffer, x->e_mbd.dst.y_stride); + + transform_mby(x); + + vp8_quantize_mby(x); + + vp8_inverse_transform_mby(&x->e_mbd); +} diff --git a/vp8/encoder/encodemb.h b/vp8/encoder/encodemb.h new file mode 100644 index 0000000..6badf7d --- /dev/null +++ b/vp8/encoder/encodemb.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_ENCODEMB_H +#define __INC_ENCODEMB_H + +#include "onyx_int.h" +void vp8_encode_inter16x16(MACROBLOCK *x); + +void vp8_build_dcblock(MACROBLOCK *b); +void vp8_transform_mb(MACROBLOCK *mb); +void vp8_transform_mbuv(MACROBLOCK *x); +void vp8_transform_intra_mby(MACROBLOCK *x); + +void vp8_optimize_mby(MACROBLOCK *x); +void vp8_optimize_mbuv(MACROBLOCK *x); +void vp8_encode_inter16x16y(MACROBLOCK *x); +#endif diff --git a/vp8/encoder/encodemv.c b/vp8/encoder/encodemv.c new file mode 100644 index 0000000..0145f6d --- /dev/null +++ b/vp8/encoder/encodemv.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/common.h" +#include "encodemv.h" +#include "vp8/common/entropymode.h" +#include "vp8/common/systemdependent.h" + +#include + +#ifdef ENTROPY_STATS +extern unsigned int active_section; +#endif + +static void encode_mvcomponent( + vp8_writer *const w, + const int v, + const struct mv_context *mvc +) +{ + const vp8_prob *p = mvc->prob; + const int x = v < 0 ? -v : v; + + if (x < mvnum_short) // Small + { + vp8_write(w, 0, p [mvpis_short]); + vp8_treed_write(w, vp8_small_mvtree, p + MVPshort, x, 3); + + if (!x) + return; // no sign bit + } + else // Large + { + int i = 0; + + vp8_write(w, 1, p [mvpis_short]); + + do + vp8_write(w, (x >> i) & 1, p [MVPbits + i]); + + while (++i < 3); + + i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ + + do + vp8_write(w, (x >> i) & 1, p [MVPbits + i]); + + while (--i > 3); + + if (x & 0xFFF0) + vp8_write(w, (x >> 3) & 1, p [MVPbits + 3]); + } + + vp8_write(w, v < 0, p [MVPsign]); +} +#if 0 +static int max_mv_r = 0; +static int max_mv_c = 0; +#endif +void vp8_encode_motion_vector(vp8_writer *w, const MV *mv, const MV_CONTEXT *mvc) +{ + +#if 0 + { + if (abs(mv->row >> 1) > max_mv_r) + { + FILE *f = fopen("maxmv.stt", "a"); + max_mv_r = abs(mv->row >> 1); + fprintf(f, "New Mv Row Max %6d\n", (mv->row >> 1)); + + if ((abs(mv->row) / 2) != max_mv_r) + fprintf(f, "MV Row conversion error %6d\n", abs(mv->row) / 2); + + fclose(f); + } + + if (abs(mv->col >> 1) > max_mv_c) + { + FILE *f = fopen("maxmv.stt", "a"); + fprintf(f, "New Mv Col Max %6d\n", (mv->col >> 1)); + max_mv_c = abs(mv->col >> 1); + fclose(f); + } + } +#endif + + encode_mvcomponent(w, mv->row >> 1, &mvc[0]); + encode_mvcomponent(w, mv->col >> 1, &mvc[1]); +} + + +static unsigned int cost_mvcomponent(const int v, const struct mv_context *mvc) +{ + const vp8_prob *p = mvc->prob; + const int x = v; //v<0? -v:v; + unsigned int cost; + + if (x < mvnum_short) + { + cost = vp8_cost_zero(p [mvpis_short]) + + vp8_treed_cost(vp8_small_mvtree, p + MVPshort, x, 3); + + if (!x) + return cost; + } + else + { + int i = 0; + cost = vp8_cost_one(p [mvpis_short]); + + do + cost += vp8_cost_bit(p [MVPbits + i], (x >> i) & 1); + + while (++i < 3); + + i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ + + do + cost += vp8_cost_bit(p [MVPbits + i], (x >> i) & 1); + + while (--i > 3); + + if (x & 0xFFF0) + cost += vp8_cost_bit(p [MVPbits + 3], (x >> 3) & 1); + } + + return cost; // + vp8_cost_bit( p [MVPsign], v < 0); +} + +void vp8_build_component_cost_table(int *mvcost[2], const MV_CONTEXT *mvc, int mvc_flag[2]) +{ + int i = 1; //-mv_max; + unsigned int cost0 = 0; + unsigned int cost1 = 0; + + vp8_clear_system_state(); + + i = 1; + + if (mvc_flag[0]) + { + mvcost [0] [0] = cost_mvcomponent(0, &mvc[0]); + + do + { + //mvcost [0] [i] = cost_mvcomponent( i, &mvc[0]); + cost0 = cost_mvcomponent(i, &mvc[0]); + + mvcost [0] [i] = cost0 + vp8_cost_zero(mvc[0].prob[MVPsign]); + mvcost [0] [-i] = cost0 + vp8_cost_one(mvc[0].prob[MVPsign]); + } + while (++i <= mv_max); + } + + i = 1; + + if (mvc_flag[1]) + { + mvcost [1] [0] = cost_mvcomponent(0, &mvc[1]); + + do + { + //mvcost [1] [i] = cost_mvcomponent( i, mvc[1]); + cost1 = cost_mvcomponent(i, &mvc[1]); + + mvcost [1] [i] = cost1 + vp8_cost_zero(mvc[1].prob[MVPsign]); + mvcost [1] [-i] = cost1 + vp8_cost_one(mvc[1].prob[MVPsign]); + } + while (++i <= mv_max); + } +} + + +// Motion vector probability table update depends on benefit. +// Small correction allows for the fact that an update to an MV probability +// may have benefit in subsequent frames as well as the current one. + +#define MV_PROB_UPDATE_CORRECTION -1 + + +static void calc_prob(vp8_prob *p, const unsigned int ct[2]) +{ + const unsigned int tot = ct[0] + ct[1]; + + if (tot) + { + const vp8_prob x = ((ct[0] * 255) / tot) & -2; + *p = x ? x : 1; + } +} + +static void update( + vp8_writer *const w, + const unsigned int ct[2], + vp8_prob *const cur_p, + const vp8_prob new_p, + const vp8_prob update_p, + int *updated +) +{ + const int cur_b = vp8_cost_branch(ct, *cur_p); + const int new_b = vp8_cost_branch(ct, new_p); + const int cost = 7 + MV_PROB_UPDATE_CORRECTION + ((vp8_cost_one(update_p) - vp8_cost_zero(update_p) + 128) >> 8); + + if (cur_b - new_b > cost) + { + *cur_p = new_p; + vp8_write(w, 1, update_p); + vp8_write_literal(w, new_p >> 1, 7); + *updated = 1; + + } + else + vp8_write(w, 0, update_p); +} + +static void write_component_probs( + vp8_writer *const w, + struct mv_context *cur_mvc, + const struct mv_context *default_mvc_, + const struct mv_context *update_mvc, + const unsigned int events [MVvals], + unsigned int rc, + int *updated +) +{ + vp8_prob *Pcur = cur_mvc->prob; + const vp8_prob *default_mvc = default_mvc_->prob; + const vp8_prob *Pupdate = update_mvc->prob; + unsigned int is_short_ct[2], sign_ct[2]; + + unsigned int bit_ct [mvlong_width] [2]; + + unsigned int short_ct [mvnum_short]; + unsigned int short_bct [mvnum_short-1] [2]; + + vp8_prob Pnew [MVPcount]; + + (void) rc; + vp8_copy_array(Pnew, default_mvc, MVPcount); + + vp8_zero(is_short_ct) + vp8_zero(sign_ct) + vp8_zero(bit_ct) + vp8_zero(short_ct) + vp8_zero(short_bct) + + + //j=0 + { + const int c = events [mv_max]; + + is_short_ct [0] += c; // Short vector + short_ct [0] += c; // Magnitude distribution + } + + //j: 1 ~ mv_max (1023) + { + int j = 1; + + do + { + const int c1 = events [mv_max + j]; //positive + const int c2 = events [mv_max - j]; //negative + const int c = c1 + c2; + int a = j; + + sign_ct [0] += c1; + sign_ct [1] += c2; + + if (a < mvnum_short) + { + is_short_ct [0] += c; // Short vector + short_ct [a] += c; // Magnitude distribution + } + else + { + int k = mvlong_width - 1; + is_short_ct [1] += c; // Long vector + + /* bit 3 not always encoded. */ + do + bit_ct [k] [(a >> k) & 1] += c; + + while (--k >= 0); + } + } + while (++j <= mv_max); + } + + /* + { + int j = -mv_max; + do + { + + const int c = events [mv_max + j]; + int a = j; + + if( j < 0) + { + sign_ct [1] += c; + a = -j; + } + else if( j) + sign_ct [0] += c; + + if( a < mvnum_short) + { + is_short_ct [0] += c; // Short vector + short_ct [a] += c; // Magnitude distribution + } + else + { + int k = mvlong_width - 1; + is_short_ct [1] += c; // Long vector + + // bit 3 not always encoded. + + do + bit_ct [k] [(a >> k) & 1] += c; + while( --k >= 0); + } + } while( ++j <= mv_max); + } + */ + + calc_prob(Pnew + mvpis_short, is_short_ct); + + calc_prob(Pnew + MVPsign, sign_ct); + + { + vp8_prob p [mvnum_short - 1]; /* actually only need branch ct */ + int j = 0; + + vp8_tree_probs_from_distribution( + 8, vp8_small_mvencodings, vp8_small_mvtree, + p, short_bct, short_ct, + 256, 1 + ); + + do + calc_prob(Pnew + MVPshort + j, short_bct[j]); + + while (++j < mvnum_short - 1); + } + + { + int j = 0; + + do + calc_prob(Pnew + MVPbits + j, bit_ct[j]); + + while (++j < mvlong_width); + } + + update(w, is_short_ct, Pcur + mvpis_short, Pnew[mvpis_short], *Pupdate++, updated); + + update(w, sign_ct, Pcur + MVPsign, Pnew[MVPsign], *Pupdate++, updated); + + { + const vp8_prob *const new_p = Pnew + MVPshort; + vp8_prob *const cur_p = Pcur + MVPshort; + + int j = 0; + + do + + update(w, short_bct[j], cur_p + j, new_p[j], *Pupdate++, updated); + + while (++j < mvnum_short - 1); + } + + { + const vp8_prob *const new_p = Pnew + MVPbits; + vp8_prob *const cur_p = Pcur + MVPbits; + + int j = 0; + + do + + update(w, bit_ct[j], cur_p + j, new_p[j], *Pupdate++, updated); + + while (++j < mvlong_width); + } +} + +void vp8_write_mvprobs(VP8_COMP *cpi) +{ + vp8_writer *const w = cpi->bc; + MV_CONTEXT *mvc = cpi->common.fc.mvc; + int flags[2] = {0, 0}; +#ifdef ENTROPY_STATS + active_section = 4; +#endif + write_component_probs( + w, &mvc[0], &vp8_default_mv_context[0], &vp8_mv_update_probs[0], cpi->MVcount[0], 0, &flags[0] + ); + write_component_probs( + w, &mvc[1], &vp8_default_mv_context[1], &vp8_mv_update_probs[1], cpi->MVcount[1], 1, &flags[1] + ); + + if (flags[0] || flags[1]) + vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) cpi->common.fc.mvc, flags); + +#ifdef ENTROPY_STATS + active_section = 5; +#endif +} diff --git a/vp8/encoder/encodemv.h b/vp8/encoder/encodemv.h new file mode 100644 index 0000000..a6116c1 --- /dev/null +++ b/vp8/encoder/encodemv.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_ENCODEMV_H +#define __INC_ENCODEMV_H + +#include "onyx_int.h" + +void vp8_write_mvprobs(VP8_COMP *); +void vp8_encode_motion_vector(vp8_writer *, const MV *, const MV_CONTEXT *); +void vp8_build_component_cost_table(int *mvcost[2], const MV_CONTEXT *mvc, int mvc_flag[2]); + +#endif diff --git a/vp8/encoder/ethreading.c b/vp8/encoder/ethreading.c new file mode 100644 index 0000000..2a2cb2f --- /dev/null +++ b/vp8/encoder/ethreading.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "onyx_int.h" +#include "vp8/common/threading.h" +#include "vp8/common/common.h" +#include "vp8/common/extend.h" +#include "bitstream.h" +#include "encodeframe.h" + +#if CONFIG_MULTITHREAD + +extern int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, + TOKENEXTRA **t, + int recon_yoffset, int recon_uvoffset, + int mb_row, int mb_col); +extern int vp8cx_encode_intra_macroblock(VP8_COMP *cpi, MACROBLOCK *x, + TOKENEXTRA **t); +extern void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x, int ok_to_skip); + +extern void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm); + +static THREAD_FUNCTION thread_loopfilter(void *p_data) +{ + VP8_COMP *cpi = (VP8_COMP *)(((LPFTHREAD_DATA *)p_data)->ptr1); + VP8_COMMON *cm = &cpi->common; + + while (1) + { + if (cpi->b_multi_threaded == 0) + break; + + if (sem_wait(&cpi->h_event_start_lpf) == 0) + { + if (cpi->b_multi_threaded == 0) // we're shutting down + break; + + vp8_loopfilter_frame(cpi, cm); + + sem_post(&cpi->h_event_end_lpf); + } + } + + return 0; +} + +static +THREAD_FUNCTION thread_encoding_proc(void *p_data) +{ + int ithread = ((ENCODETHREAD_DATA *)p_data)->ithread; + VP8_COMP *cpi = (VP8_COMP *)(((ENCODETHREAD_DATA *)p_data)->ptr1); + MB_ROW_COMP *mbri = (MB_ROW_COMP *)(((ENCODETHREAD_DATA *)p_data)->ptr2); + ENTROPY_CONTEXT_PLANES mb_row_left_context; + + const int nsync = cpi->mt_sync_range; + //printf("Started thread %d\n", ithread); + + while (1) + { + if (cpi->b_multi_threaded == 0) + break; + + //if(WaitForSingleObject(cpi->h_event_mbrencoding[ithread], INFINITE) == WAIT_OBJECT_0) + if (sem_wait(&cpi->h_event_start_encoding[ithread]) == 0) + { + VP8_COMMON *cm = &cpi->common; + int mb_row; + MACROBLOCK *x = &mbri->mb; + MACROBLOCKD *xd = &x->e_mbd; + TOKENEXTRA *tp ; +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + TOKENEXTRA *tp_start = cpi->tok + (1 + ithread) * (16 * 24); + const int num_part = (1 << cm->multi_token_partition); +#endif + + int *segment_counts = mbri->segment_counts; + int *totalrate = &mbri->totalrate; + + if (cpi->b_multi_threaded == 0) // we're shutting down + break; + + for (mb_row = ithread + 1; mb_row < cm->mb_rows; mb_row += (cpi->encoding_thread_count + 1)) + { + + int recon_yoffset, recon_uvoffset; + int mb_col; + int ref_fb_idx = cm->lst_fb_idx; + int dst_fb_idx = cm->new_fb_idx; + int recon_y_stride = cm->yv12_fb[ref_fb_idx].y_stride; + int recon_uv_stride = cm->yv12_fb[ref_fb_idx].uv_stride; + int map_index = (mb_row * cm->mb_cols); + volatile const int *last_row_current_mb_col; + volatile int *current_mb_col = &cpi->mt_current_mb_col[mb_row]; + +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + vp8_writer *w = &cpi->bc[1 + (mb_row % num_part)]; +#else + tp = cpi->tok + (mb_row * (cm->mb_cols * 16 * 24)); + cpi->tplist[mb_row].start = tp; +#endif + + last_row_current_mb_col = &cpi->mt_current_mb_col[mb_row - 1]; + + // reset above block coeffs + xd->above_context = cm->above_context; + xd->left_context = &mb_row_left_context; + + vp8_zero(mb_row_left_context); + + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); + recon_uvoffset = (mb_row * recon_uv_stride * 8); + + // Set the mb activity pointer to the start of the row. + x->mb_activity_ptr = &cpi->mb_activity_map[map_index]; + + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + *current_mb_col = mb_col - 1; + + if ((mb_col & (nsync - 1)) == 0) + { + while (mb_col > (*last_row_current_mb_col - nsync)) + { + x86_pause_hint(); + thread_sleep(0); + } + } + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + tp = tp_start; +#endif + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((cm->mb_cols - 1 - mb_col) * 16) << 3; + xd->mb_to_top_edge = -((mb_row * 16) << 3); + xd->mb_to_bottom_edge = ((cm->mb_rows - 1 - mb_row) * 16) << 3; + + // Set up limit values for motion vectors used to prevent them extending outside the UMV borders + x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + (VP8BORDERINPIXELS - 16); + x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + (VP8BORDERINPIXELS - 16); + + xd->dst.y_buffer = cm->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset; + xd->dst.u_buffer = cm->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset; + xd->dst.v_buffer = cm->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset; + xd->left_available = (mb_col != 0); + + x->rddiv = cpi->RDDIV; + x->rdmult = cpi->RDMULT; + + //Copy current mb to a buffer + vp8_copy_mem16x16(x->src.y_buffer, x->src.y_stride, x->thismb, 16); + + if (cpi->oxcf.tuning == VP8_TUNE_SSIM) + vp8_activity_masking(cpi, x); + + // Is segmentation enabled + // MB level adjustment to quantizer + if (xd->segmentation_enabled) + { + // Code to set segment id in xd->mbmi.segment_id for current MB (with range checking) + if (cpi->segmentation_map[map_index + mb_col] <= 3) + xd->mode_info_context->mbmi.segment_id = cpi->segmentation_map[map_index + mb_col]; + else + xd->mode_info_context->mbmi.segment_id = 0; + + vp8cx_mb_init_quantizer(cpi, x, 1); + } + else + xd->mode_info_context->mbmi.segment_id = 0; // Set to Segment 0 by default + + x->active_ptr = cpi->active_map + map_index + mb_col; + + if (cm->frame_type == KEY_FRAME) + { + *totalrate += vp8cx_encode_intra_macroblock(cpi, x, &tp); +#ifdef MODE_STATS + y_modes[xd->mbmi.mode] ++; +#endif + } + else + { + *totalrate += vp8cx_encode_inter_macroblock(cpi, x, &tp, recon_yoffset, recon_uvoffset, mb_row, mb_col); + +#ifdef MODE_STATS + inter_y_modes[xd->mbmi.mode] ++; + + if (xd->mbmi.mode == SPLITMV) + { + int b; + + for (b = 0; b < xd->mbmi.partition_count; b++) + { + inter_b_modes[x->partition->bmi[b].mode] ++; + } + } + +#endif + + // Count of last ref frame 0,0 usage + if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)) + cpi->inter_zz_count++; + + // Special case code for cyclic refresh + // If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode + // during vp8cx_encode_inter_macroblock()) back into the global segmentation map + if (cpi->cyclic_refresh_mode_enabled && xd->segmentation_enabled) + { + const MB_MODE_INFO * mbmi = &xd->mode_info_context->mbmi; + cpi->segmentation_map[map_index + mb_col] = mbmi->segment_id; + + // If the block has been refreshed mark it as clean (the magnitude of the -ve influences how long it will be before we consider another refresh): + // Else if it was coded (last frame 0,0) and has not already been refreshed then mark it as a candidate for cleanup next time (marked 0) + // else mark it as dirty (1). + if (mbmi->segment_id) + cpi->cyclic_refresh_map[map_index + mb_col] = -1; + else if ((mbmi->mode == ZEROMV) && (mbmi->ref_frame == LAST_FRAME)) + { + if (cpi->cyclic_refresh_map[map_index + mb_col] == 1) + cpi->cyclic_refresh_map[map_index + mb_col] = 0; + } + else + cpi->cyclic_refresh_map[map_index + mb_col] = 1; + + } + } + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + /* pack tokens for this MB */ + { + int tok_count = tp - tp_start; + pack_tokens(w, tp_start, tok_count); + } +#else + cpi->tplist[mb_row].stop = tp; +#endif + // Increment pointer into gf usage flags structure. + x->gf_active_ptr++; + + // Increment the activity mask pointers. + x->mb_activity_ptr++; + + // adjust to the next column of macroblocks + x->src.y_buffer += 16; + x->src.u_buffer += 8; + x->src.v_buffer += 8; + + recon_yoffset += 16; + recon_uvoffset += 8; + + // Keep track of segment usage + segment_counts[xd->mode_info_context->mbmi.segment_id]++; + + // skip to next mb + xd->mode_info_context++; + x->partition_info++; + xd->above_context++; + } + + vp8_extend_mb_row( &cm->yv12_fb[dst_fb_idx], + xd->dst.y_buffer + 16, + xd->dst.u_buffer + 8, + xd->dst.v_buffer + 8); + + *current_mb_col = mb_col + nsync; + + // this is to account for the border + xd->mode_info_context++; + x->partition_info++; + + x->src.y_buffer += 16 * x->src.y_stride * (cpi->encoding_thread_count + 1) - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + + xd->mode_info_context += xd->mode_info_stride * cpi->encoding_thread_count; + x->partition_info += xd->mode_info_stride * cpi->encoding_thread_count; + x->gf_active_ptr += cm->mb_cols * cpi->encoding_thread_count; + + if (mb_row == cm->mb_rows - 1) + { + sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */ + } + } + } + } + + //printf("exit thread %d\n", ithread); + return 0; +} + +static void setup_mbby_copy(MACROBLOCK *mbdst, MACROBLOCK *mbsrc) +{ + + MACROBLOCK *x = mbsrc; + MACROBLOCK *z = mbdst; + int i; + + z->ss = x->ss; + z->ss_count = x->ss_count; + z->searches_per_step = x->searches_per_step; + z->errorperbit = x->errorperbit; + + z->sadperbit16 = x->sadperbit16; + z->sadperbit4 = x->sadperbit4; + + /* + z->mv_col_min = x->mv_col_min; + z->mv_col_max = x->mv_col_max; + z->mv_row_min = x->mv_row_min; + z->mv_row_max = x->mv_row_max; + */ + + z->short_fdct4x4 = x->short_fdct4x4; + z->short_fdct8x4 = x->short_fdct8x4; + z->short_walsh4x4 = x->short_walsh4x4; + z->quantize_b = x->quantize_b; + z->quantize_b_pair = x->quantize_b_pair; + z->optimize = x->optimize; + + /* + z->mvc = x->mvc; + z->src.y_buffer = x->src.y_buffer; + z->src.u_buffer = x->src.u_buffer; + z->src.v_buffer = x->src.v_buffer; + */ + + + vpx_memcpy(z->mvcosts, x->mvcosts, sizeof(x->mvcosts)); + z->mvcost[0] = &z->mvcosts[0][mv_max+1]; + z->mvcost[1] = &z->mvcosts[1][mv_max+1]; + z->mvsadcost[0] = &z->mvsadcosts[0][mvfp_max+1]; + z->mvsadcost[1] = &z->mvsadcosts[1][mvfp_max+1]; + + + vpx_memcpy(z->token_costs, x->token_costs, sizeof(x->token_costs)); + vpx_memcpy(z->inter_bmode_costs, x->inter_bmode_costs, sizeof(x->inter_bmode_costs)); + //memcpy(z->mvcosts, x->mvcosts, sizeof(x->mvcosts)); + //memcpy(z->mvcost, x->mvcost, sizeof(x->mvcost)); + vpx_memcpy(z->mbmode_cost, x->mbmode_cost, sizeof(x->mbmode_cost)); + vpx_memcpy(z->intra_uv_mode_cost, x->intra_uv_mode_cost, sizeof(x->intra_uv_mode_cost)); + vpx_memcpy(z->bmode_costs, x->bmode_costs, sizeof(x->bmode_costs)); + + for (i = 0; i < 25; i++) + { + z->block[i].quant = x->block[i].quant; + z->block[i].quant_fast = x->block[i].quant_fast; + z->block[i].quant_shift = x->block[i].quant_shift; + z->block[i].zbin = x->block[i].zbin; + z->block[i].zrun_zbin_boost = x->block[i].zrun_zbin_boost; + z->block[i].round = x->block[i].round; + z->q_index = x->q_index; + z->act_zbin_adj = x->act_zbin_adj; + z->last_act_zbin_adj = x->last_act_zbin_adj; + /* + z->block[i].src = x->block[i].src; + */ + z->block[i].src_stride = x->block[i].src_stride; + } + + { + MACROBLOCKD *xd = &x->e_mbd; + MACROBLOCKD *zd = &z->e_mbd; + + /* + zd->mode_info_context = xd->mode_info_context; + zd->mode_info = xd->mode_info; + + zd->mode_info_stride = xd->mode_info_stride; + zd->frame_type = xd->frame_type; + zd->up_available = xd->up_available ; + zd->left_available = xd->left_available; + zd->left_context = xd->left_context; + zd->last_frame_dc = xd->last_frame_dc; + zd->last_frame_dccons = xd->last_frame_dccons; + zd->gold_frame_dc = xd->gold_frame_dc; + zd->gold_frame_dccons = xd->gold_frame_dccons; + zd->mb_to_left_edge = xd->mb_to_left_edge; + zd->mb_to_right_edge = xd->mb_to_right_edge; + zd->mb_to_top_edge = xd->mb_to_top_edge ; + zd->mb_to_bottom_edge = xd->mb_to_bottom_edge; + zd->gf_active_ptr = xd->gf_active_ptr; + zd->frames_since_golden = xd->frames_since_golden; + zd->frames_till_alt_ref_frame = xd->frames_till_alt_ref_frame; + */ + zd->subpixel_predict = xd->subpixel_predict; + zd->subpixel_predict8x4 = xd->subpixel_predict8x4; + zd->subpixel_predict8x8 = xd->subpixel_predict8x8; + zd->subpixel_predict16x16 = xd->subpixel_predict16x16; + zd->segmentation_enabled = xd->segmentation_enabled; + zd->mb_segement_abs_delta = xd->mb_segement_abs_delta; + vpx_memcpy(zd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); + + vpx_memcpy(zd->dequant_y1_dc, xd->dequant_y1_dc, sizeof(xd->dequant_y1_dc)); + vpx_memcpy(zd->dequant_y1, xd->dequant_y1, sizeof(xd->dequant_y1)); + vpx_memcpy(zd->dequant_y2, xd->dequant_y2, sizeof(xd->dequant_y2)); + vpx_memcpy(zd->dequant_uv, xd->dequant_uv, sizeof(xd->dequant_uv)); + +#if 1 + /*TODO: Remove dequant from BLOCKD. This is a temporary solution until + * the quantizer code uses a passed in pointer to the dequant constants. + * This will also require modifications to the x86 and neon assembly. + * */ + for (i = 0; i < 16; i++) + zd->block[i].dequant = zd->dequant_y1; + for (i = 16; i < 24; i++) + zd->block[i].dequant = zd->dequant_uv; + zd->block[24].dequant = zd->dequant_y2; +#endif + } +} + +void vp8cx_init_mbrthread_data(VP8_COMP *cpi, + MACROBLOCK *x, + MB_ROW_COMP *mbr_ei, + int mb_row, + int count + ) +{ + + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + int i; + (void) mb_row; + + for (i = 0; i < count; i++) + { + MACROBLOCK *mb = & mbr_ei[i].mb; + MACROBLOCKD *mbd = &mb->e_mbd; + + mbd->subpixel_predict = xd->subpixel_predict; + mbd->subpixel_predict8x4 = xd->subpixel_predict8x4; + mbd->subpixel_predict8x8 = xd->subpixel_predict8x8; + mbd->subpixel_predict16x16 = xd->subpixel_predict16x16; + mb->gf_active_ptr = x->gf_active_ptr; + + vpx_memset(mbr_ei[i].segment_counts, 0, sizeof(mbr_ei[i].segment_counts)); + mbr_ei[i].totalrate = 0; + + mb->partition_info = x->pi + x->e_mbd.mode_info_stride * (i + 1); + + mbd->mode_info_context = cm->mi + x->e_mbd.mode_info_stride * (i + 1); + mbd->mode_info_stride = cm->mode_info_stride; + + mbd->frame_type = cm->frame_type; + + mb->src = * cpi->Source; + mbd->pre = cm->yv12_fb[cm->lst_fb_idx]; + mbd->dst = cm->yv12_fb[cm->new_fb_idx]; + + mb->src.y_buffer += 16 * x->src.y_stride * (i + 1); + mb->src.u_buffer += 8 * x->src.uv_stride * (i + 1); + mb->src.v_buffer += 8 * x->src.uv_stride * (i + 1); + + vp8_build_block_offsets(mb); + + vp8_setup_block_dptrs(mbd); + + vp8_setup_block_ptrs(mb); + + mbd->left_context = &cm->left_context; + mb->mvc = cm->fc.mvc; + + setup_mbby_copy(&mbr_ei[i].mb, x); + + mbd->fullpixel_mask = 0xffffffff; + if(cm->full_pixel) + mbd->fullpixel_mask = 0xfffffff8; + } +} + +void vp8cx_create_encoder_threads(VP8_COMP *cpi) +{ + const VP8_COMMON * cm = &cpi->common; + + cpi->b_multi_threaded = 0; + cpi->encoding_thread_count = 0; + cpi->b_lpf_running = 0; + + if (cm->processor_core_count > 1 && cpi->oxcf.multi_threaded > 1) + { + int ithread; + int th_count = cpi->oxcf.multi_threaded - 1; + + /* don't allocate more threads than cores available */ + if (cpi->oxcf.multi_threaded > cm->processor_core_count) + th_count = cm->processor_core_count - 1; + + /* we have th_count + 1 (main) threads processing one row each */ + /* no point to have more threads than the sync range allows */ + if(th_count > ((cm->mb_cols / cpi->mt_sync_range) - 1)) + { + th_count = (cm->mb_cols / cpi->mt_sync_range) - 1; + } + + if(th_count == 0) + return; + + CHECK_MEM_ERROR(cpi->h_encoding_thread, vpx_malloc(sizeof(pthread_t) * th_count)); + CHECK_MEM_ERROR(cpi->h_event_start_encoding, vpx_malloc(sizeof(sem_t) * th_count)); + CHECK_MEM_ERROR(cpi->mb_row_ei, vpx_memalign(32, sizeof(MB_ROW_COMP) * th_count)); + vpx_memset(cpi->mb_row_ei, 0, sizeof(MB_ROW_COMP) * th_count); + CHECK_MEM_ERROR(cpi->en_thread_data, + vpx_malloc(sizeof(ENCODETHREAD_DATA) * th_count)); + CHECK_MEM_ERROR(cpi->mt_current_mb_col, + vpx_malloc(sizeof(*cpi->mt_current_mb_col) * cm->mb_rows)); + + sem_init(&cpi->h_event_end_encoding, 0, 0); + + cpi->b_multi_threaded = 1; + cpi->encoding_thread_count = th_count; + + /* + printf("[VP8:] multi_threaded encoding is enabled with %d threads\n\n", + (cpi->encoding_thread_count +1)); + */ + + for (ithread = 0; ithread < th_count; ithread++) + { + ENCODETHREAD_DATA * ethd = &cpi->en_thread_data[ithread]; + + sem_init(&cpi->h_event_start_encoding[ithread], 0, 0); + ethd->ithread = ithread; + ethd->ptr1 = (void *)cpi; + ethd->ptr2 = (void *)&cpi->mb_row_ei[ithread]; + + pthread_create(&cpi->h_encoding_thread[ithread], 0, thread_encoding_proc, ethd); + } + + { + LPFTHREAD_DATA * lpfthd = &cpi->lpf_thread_data; + + sem_init(&cpi->h_event_start_lpf, 0, 0); + sem_init(&cpi->h_event_end_lpf, 0, 0); + + lpfthd->ptr1 = (void *)cpi; + pthread_create(&cpi->h_filter_thread, 0, thread_loopfilter, lpfthd); + } + } + +} + +void vp8cx_remove_encoder_threads(VP8_COMP *cpi) +{ + if (cpi->b_multi_threaded) + { + //shutdown other threads + cpi->b_multi_threaded = 0; + { + int i; + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + //SetEvent(cpi->h_event_mbrencoding[i]); + sem_post(&cpi->h_event_start_encoding[i]); + pthread_join(cpi->h_encoding_thread[i], 0); + + sem_destroy(&cpi->h_event_start_encoding[i]); + } + + sem_post(&cpi->h_event_start_lpf); + pthread_join(cpi->h_filter_thread, 0); + } + + sem_destroy(&cpi->h_event_end_encoding); + sem_destroy(&cpi->h_event_end_lpf); + sem_destroy(&cpi->h_event_start_lpf); + + //free thread related resources + vpx_free(cpi->h_event_start_encoding); + vpx_free(cpi->h_encoding_thread); + vpx_free(cpi->mb_row_ei); + vpx_free(cpi->en_thread_data); + vpx_free(cpi->mt_current_mb_col); + } +} +#endif diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c new file mode 100644 index 0000000..8de1a6a --- /dev/null +++ b/vp8/encoder/firstpass.c @@ -0,0 +1,3198 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include + +#include "block.h" +#include "onyx_int.h" +#include "vp8/common/variance.h" +#include "encodeintra.h" +#include "vp8/common/setupintrarecon.h" +#include "vp8/common/systemdependent.h" +#include "mcomp.h" +#include "firstpass.h" +#include "vpx_scale/vpxscale.h" +#include "encodemb.h" +#include "vp8/common/extend.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/swapyv12buffer.h" +#include "rdopt.h" +#include "vp8/common/quant_common.h" +#include "encodemv.h" +#include "encodeframe.h" + +//#define OUTPUT_FPF 1 + +extern void vp8cx_frame_init_quantizer(VP8_COMP *cpi); +extern void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, int_mv *mv); +extern void vp8_alloc_compressor_data(VP8_COMP *cpi); + +//#define GFQ_ADJUSTMENT (40 + ((15*Q)/10)) +//#define GFQ_ADJUSTMENT (80 + ((15*Q)/10)) +#define GFQ_ADJUSTMENT vp8_gf_boost_qadjustment[Q] +extern int vp8_kf_boost_qadjustment[QINDEX_RANGE]; + +extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; + +#define IIFACTOR 1.5 +#define IIKFACTOR1 1.40 +#define IIKFACTOR2 1.5 +#define RMAX 14.0 +#define GF_RMAX 48.0 + +#define KF_MB_INTRA_MIN 300 +#define GF_MB_INTRA_MIN 200 + +#define DOUBLE_DIVIDE_CHECK(X) ((X)<0?(X)-.000001:(X)+.000001) + +#define POW1 (double)cpi->oxcf.two_pass_vbrbias/100.0 +#define POW2 (double)cpi->oxcf.two_pass_vbrbias/100.0 + +#define NEW_BOOST 1 + +static int vscale_lookup[7] = {0, 1, 1, 2, 2, 3, 3}; +static int hscale_lookup[7] = {0, 0, 1, 1, 2, 2, 3}; + + +static const int cq_level[QINDEX_RANGE] = +{ + 0,0,1,1,2,3,3,4,4,5,6,6,7,8,8,9, + 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,20, + 20,21,22,22,23,24,24,25,26,27,27,28,29,30,30,31, + 32,33,33,34,35,36,36,37,38,39,39,40,41,42,42,43, + 44,45,46,46,47,48,49,50,50,51,52,53,54,55,55,56, + 57,58,59,60,60,61,62,63,64,65,66,67,67,68,69,70, + 71,72,73,74,75,75,76,77,78,79,80,81,82,83,84,85, + 86,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100 +}; + +static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame); + +// Resets the first pass file to the given position using a relative seek from the current position +static void reset_fpf_position(VP8_COMP *cpi, FIRSTPASS_STATS *Position) +{ + cpi->twopass.stats_in = Position; +} + +static int lookup_next_frame_stats(VP8_COMP *cpi, FIRSTPASS_STATS *next_frame) +{ + if (cpi->twopass.stats_in >= cpi->twopass.stats_in_end) + return EOF; + + *next_frame = *cpi->twopass.stats_in; + return 1; +} + +// Read frame stats at an offset from the current position +static int read_frame_stats( VP8_COMP *cpi, + FIRSTPASS_STATS *frame_stats, + int offset ) +{ + FIRSTPASS_STATS * fps_ptr = cpi->twopass.stats_in; + + // Check legality of offset + if ( offset >= 0 ) + { + if ( &fps_ptr[offset] >= cpi->twopass.stats_in_end ) + return EOF; + } + else if ( offset < 0 ) + { + if ( &fps_ptr[offset] < cpi->twopass.stats_in_start ) + return EOF; + } + + *frame_stats = fps_ptr[offset]; + return 1; +} + +static int input_stats(VP8_COMP *cpi, FIRSTPASS_STATS *fps) +{ + if (cpi->twopass.stats_in >= cpi->twopass.stats_in_end) + return EOF; + + *fps = *cpi->twopass.stats_in; + cpi->twopass.stats_in = + (void*)((char *)cpi->twopass.stats_in + sizeof(FIRSTPASS_STATS)); + return 1; +} + +static void output_stats(const VP8_COMP *cpi, + struct vpx_codec_pkt_list *pktlist, + FIRSTPASS_STATS *stats) +{ + struct vpx_codec_cx_pkt pkt; + pkt.kind = VPX_CODEC_STATS_PKT; + pkt.data.twopass_stats.buf = stats; + pkt.data.twopass_stats.sz = sizeof(FIRSTPASS_STATS); + vpx_codec_pkt_list_add(pktlist, &pkt); + +// TEMP debug code +#if OUTPUT_FPF + + { + FILE *fpfile; + fpfile = fopen("firstpass.stt", "a"); + + fprintf(fpfile, "%12.0f %12.0f %12.0f %12.4f %12.4f %12.4f %12.4f" + " %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f" + " %12.0f %12.0f %12.4f\n", + stats->frame, + stats->intra_error, + stats->coded_error, + stats->ssim_weighted_pred_err, + stats->pcnt_inter, + stats->pcnt_motion, + stats->pcnt_second_ref, + stats->pcnt_neutral, + stats->MVr, + stats->mvr_abs, + stats->MVc, + stats->mvc_abs, + stats->MVrv, + stats->MVcv, + stats->mv_in_out_count, + stats->new_mv_count, + stats->count, + stats->duration); + fclose(fpfile); + } +#endif +} + +static void zero_stats(FIRSTPASS_STATS *section) +{ + section->frame = 0.0; + section->intra_error = 0.0; + section->coded_error = 0.0; + section->ssim_weighted_pred_err = 0.0; + section->pcnt_inter = 0.0; + section->pcnt_motion = 0.0; + section->pcnt_second_ref = 0.0; + section->pcnt_neutral = 0.0; + section->MVr = 0.0; + section->mvr_abs = 0.0; + section->MVc = 0.0; + section->mvc_abs = 0.0; + section->MVrv = 0.0; + section->MVcv = 0.0; + section->mv_in_out_count = 0.0; + section->new_mv_count = 0.0; + section->count = 0.0; + section->duration = 1.0; +} + +static void accumulate_stats(FIRSTPASS_STATS *section, FIRSTPASS_STATS *frame) +{ + section->frame += frame->frame; + section->intra_error += frame->intra_error; + section->coded_error += frame->coded_error; + section->ssim_weighted_pred_err += frame->ssim_weighted_pred_err; + section->pcnt_inter += frame->pcnt_inter; + section->pcnt_motion += frame->pcnt_motion; + section->pcnt_second_ref += frame->pcnt_second_ref; + section->pcnt_neutral += frame->pcnt_neutral; + section->MVr += frame->MVr; + section->mvr_abs += frame->mvr_abs; + section->MVc += frame->MVc; + section->mvc_abs += frame->mvc_abs; + section->MVrv += frame->MVrv; + section->MVcv += frame->MVcv; + section->mv_in_out_count += frame->mv_in_out_count; + section->new_mv_count += frame->new_mv_count; + section->count += frame->count; + section->duration += frame->duration; +} + +static void subtract_stats(FIRSTPASS_STATS *section, FIRSTPASS_STATS *frame) +{ + section->frame -= frame->frame; + section->intra_error -= frame->intra_error; + section->coded_error -= frame->coded_error; + section->ssim_weighted_pred_err -= frame->ssim_weighted_pred_err; + section->pcnt_inter -= frame->pcnt_inter; + section->pcnt_motion -= frame->pcnt_motion; + section->pcnt_second_ref -= frame->pcnt_second_ref; + section->pcnt_neutral -= frame->pcnt_neutral; + section->MVr -= frame->MVr; + section->mvr_abs -= frame->mvr_abs; + section->MVc -= frame->MVc; + section->mvc_abs -= frame->mvc_abs; + section->MVrv -= frame->MVrv; + section->MVcv -= frame->MVcv; + section->mv_in_out_count -= frame->mv_in_out_count; + section->new_mv_count -= frame->new_mv_count; + section->count -= frame->count; + section->duration -= frame->duration; +} + +static void avg_stats(FIRSTPASS_STATS *section) +{ + if (section->count < 1.0) + return; + + section->intra_error /= section->count; + section->coded_error /= section->count; + section->ssim_weighted_pred_err /= section->count; + section->pcnt_inter /= section->count; + section->pcnt_second_ref /= section->count; + section->pcnt_neutral /= section->count; + section->pcnt_motion /= section->count; + section->MVr /= section->count; + section->mvr_abs /= section->count; + section->MVc /= section->count; + section->mvc_abs /= section->count; + section->MVrv /= section->count; + section->MVcv /= section->count; + section->mv_in_out_count /= section->count; + section->duration /= section->count; +} + +// Calculate a modified Error used in distributing bits between easier and harder frames +static double calculate_modified_err(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + double av_err = ( cpi->twopass.total_stats.ssim_weighted_pred_err / + cpi->twopass.total_stats.count ); + double this_err = this_frame->ssim_weighted_pred_err; + double modified_err; + + if (this_err > av_err) + modified_err = av_err * pow((this_err / DOUBLE_DIVIDE_CHECK(av_err)), POW1); + else + modified_err = av_err * pow((this_err / DOUBLE_DIVIDE_CHECK(av_err)), POW2); + + return modified_err; +} + +static const double weight_table[256] = { +0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, +0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, +0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, +0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, 0.020000, +0.020000, 0.031250, 0.062500, 0.093750, 0.125000, 0.156250, 0.187500, 0.218750, +0.250000, 0.281250, 0.312500, 0.343750, 0.375000, 0.406250, 0.437500, 0.468750, +0.500000, 0.531250, 0.562500, 0.593750, 0.625000, 0.656250, 0.687500, 0.718750, +0.750000, 0.781250, 0.812500, 0.843750, 0.875000, 0.906250, 0.937500, 0.968750, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, +1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000 +}; + +static double simple_weight(YV12_BUFFER_CONFIG *source) +{ + int i, j; + + unsigned char *src = source->y_buffer; + double sum_weights = 0.0; + + // Loop throught the Y plane raw examining levels and creating a weight for the image + i = source->y_height; + do + { + j = source->y_width; + do + { + sum_weights += weight_table[ *src]; + src++; + }while(--j); + src -= source->y_width; + src += source->y_stride; + }while(--i); + + sum_weights /= (source->y_height * source->y_width); + + return sum_weights; +} + + +// This function returns the current per frame maximum bitrate target +static int frame_max_bits(VP8_COMP *cpi) +{ + // Max allocation for a single frame based on the max section guidelines passed in and how many bits are left + int max_bits; + + // For CBR we need to also consider buffer fullness. + // If we are running below the optimal level then we need to gradually tighten up on max_bits. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + double buffer_fullness_ratio = (double)cpi->buffer_level / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.optimal_buffer_level); + + // For CBR base this on the target average bits per frame plus the maximum sedction rate passed in by the user + max_bits = (int)(cpi->av_per_frame_bandwidth * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); + + // If our buffer is below the optimum level + if (buffer_fullness_ratio < 1.0) + { + // The lower of max_bits / 4 or cpi->av_per_frame_bandwidth / 4. + int min_max_bits = ((cpi->av_per_frame_bandwidth >> 2) < (max_bits >> 2)) ? cpi->av_per_frame_bandwidth >> 2 : max_bits >> 2; + + max_bits = (int)(max_bits * buffer_fullness_ratio); + + if (max_bits < min_max_bits) + max_bits = min_max_bits; // Lowest value we will set ... which should allow the buffer to refil. + } + } + // VBR + else + { + // For VBR base this on the bits and frames left plus the two_pass_vbrmax_section rate passed in by the user + max_bits = (int)(((double)cpi->twopass.bits_left / (cpi->twopass.total_stats.count - (double)cpi->common.current_video_frame)) * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); + } + + // Trap case where we are out of bits + if (max_bits < 0) + max_bits = 0; + + return max_bits; +} + +void vp8_init_first_pass(VP8_COMP *cpi) +{ + zero_stats(&cpi->twopass.total_stats); +} + +void vp8_end_first_pass(VP8_COMP *cpi) +{ + output_stats(cpi, cpi->output_pkt_list, &cpi->twopass.total_stats); +} + +static void zz_motion_search( VP8_COMP *cpi, MACROBLOCK * x, + YV12_BUFFER_CONFIG * raw_buffer, + int * raw_motion_err, + YV12_BUFFER_CONFIG * recon_buffer, + int * best_motion_err, int recon_yoffset) +{ + MACROBLOCKD * const xd = & x->e_mbd; + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + + unsigned char *src_ptr = (*(b->base_src) + b->src); + int src_stride = b->src_stride; + unsigned char *raw_ptr; + int raw_stride = raw_buffer->y_stride; + unsigned char *ref_ptr; + int ref_stride = x->e_mbd.pre.y_stride; + + // Set up pointers for this macro block raw buffer + raw_ptr = (unsigned char *)(raw_buffer->y_buffer + recon_yoffset + + d->offset); + vp8_mse16x16 ( src_ptr, src_stride, raw_ptr, raw_stride, + (unsigned int *)(raw_motion_err)); + + // Set up pointers for this macro block recon buffer + xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset; + ref_ptr = (unsigned char *)(xd->pre.y_buffer + d->offset ); + vp8_mse16x16 ( src_ptr, src_stride, ref_ptr, ref_stride, + (unsigned int *)(best_motion_err)); +} + +static void first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x, + int_mv *ref_mv, MV *best_mv, + YV12_BUFFER_CONFIG *recon_buffer, + int *best_motion_err, int recon_yoffset ) +{ + MACROBLOCKD *const xd = & x->e_mbd; + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + int num00; + + int_mv tmp_mv; + int_mv ref_mv_full; + + int tmp_err; + int step_param = 3; //3; // Dont search over full range for first pass + int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param; //3; + int n; + vp8_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[BLOCK_16X16]; + int new_mv_mode_penalty = 256; + + // override the default variance function to use MSE + v_fn_ptr.vf = vp8_mse16x16; + + // Set up pointers for this macro block recon buffer + xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset; + + // Initial step/diamond search centred on best mv + tmp_mv.as_int = 0; + ref_mv_full.as_mv.col = ref_mv->as_mv.col>>3; + ref_mv_full.as_mv.row = ref_mv->as_mv.row>>3; + tmp_err = cpi->diamond_search_sad(x, b, d, &ref_mv_full, &tmp_mv, step_param, + x->sadperbit16, &num00, &v_fn_ptr, + x->mvcost, ref_mv); + if ( tmp_err < INT_MAX-new_mv_mode_penalty ) + tmp_err += new_mv_mode_penalty; + + if (tmp_err < *best_motion_err) + { + *best_motion_err = tmp_err; + best_mv->row = tmp_mv.as_mv.row; + best_mv->col = tmp_mv.as_mv.col; + } + + // Further step/diamond searches as necessary + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + tmp_err = cpi->diamond_search_sad(x, b, d, &ref_mv_full, &tmp_mv, + step_param + n, x->sadperbit16, + &num00, &v_fn_ptr, x->mvcost, + ref_mv); + if ( tmp_err < INT_MAX-new_mv_mode_penalty ) + tmp_err += new_mv_mode_penalty; + + if (tmp_err < *best_motion_err) + { + *best_motion_err = tmp_err; + best_mv->row = tmp_mv.as_mv.row; + best_mv->col = tmp_mv.as_mv.col; + } + } + } +} + +void vp8_first_pass(VP8_COMP *cpi) +{ + int mb_row, mb_col; + MACROBLOCK *const x = & cpi->mb; + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + + int recon_yoffset, recon_uvoffset; + YV12_BUFFER_CONFIG *lst_yv12 = &cm->yv12_fb[cm->lst_fb_idx]; + YV12_BUFFER_CONFIG *new_yv12 = &cm->yv12_fb[cm->new_fb_idx]; + YV12_BUFFER_CONFIG *gld_yv12 = &cm->yv12_fb[cm->gld_fb_idx]; + int recon_y_stride = lst_yv12->y_stride; + int recon_uv_stride = lst_yv12->uv_stride; + int64_t intra_error = 0; + int64_t coded_error = 0; + + int sum_mvr = 0, sum_mvc = 0; + int sum_mvr_abs = 0, sum_mvc_abs = 0; + int sum_mvrs = 0, sum_mvcs = 0; + int mvcount = 0; + int intercount = 0; + int second_ref_count = 0; + int intrapenalty = 256; + int neutral_count = 0; + int new_mv_count = 0; + int sum_in_vectors = 0; + uint32_t lastmv_as_int = 0; + + int_mv zero_ref_mv; + + zero_ref_mv.as_int = 0; + + vp8_clear_system_state(); //__asm emms; + + x->src = * cpi->Source; + xd->pre = *lst_yv12; + xd->dst = *new_yv12; + + x->partition_info = x->pi; + + xd->mode_info_context = cm->mi; + + vp8_build_block_offsets(x); + + vp8_setup_block_dptrs(&x->e_mbd); + + vp8_setup_block_ptrs(x); + + // set up frame new frame for intra coded blocks + vp8_setup_intra_recon(new_yv12); + vp8cx_frame_init_quantizer(cpi); + + // Initialise the MV cost table to the defaults + //if( cm->current_video_frame == 0) + //if ( 0 ) + { + int flag[2] = {1, 1}; + vp8_initialize_rd_consts(cpi, vp8_dc_quant(cm->base_qindex, cm->y1dc_delta_q)); + vpx_memcpy(cm->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); + vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) cm->fc.mvc, flag); + } + + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + int_mv best_ref_mv; + + best_ref_mv.as_int = 0; + + // reset above block coeffs + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); + recon_uvoffset = (mb_row * recon_uv_stride * 8); + + // Set up limit values for motion vectors to prevent them extending outside the UMV borders + x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + (VP8BORDERINPIXELS - 16); + + + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int this_error; + int gf_motion_error = INT_MAX; + int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); + + xd->dst.y_buffer = new_yv12->y_buffer + recon_yoffset; + xd->dst.u_buffer = new_yv12->u_buffer + recon_uvoffset; + xd->dst.v_buffer = new_yv12->v_buffer + recon_uvoffset; + xd->left_available = (mb_col != 0); + + //Copy current mb to a buffer + vp8_copy_mem16x16(x->src.y_buffer, x->src.y_stride, x->thismb, 16); + + // do intra 16x16 prediction + this_error = vp8_encode_intra(cpi, x, use_dc_pred); + + // "intrapenalty" below deals with situations where the intra and inter error scores are very low (eg a plain black frame) + // We do not have special cases in first pass for 0,0 and nearest etc so all inter modes carry an overhead cost estimate fot the mv. + // When the error score is very low this causes us to pick all or lots of INTRA modes and throw lots of key frames. + // This penalty adds a cost matching that of a 0,0 mv to the intra case. + this_error += intrapenalty; + + // Cumulative intra error total + intra_error += (int64_t)this_error; + + // Set up limit values for motion vectors to prevent them extending outside the UMV borders + x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + (VP8BORDERINPIXELS - 16); + + // Other than for the first frame do a motion search + if (cm->current_video_frame > 0) + { + BLOCKD *d = &x->e_mbd.block[0]; + MV tmp_mv = {0, 0}; + int tmp_err; + int motion_error = INT_MAX; + int raw_motion_error = INT_MAX; + + // Simple 0,0 motion with no mv overhead + zz_motion_search( cpi, x, cpi->last_frame_unscaled_source, + &raw_motion_error, lst_yv12, &motion_error, + recon_yoffset ); + d->bmi.mv.as_mv.row = 0; + d->bmi.mv.as_mv.col = 0; + + if (raw_motion_error < cpi->oxcf.encode_breakout) + goto skip_motion_search; + + // Test last reference frame using the previous best mv as the + // starting point (best reference) for the search + first_pass_motion_search(cpi, x, &best_ref_mv, + &d->bmi.mv.as_mv, lst_yv12, + &motion_error, recon_yoffset); + + // If the current best reference mv is not centred on 0,0 then do a 0,0 based search as well + if (best_ref_mv.as_int) + { + tmp_err = INT_MAX; + first_pass_motion_search(cpi, x, &zero_ref_mv, &tmp_mv, + lst_yv12, &tmp_err, recon_yoffset); + + if ( tmp_err < motion_error ) + { + motion_error = tmp_err; + d->bmi.mv.as_mv.row = tmp_mv.row; + d->bmi.mv.as_mv.col = tmp_mv.col; + } + } + + // Experimental search in a second reference frame ((0,0) based only) + if (cm->current_video_frame > 1) + { + first_pass_motion_search(cpi, x, &zero_ref_mv, &tmp_mv, gld_yv12, &gf_motion_error, recon_yoffset); + + if ((gf_motion_error < motion_error) && (gf_motion_error < this_error)) + { + second_ref_count++; + //motion_error = gf_motion_error; + //d->bmi.mv.as_mv.row = tmp_mv.row; + //d->bmi.mv.as_mv.col = tmp_mv.col; + } + /*else + { + xd->pre.y_buffer = cm->last_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = cm->last_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = cm->last_frame.v_buffer + recon_uvoffset; + }*/ + + + // Reset to last frame as reference buffer + xd->pre.y_buffer = lst_yv12->y_buffer + recon_yoffset; + xd->pre.u_buffer = lst_yv12->u_buffer + recon_uvoffset; + xd->pre.v_buffer = lst_yv12->v_buffer + recon_uvoffset; + } + +skip_motion_search: + /* Intra assumed best */ + best_ref_mv.as_int = 0; + + if (motion_error <= this_error) + { + // Keep a count of cases where the inter and intra were + // very close and very low. This helps with scene cut + // detection for example in cropped clips with black bars + // at the sides or top and bottom. + if( (((this_error-intrapenalty) * 9) <= + (motion_error*10)) && + (this_error < (2*intrapenalty)) ) + { + neutral_count++; + } + + d->bmi.mv.as_mv.row <<= 3; + d->bmi.mv.as_mv.col <<= 3; + this_error = motion_error; + vp8_set_mbmode_and_mvs(x, NEWMV, &d->bmi.mv); + vp8_encode_inter16x16y(x); + sum_mvr += d->bmi.mv.as_mv.row; + sum_mvr_abs += abs(d->bmi.mv.as_mv.row); + sum_mvc += d->bmi.mv.as_mv.col; + sum_mvc_abs += abs(d->bmi.mv.as_mv.col); + sum_mvrs += d->bmi.mv.as_mv.row * d->bmi.mv.as_mv.row; + sum_mvcs += d->bmi.mv.as_mv.col * d->bmi.mv.as_mv.col; + intercount++; + + best_ref_mv.as_int = d->bmi.mv.as_int; + + // Was the vector non-zero + if (d->bmi.mv.as_int) + { + mvcount++; + + // Was it different from the last non zero vector + if ( d->bmi.mv.as_int != lastmv_as_int ) + new_mv_count++; + lastmv_as_int = d->bmi.mv.as_int; + + // Does the Row vector point inwards or outwards + if (mb_row < cm->mb_rows / 2) + { + if (d->bmi.mv.as_mv.row > 0) + sum_in_vectors--; + else if (d->bmi.mv.as_mv.row < 0) + sum_in_vectors++; + } + else if (mb_row > cm->mb_rows / 2) + { + if (d->bmi.mv.as_mv.row > 0) + sum_in_vectors++; + else if (d->bmi.mv.as_mv.row < 0) + sum_in_vectors--; + } + + // Does the Row vector point inwards or outwards + if (mb_col < cm->mb_cols / 2) + { + if (d->bmi.mv.as_mv.col > 0) + sum_in_vectors--; + else if (d->bmi.mv.as_mv.col < 0) + sum_in_vectors++; + } + else if (mb_col > cm->mb_cols / 2) + { + if (d->bmi.mv.as_mv.col > 0) + sum_in_vectors++; + else if (d->bmi.mv.as_mv.col < 0) + sum_in_vectors--; + } + } + } + } + + coded_error += (int64_t)this_error; + + // adjust to the next column of macroblocks + x->src.y_buffer += 16; + x->src.u_buffer += 8; + x->src.v_buffer += 8; + + recon_yoffset += 16; + recon_uvoffset += 8; + } + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + + //extend the recon for intra prediction + vp8_extend_mb_row(new_yv12, xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8); + vp8_clear_system_state(); //__asm emms; + } + + vp8_clear_system_state(); //__asm emms; + { + double weight = 0.0; + + FIRSTPASS_STATS fps; + + fps.frame = cm->current_video_frame ; + fps.intra_error = intra_error >> 8; + fps.coded_error = coded_error >> 8; + weight = simple_weight(cpi->Source); + + + if (weight < 0.1) + weight = 0.1; + + fps.ssim_weighted_pred_err = fps.coded_error * weight; + + fps.pcnt_inter = 0.0; + fps.pcnt_motion = 0.0; + fps.MVr = 0.0; + fps.mvr_abs = 0.0; + fps.MVc = 0.0; + fps.mvc_abs = 0.0; + fps.MVrv = 0.0; + fps.MVcv = 0.0; + fps.mv_in_out_count = 0.0; + fps.new_mv_count = 0.0; + fps.count = 1.0; + + fps.pcnt_inter = 1.0 * (double)intercount / cm->MBs; + fps.pcnt_second_ref = 1.0 * (double)second_ref_count / cm->MBs; + fps.pcnt_neutral = 1.0 * (double)neutral_count / cm->MBs; + + if (mvcount > 0) + { + fps.MVr = (double)sum_mvr / (double)mvcount; + fps.mvr_abs = (double)sum_mvr_abs / (double)mvcount; + fps.MVc = (double)sum_mvc / (double)mvcount; + fps.mvc_abs = (double)sum_mvc_abs / (double)mvcount; + fps.MVrv = ((double)sum_mvrs - (fps.MVr * fps.MVr / (double)mvcount)) / (double)mvcount; + fps.MVcv = ((double)sum_mvcs - (fps.MVc * fps.MVc / (double)mvcount)) / (double)mvcount; + fps.mv_in_out_count = (double)sum_in_vectors / (double)(mvcount * 2); + fps.new_mv_count = new_mv_count; + + fps.pcnt_motion = 1.0 * (double)mvcount / cpi->common.MBs; + } + + // TODO: handle the case when duration is set to 0, or something less + // than the full time between subsequent cpi->source_time_stamp s . + fps.duration = cpi->source->ts_end + - cpi->source->ts_start; + + // don't want to do output stats with a stack variable! + memcpy(&cpi->twopass.this_frame_stats, + &fps, + sizeof(FIRSTPASS_STATS)); + output_stats(cpi, cpi->output_pkt_list, &cpi->twopass.this_frame_stats); + accumulate_stats(&cpi->twopass.total_stats, &fps); + } + + // Copy the previous Last Frame into the GF buffer if specific conditions for doing so are met + if ((cm->current_video_frame > 0) && + (cpi->twopass.this_frame_stats.pcnt_inter > 0.20) && + ((cpi->twopass.this_frame_stats.intra_error / cpi->twopass.this_frame_stats.coded_error) > 2.0)) + { + vp8_yv12_copy_frame(lst_yv12, gld_yv12); + } + + // swap frame pointers so last frame refers to the frame we just compressed + vp8_swap_yv12_buffer(lst_yv12, new_yv12); + vp8_yv12_extend_frame_borders(lst_yv12); + + // Special case for the first frame. Copy into the GF buffer as a second reference. + if (cm->current_video_frame == 0) + { + vp8_yv12_copy_frame(lst_yv12, gld_yv12); + } + + + // use this to see what the first pass reconstruction looks like + if (0) + { + char filename[512]; + FILE *recon_file; + sprintf(filename, "enc%04d.yuv", (int) cm->current_video_frame); + + if (cm->current_video_frame == 0) + recon_file = fopen(filename, "wb"); + else + recon_file = fopen(filename, "ab"); + + if(fwrite(lst_yv12->buffer_alloc, lst_yv12->frame_size, 1, recon_file)); + fclose(recon_file); + } + + cm->current_video_frame++; + +} +extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; + +// Estimate a cost per mb attributable to overheads such as the coding of +// modes and motion vectors. +// Currently simplistic in its assumptions for testing. +// + + +static double bitcost( double prob ) +{ + return -(log( prob ) / log( 2.0 )); +} +static int64_t estimate_modemvcost(VP8_COMP *cpi, + FIRSTPASS_STATS * fpstats) +{ + int mv_cost; + int mode_cost; + + double av_pct_inter = fpstats->pcnt_inter / fpstats->count; + double av_pct_motion = fpstats->pcnt_motion / fpstats->count; + double av_intra = (1.0 - av_pct_inter); + + double zz_cost; + double motion_cost; + double intra_cost; + + zz_cost = bitcost(av_pct_inter - av_pct_motion); + motion_cost = bitcost(av_pct_motion); + intra_cost = bitcost(av_intra); + + // Estimate of extra bits per mv overhead for mbs + // << 9 is the normalization to the (bits * 512) used in vp8_bits_per_mb + mv_cost = ((int)(fpstats->new_mv_count / fpstats->count) * 8) << 9; + + // Crude estimate of overhead cost from modes + // << 9 is the normalization to (bits * 512) used in vp8_bits_per_mb + mode_cost = + (int)( ( ((av_pct_inter - av_pct_motion) * zz_cost) + + (av_pct_motion * motion_cost) + + (av_intra * intra_cost) ) * cpi->common.MBs ) << 9; + + return mv_cost + mode_cost; +} + +static double calc_correction_factor( double err_per_mb, + double err_devisor, + double pt_low, + double pt_high, + int Q ) +{ + double power_term; + double error_term = err_per_mb / err_devisor; + double correction_factor; + + // Adjustment based on Q to power term. + power_term = pt_low + (Q * 0.01); + power_term = (power_term > pt_high) ? pt_high : power_term; + + // Adjustments to error term + // TBD + + // Calculate correction factor + correction_factor = pow(error_term, power_term); + + // Clip range + correction_factor = + (correction_factor < 0.05) + ? 0.05 : (correction_factor > 5.0) ? 5.0 : correction_factor; + + return correction_factor; +} + +static int estimate_max_q(VP8_COMP *cpi, + FIRSTPASS_STATS * fpstats, + int section_target_bandwitdh, + int overhead_bits ) +{ + int Q; + int num_mbs = cpi->common.MBs; + int target_norm_bits_per_mb; + + double section_err = (fpstats->coded_error / fpstats->count); + double err_per_mb = section_err / num_mbs; + double err_correction_factor; + double speed_correction = 1.0; + int overhead_bits_per_mb; + + if (section_target_bandwitdh <= 0) + return cpi->twopass.maxq_max_limit; // Highest value allowed + + target_norm_bits_per_mb = + (section_target_bandwitdh < (1 << 20)) + ? (512 * section_target_bandwitdh) / num_mbs + : 512 * (section_target_bandwitdh / num_mbs); + + // Calculate a corrective factor based on a rolling ratio of bits spent + // vs target bits + if ((cpi->rolling_target_bits > 0) && + (cpi->active_worst_quality < cpi->worst_quality)) + { + double rolling_ratio; + + rolling_ratio = (double)cpi->rolling_actual_bits / + (double)cpi->rolling_target_bits; + + if (rolling_ratio < 0.95) + cpi->twopass.est_max_qcorrection_factor -= 0.005; + else if (rolling_ratio > 1.05) + cpi->twopass.est_max_qcorrection_factor += 0.005; + + cpi->twopass.est_max_qcorrection_factor = + (cpi->twopass.est_max_qcorrection_factor < 0.1) + ? 0.1 + : (cpi->twopass.est_max_qcorrection_factor > 10.0) + ? 10.0 : cpi->twopass.est_max_qcorrection_factor; + } + + // Corrections for higher compression speed settings + // (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Estimate of overhead bits per mb + // Correction to overhead bits for min allowed Q. + overhead_bits_per_mb = overhead_bits / num_mbs; + overhead_bits_per_mb *= pow( 0.98, (double)cpi->twopass.maxq_min_limit ); + + // Try and pick a max Q that will be high enough to encode the + // content at the given rate. + for (Q = cpi->twopass.maxq_min_limit; Q < cpi->twopass.maxq_max_limit; Q++) + { + int bits_per_mb_at_this_q; + + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, 150.0, 0.40, 0.90, Q); + + bits_per_mb_at_this_q = + vp8_bits_per_mb[INTER_FRAME][Q] + overhead_bits_per_mb; + + bits_per_mb_at_this_q = (int)(.5 + err_correction_factor + * speed_correction * cpi->twopass.est_max_qcorrection_factor + * cpi->twopass.section_max_qfactor + * (double)bits_per_mb_at_this_q); + + // Mode and motion overhead + // As Q rises in real encode loop rd code will force overhead down + // We make a crude adjustment for this here as *.98 per Q step. + overhead_bits_per_mb = (int)((double)overhead_bits_per_mb * 0.98); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + // Restriction on active max q for constrained quality mode. + if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (Q < cpi->cq_target_quality) ) + { + Q = cpi->cq_target_quality; + } + + // Adjust maxq_min_limit and maxq_max_limit limits based on + // averaga q observed in clip for non kf/gf.arf frames + // Give average a chance to settle though. + if ( (cpi->ni_frames > + ((unsigned int)cpi->twopass.total_stats.count >> 8)) && + (cpi->ni_frames > 150) ) + { + cpi->twopass.maxq_max_limit = ((cpi->ni_av_qi + 32) < cpi->worst_quality) + ? (cpi->ni_av_qi + 32) : cpi->worst_quality; + cpi->twopass.maxq_min_limit = ((cpi->ni_av_qi - 32) > cpi->best_quality) + ? (cpi->ni_av_qi - 32) : cpi->best_quality; + } + + return Q; +} + +// For cq mode estimate a cq level that matches the observed +// complexity and data rate. +static int estimate_cq( VP8_COMP *cpi, + FIRSTPASS_STATS * fpstats, + int section_target_bandwitdh, + int overhead_bits ) +{ + int Q; + int num_mbs = cpi->common.MBs; + int target_norm_bits_per_mb; + + double section_err = (fpstats->coded_error / fpstats->count); + double err_per_mb = section_err / num_mbs; + double err_correction_factor; + double speed_correction = 1.0; + double clip_iiratio; + double clip_iifactor; + int overhead_bits_per_mb; + + if (0) + { + FILE *f = fopen("epmp.stt", "a"); + fprintf(f, "%10.2f\n", err_per_mb ); + fclose(f); + } + + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) + ? (512 * section_target_bandwitdh) / num_mbs + : 512 * (section_target_bandwitdh / num_mbs); + + // Estimate of overhead bits per mb + overhead_bits_per_mb = overhead_bits / num_mbs; + + // Corrections for higher compression speed settings + // (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // II ratio correction factor for clip as a whole + clip_iiratio = cpi->twopass.total_stats.intra_error / + DOUBLE_DIVIDE_CHECK(cpi->twopass.total_stats.coded_error); + clip_iifactor = 1.0 - ((clip_iiratio - 10.0) * 0.025); + if (clip_iifactor < 0.80) + clip_iifactor = 0.80; + + // Try and pick a Q that can encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + int bits_per_mb_at_this_q; + + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, 100.0, 0.40, 0.90, Q); + + bits_per_mb_at_this_q = + vp8_bits_per_mb[INTER_FRAME][Q] + overhead_bits_per_mb; + + bits_per_mb_at_this_q = + (int)( .5 + err_correction_factor * + speed_correction * + clip_iifactor * + (double)bits_per_mb_at_this_q); + + // Mode and motion overhead + // As Q rises in real encode loop rd code will force overhead down + // We make a crude adjustment for this here as *.98 per Q step. + overhead_bits_per_mb = (int)((double)overhead_bits_per_mb * 0.98); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + // Clip value to range "best allowed to (worst allowed - 1)" + Q = cq_level[Q]; + if ( Q >= cpi->worst_quality ) + Q = cpi->worst_quality - 1; + if ( Q < cpi->best_quality ) + Q = cpi->best_quality; + + return Q; +} + +static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh) +{ + int Q; + int num_mbs = cpi->common.MBs; + int target_norm_bits_per_mb; + + double err_per_mb = section_err / num_mbs; + double err_correction_factor; + double speed_correction = 1.0; + + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); + + // Corrections for higher compression speed settings (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Try and pick a Q that can encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + int bits_per_mb_at_this_q; + + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, 150.0, 0.40, 0.90, Q); + + bits_per_mb_at_this_q = + (int)( .5 + ( err_correction_factor * + speed_correction * + cpi->twopass.est_max_qcorrection_factor * + (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0 ) ); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + return Q; +} + +// Estimate a worst case Q for a KF group +static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, double group_iiratio) +{ + int Q; + int num_mbs = cpi->common.MBs; + int target_norm_bits_per_mb = (512 * section_target_bandwitdh) / num_mbs; + int bits_per_mb_at_this_q; + + double err_per_mb = section_err / num_mbs; + double err_correction_factor; + double speed_correction = 1.0; + double current_spend_ratio = 1.0; + + double pow_highq = (POW1 < 0.6) ? POW1 + 0.3 : 0.90; + double pow_lowq = (POW1 < 0.7) ? POW1 + 0.1 : 0.80; + + double iiratio_correction_factor = 1.0; + + double combined_correction_factor; + + // Trap special case where the target is <= 0 + if (target_norm_bits_per_mb <= 0) + return MAXQ * 2; + + // Calculate a corrective factor based on a rolling ratio of bits spent vs target bits + // This is clamped to the range 0.1 to 10.0 + if (cpi->long_rolling_target_bits <= 0) + current_spend_ratio = 10.0; + else + { + current_spend_ratio = (double)cpi->long_rolling_actual_bits / (double)cpi->long_rolling_target_bits; + current_spend_ratio = (current_spend_ratio > 10.0) ? 10.0 : (current_spend_ratio < 0.1) ? 0.1 : current_spend_ratio; + } + + // Calculate a correction factor based on the quality of prediction in the sequence as indicated by intra_inter error score ratio (IIRatio) + // The idea here is to favour subsampling in the hardest sections vs the easyest. + iiratio_correction_factor = 1.0 - ((group_iiratio - 6.0) * 0.1); + + if (iiratio_correction_factor < 0.5) + iiratio_correction_factor = 0.5; + + // Corrections for higher compression speed settings (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Combine the various factors calculated above + combined_correction_factor = speed_correction * iiratio_correction_factor * current_spend_ratio; + + // Try and pick a Q that should be high enough to encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + // Error per MB based correction factor + err_correction_factor = + calc_correction_factor(err_per_mb, 150.0, pow_lowq, pow_highq, Q); + + bits_per_mb_at_this_q = + (int)(.5 + ( err_correction_factor * + combined_correction_factor * + (double)vp8_bits_per_mb[INTER_FRAME][Q]) ); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + // If we could not hit the target even at Max Q then estimate what Q would have bee required + while ((bits_per_mb_at_this_q > target_norm_bits_per_mb) && (Q < (MAXQ * 2))) + { + + bits_per_mb_at_this_q = (int)(0.96 * bits_per_mb_at_this_q); + Q++; + } + + if (0) + { + FILE *f = fopen("estkf_q.stt", "a"); + fprintf(f, "%8d %8d %8d %8.2f %8.3f %8.2f %8.3f %8.3f %8.3f %8d\n", cpi->common.current_video_frame, bits_per_mb_at_this_q, + target_norm_bits_per_mb, err_per_mb, err_correction_factor, + current_spend_ratio, group_iiratio, iiratio_correction_factor, + (double)cpi->buffer_level / (double)cpi->oxcf.optimal_buffer_level, Q); + fclose(f); + } + + return Q; +} + +extern void vp8_new_frame_rate(VP8_COMP *cpi, double framerate); + +void vp8_init_second_pass(VP8_COMP *cpi) +{ + FIRSTPASS_STATS this_frame; + FIRSTPASS_STATS *start_pos; + + double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + + zero_stats(&cpi->twopass.total_stats); + zero_stats(&cpi->twopass.total_left_stats); + + if (!cpi->twopass.stats_in_end) + return; + + cpi->twopass.total_stats = *cpi->twopass.stats_in_end; + cpi->twopass.total_left_stats = cpi->twopass.total_stats; + + // each frame can have a different duration, as the frame rate in the source + // isn't guaranteed to be constant. The frame rate prior to the first frame + // encoded in the second pass is a guess. However the sum duration is not. + // Its calculated based on the actual durations of all frames from the first + // pass. + vp8_new_frame_rate(cpi, 10000000.0 * cpi->twopass.total_stats.count / cpi->twopass.total_stats.duration); + + cpi->output_frame_rate = cpi->frame_rate; + cpi->twopass.bits_left = (int64_t)(cpi->twopass.total_stats.duration * cpi->oxcf.target_bandwidth / 10000000.0) ; + cpi->twopass.bits_left -= (int64_t)(cpi->twopass.total_stats.duration * two_pass_min_rate / 10000000.0); + + // Calculate a minimum intra value to be used in determining the IIratio + // scores used in the second pass. We have this minimum to make sure + // that clips that are static but "low complexity" in the intra domain + // are still boosted appropriately for KF/GF/ARF + cpi->twopass.kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs; + cpi->twopass.gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs; + + // Scan the first pass file and calculate an average Intra / Inter error score ratio for the sequence + { + double sum_iiratio = 0.0; + double IIRatio; + + start_pos = cpi->twopass.stats_in; // Note starting "file" position + + while (input_stats(cpi, &this_frame) != EOF) + { + IIRatio = this_frame.intra_error / DOUBLE_DIVIDE_CHECK(this_frame.coded_error); + IIRatio = (IIRatio < 1.0) ? 1.0 : (IIRatio > 20.0) ? 20.0 : IIRatio; + sum_iiratio += IIRatio; + } + + cpi->twopass.avg_iiratio = sum_iiratio / DOUBLE_DIVIDE_CHECK((double)cpi->twopass.total_stats.count); + + // Reset file position + reset_fpf_position(cpi, start_pos); + } + + // Scan the first pass file and calculate a modified total error based upon the bias/power function + // used to allocate bits + { + start_pos = cpi->twopass.stats_in; // Note starting "file" position + + cpi->twopass.modified_error_total = 0.0; + cpi->twopass.modified_error_used = 0.0; + + while (input_stats(cpi, &this_frame) != EOF) + { + cpi->twopass.modified_error_total += calculate_modified_err(cpi, &this_frame); + } + cpi->twopass.modified_error_left = cpi->twopass.modified_error_total; + + reset_fpf_position(cpi, start_pos); // Reset file position + + } +} + +void vp8_end_second_pass(VP8_COMP *cpi) +{ +} + +// This function gives and estimate of how badly we believe +// the prediction quality is decaying from frame to frame. +static double get_prediction_decay_rate(VP8_COMP *cpi, FIRSTPASS_STATS *next_frame) +{ + double prediction_decay_rate; + double motion_decay; + double motion_pct = next_frame->pcnt_motion; + + // Initial basis is the % mbs inter coded + prediction_decay_rate = next_frame->pcnt_inter; + + // High % motion -> somewhat higher decay rate + motion_decay = (1.0 - (motion_pct / 20.0)); + if (motion_decay < prediction_decay_rate) + prediction_decay_rate = motion_decay; + + // Adjustment to decay rate based on speed of motion + { + double this_mv_rabs; + double this_mv_cabs; + double distance_factor; + + this_mv_rabs = fabs(next_frame->mvr_abs * motion_pct); + this_mv_cabs = fabs(next_frame->mvc_abs * motion_pct); + + distance_factor = sqrt((this_mv_rabs * this_mv_rabs) + + (this_mv_cabs * this_mv_cabs)) / 250.0; + distance_factor = ((distance_factor > 1.0) + ? 0.0 : (1.0 - distance_factor)); + if (distance_factor < prediction_decay_rate) + prediction_decay_rate = distance_factor; + } + + return prediction_decay_rate; +} + +// Function to test for a condition where a complex transition is followed +// by a static section. For example in slide shows where there is a fade +// between slides. This is to help with more optimal kf and gf positioning. +static int detect_transition_to_still( + VP8_COMP *cpi, + int frame_interval, + int still_interval, + double loop_decay_rate, + double decay_accumulator ) +{ + int trans_to_still = 0; + + // Break clause to detect very still sections after motion + // For example a static image after a fade or other transition + // instead of a clean scene cut. + if ( (frame_interval > MIN_GF_INTERVAL) && + (loop_decay_rate >= 0.999) && + (decay_accumulator < 0.9) ) + { + int j; + FIRSTPASS_STATS * position = cpi->twopass.stats_in; + FIRSTPASS_STATS tmp_next_frame; + double decay_rate; + + // Look ahead a few frames to see if static condition + // persists... + for ( j = 0; j < still_interval; j++ ) + { + if (EOF == input_stats(cpi, &tmp_next_frame)) + break; + + decay_rate = get_prediction_decay_rate(cpi, &tmp_next_frame); + if ( decay_rate < 0.999 ) + break; + } + // Reset file position + reset_fpf_position(cpi, position); + + // Only if it does do we signal a transition to still + if ( j == still_interval ) + trans_to_still = 1; + } + + return trans_to_still; +} + +// This function detects a flash through the high relative pcnt_second_ref +// score in the frame following a flash frame. The offset passed in should +// reflect this +static int detect_flash( VP8_COMP *cpi, int offset ) +{ + FIRSTPASS_STATS next_frame; + + int flash_detected = 0; + + // Read the frame data. + // The return is 0 (no flash detected) if not a valid frame + if ( read_frame_stats(cpi, &next_frame, offset) != EOF ) + { + // What we are looking for here is a situation where there is a + // brief break in prediction (such as a flash) but subsequent frames + // are reasonably well predicted by an earlier (pre flash) frame. + // The recovery after a flash is indicated by a high pcnt_second_ref + // comapred to pcnt_inter. + if ( (next_frame.pcnt_second_ref > next_frame.pcnt_inter) && + (next_frame.pcnt_second_ref >= 0.5 ) ) + { + flash_detected = 1; + + /*if (1) + { + FILE *f = fopen("flash.stt", "a"); + fprintf(f, "%8.0f %6.2f %6.2f\n", + next_frame.frame, + next_frame.pcnt_inter, + next_frame.pcnt_second_ref); + fclose(f); + }*/ + } + } + + return flash_detected; +} + +// Update the motion related elements to the GF arf boost calculation +static void accumulate_frame_motion_stats( + VP8_COMP *cpi, + FIRSTPASS_STATS * this_frame, + double * this_frame_mv_in_out, + double * mv_in_out_accumulator, + double * abs_mv_in_out_accumulator, + double * mv_ratio_accumulator ) +{ + //double this_frame_mv_in_out; + double this_frame_mvr_ratio; + double this_frame_mvc_ratio; + double motion_pct; + + // Accumulate motion stats. + motion_pct = this_frame->pcnt_motion; + + // Accumulate Motion In/Out of frame stats + *this_frame_mv_in_out = this_frame->mv_in_out_count * motion_pct; + *mv_in_out_accumulator += this_frame->mv_in_out_count * motion_pct; + *abs_mv_in_out_accumulator += + fabs(this_frame->mv_in_out_count * motion_pct); + + // Accumulate a measure of how uniform (or conversely how random) + // the motion field is. (A ratio of absmv / mv) + if (motion_pct > 0.05) + { + this_frame_mvr_ratio = fabs(this_frame->mvr_abs) / + DOUBLE_DIVIDE_CHECK(fabs(this_frame->MVr)); + + this_frame_mvc_ratio = fabs(this_frame->mvc_abs) / + DOUBLE_DIVIDE_CHECK(fabs(this_frame->MVc)); + + *mv_ratio_accumulator += + (this_frame_mvr_ratio < this_frame->mvr_abs) + ? (this_frame_mvr_ratio * motion_pct) + : this_frame->mvr_abs * motion_pct; + + *mv_ratio_accumulator += + (this_frame_mvc_ratio < this_frame->mvc_abs) + ? (this_frame_mvc_ratio * motion_pct) + : this_frame->mvc_abs * motion_pct; + + } +} + +// Calculate a baseline boost number for the current frame. +static double calc_frame_boost( + VP8_COMP *cpi, + FIRSTPASS_STATS * this_frame, + double this_frame_mv_in_out ) +{ + double frame_boost; + + // Underlying boost factor is based on inter intra error ratio + if (this_frame->intra_error > cpi->twopass.gf_intra_err_min) + frame_boost = (IIFACTOR * this_frame->intra_error / + DOUBLE_DIVIDE_CHECK(this_frame->coded_error)); + else + frame_boost = (IIFACTOR * cpi->twopass.gf_intra_err_min / + DOUBLE_DIVIDE_CHECK(this_frame->coded_error)); + + // Increase boost for frames where new data coming into frame + // (eg zoom out). Slightly reduce boost if there is a net balance + // of motion out of the frame (zoom in). + // The range for this_frame_mv_in_out is -1.0 to +1.0 + if (this_frame_mv_in_out > 0.0) + frame_boost += frame_boost * (this_frame_mv_in_out * 2.0); + // In extreme case boost is halved + else + frame_boost += frame_boost * (this_frame_mv_in_out / 2.0); + + // Clip to maximum + if (frame_boost > GF_RMAX) + frame_boost = GF_RMAX; + + return frame_boost; +} + +#if NEW_BOOST +static int calc_arf_boost( + VP8_COMP *cpi, + int offset, + int f_frames, + int b_frames, + int *f_boost, + int *b_boost ) +{ + FIRSTPASS_STATS this_frame; + + int i; + double boost_score = 0.0; + double mv_ratio_accumulator = 0.0; + double decay_accumulator = 1.0; + double this_frame_mv_in_out = 0.0; + double mv_in_out_accumulator = 0.0; + double abs_mv_in_out_accumulator = 0.0; + double r; + int flash_detected = 0; + + // Search forward from the proposed arf/next gf position + for ( i = 0; i < f_frames; i++ ) + { + if ( read_frame_stats(cpi, &this_frame, (i+offset)) == EOF ) + break; + + // Update the motion related elements to the boost calculation + accumulate_frame_motion_stats( cpi, &this_frame, + &this_frame_mv_in_out, &mv_in_out_accumulator, + &abs_mv_in_out_accumulator, &mv_ratio_accumulator ); + + // Calculate the baseline boost number for this frame + r = calc_frame_boost( cpi, &this_frame, this_frame_mv_in_out ); + + // We want to discount the the flash frame itself and the recovery + // frame that follows as both will have poor scores. + flash_detected = detect_flash(cpi, (i+offset)) || + detect_flash(cpi, (i+offset+1)); + + // Cumulative effect of prediction quality decay + if ( !flash_detected ) + { + decay_accumulator = + decay_accumulator * + get_prediction_decay_rate(cpi, &this_frame); + decay_accumulator = + decay_accumulator < 0.1 ? 0.1 : decay_accumulator; + } + boost_score += (decay_accumulator * r); + + // Break out conditions. + if ( (!flash_detected) && + ((mv_ratio_accumulator > 100.0) || + (abs_mv_in_out_accumulator > 3.0) || + (mv_in_out_accumulator < -2.0) ) ) + { + break; + } + } + + *f_boost = (int)(boost_score * 100.0) >> 4; + + // Reset for backward looking loop + boost_score = 0.0; + mv_ratio_accumulator = 0.0; + decay_accumulator = 1.0; + this_frame_mv_in_out = 0.0; + mv_in_out_accumulator = 0.0; + abs_mv_in_out_accumulator = 0.0; + + // Search forward from the proposed arf/next gf position + for ( i = -1; i >= -b_frames; i-- ) + { + if ( read_frame_stats(cpi, &this_frame, (i+offset)) == EOF ) + break; + + // Update the motion related elements to the boost calculation + accumulate_frame_motion_stats( cpi, &this_frame, + &this_frame_mv_in_out, &mv_in_out_accumulator, + &abs_mv_in_out_accumulator, &mv_ratio_accumulator ); + + // Calculate the baseline boost number for this frame + r = calc_frame_boost( cpi, &this_frame, this_frame_mv_in_out ); + + // We want to discount the the flash frame itself and the recovery + // frame that follows as both will have poor scores. + flash_detected = detect_flash(cpi, (i+offset)) || + detect_flash(cpi, (i+offset+1)); + + // Cumulative effect of prediction quality decay + if ( !flash_detected ) + { + decay_accumulator = + decay_accumulator * + get_prediction_decay_rate(cpi, &this_frame); + decay_accumulator = + decay_accumulator < 0.1 ? 0.1 : decay_accumulator; + } + + boost_score += (decay_accumulator * r); + + // Break out conditions. + if ( (!flash_detected) && + ((mv_ratio_accumulator > 100.0) || + (abs_mv_in_out_accumulator > 3.0) || + (mv_in_out_accumulator < -2.0) ) ) + { + break; + } + } + *b_boost = (int)(boost_score * 100.0) >> 4; + + return (*f_boost + *b_boost); +} +#endif + +// Analyse and define a gf/arf group . +static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + FIRSTPASS_STATS next_frame; + FIRSTPASS_STATS *start_pos; + int i; + double r; + double boost_score = 0.0; + double old_boost_score = 0.0; + double gf_group_err = 0.0; + double gf_first_frame_err = 0.0; + double mod_frame_err = 0.0; + + double mv_ratio_accumulator = 0.0; + double decay_accumulator = 1.0; + + double loop_decay_rate = 1.00; // Starting decay rate + + double this_frame_mv_in_out = 0.0; + double mv_in_out_accumulator = 0.0; + double abs_mv_in_out_accumulator = 0.0; + double mod_err_per_mb_accumulator = 0.0; + + int max_bits = frame_max_bits(cpi); // Max for a single frame + + unsigned int allow_alt_ref = + cpi->oxcf.play_alternate && cpi->oxcf.lag_in_frames; + + int alt_boost = 0; + int f_boost = 0; + int b_boost = 0; + int flash_detected; + + cpi->twopass.gf_group_bits = 0; + cpi->twopass.gf_decay_rate = 0; + + vp8_clear_system_state(); //__asm emms; + + start_pos = cpi->twopass.stats_in; + + vpx_memset(&next_frame, 0, sizeof(next_frame)); // assure clean + + // Load stats for the current frame. + mod_frame_err = calculate_modified_err(cpi, this_frame); + + // Note the error of the frame at the start of the group (this will be + // the GF frame error if we code a normal gf + gf_first_frame_err = mod_frame_err; + + // Special treatment if the current frame is a key frame (which is also + // a gf). If it is then its error score (and hence bit allocation) need + // to be subtracted out from the calculation for the GF group + if (cpi->common.frame_type == KEY_FRAME) + gf_group_err -= gf_first_frame_err; + + // Scan forward to try and work out how many frames the next gf group + // should contain and what level of boost is appropriate for the GF + // or ARF that will be coded with the group + i = 0; + + while (((i < cpi->twopass.static_scene_max_gf_interval) || + ((cpi->twopass.frames_to_key - i) < MIN_GF_INTERVAL)) && + (i < cpi->twopass.frames_to_key)) + { + i++; // Increment the loop counter + + // Accumulate error score of frames in this gf group + mod_frame_err = calculate_modified_err(cpi, this_frame); + + gf_group_err += mod_frame_err; + + mod_err_per_mb_accumulator += + mod_frame_err / DOUBLE_DIVIDE_CHECK((double)cpi->common.MBs); + + if (EOF == input_stats(cpi, &next_frame)) + break; + + // Test for the case where there is a brief flash but the prediction + // quality back to an earlier frame is then restored. + flash_detected = detect_flash(cpi, 0); + + // Update the motion related elements to the boost calculation + accumulate_frame_motion_stats( cpi, &next_frame, + &this_frame_mv_in_out, &mv_in_out_accumulator, + &abs_mv_in_out_accumulator, &mv_ratio_accumulator ); + + // Calculate a baseline boost number for this frame + r = calc_frame_boost( cpi, &next_frame, this_frame_mv_in_out ); + + // Cumulative effect of prediction quality decay + if ( !flash_detected ) + { + loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); + decay_accumulator = decay_accumulator * loop_decay_rate; + decay_accumulator = + decay_accumulator < 0.1 ? 0.1 : decay_accumulator; + } + boost_score += (decay_accumulator * r); + + // Break clause to detect very still sections after motion + // For example a staic image after a fade or other transition. + if ( detect_transition_to_still( cpi, i, 5, + loop_decay_rate, + decay_accumulator ) ) + { + allow_alt_ref = 0; + boost_score = old_boost_score; + break; + } + + // Break out conditions. + if ( + // Break at cpi->max_gf_interval unless almost totally static + (i >= cpi->max_gf_interval && (decay_accumulator < 0.995)) || + ( + // Dont break out with a very short interval + (i > MIN_GF_INTERVAL) && + // Dont break out very close to a key frame + ((cpi->twopass.frames_to_key - i) >= MIN_GF_INTERVAL) && + ((boost_score > 20.0) || (next_frame.pcnt_inter < 0.75)) && + (!flash_detected) && + ((mv_ratio_accumulator > 100.0) || + (abs_mv_in_out_accumulator > 3.0) || + (mv_in_out_accumulator < -2.0) || + ((boost_score - old_boost_score) < 2.0)) + ) ) + { + boost_score = old_boost_score; + break; + } + + vpx_memcpy(this_frame, &next_frame, sizeof(*this_frame)); + + old_boost_score = boost_score; + } + + cpi->twopass.gf_decay_rate = + (i > 0) ? (int)(100.0 * (1.0 - decay_accumulator)) / i : 0; + + // When using CBR apply additional buffer related upper limits + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + double max_boost; + + // For cbr apply buffer related limits + if (cpi->drop_frames_allowed) + { + int df_buffer_level = cpi->oxcf.drop_frames_water_mark * + (cpi->oxcf.optimal_buffer_level / 100); + + if (cpi->buffer_level > df_buffer_level) + max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + else + max_boost = 0.0; + } + else if (cpi->buffer_level > 0) + { + max_boost = ((double)(cpi->buffer_level * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + } + else + { + max_boost = 0.0; + } + + if (boost_score > max_boost) + boost_score = max_boost; + } + + // Dont allow conventional gf too near the next kf + if ((cpi->twopass.frames_to_key - i) < MIN_GF_INTERVAL) + { + while (i < cpi->twopass.frames_to_key) + { + i++; + + if (EOF == input_stats(cpi, this_frame)) + break; + + if (i < cpi->twopass.frames_to_key) + { + mod_frame_err = calculate_modified_err(cpi, this_frame); + gf_group_err += mod_frame_err; + } + } + } + + cpi->gfu_boost = (int)(boost_score * 100.0) >> 4; + +#if NEW_BOOST + // Alterrnative boost calculation for alt ref + alt_boost = calc_arf_boost( cpi, 0, (i-1), (i-1), &f_boost, &b_boost ); +#endif + + // Should we use the alternate refernce frame + if (allow_alt_ref && + (i >= MIN_GF_INTERVAL) && + // dont use ARF very near next kf + (i <= (cpi->twopass.frames_to_key - MIN_GF_INTERVAL)) && +#if NEW_BOOST + ((next_frame.pcnt_inter > 0.75) || + (next_frame.pcnt_second_ref > 0.5)) && + ((mv_in_out_accumulator / (double)i > -0.2) || + (mv_in_out_accumulator > -2.0)) && + (b_boost > 100) && + (f_boost > 100) ) +#else + (next_frame.pcnt_inter > 0.75) && + ((mv_in_out_accumulator / (double)i > -0.2) || + (mv_in_out_accumulator > -2.0)) && + (cpi->gfu_boost > 100) && + (cpi->twopass.gf_decay_rate <= + (ARF_DECAY_THRESH + (cpi->gfu_boost / 200))) ) +#endif + { + int Boost; + int allocation_chunks; + int Q = (cpi->oxcf.fixed_q < 0) + ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int tmp_q; + int arf_frame_bits = 0; + int group_bits; + +#if NEW_BOOST + cpi->gfu_boost = alt_boost; +#endif + + // Estimate the bits to be allocated to the group as a whole + if ((cpi->twopass.kf_group_bits > 0) && + (cpi->twopass.kf_group_error_left > 0)) + { + group_bits = (int)((double)cpi->twopass.kf_group_bits * + (gf_group_err / (double)cpi->twopass.kf_group_error_left)); + } + else + group_bits = 0; + + // Boost for arf frame +#if NEW_BOOST + Boost = (alt_boost * GFQ_ADJUSTMENT) / 100; +#else + Boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); +#endif + Boost += (i * 50); + + // Set max and minimum boost and hence minimum allocation + if (Boost > ((cpi->baseline_gf_interval + 1) * 200)) + Boost = ((cpi->baseline_gf_interval + 1) * 200); + else if (Boost < 125) + Boost = 125; + + allocation_chunks = (i * 100) + Boost; + + // Normalize Altboost and allocations chunck down to prevent overflow + while (Boost > 1000) + { + Boost /= 2; + allocation_chunks /= 2; + } + + // Calculate the number of bits to be spent on the arf based on the + // boost number + arf_frame_bits = (int)((double)Boost * (group_bits / + (double)allocation_chunks)); + + // Estimate if there are enough bits available to make worthwhile use + // of an arf. + tmp_q = estimate_q(cpi, mod_frame_err, (int)arf_frame_bits); + + // Only use an arf if it is likely we will be able to code + // it at a lower Q than the surrounding frames. + if (tmp_q < cpi->worst_quality) + { + int half_gf_int; + int frames_after_arf; + int frames_bwd = cpi->oxcf.arnr_max_frames - 1; + int frames_fwd = cpi->oxcf.arnr_max_frames - 1; + + cpi->source_alt_ref_pending = 1; + + // For alt ref frames the error score for the end frame of the + // group (the alt ref frame) should not contribute to the group + // total and hence the number of bit allocated to the group. + // Rather it forms part of the next group (it is the GF at the + // start of the next group) + // gf_group_err -= mod_frame_err; + + // For alt ref frames alt ref frame is technically part of the + // GF frame for the next group but we always base the error + // calculation and bit allocation on the current group of frames. + + // Set the interval till the next gf or arf. + // For ARFs this is the number of frames to be coded before the + // future frame that is coded as an ARF. + // The future frame itself is part of the next group + cpi->baseline_gf_interval = i; + + // Define the arnr filter width for this group of frames: + // We only filter frames that lie within a distance of half + // the GF interval from the ARF frame. We also have to trap + // cases where the filter extends beyond the end of clip. + // Note: this_frame->frame has been updated in the loop + // so it now points at the ARF frame. + half_gf_int = cpi->baseline_gf_interval >> 1; + frames_after_arf = cpi->twopass.total_stats.count - + this_frame->frame - 1; + + switch (cpi->oxcf.arnr_type) + { + case 1: // Backward filter + frames_fwd = 0; + if (frames_bwd > half_gf_int) + frames_bwd = half_gf_int; + break; + + case 2: // Forward filter + if (frames_fwd > half_gf_int) + frames_fwd = half_gf_int; + if (frames_fwd > frames_after_arf) + frames_fwd = frames_after_arf; + frames_bwd = 0; + break; + + case 3: // Centered filter + default: + frames_fwd >>= 1; + if (frames_fwd > frames_after_arf) + frames_fwd = frames_after_arf; + if (frames_fwd > half_gf_int) + frames_fwd = half_gf_int; + + frames_bwd = frames_fwd; + + // For even length filter there is one more frame backward + // than forward: e.g. len=6 ==> bbbAff, len=7 ==> bbbAfff. + if (frames_bwd < half_gf_int) + frames_bwd += (cpi->oxcf.arnr_max_frames+1) & 0x1; + break; + } + + cpi->active_arnr_frames = frames_bwd + 1 + frames_fwd; + } + else + { + cpi->source_alt_ref_pending = 0; + cpi->baseline_gf_interval = i; + } + } + else + { + cpi->source_alt_ref_pending = 0; + cpi->baseline_gf_interval = i; + } + + // Now decide how many bits should be allocated to the GF group as a + // proportion of those remaining in the kf group. + // The final key frame group in the clip is treated as a special case + // where cpi->twopass.kf_group_bits is tied to cpi->twopass.bits_left. + // This is also important for short clips where there may only be one + // key frame. + if (cpi->twopass.frames_to_key >= (int)(cpi->twopass.total_stats.count - + cpi->common.current_video_frame)) + { + cpi->twopass.kf_group_bits = + (cpi->twopass.bits_left > 0) ? cpi->twopass.bits_left : 0; + } + + // Calculate the bits to be allocated to the group as a whole + if ((cpi->twopass.kf_group_bits > 0) && + (cpi->twopass.kf_group_error_left > 0)) + { + cpi->twopass.gf_group_bits = + (int)((double)cpi->twopass.kf_group_bits * + (gf_group_err / (double)cpi->twopass.kf_group_error_left)); + } + else + cpi->twopass.gf_group_bits = 0; + + cpi->twopass.gf_group_bits = + (cpi->twopass.gf_group_bits < 0) + ? 0 + : (cpi->twopass.gf_group_bits > cpi->twopass.kf_group_bits) + ? cpi->twopass.kf_group_bits : cpi->twopass.gf_group_bits; + + // Clip cpi->twopass.gf_group_bits based on user supplied data rate + // variability limit (cpi->oxcf.two_pass_vbrmax_section) + if (cpi->twopass.gf_group_bits > max_bits * cpi->baseline_gf_interval) + cpi->twopass.gf_group_bits = max_bits * cpi->baseline_gf_interval; + + // Reset the file position + reset_fpf_position(cpi, start_pos); + + // Update the record of error used so far (only done once per gf group) + cpi->twopass.modified_error_used += gf_group_err; + + // Assign bits to the arf or gf. + for (i = 0; i <= (cpi->source_alt_ref_pending && cpi->common.frame_type != KEY_FRAME); i++) { + int Boost; + int allocation_chunks; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int gf_bits; + + // For ARF frames + if (cpi->source_alt_ref_pending && i == 0) + { +#if NEW_BOOST + Boost = (alt_boost * GFQ_ADJUSTMENT) / 100; +#else + Boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); +#endif + Boost += (cpi->baseline_gf_interval * 50); + + // Set max and minimum boost and hence minimum allocation + if (Boost > ((cpi->baseline_gf_interval + 1) * 200)) + Boost = ((cpi->baseline_gf_interval + 1) * 200); + else if (Boost < 125) + Boost = 125; + + allocation_chunks = + ((cpi->baseline_gf_interval + 1) * 100) + Boost; + } + // Else for standard golden frames + else + { + // boost based on inter / intra ratio of subsequent frames + Boost = (cpi->gfu_boost * GFQ_ADJUSTMENT) / 100; + + // Set max and minimum boost and hence minimum allocation + if (Boost > (cpi->baseline_gf_interval * 150)) + Boost = (cpi->baseline_gf_interval * 150); + else if (Boost < 125) + Boost = 125; + + allocation_chunks = + (cpi->baseline_gf_interval * 100) + (Boost - 100); + } + + // Normalize Altboost and allocations chunck down to prevent overflow + while (Boost > 1000) + { + Boost /= 2; + allocation_chunks /= 2; + } + + // Calculate the number of bits to be spent on the gf or arf based on + // the boost number + gf_bits = (int)((double)Boost * + (cpi->twopass.gf_group_bits / + (double)allocation_chunks)); + + // If the frame that is to be boosted is simpler than the average for + // the gf/arf group then use an alternative calculation + // based on the error score of the frame itself + if (mod_frame_err < gf_group_err / (double)cpi->baseline_gf_interval) + { + double alt_gf_grp_bits; + int alt_gf_bits; + + alt_gf_grp_bits = + (double)cpi->twopass.kf_group_bits * + (mod_frame_err * (double)cpi->baseline_gf_interval) / + DOUBLE_DIVIDE_CHECK((double)cpi->twopass.kf_group_error_left); + + alt_gf_bits = (int)((double)Boost * (alt_gf_grp_bits / + (double)allocation_chunks)); + + if (gf_bits > alt_gf_bits) + { + gf_bits = alt_gf_bits; + } + } + // Else if it is harder than other frames in the group make sure it at + // least receives an allocation in keeping with its relative error + // score, otherwise it may be worse off than an "un-boosted" frame + else + { + int alt_gf_bits = + (int)((double)cpi->twopass.kf_group_bits * + mod_frame_err / + DOUBLE_DIVIDE_CHECK((double)cpi->twopass.kf_group_error_left)); + + if (alt_gf_bits > gf_bits) + { + gf_bits = alt_gf_bits; + } + } + + // Apply an additional limit for CBR + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + if (cpi->twopass.gf_bits > (cpi->buffer_level >> 1)) + cpi->twopass.gf_bits = cpi->buffer_level >> 1; + } + + // Dont allow a negative value for gf_bits + if (gf_bits < 0) + gf_bits = 0; + + gf_bits += cpi->min_frame_bandwidth; // Add in minimum for a frame + + if (i == 0) + { + cpi->twopass.gf_bits = gf_bits; + } + if (i == 1 || (!cpi->source_alt_ref_pending && (cpi->common.frame_type != KEY_FRAME))) + { + cpi->per_frame_bandwidth = gf_bits; // Per frame bit target for this frame + } + } + + { + // Adjust KF group bits and error remainin + cpi->twopass.kf_group_error_left -= gf_group_err; + cpi->twopass.kf_group_bits -= cpi->twopass.gf_group_bits; + + if (cpi->twopass.kf_group_bits < 0) + cpi->twopass.kf_group_bits = 0; + + // Note the error score left in the remaining frames of the group. + // For normal GFs we want to remove the error score for the first frame of the group (except in Key frame case where this has already happened) + if (!cpi->source_alt_ref_pending && cpi->common.frame_type != KEY_FRAME) + cpi->twopass.gf_group_error_left = gf_group_err - gf_first_frame_err; + else + cpi->twopass.gf_group_error_left = gf_group_err; + + cpi->twopass.gf_group_bits -= cpi->twopass.gf_bits - cpi->min_frame_bandwidth; + + if (cpi->twopass.gf_group_bits < 0) + cpi->twopass.gf_group_bits = 0; + + // This condition could fail if there are two kfs very close together + // despite (MIN_GF_INTERVAL) and would cause a devide by 0 in the + // calculation of cpi->twopass.alt_extra_bits. + if ( cpi->baseline_gf_interval >= 3 ) + { +#if NEW_BOOST + int boost = (cpi->source_alt_ref_pending) + ? b_boost : cpi->gfu_boost; +#else + int boost = cpi->gfu_boost; +#endif + if ( boost >= 150 ) + { + int pct_extra; + + pct_extra = (boost - 100) / 50; + pct_extra = (pct_extra > 20) ? 20 : pct_extra; + + cpi->twopass.alt_extra_bits = + (cpi->twopass.gf_group_bits * pct_extra) / 100; + cpi->twopass.gf_group_bits -= cpi->twopass.alt_extra_bits; + cpi->twopass.alt_extra_bits /= + ((cpi->baseline_gf_interval-1)>>1); + } + else + cpi->twopass.alt_extra_bits = 0; + } + else + cpi->twopass.alt_extra_bits = 0; + } + + // Adjustments based on a measure of complexity of the section + if (cpi->common.frame_type != KEY_FRAME) + { + FIRSTPASS_STATS sectionstats; + double Ratio; + + zero_stats(§ionstats); + reset_fpf_position(cpi, start_pos); + + for (i = 0 ; i < cpi->baseline_gf_interval ; i++) + { + input_stats(cpi, &next_frame); + accumulate_stats(§ionstats, &next_frame); + } + + avg_stats(§ionstats); + + cpi->twopass.section_intra_rating = + sectionstats.intra_error / + DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + + Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + //if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) ) + //{ + cpi->twopass.section_max_qfactor = 1.0 - ((Ratio - 10.0) * 0.025); + + if (cpi->twopass.section_max_qfactor < 0.80) + cpi->twopass.section_max_qfactor = 0.80; + + //} + //else + // cpi->twopass.section_max_qfactor = 1.0; + + reset_fpf_position(cpi, start_pos); + } +} + +// Allocate bits to a normal frame that is neither a gf an arf or a key frame. +static void assign_std_frame_bits(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + int target_frame_size; // gf_group_error_left + + double modified_err; + double err_fraction; // What portion of the remaining GF group error is used by this frame + + int max_bits = frame_max_bits(cpi); // Max for a single frame + + // Calculate modified prediction error used in bit allocation + modified_err = calculate_modified_err(cpi, this_frame); + + if (cpi->twopass.gf_group_error_left > 0) + err_fraction = modified_err / cpi->twopass.gf_group_error_left; // What portion of the remaining GF group error is used by this frame + else + err_fraction = 0.0; + + target_frame_size = (int)((double)cpi->twopass.gf_group_bits * err_fraction); // How many of those bits available for allocation should we give it? + + // Clip to target size to 0 - max_bits (or cpi->twopass.gf_group_bits) at the top end. + if (target_frame_size < 0) + target_frame_size = 0; + else + { + if (target_frame_size > max_bits) + target_frame_size = max_bits; + + if (target_frame_size > cpi->twopass.gf_group_bits) + target_frame_size = cpi->twopass.gf_group_bits; + } + + cpi->twopass.gf_group_error_left -= modified_err; // Adjust error remaining + cpi->twopass.gf_group_bits -= target_frame_size; // Adjust bits remaining + + if (cpi->twopass.gf_group_bits < 0) + cpi->twopass.gf_group_bits = 0; + + target_frame_size += cpi->min_frame_bandwidth; // Add in the minimum number of bits that is set aside for every frame. + + // Every other frame gets a few extra bits + if ( (cpi->common.frames_since_golden & 0x01) && + (cpi->frames_till_gf_update_due > 0) ) + { + target_frame_size += cpi->twopass.alt_extra_bits; + } + + cpi->per_frame_bandwidth = target_frame_size; // Per frame bit target for this frame +} + +void vp8_second_pass(VP8_COMP *cpi) +{ + int tmp_q; + int frames_left = (int)(cpi->twopass.total_stats.count - cpi->common.current_video_frame); + + FIRSTPASS_STATS this_frame = {0}; + FIRSTPASS_STATS this_frame_copy; + + double this_frame_intra_error; + double this_frame_coded_error; + + int overhead_bits; + + if (!cpi->twopass.stats_in) + { + return ; + } + + vp8_clear_system_state(); + + if (EOF == input_stats(cpi, &this_frame)) + return; + + this_frame_intra_error = this_frame.intra_error; + this_frame_coded_error = this_frame.coded_error; + + // keyframe and section processing ! + if (cpi->twopass.frames_to_key == 0) + { + // Define next KF group and assign bits to it + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + find_next_key_frame(cpi, &this_frame_copy); + + // Special case: Error error_resilient_mode mode does not make much sense for two pass but with its current meaning but this code is designed to stop + // outlandish behaviour if someone does set it when using two pass. It effectively disables GF groups. + // This is temporary code till we decide what should really happen in this case. + if (cpi->oxcf.error_resilient_mode) + { + cpi->twopass.gf_group_bits = cpi->twopass.kf_group_bits; + cpi->twopass.gf_group_error_left = cpi->twopass.kf_group_error_left; + cpi->baseline_gf_interval = cpi->twopass.frames_to_key; + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + cpi->source_alt_ref_pending = 0; + } + + } + + // Is this a GF / ARF (Note that a KF is always also a GF) + if (cpi->frames_till_gf_update_due == 0) + { + // Define next gf group and assign bits to it + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + define_gf_group(cpi, &this_frame_copy); + + // If we are going to code an altref frame at the end of the group and the current frame is not a key frame.... + // If the previous group used an arf this frame has already benefited from that arf boost and it should not be given extra bits + // If the previous group was NOT coded using arf we may want to apply some boost to this GF as well + if (cpi->source_alt_ref_pending && (cpi->common.frame_type != KEY_FRAME)) + { + // Assign a standard frames worth of bits from those allocated to the GF group + int bak = cpi->per_frame_bandwidth; + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); + cpi->per_frame_bandwidth = bak; + } + } + + // Otherwise this is an ordinary frame + else + { + // Special case: Error error_resilient_mode mode does not make much sense for two pass but with its current meaning but this code is designed to stop + // outlandish behaviour if someone does set it when using two pass. It effectively disables GF groups. + // This is temporary code till we decide what should really happen in this case. + if (cpi->oxcf.error_resilient_mode) + { + cpi->frames_till_gf_update_due = cpi->twopass.frames_to_key; + + if (cpi->common.frame_type != KEY_FRAME) + { + // Assign bits from those allocated to the GF group + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); + } + } + else + { + // Assign bits from those allocated to the GF group + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); + } + } + + // Keep a globally available copy of this and the next frame's iiratio. + cpi->twopass.this_iiratio = this_frame_intra_error / + DOUBLE_DIVIDE_CHECK(this_frame_coded_error); + { + FIRSTPASS_STATS next_frame; + if ( lookup_next_frame_stats(cpi, &next_frame) != EOF ) + { + cpi->twopass.next_iiratio = next_frame.intra_error / + DOUBLE_DIVIDE_CHECK(next_frame.coded_error); + } + } + + // Set nominal per second bandwidth for this frame + cpi->target_bandwidth = cpi->per_frame_bandwidth * cpi->output_frame_rate; + if (cpi->target_bandwidth < 0) + cpi->target_bandwidth = 0; + + + // Account for mv, mode and other overheads. + overhead_bits = estimate_modemvcost( + cpi, &cpi->twopass.total_left_stats ); + + // Special case code for first frame. + if (cpi->common.current_video_frame == 0) + { + cpi->twopass.est_max_qcorrection_factor = 1.0; + + // Set a cq_level in constrained quality mode. + if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY ) + { + int est_cq; + + est_cq = + estimate_cq( cpi, + &cpi->twopass.total_left_stats, + (int)(cpi->twopass.bits_left / frames_left), + overhead_bits ); + + cpi->cq_target_quality = cpi->oxcf.cq_level; + if ( est_cq > cpi->cq_target_quality ) + cpi->cq_target_quality = est_cq; + } + + // guess at maxq needed in 2nd pass + cpi->twopass.maxq_max_limit = cpi->worst_quality; + cpi->twopass.maxq_min_limit = cpi->best_quality; + + tmp_q = estimate_max_q( + cpi, + &cpi->twopass.total_left_stats, + (int)(cpi->twopass.bits_left / frames_left), + overhead_bits ); + + // Limit the maxq value returned subsequently. + // This increases the risk of overspend or underspend if the initial + // estimate for the clip is bad, but helps prevent excessive + // variation in Q, especially near the end of a clip + // where for example a small overspend may cause Q to crash + cpi->twopass.maxq_max_limit = ((tmp_q + 32) < cpi->worst_quality) + ? (tmp_q + 32) : cpi->worst_quality; + cpi->twopass.maxq_min_limit = ((tmp_q - 32) > cpi->best_quality) + ? (tmp_q - 32) : cpi->best_quality; + + cpi->active_worst_quality = tmp_q; + cpi->ni_av_qi = tmp_q; + } + + // The last few frames of a clip almost always have to few or too many + // bits and for the sake of over exact rate control we dont want to make + // radical adjustments to the allowed quantizer range just to use up a + // few surplus bits or get beneath the target rate. + else if ( (cpi->common.current_video_frame < + (((unsigned int)cpi->twopass.total_stats.count * 255)>>8)) && + ((cpi->common.current_video_frame + cpi->baseline_gf_interval) < + (unsigned int)cpi->twopass.total_stats.count) ) + { + if (frames_left < 1) + frames_left = 1; + + tmp_q = estimate_max_q( + cpi, + &cpi->twopass.total_left_stats, + (int)(cpi->twopass.bits_left / frames_left), + overhead_bits ); + + // Move active_worst_quality but in a damped way + if (tmp_q > cpi->active_worst_quality) + cpi->active_worst_quality ++; + else if (tmp_q < cpi->active_worst_quality) + cpi->active_worst_quality --; + + cpi->active_worst_quality = + ((cpi->active_worst_quality * 3) + tmp_q + 2) / 4; + } + + cpi->twopass.frames_to_key --; + + // Update the total stats remaining sturcture + subtract_stats(&cpi->twopass.total_left_stats, &this_frame ); +} + + +static int test_candidate_kf(VP8_COMP *cpi, FIRSTPASS_STATS *last_frame, FIRSTPASS_STATS *this_frame, FIRSTPASS_STATS *next_frame) +{ + int is_viable_kf = 0; + + // Does the frame satisfy the primary criteria of a key frame + // If so, then examine how well it predicts subsequent frames + if ((this_frame->pcnt_second_ref < 0.10) && + (next_frame->pcnt_second_ref < 0.10) && + ((this_frame->pcnt_inter < 0.05) || + ( + ((this_frame->pcnt_inter - this_frame->pcnt_neutral) < .25) && + ((this_frame->intra_error / DOUBLE_DIVIDE_CHECK(this_frame->coded_error)) < 2.5) && + ((fabs(last_frame->coded_error - this_frame->coded_error) / DOUBLE_DIVIDE_CHECK(this_frame->coded_error) > .40) || + (fabs(last_frame->intra_error - this_frame->intra_error) / DOUBLE_DIVIDE_CHECK(this_frame->intra_error) > .40) || + ((next_frame->intra_error / DOUBLE_DIVIDE_CHECK(next_frame->coded_error)) > 3.5) + ) + ) + ) + ) + { + int i; + FIRSTPASS_STATS *start_pos; + + FIRSTPASS_STATS local_next_frame; + + double boost_score = 0.0; + double old_boost_score = 0.0; + double decay_accumulator = 1.0; + double next_iiratio; + + vpx_memcpy(&local_next_frame, next_frame, sizeof(*next_frame)); + + // Note the starting file position so we can reset to it + start_pos = cpi->twopass.stats_in; + + // Examine how well the key frame predicts subsequent frames + for (i = 0 ; i < 16; i++) + { + next_iiratio = (IIKFACTOR1 * local_next_frame.intra_error / DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error)) ; + + if (next_iiratio > RMAX) + next_iiratio = RMAX; + + // Cumulative effect of decay in prediction quality + if (local_next_frame.pcnt_inter > 0.85) + decay_accumulator = decay_accumulator * local_next_frame.pcnt_inter; + else + decay_accumulator = decay_accumulator * ((0.85 + local_next_frame.pcnt_inter) / 2.0); + + //decay_accumulator = decay_accumulator * local_next_frame.pcnt_inter; + + // Keep a running total + boost_score += (decay_accumulator * next_iiratio); + + // Test various breakout clauses + if ((local_next_frame.pcnt_inter < 0.05) || + (next_iiratio < 1.5) || + (((local_next_frame.pcnt_inter - + local_next_frame.pcnt_neutral) < 0.20) && + (next_iiratio < 3.0)) || + ((boost_score - old_boost_score) < 0.5) || + (local_next_frame.intra_error < 200) + ) + { + break; + } + + old_boost_score = boost_score; + + // Get the next frame details + if (EOF == input_stats(cpi, &local_next_frame)) + break; + } + + // If there is tolerable prediction for at least the next 3 frames then break out else discard this pottential key frame and move on + if (boost_score > 5.0 && (i > 3)) + is_viable_kf = 1; + else + { + // Reset the file position + reset_fpf_position(cpi, start_pos); + + is_viable_kf = 0; + } + } + + return is_viable_kf; +} +static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + int i,j; + FIRSTPASS_STATS last_frame; + FIRSTPASS_STATS first_frame; + FIRSTPASS_STATS next_frame; + FIRSTPASS_STATS *start_position; + + double decay_accumulator = 1.0; + double boost_score = 0; + double old_boost_score = 0.0; + double loop_decay_rate; + + double kf_mod_err = 0.0; + double kf_group_err = 0.0; + double kf_group_intra_err = 0.0; + double kf_group_coded_err = 0.0; + double recent_loop_decay[8] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0}; + + vpx_memset(&next_frame, 0, sizeof(next_frame)); // assure clean + + vp8_clear_system_state(); //__asm emms; + start_position = cpi->twopass.stats_in; + + cpi->common.frame_type = KEY_FRAME; + + // is this a forced key frame by interval + cpi->this_key_frame_forced = cpi->next_key_frame_forced; + + // Clear the alt ref active flag as this can never be active on a key frame + cpi->source_alt_ref_active = 0; + + // Kf is always a gf so clear frames till next gf counter + cpi->frames_till_gf_update_due = 0; + + cpi->twopass.frames_to_key = 1; + + // Take a copy of the initial frame details + vpx_memcpy(&first_frame, this_frame, sizeof(*this_frame)); + + cpi->twopass.kf_group_bits = 0; // Total bits avaialable to kf group + cpi->twopass.kf_group_error_left = 0; // Group modified error score. + + kf_mod_err = calculate_modified_err(cpi, this_frame); + + // find the next keyframe + i = 0; + while (cpi->twopass.stats_in < cpi->twopass.stats_in_end) + { + // Accumulate kf group error + kf_group_err += calculate_modified_err(cpi, this_frame); + + // These figures keep intra and coded error counts for all frames including key frames in the group. + // The effect of the key frame itself can be subtracted out using the first_frame data collected above + kf_group_intra_err += this_frame->intra_error; + kf_group_coded_err += this_frame->coded_error; + + // load a the next frame's stats + vpx_memcpy(&last_frame, this_frame, sizeof(*this_frame)); + input_stats(cpi, this_frame); + + // Provided that we are not at the end of the file... + if (cpi->oxcf.auto_key + && lookup_next_frame_stats(cpi, &next_frame) != EOF) + { + // Normal scene cut check + if ( ( i >= MIN_GF_INTERVAL ) && + test_candidate_kf(cpi, &last_frame, this_frame, &next_frame) ) + { + break; + } + + // How fast is prediction quality decaying + loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); + + // We want to know something about the recent past... rather than + // as used elsewhere where we are concened with decay in prediction + // quality since the last GF or KF. + recent_loop_decay[i%8] = loop_decay_rate; + decay_accumulator = 1.0; + for (j = 0; j < 8; j++) + { + decay_accumulator = decay_accumulator * recent_loop_decay[j]; + } + + // Special check for transition or high motion followed by a + // to a static scene. + if ( detect_transition_to_still( cpi, i, + (cpi->key_frame_frequency-i), + loop_decay_rate, + decay_accumulator ) ) + { + break; + } + + + // Step on to the next frame + cpi->twopass.frames_to_key ++; + + // If we don't have a real key frame within the next two + // forcekeyframeevery intervals then break out of the loop. + if (cpi->twopass.frames_to_key >= 2 *(int)cpi->key_frame_frequency) + break; + } else + cpi->twopass.frames_to_key ++; + + i++; + } + + // If there is a max kf interval set by the user we must obey it. + // We already breakout of the loop above at 2x max. + // This code centers the extra kf if the actual natural + // interval is between 1x and 2x + if (cpi->oxcf.auto_key + && cpi->twopass.frames_to_key > (int)cpi->key_frame_frequency ) + { + FIRSTPASS_STATS *current_pos = cpi->twopass.stats_in; + FIRSTPASS_STATS tmp_frame; + + cpi->twopass.frames_to_key /= 2; + + // Copy first frame details + vpx_memcpy(&tmp_frame, &first_frame, sizeof(first_frame)); + + // Reset to the start of the group + reset_fpf_position(cpi, start_position); + + kf_group_err = 0; + kf_group_intra_err = 0; + kf_group_coded_err = 0; + + // Rescan to get the correct error data for the forced kf group + for( i = 0; i < cpi->twopass.frames_to_key; i++ ) + { + // Accumulate kf group errors + kf_group_err += calculate_modified_err(cpi, &tmp_frame); + kf_group_intra_err += tmp_frame.intra_error; + kf_group_coded_err += tmp_frame.coded_error; + + // Load a the next frame's stats + input_stats(cpi, &tmp_frame); + } + + // Reset to the start of the group + reset_fpf_position(cpi, current_pos); + + cpi->next_key_frame_forced = 1; + } + else + cpi->next_key_frame_forced = 0; + + // Special case for the last frame of the file + if (cpi->twopass.stats_in >= cpi->twopass.stats_in_end) + { + // Accumulate kf group error + kf_group_err += calculate_modified_err(cpi, this_frame); + + // These figures keep intra and coded error counts for all frames including key frames in the group. + // The effect of the key frame itself can be subtracted out using the first_frame data collected above + kf_group_intra_err += this_frame->intra_error; + kf_group_coded_err += this_frame->coded_error; + } + + // Calculate the number of bits that should be assigned to the kf group. + if ((cpi->twopass.bits_left > 0) && (cpi->twopass.modified_error_left > 0.0)) + { + // Max for a single normal frame (not key frame) + int max_bits = frame_max_bits(cpi); + + // Maximum bits for the kf group + int64_t max_grp_bits; + + // Default allocation based on bits left and relative + // complexity of the section + cpi->twopass.kf_group_bits = (int64_t)( cpi->twopass.bits_left * + ( kf_group_err / + cpi->twopass.modified_error_left )); + + // Clip based on maximum per frame rate defined by the user. + max_grp_bits = (int64_t)max_bits * (int64_t)cpi->twopass.frames_to_key; + if (cpi->twopass.kf_group_bits > max_grp_bits) + cpi->twopass.kf_group_bits = max_grp_bits; + + // Additional special case for CBR if buffer is getting full. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + int opt_buffer_lvl = cpi->oxcf.optimal_buffer_level; + int buffer_lvl = cpi->buffer_level; + + // If the buffer is near or above the optimal and this kf group is + // not being allocated much then increase the allocation a bit. + if (buffer_lvl >= opt_buffer_lvl) + { + int high_water_mark = (opt_buffer_lvl + + cpi->oxcf.maximum_buffer_size) >> 1; + + int64_t av_group_bits; + + // Av bits per frame * number of frames + av_group_bits = (int64_t)cpi->av_per_frame_bandwidth * + (int64_t)cpi->twopass.frames_to_key; + + // We are at or above the maximum. + if (cpi->buffer_level >= high_water_mark) + { + int64_t min_group_bits; + + min_group_bits = av_group_bits + + (int64_t)(buffer_lvl - + high_water_mark); + + if (cpi->twopass.kf_group_bits < min_group_bits) + cpi->twopass.kf_group_bits = min_group_bits; + } + // We are above optimal but below the maximum + else if (cpi->twopass.kf_group_bits < av_group_bits) + { + int64_t bits_below_av = av_group_bits - + cpi->twopass.kf_group_bits; + + cpi->twopass.kf_group_bits += + (int64_t)((double)bits_below_av * + (double)(buffer_lvl - opt_buffer_lvl) / + (double)(high_water_mark - opt_buffer_lvl)); + } + } + } + } + else + cpi->twopass.kf_group_bits = 0; + + // Reset the first pass file position + reset_fpf_position(cpi, start_position); + + // determine how big to make this keyframe based on how well the subsequent frames use inter blocks + decay_accumulator = 1.0; + boost_score = 0.0; + loop_decay_rate = 1.00; // Starting decay rate + + for (i = 0 ; i < cpi->twopass.frames_to_key ; i++) + { + double r; + + if (EOF == input_stats(cpi, &next_frame)) + break; + + if (next_frame.intra_error > cpi->twopass.kf_intra_err_min) + r = (IIKFACTOR2 * next_frame.intra_error / + DOUBLE_DIVIDE_CHECK(next_frame.coded_error)); + else + r = (IIKFACTOR2 * cpi->twopass.kf_intra_err_min / + DOUBLE_DIVIDE_CHECK(next_frame.coded_error)); + + if (r > RMAX) + r = RMAX; + + // How fast is prediction quality decaying + loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); + + decay_accumulator = decay_accumulator * loop_decay_rate; + decay_accumulator = decay_accumulator < 0.1 ? 0.1 : decay_accumulator; + + boost_score += (decay_accumulator * r); + + if ((i > MIN_GF_INTERVAL) && + ((boost_score - old_boost_score) < 1.0)) + { + break; + } + + old_boost_score = boost_score; + } + + if (1) + { + FIRSTPASS_STATS sectionstats; + double Ratio; + + zero_stats(§ionstats); + reset_fpf_position(cpi, start_position); + + for (i = 0 ; i < cpi->twopass.frames_to_key ; i++) + { + input_stats(cpi, &next_frame); + accumulate_stats(§ionstats, &next_frame); + } + + avg_stats(§ionstats); + + cpi->twopass.section_intra_rating = + sectionstats.intra_error + / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + + Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + // if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) ) + //{ + cpi->twopass.section_max_qfactor = 1.0 - ((Ratio - 10.0) * 0.025); + + if (cpi->twopass.section_max_qfactor < 0.80) + cpi->twopass.section_max_qfactor = 0.80; + + //} + //else + // cpi->twopass.section_max_qfactor = 1.0; + } + + // When using CBR apply additional buffer fullness related upper limits + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + double max_boost; + + if (cpi->drop_frames_allowed) + { + int df_buffer_level = cpi->oxcf.drop_frames_water_mark * (cpi->oxcf.optimal_buffer_level / 100); + + if (cpi->buffer_level > df_buffer_level) + max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + else + max_boost = 0.0; + } + else if (cpi->buffer_level > 0) + { + max_boost = ((double)(cpi->buffer_level * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + } + else + { + max_boost = 0.0; + } + + if (boost_score > max_boost) + boost_score = max_boost; + } + + // Reset the first pass file position + reset_fpf_position(cpi, start_position); + + // Work out how many bits to allocate for the key frame itself + if (1) + { + int kf_boost = boost_score; + int allocation_chunks; + int Counter = cpi->twopass.frames_to_key; + int alt_kf_bits; + YV12_BUFFER_CONFIG *lst_yv12 = &cpi->common.yv12_fb[cpi->common.lst_fb_idx]; + // Min boost based on kf interval +#if 0 + + while ((kf_boost < 48) && (Counter > 0)) + { + Counter -= 2; + kf_boost ++; + } + +#endif + + if (kf_boost < 48) + { + kf_boost += ((Counter + 1) >> 1); + + if (kf_boost > 48) kf_boost = 48; + } + + // bigger frame sizes need larger kf boosts, smaller frames smaller boosts... + if ((lst_yv12->y_width * lst_yv12->y_height) > (320 * 240)) + kf_boost += 2 * (lst_yv12->y_width * lst_yv12->y_height) / (320 * 240); + else if ((lst_yv12->y_width * lst_yv12->y_height) < (320 * 240)) + kf_boost -= 4 * (320 * 240) / (lst_yv12->y_width * lst_yv12->y_height); + + kf_boost = (int)((double)kf_boost * 100.0) >> 4; // Scale 16 to 100 + + // Adjustment to boost based on recent average q + //kf_boost = kf_boost * vp8_kf_boost_qadjustment[cpi->ni_av_qi] / 100; + + if (kf_boost < 250) // Min KF boost + kf_boost = 250; + + // We do three calculations for kf size. + // The first is based on the error score for the whole kf group. + // The second (optionaly) on the key frames own error if this is + // smaller than the average for the group. + // The final one insures that the frame receives at least the + // allocation it would have received based on its own error score vs + // the error score remaining + // Special case if the sequence appears almost totaly static + // as measured by the decay accumulator. In this case we want to + // spend almost all of the bits on the key frame. + // cpi->twopass.frames_to_key-1 because key frame itself is taken + // care of by kf_boost. + if ( decay_accumulator >= 0.99 ) + { + allocation_chunks = + ((cpi->twopass.frames_to_key - 1) * 10) + kf_boost; + } + else + { + allocation_chunks = + ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost; + } + + // Normalize Altboost and allocations chunck down to prevent overflow + while (kf_boost > 1000) + { + kf_boost /= 2; + allocation_chunks /= 2; + } + + cpi->twopass.kf_group_bits = (cpi->twopass.kf_group_bits < 0) ? 0 : cpi->twopass.kf_group_bits; + + // Calculate the number of bits to be spent on the key frame + cpi->twopass.kf_bits = (int)((double)kf_boost * ((double)cpi->twopass.kf_group_bits / (double)allocation_chunks)); + + // Apply an additional limit for CBR + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + if (cpi->twopass.kf_bits > ((3 * cpi->buffer_level) >> 2)) + cpi->twopass.kf_bits = (3 * cpi->buffer_level) >> 2; + } + + // If the key frame is actually easier than the average for the + // kf group (which does sometimes happen... eg a blank intro frame) + // Then use an alternate calculation based on the kf error score + // which should give a smaller key frame. + if (kf_mod_err < kf_group_err / cpi->twopass.frames_to_key) + { + double alt_kf_grp_bits = + ((double)cpi->twopass.bits_left * + (kf_mod_err * (double)cpi->twopass.frames_to_key) / + DOUBLE_DIVIDE_CHECK(cpi->twopass.modified_error_left)); + + alt_kf_bits = (int)((double)kf_boost * + (alt_kf_grp_bits / (double)allocation_chunks)); + + if (cpi->twopass.kf_bits > alt_kf_bits) + { + cpi->twopass.kf_bits = alt_kf_bits; + } + } + // Else if it is much harder than other frames in the group make sure + // it at least receives an allocation in keeping with its relative + // error score + else + { + alt_kf_bits = + (int)((double)cpi->twopass.bits_left * + (kf_mod_err / + DOUBLE_DIVIDE_CHECK(cpi->twopass.modified_error_left))); + + if (alt_kf_bits > cpi->twopass.kf_bits) + { + cpi->twopass.kf_bits = alt_kf_bits; + } + } + + cpi->twopass.kf_group_bits -= cpi->twopass.kf_bits; + cpi->twopass.kf_bits += cpi->min_frame_bandwidth; // Add in the minimum frame allowance + + cpi->per_frame_bandwidth = cpi->twopass.kf_bits; // Peer frame bit target for this frame + cpi->target_bandwidth = cpi->twopass.kf_bits * cpi->output_frame_rate; // Convert to a per second bitrate + } + + // Note the total error score of the kf group minus the key frame itself + cpi->twopass.kf_group_error_left = (int)(kf_group_err - kf_mod_err); + + // Adjust the count of total modified error left. + // The count of bits left is adjusted elsewhere based on real coded frame sizes + cpi->twopass.modified_error_left -= kf_group_err; + + if (cpi->oxcf.allow_spatial_resampling) + { + int resample_trigger = 0; + int last_kf_resampled = 0; + int kf_q; + int scale_val = 0; + int hr, hs, vr, vs; + int new_width = cpi->oxcf.Width; + int new_height = cpi->oxcf.Height; + + int projected_buffer_level = cpi->buffer_level; + int tmp_q; + + double projected_bits_perframe; + double group_iiratio = (kf_group_intra_err - first_frame.intra_error) / (kf_group_coded_err - first_frame.coded_error); + double err_per_frame = kf_group_err / cpi->twopass.frames_to_key; + double bits_per_frame; + double av_bits_per_frame; + double effective_size_ratio; + + if ((cpi->common.Width != cpi->oxcf.Width) || (cpi->common.Height != cpi->oxcf.Height)) + last_kf_resampled = 1; + + // Set back to unscaled by defaults + cpi->common.horiz_scale = NORMAL; + cpi->common.vert_scale = NORMAL; + + // Calculate Average bits per frame. + //av_bits_per_frame = cpi->twopass.bits_left/(double)(cpi->twopass.total_stats.count - cpi->common.current_video_frame); + av_bits_per_frame = cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->frame_rate); + //if ( av_bits_per_frame < 0.0 ) + // av_bits_per_frame = 0.0 + + // CBR... Use the clip average as the target for deciding resample + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + bits_per_frame = av_bits_per_frame; + } + + // In VBR we want to avoid downsampling in easy section unless we are under extreme pressure + // So use the larger of target bitrate for this sectoion or average bitrate for sequence + else + { + bits_per_frame = cpi->twopass.kf_group_bits / cpi->twopass.frames_to_key; // This accounts for how hard the section is... + + if (bits_per_frame < av_bits_per_frame) // Dont turn to resampling in easy sections just because they have been assigned a small number of bits + bits_per_frame = av_bits_per_frame; + } + + // bits_per_frame should comply with our minimum + if (bits_per_frame < (cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100)) + bits_per_frame = (cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + + // Work out if spatial resampling is necessary + kf_q = estimate_kf_group_q(cpi, err_per_frame, bits_per_frame, group_iiratio); + + // If we project a required Q higher than the maximum allowed Q then make a guess at the actual size of frames in this section + projected_bits_perframe = bits_per_frame; + tmp_q = kf_q; + + while (tmp_q > cpi->worst_quality) + { + projected_bits_perframe *= 1.04; + tmp_q--; + } + + // Guess at buffer level at the end of the section + projected_buffer_level = cpi->buffer_level - (int)((projected_bits_perframe - av_bits_per_frame) * cpi->twopass.frames_to_key); + + if (0) + { + FILE *f = fopen("Subsamle.stt", "a"); + fprintf(f, " %8d %8d %8d %8d %12.0f %8d %8d %8d\n", cpi->common.current_video_frame, kf_q, cpi->common.horiz_scale, cpi->common.vert_scale, kf_group_err / cpi->twopass.frames_to_key, (int)(cpi->twopass.kf_group_bits / cpi->twopass.frames_to_key), new_height, new_width); + fclose(f); + } + + // The trigger for spatial resampling depends on the various parameters such as whether we are streaming (CBR) or VBR. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // Trigger resample if we are projected to fall below down sample level or + // resampled last time and are projected to remain below the up sample level + if ((projected_buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100)) || + (last_kf_resampled && (projected_buffer_level < (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100)))) + //( ((cpi->buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100))) && + // ((projected_buffer_level < (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100))) )) + resample_trigger = 1; + else + resample_trigger = 0; + } + else + { + int64_t clip_bits = (int64_t)(cpi->twopass.total_stats.count * cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->frame_rate)); + int64_t over_spend = cpi->oxcf.starting_buffer_level - cpi->buffer_level; + + if ((last_kf_resampled && (kf_q > cpi->worst_quality)) || // If triggered last time the threshold for triggering again is reduced + ((kf_q > cpi->worst_quality) && // Projected Q higher than allowed and ... + (over_spend > clip_bits / 20))) // ... Overspend > 5% of total bits + resample_trigger = 1; + else + resample_trigger = 0; + + } + + if (resample_trigger) + { + while ((kf_q >= cpi->worst_quality) && (scale_val < 6)) + { + scale_val ++; + + cpi->common.vert_scale = vscale_lookup[scale_val]; + cpi->common.horiz_scale = hscale_lookup[scale_val]; + + Scale2Ratio(cpi->common.horiz_scale, &hr, &hs); + Scale2Ratio(cpi->common.vert_scale, &vr, &vs); + + new_width = ((hs - 1) + (cpi->oxcf.Width * hr)) / hs; + new_height = ((vs - 1) + (cpi->oxcf.Height * vr)) / vs; + + // Reducing the area to 1/4 does not reduce the complexity (err_per_frame) to 1/4... + // effective_sizeratio attempts to provide a crude correction for this + effective_size_ratio = (double)(new_width * new_height) / (double)(cpi->oxcf.Width * cpi->oxcf.Height); + effective_size_ratio = (1.0 + (3.0 * effective_size_ratio)) / 4.0; + + // Now try again and see what Q we get with the smaller image size + kf_q = estimate_kf_group_q(cpi, err_per_frame * effective_size_ratio, bits_per_frame, group_iiratio); + + if (0) + { + FILE *f = fopen("Subsamle.stt", "a"); + fprintf(f, "******** %8d %8d %8d %12.0f %8d %8d %8d\n", kf_q, cpi->common.horiz_scale, cpi->common.vert_scale, kf_group_err / cpi->twopass.frames_to_key, (int)(cpi->twopass.kf_group_bits / cpi->twopass.frames_to_key), new_height, new_width); + fclose(f); + } + } + } + + if ((cpi->common.Width != new_width) || (cpi->common.Height != new_height)) + { + cpi->common.Width = new_width; + cpi->common.Height = new_height; + vp8_alloc_compressor_data(cpi); + } + } +} diff --git a/vp8/encoder/firstpass.h b/vp8/encoder/firstpass.h new file mode 100644 index 0000000..95e1e54 --- /dev/null +++ b/vp8/encoder/firstpass.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#if !defined __INC_FIRSTPASS_H +#define __INC_FIRSTPASS_H + +extern void vp8_init_first_pass(VP8_COMP *cpi); +extern void vp8_first_pass(VP8_COMP *cpi); +extern void vp8_end_first_pass(VP8_COMP *cpi); + +extern void vp8_init_second_pass(VP8_COMP *cpi); +extern void vp8_second_pass(VP8_COMP *cpi); +extern void vp8_end_second_pass(VP8_COMP *cpi); + +extern size_t vp8_firstpass_stats_sz(unsigned int mb_count); +#endif diff --git a/vp8/encoder/lookahead.c b/vp8/encoder/lookahead.c new file mode 100644 index 0000000..4c92281 --- /dev/null +++ b/vp8/encoder/lookahead.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include +#include +#include "vpx_config.h" +#include "lookahead.h" +#include "vp8/common/extend.h" + +#define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY? 1 : 25) + +struct lookahead_ctx +{ + unsigned int max_sz; /* Absolute size of the queue */ + unsigned int sz; /* Number of buffers currently in the queue */ + unsigned int read_idx; /* Read index */ + unsigned int write_idx; /* Write index */ + struct lookahead_entry *buf; /* Buffer list */ +}; + + +/* Return the buffer at the given absolute index and increment the index */ +static struct lookahead_entry * +pop(struct lookahead_ctx *ctx, + unsigned int *idx) +{ + unsigned int index = *idx; + struct lookahead_entry *buf = ctx->buf + index; + + assert(index < ctx->max_sz); + if(++index >= ctx->max_sz) + index -= ctx->max_sz; + *idx = index; + return buf; +} + + +void +vp8_lookahead_destroy(struct lookahead_ctx *ctx) +{ + if(ctx) + { + if(ctx->buf) + { + unsigned int i; + + for(i = 0; i < ctx->max_sz; i++) + vp8_yv12_de_alloc_frame_buffer(&ctx->buf[i].img); + free(ctx->buf); + } + free(ctx); + } +} + + +struct lookahead_ctx* +vp8_lookahead_init(unsigned int width, + unsigned int height, + unsigned int depth) +{ + struct lookahead_ctx *ctx = NULL; + unsigned int i; + + /* Clamp the lookahead queue depth */ + if(depth < 1) + depth = 1; + else if(depth > MAX_LAG_BUFFERS) + depth = MAX_LAG_BUFFERS; + + /* Keep last frame in lookahead buffer by increasing depth by 1.*/ + depth += 1; + + /* Align the buffer dimensions */ + width = (width + 15) & ~15; + height = (height + 15) & ~15; + + /* Allocate the lookahead structures */ + ctx = calloc(1, sizeof(*ctx)); + if(ctx) + { + ctx->max_sz = depth; + ctx->buf = calloc(depth, sizeof(*ctx->buf)); + if(!ctx->buf) + goto bail; + for(i=0; ibuf[i].img, + width, height, VP8BORDERINPIXELS)) + goto bail; + } + return ctx; +bail: + vp8_lookahead_destroy(ctx); + return NULL; +} + + +int +vp8_lookahead_push(struct lookahead_ctx *ctx, + YV12_BUFFER_CONFIG *src, + int64_t ts_start, + int64_t ts_end, + unsigned int flags, + unsigned char *active_map) +{ + struct lookahead_entry* buf; + int row, col, active_end; + int mb_rows = (src->y_height + 15) >> 4; + int mb_cols = (src->y_width + 15) >> 4; + + if(ctx->sz + 2 > ctx->max_sz) + return 1; + ctx->sz++; + buf = pop(ctx, &ctx->write_idx); + + // Only do this partial copy if the following conditions are all met: + // 1. Lookahead queue has has size of 1. + // 2. Active map is provided. + // 3. This is not a key frame, golden nor altref frame. + if (ctx->max_sz == 1 && active_map && !flags) + { + for (row = 0; row < mb_rows; ++row) + { + col = 0; + + while (1) + { + // Find the first active macroblock in this row. + for (; col < mb_cols; ++col) + { + if (active_map[col]) + break; + } + + // No more active macroblock in this row. + if (col == mb_cols) + break; + + // Find the end of active region in this row. + active_end = col; + + for (; active_end < mb_cols; ++active_end) + { + if (!active_map[active_end]) + break; + } + + // Only copy this active region. + vp8_copy_and_extend_frame_with_rect(src, &buf->img, + row << 4, + col << 4, 16, + (active_end - col) << 4); + + // Start again from the end of this active region. + col = active_end; + } + + active_map += mb_cols; + } + } + else + { + vp8_copy_and_extend_frame(src, &buf->img); + } + buf->ts_start = ts_start; + buf->ts_end = ts_end; + buf->flags = flags; + return 0; +} + + +struct lookahead_entry* +vp8_lookahead_pop(struct lookahead_ctx *ctx, + int drain) +{ + struct lookahead_entry* buf = NULL; + + if(ctx->sz && (drain || ctx->sz == ctx->max_sz - 1)) + { + buf = pop(ctx, &ctx->read_idx); + ctx->sz--; + } + return buf; +} + + +struct lookahead_entry* +vp8_lookahead_peek(struct lookahead_ctx *ctx, + unsigned int index, + int direction) +{ + struct lookahead_entry* buf = NULL; + + if (direction == PEEK_FORWARD) + { + assert(index < ctx->max_sz - 1); + if(index < ctx->sz) + { + index += ctx->read_idx; + if(index >= ctx->max_sz) + index -= ctx->max_sz; + buf = ctx->buf + index; + } + } + else if (direction == PEEK_BACKWARD) + { + assert(index == 1); + + if(ctx->read_idx == 0) + index = ctx->max_sz - 1; + else + index = ctx->read_idx - index; + buf = ctx->buf + index; + } + + return buf; +} + + +unsigned int +vp8_lookahead_depth(struct lookahead_ctx *ctx) +{ + return ctx->sz; +} diff --git a/vp8/encoder/lookahead.h b/vp8/encoder/lookahead.h new file mode 100644 index 0000000..cf56b75 --- /dev/null +++ b/vp8/encoder/lookahead.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef LOOKAHEAD_H +#define LOOKAHEAD_H +#include "vpx_scale/yv12config.h" +#include "vpx/vpx_integer.h" + +struct lookahead_entry +{ + YV12_BUFFER_CONFIG img; + int64_t ts_start; + int64_t ts_end; + unsigned int flags; +}; + + +struct lookahead_ctx; + +/**\brief Initializes the lookahead stage + * + * The lookahead stage is a queue of frame buffers on which some analysis + * may be done when buffers are enqueued. + * + * + */ +struct lookahead_ctx* vp8_lookahead_init(unsigned int width, + unsigned int height, + unsigned int depth + ); + + +/**\brief Destroys the lookahead stage + * + */ +void vp8_lookahead_destroy(struct lookahead_ctx *ctx); + + +/**\brief Enqueue a source buffer + * + * This function will copy the source image into a new framebuffer with + * the expected stride/border. + * + * If active_map is non-NULL and there is only one frame in the queue, then copy + * only active macroblocks. + * + * \param[in] ctx Pointer to the lookahead context + * \param[in] src Pointer to the image to enqueue + * \param[in] ts_start Timestamp for the start of this frame + * \param[in] ts_end Timestamp for the end of this frame + * \param[in] flags Flags set on this frame + * \param[in] active_map Map that specifies which macroblock is active + */ +int +vp8_lookahead_push(struct lookahead_ctx *ctx, + YV12_BUFFER_CONFIG *src, + int64_t ts_start, + int64_t ts_end, + unsigned int flags, + unsigned char *active_map); + + +/**\brief Get the next source buffer to encode + * + * + * \param[in] ctx Pointer to the lookahead context + * \param[in] drain Flag indicating the buffer should be drained + * (return a buffer regardless of the current queue depth) + * + * \retval NULL, if drain set and queue is empty + * \retval NULL, if drain not set and queue not of the configured depth + * + */ +struct lookahead_entry* +vp8_lookahead_pop(struct lookahead_ctx *ctx, + int drain); + + +#define PEEK_FORWARD 1 +#define PEEK_BACKWARD -1 +/**\brief Get a future source buffer to encode + * + * \param[in] ctx Pointer to the lookahead context + * \param[in] index Index of the frame to be returned, 0 == next frame + * + * \retval NULL, if no buffer exists at the specified index + * + */ +struct lookahead_entry* +vp8_lookahead_peek(struct lookahead_ctx *ctx, + unsigned int index, + int direction); + + +/**\brief Get the number of frames currently in the lookahead queue + * + * \param[in] ctx Pointer to the lookahead context + */ +unsigned int +vp8_lookahead_depth(struct lookahead_ctx *ctx); + + +#endif diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c new file mode 100644 index 0000000..67e4f7e --- /dev/null +++ b/vp8/encoder/mcomp.c @@ -0,0 +1,2003 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "onyx_int.h" +#include "mcomp.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_config.h" +#include +#include +#include +#include "vp8/common/findnearmv.h" + +#ifdef ENTROPY_STATS +static int mv_ref_ct [31] [4] [2]; +static int mv_mode_cts [4] [2]; +#endif + +int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight) +{ + // MV costing is based on the distribution of vectors in the previous frame and as such will tend to + // over state the cost of vectors. In addition coding a new vector can have a knock on effect on the + // cost of subsequent vectors and the quality of prediction from NEAR and NEAREST for subsequent blocks. + // The "Weight" parameter allows, to a limited extent, for some account to be taken of these factors. + return ((mvcost[0][(mv->as_mv.row - ref->as_mv.row) >> 1] + mvcost[1][(mv->as_mv.col - ref->as_mv.col) >> 1]) * Weight) >> 7; +} + +static int mv_err_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int error_per_bit) +{ + return ((mvcost[0][(mv->as_mv.row - ref->as_mv.row) >> 1] + + mvcost[1][(mv->as_mv.col - ref->as_mv.col) >> 1]) + * error_per_bit + 128) >> 8; +} + +static int mvsad_err_cost(int_mv *mv, int_mv *ref, int *mvsadcost[2], int error_per_bit) +{ + /* Calculate sad error cost on full pixel basis. */ + return ((mvsadcost[0][(mv->as_mv.row - ref->as_mv.row)] + + mvsadcost[1][(mv->as_mv.col - ref->as_mv.col)]) + * error_per_bit + 128) >> 8; +} + +void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride) +{ + int Len; + int search_site_count = 0; + + + // Generate offsets for 4 search sites per step. + Len = MAX_FIRST_STEP; + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = 0; + search_site_count++; + + while (Len > 0) + { + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = -Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = Len; + search_site_count++; + + // Contract. + Len /= 2; + } + + x->ss_count = search_site_count; + x->searches_per_step = 4; +} + +void vp8_init3smotion_compensation(MACROBLOCK *x, int stride) +{ + int Len; + int search_site_count = 0; + + // Generate offsets for 8 search sites per step. + Len = MAX_FIRST_STEP; + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = 0; + search_site_count++; + + while (Len > 0) + { + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = -Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride - Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride + Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride - Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride + Len; + search_site_count++; + + + // Contract. + Len /= 2; + } + + x->ss_count = search_site_count; + x->searches_per_step = 8; +} + +/* + * To avoid the penalty for crossing cache-line read, preload the reference + * area in a small buffer, which is aligned to make sure there won't be crossing + * cache-line read while reading from this buffer. This reduced the cpu + * cycles spent on reading ref data in sub-pixel filter functions. + * TODO: Currently, since sub-pixel search range here is -3 ~ 3, copy 22 rows x + * 32 cols area that is enough for 16x16 macroblock. Later, for SPLITMV, we + * could reduce the area. + */ +#define MVC(r,c) (((mvcost[0][(r)-rr] + mvcost[1][(c) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) +#define PRE(r,c) (y + (((r)>>2) * y_stride + ((c)>>2) -(offset))) // pointer to predictor base of a motionvector +#define SP(x) (((x)&3)<<1) // convert motion vector component to offset for svf calc +#define DIST(r,c) vfp->svf( PRE(r,c), y_stride, SP(c),SP(r), z,b->src_stride,&sse) // returns subpixel variance error function. +#define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; +#define ERR(r,c) (MVC(r,c)+DIST(r,c)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) IFMVCV(r,c,{thismse = DIST(r,c); if((v = (MVC(r,c)+thismse)) < besterr) { besterr = v; br=r; bc=c; *distortion = thismse; *sse1 = sse; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best + +int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, + int_mv *bestmv, int_mv *ref_mv, + int error_per_bit, + const vp8_variance_fn_ptr_t *vfp, + int *mvcost[2], int *distortion, + unsigned int *sse1) +{ + unsigned char *z = (*(b->base_src) + b->src); + + int rr = ref_mv->as_mv.row >> 1, rc = ref_mv->as_mv.col >> 1; + int br = bestmv->as_mv.row << 2, bc = bestmv->as_mv.col << 2; + int tr = br, tc = bc; + unsigned int besterr = INT_MAX; + unsigned int left, right, up, down, diag; + unsigned int sse; + unsigned int whichdir; + unsigned int halfiters = 4; + unsigned int quarteriters = 4; + int thismse; + + int minc = MAX(x->mv_col_min << 2, (ref_mv->as_mv.col >> 1) - ((1 << mvlong_width) - 1)); + int maxc = MIN(x->mv_col_max << 2, (ref_mv->as_mv.col >> 1) + ((1 << mvlong_width) - 1)); + int minr = MAX(x->mv_row_min << 2, (ref_mv->as_mv.row >> 1) - ((1 << mvlong_width) - 1)); + int maxr = MIN(x->mv_row_max << 2, (ref_mv->as_mv.row >> 1) + ((1 << mvlong_width) - 1)); + + int y_stride; + int offset; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + + +#if ARCH_X86 || ARCH_X86_64 + MACROBLOCKD *xd = &x->e_mbd; + unsigned char *y0 = base_pre + d->offset + (bestmv->as_mv.row) * pre_stride + bestmv->as_mv.col; + unsigned char *y; + int buf_r1, buf_r2, buf_c1, buf_c2; + + // Clamping to avoid out-of-range data access + buf_r1 = ((bestmv->as_mv.row - 3) < x->mv_row_min)?(bestmv->as_mv.row - x->mv_row_min):3; + buf_r2 = ((bestmv->as_mv.row + 3) > x->mv_row_max)?(x->mv_row_max - bestmv->as_mv.row):3; + buf_c1 = ((bestmv->as_mv.col - 3) < x->mv_col_min)?(bestmv->as_mv.col - x->mv_col_min):3; + buf_c2 = ((bestmv->as_mv.col + 3) > x->mv_col_max)?(x->mv_col_max - bestmv->as_mv.col):3; + y_stride = 32; + + /* Copy to intermediate buffer before searching. */ + vfp->copymem(y0 - buf_c1 - pre_stride*buf_r1, pre_stride, xd->y_buf, y_stride, 16+buf_r1+buf_r2); + y = xd->y_buf + y_stride*buf_r1 +buf_c1; +#else + unsigned char *y = base_pre + d->offset + (bestmv->as_mv.row) * pre_stride + bestmv->as_mv.col; + y_stride = pre_stride; +#endif + + offset = (bestmv->as_mv.row) * y_stride + bestmv->as_mv.col; + + // central mv + bestmv->as_mv.row <<= 3; + bestmv->as_mv.col <<= 3; + + // calculate central point error + besterr = vfp->vf(y, y_stride, z, b->src_stride, sse1); + *distortion = besterr; + besterr += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) + while (--halfiters) + { + // 1/2 pel + CHECK_BETTER(left, tr, tc - 2); + CHECK_BETTER(right, tr, tc + 2); + CHECK_BETTER(up, tr - 2, tc); + CHECK_BETTER(down, tr + 2, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - 2, tc - 2); + break; + case 1: + CHECK_BETTER(diag, tr - 2, tc + 2); + break; + case 2: + CHECK_BETTER(diag, tr + 2, tc - 2); + break; + case 3: + CHECK_BETTER(diag, tr + 2, tc + 2); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + + // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) + // 1/4 pel + while (--quarteriters) + { + CHECK_BETTER(left, tr, tc - 1); + CHECK_BETTER(right, tr, tc + 1); + CHECK_BETTER(up, tr - 1, tc); + CHECK_BETTER(down, tr + 1, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - 1, tc - 1); + break; + case 1: + CHECK_BETTER(diag, tr - 1, tc + 1); + break; + case 2: + CHECK_BETTER(diag, tr + 1, tc - 1); + break; + case 3: + CHECK_BETTER(diag, tr + 1, tc + 1); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + + bestmv->as_mv.row = br << 1; + bestmv->as_mv.col = bc << 1; + + if ((abs(bestmv->as_mv.col - ref_mv->as_mv.col) > (MAX_FULL_PEL_VAL<<3)) || + (abs(bestmv->as_mv.row - ref_mv->as_mv.row) > (MAX_FULL_PEL_VAL<<3))) + return INT_MAX; + + return besterr; +} +#undef MVC +#undef PRE +#undef SP +#undef DIST +#undef IFMVCV +#undef ERR +#undef CHECK_BETTER + +int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, + int_mv *bestmv, int_mv *ref_mv, + int error_per_bit, + const vp8_variance_fn_ptr_t *vfp, + int *mvcost[2], int *distortion, + unsigned int *sse1) +{ + int bestmse = INT_MAX; + int_mv startmv; + int_mv this_mv; + unsigned char *z = (*(b->base_src) + b->src); + int left, right, up, down, diag; + unsigned int sse; + int whichdir ; + int thismse; + int y_stride; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + +#if ARCH_X86 || ARCH_X86_64 + MACROBLOCKD *xd = &x->e_mbd; + unsigned char *y0 = base_pre + d->offset + (bestmv->as_mv.row) * pre_stride + bestmv->as_mv.col; + unsigned char *y; + + y_stride = 32; + /* Copy 18 rows x 32 cols area to intermediate buffer before searching. */ + vfp->copymem(y0 - 1 - pre_stride, pre_stride, xd->y_buf, y_stride, 18); + y = xd->y_buf + y_stride + 1; +#else + unsigned char *y = base_pre + d->offset + (bestmv->as_mv.row) * pre_stride + bestmv->as_mv.col; + y_stride = pre_stride; +#endif + + // central mv + bestmv->as_mv.row <<= 3; + bestmv->as_mv.col <<= 3; + startmv = *bestmv; + + // calculate central point error + bestmse = vfp->vf(y, y_stride, z, b->src_stride, sse1); + *distortion = bestmse; + bestmse += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // go left then right and check error + this_mv.as_mv.row = startmv.as_mv.row; + this_mv.as_mv.col = ((startmv.as_mv.col - 8) | 4); + thismse = vfp->svf_halfpix_h(y - 1, y_stride, z, b->src_stride, &sse); + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.col += 8; + thismse = vfp->svf_halfpix_h(y, y_stride, z, b->src_stride, &sse); + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + *distortion = thismse; + *sse1 = sse; + } + + // go up then down and check error + this_mv.as_mv.col = startmv.as_mv.col; + this_mv.as_mv.row = ((startmv.as_mv.row - 8) | 4); + thismse = vfp->svf_halfpix_v(y - y_stride, y_stride, z, b->src_stride, &sse); + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.row += 8; + thismse = vfp->svf_halfpix_v(y, y_stride, z, b->src_stride, &sse); + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + *distortion = thismse; + *sse1 = sse; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + //for(whichdir =0;whichdir<4;whichdir++) + //{ + this_mv = startmv; + + switch (whichdir) + { + case 0: + this_mv.as_mv.col = (this_mv.as_mv.col - 8) | 4; + this_mv.as_mv.row = (this_mv.as_mv.row - 8) | 4; + thismse = vfp->svf_halfpix_hv(y - 1 - y_stride, y_stride, z, b->src_stride, &sse); + break; + case 1: + this_mv.as_mv.col += 4; + this_mv.as_mv.row = (this_mv.as_mv.row - 8) | 4; + thismse = vfp->svf_halfpix_hv(y - y_stride, y_stride, z, b->src_stride, &sse); + break; + case 2: + this_mv.as_mv.col = (this_mv.as_mv.col - 8) | 4; + this_mv.as_mv.row += 4; + thismse = vfp->svf_halfpix_hv(y - 1, y_stride, z, b->src_stride, &sse); + break; + case 3: + default: + this_mv.as_mv.col += 4; + this_mv.as_mv.row += 4; + thismse = vfp->svf_halfpix_hv(y, y_stride, z, b->src_stride, &sse); + break; + } + + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + *distortion = thismse; + *sse1 = sse; + } + +// } + + + // time to check quarter pels. + if (bestmv->as_mv.row < startmv.as_mv.row) + y -= y_stride; + + if (bestmv->as_mv.col < startmv.as_mv.col) + y--; + + startmv = *bestmv; + + + + // go left then right and check error + this_mv.as_mv.row = startmv.as_mv.row; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col = startmv.as_mv.col - 2; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; + thismse = vfp->svf(y - 1, y_stride, 6, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.col += 4; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + *distortion = thismse; + *sse1 = sse; + } + + // go up then down and check error + this_mv.as_mv.col = startmv.as_mv.col; + + if (startmv.as_mv.row & 7) + { + this_mv.as_mv.row = startmv.as_mv.row - 2; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.row = (startmv.as_mv.row - 8) | 6; + thismse = vfp->svf(y - y_stride, y_stride, this_mv.as_mv.col & 7, 6, z, b->src_stride, &sse); + } + + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.row += 4; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + *distortion = thismse; + *sse1 = sse; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + +// for(whichdir=0;whichdir<4;whichdir++) +// { + this_mv = startmv; + + switch (whichdir) + { + case 0: + + if (startmv.as_mv.row & 7) + { + this_mv.as_mv.row -= 2; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col -= 2; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; + thismse = vfp->svf(y - 1, y_stride, 6, this_mv.as_mv.row & 7, z, b->src_stride, &sse);; + } + } + else + { + this_mv.as_mv.row = (startmv.as_mv.row - 8) | 6; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col -= 2; + thismse = vfp->svf(y - y_stride, y_stride, this_mv.as_mv.col & 7, 6, z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; + thismse = vfp->svf(y - y_stride - 1, y_stride, 6, 6, z, b->src_stride, &sse); + } + } + + break; + case 1: + this_mv.as_mv.col += 2; + + if (startmv.as_mv.row & 7) + { + this_mv.as_mv.row -= 2; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.row = (startmv.as_mv.row - 8) | 6; + thismse = vfp->svf(y - y_stride, y_stride, this_mv.as_mv.col & 7, 6, z, b->src_stride, &sse); + } + + break; + case 2: + this_mv.as_mv.row += 2; + + if (startmv.as_mv.col & 7) + { + this_mv.as_mv.col -= 2; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.as_mv.col = (startmv.as_mv.col - 8) | 6; + thismse = vfp->svf(y - 1, y_stride, 6, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + } + + break; + case 3: + this_mv.as_mv.col += 2; + this_mv.as_mv.row += 2; + thismse = vfp->svf(y, y_stride, this_mv.as_mv.col & 7, this_mv.as_mv.row & 7, z, b->src_stride, &sse); + break; + } + + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + *distortion = thismse; + *sse1 = sse; + } + + return bestmse; +} + +int vp8_find_best_half_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, + int_mv *bestmv, int_mv *ref_mv, + int error_per_bit, + const vp8_variance_fn_ptr_t *vfp, + int *mvcost[2], int *distortion, + unsigned int *sse1) +{ + int bestmse = INT_MAX; + int_mv startmv; + int_mv this_mv; + unsigned char *z = (*(b->base_src) + b->src); + int left, right, up, down, diag; + unsigned int sse; + int whichdir ; + int thismse; + int y_stride; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + +#if ARCH_X86 || ARCH_X86_64 + MACROBLOCKD *xd = &x->e_mbd; + unsigned char *y0 = base_pre + d->offset + (bestmv->as_mv.row) * pre_stride + bestmv->as_mv.col; + unsigned char *y; + + y_stride = 32; + /* Copy 18 rows x 32 cols area to intermediate buffer before searching. */ + vfp->copymem(y0 - 1 - pre_stride, pre_stride, xd->y_buf, y_stride, 18); + y = xd->y_buf + y_stride + 1; +#else + unsigned char *y = base_pre + d->offset + (bestmv->as_mv.row) * pre_stride + bestmv->as_mv.col; + y_stride = pre_stride; +#endif + + // central mv + bestmv->as_mv.row <<= 3; + bestmv->as_mv.col <<= 3; + startmv = *bestmv; + + // calculate central point error + bestmse = vfp->vf(y, y_stride, z, b->src_stride, sse1); + *distortion = bestmse; + bestmse += mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // go left then right and check error + this_mv.as_mv.row = startmv.as_mv.row; + this_mv.as_mv.col = ((startmv.as_mv.col - 8) | 4); + thismse = vfp->svf_halfpix_h(y - 1, y_stride, z, b->src_stride, &sse); + left = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.col += 8; + thismse = vfp->svf_halfpix_h(y, y_stride, z, b->src_stride, &sse); + right = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + *distortion = thismse; + *sse1 = sse; + } + + // go up then down and check error + this_mv.as_mv.col = startmv.as_mv.col; + this_mv.as_mv.row = ((startmv.as_mv.row - 8) | 4); + thismse = vfp->svf_halfpix_v(y - y_stride, y_stride, z, b->src_stride, &sse); + up = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + *distortion = thismse; + *sse1 = sse; + } + + this_mv.as_mv.row += 8; + thismse = vfp->svf_halfpix_v(y, y_stride, z, b->src_stride, &sse); + down = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + *distortion = thismse; + *sse1 = sse; + } + + // now check 1 more diagonal - + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + this_mv = startmv; + + switch (whichdir) + { + case 0: + this_mv.as_mv.col = (this_mv.as_mv.col - 8) | 4; + this_mv.as_mv.row = (this_mv.as_mv.row - 8) | 4; + thismse = vfp->svf_halfpix_hv(y - 1 - y_stride, y_stride, z, b->src_stride, &sse); + break; + case 1: + this_mv.as_mv.col += 4; + this_mv.as_mv.row = (this_mv.as_mv.row - 8) | 4; + thismse = vfp->svf_halfpix_hv(y - y_stride, y_stride, z, b->src_stride, &sse); + break; + case 2: + this_mv.as_mv.col = (this_mv.as_mv.col - 8) | 4; + this_mv.as_mv.row += 4; + thismse = vfp->svf_halfpix_hv(y - 1, y_stride, z, b->src_stride, &sse); + break; + case 3: + default: + this_mv.as_mv.col += 4; + this_mv.as_mv.row += 4; + thismse = vfp->svf_halfpix_hv(y, y_stride, z, b->src_stride, &sse); + break; + } + + diag = thismse + mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + *distortion = thismse; + *sse1 = sse; + } + + return bestmse; +} + +#define CHECK_BOUNDS(range) \ +{\ + all_in = 1;\ + all_in &= ((br-range) >= x->mv_row_min);\ + all_in &= ((br+range) <= x->mv_row_max);\ + all_in &= ((bc-range) >= x->mv_col_min);\ + all_in &= ((bc+range) <= x->mv_col_max);\ +} + +#define CHECK_POINT \ +{\ + if (this_mv.as_mv.col < x->mv_col_min) continue;\ + if (this_mv.as_mv.col > x->mv_col_max) continue;\ + if (this_mv.as_mv.row < x->mv_row_min) continue;\ + if (this_mv.as_mv.row > x->mv_row_max) continue;\ +} + +#define CHECK_BETTER \ +{\ + if (thissad < bestsad)\ + {\ + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, sad_per_bit);\ + if (thissad < bestsad)\ + {\ + bestsad = thissad;\ + best_site = i;\ + }\ + }\ +} + +static const MV next_chkpts[6][3] = +{ + {{ -2, 0}, { -1, -2}, {1, -2}}, + {{ -1, -2}, {1, -2}, {2, 0}}, + {{1, -2}, {2, 0}, {1, 2}}, + {{2, 0}, {1, 2}, { -1, 2}}, + {{1, 2}, { -1, 2}, { -2, 0}}, + {{ -1, 2}, { -2, 0}, { -1, -2}} +}; + +int vp8_hex_search +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int_mv *best_mv, + int search_param, + int sad_per_bit, + const vp8_variance_fn_ptr_t *vfp, + int *mvsadcost[2], + int *mvcost[2], + int_mv *center_mv +) +{ + MV hex[6] = { { -1, -2}, {1, -2}, {2, 0}, {1, 2}, { -1, 2}, { -2, 0} } ; + MV neighbors[4] = {{0, -1}, { -1, 0}, {1, 0}, {0, 1}} ; + int i, j; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + + int in_what_stride = pre_stride; + int br, bc; + int_mv this_mv; + unsigned int bestsad = 0x7fffffff; + unsigned int thissad; + unsigned char *base_offset; + unsigned char *this_offset; + int k = -1; + int all_in; + int best_site = -1; + int hex_range = 127; + int dia_range = 8; + + int_mv fcenter_mv; + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + // adjust ref_mv to make sure it is within MV range + vp8_clamp_mv(ref_mv, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max); + br = ref_mv->as_mv.row; + bc = ref_mv->as_mv.col; + + // Work out the start point for the search + base_offset = (unsigned char *)(base_pre + d->offset); + this_offset = base_offset + (br * (pre_stride)) + bc; + this_mv.as_mv.row = br; + this_mv.as_mv.col = bc; + bestsad = vfp->sdf( what, what_stride, this_offset, + in_what_stride, 0x7fffffff) + + mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, sad_per_bit); + +#if CONFIG_MULTI_RES_ENCODING + /* Lower search range based on prediction info */ + if (search_param >= 6) goto cal_neighbors; + else if (search_param >= 5) hex_range = 4; + else if (search_param >= 4) hex_range = 6; + else if (search_param >= 3) hex_range = 15; + else if (search_param >= 2) hex_range = 31; + else if (search_param >= 1) hex_range = 63; + + dia_range = 8; +#endif + + // hex search + //j=0 + CHECK_BOUNDS(2) + + if(all_in) + { + for (i = 0; i < 6; i++) + { + this_mv.as_mv.row = br + hex[i].row; + this_mv.as_mv.col = bc + hex[i].col; + this_offset = base_offset + (this_mv.as_mv.row * in_what_stride) + this_mv.as_mv.col; + thissad=vfp->sdf( what, what_stride, this_offset, in_what_stride, bestsad); + CHECK_BETTER + } + }else + { + for (i = 0; i < 6; i++) + { + this_mv.as_mv.row = br + hex[i].row; + this_mv.as_mv.col = bc + hex[i].col; + CHECK_POINT + this_offset = base_offset + (this_mv.as_mv.row * in_what_stride) + this_mv.as_mv.col; + thissad=vfp->sdf( what, what_stride, this_offset, in_what_stride, bestsad); + CHECK_BETTER + } + } + + if (best_site == -1) + goto cal_neighbors; + else + { + br += hex[best_site].row; + bc += hex[best_site].col; + k = best_site; + } + + for (j = 1; j < hex_range; j++) + { + best_site = -1; + CHECK_BOUNDS(2) + + if(all_in) + { + for (i = 0; i < 3; i++) + { + this_mv.as_mv.row = br + next_chkpts[k][i].row; + this_mv.as_mv.col = bc + next_chkpts[k][i].col; + this_offset = base_offset + (this_mv.as_mv.row * (in_what_stride)) + this_mv.as_mv.col; + thissad = vfp->sdf( what, what_stride, this_offset, in_what_stride, bestsad); + CHECK_BETTER + } + }else + { + for (i = 0; i < 3; i++) + { + this_mv.as_mv.row = br + next_chkpts[k][i].row; + this_mv.as_mv.col = bc + next_chkpts[k][i].col; + CHECK_POINT + this_offset = base_offset + (this_mv.as_mv.row * (in_what_stride)) + this_mv.as_mv.col; + thissad = vfp->sdf( what, what_stride, this_offset, in_what_stride, bestsad); + CHECK_BETTER + } + } + + if (best_site == -1) + break; + else + { + br += next_chkpts[k][best_site].row; + bc += next_chkpts[k][best_site].col; + k += 5 + best_site; + if (k >= 12) k -= 12; + else if (k >= 6) k -= 6; + } + } + + // check 4 1-away neighbors +cal_neighbors: + for (j = 0; j < dia_range; j++) + { + best_site = -1; + CHECK_BOUNDS(1) + + if(all_in) + { + for (i = 0; i < 4; i++) + { + this_mv.as_mv.row = br + neighbors[i].row; + this_mv.as_mv.col = bc + neighbors[i].col; + this_offset = base_offset + (this_mv.as_mv.row * (in_what_stride)) + this_mv.as_mv.col; + thissad = vfp->sdf( what, what_stride, this_offset, in_what_stride, bestsad); + CHECK_BETTER + } + }else + { + for (i = 0; i < 4; i++) + { + this_mv.as_mv.row = br + neighbors[i].row; + this_mv.as_mv.col = bc + neighbors[i].col; + CHECK_POINT + this_offset = base_offset + (this_mv.as_mv.row * (in_what_stride)) + this_mv.as_mv.col; + thissad = vfp->sdf( what, what_stride, this_offset, in_what_stride, bestsad); + CHECK_BETTER + } + } + + if (best_site == -1) + break; + else + { + br += neighbors[best_site].row; + bc += neighbors[best_site].col; + } + } + + best_mv->as_mv.row = br; + best_mv->as_mv.col = bc; + + return bestsad; +} +#undef CHECK_BOUNDS +#undef CHECK_POINT +#undef CHECK_BETTER + +int vp8_diamond_search_sad_c +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int_mv *best_mv, + int search_param, + int sad_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvcost[2], + int_mv *center_mv +) +{ + int i, j, step; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int in_what_stride = pre_stride; + unsigned char *best_address; + + int tot_steps; + int_mv this_mv; + + int bestsad = INT_MAX; + int best_site = 0; + int last_site = 0; + + int ref_row; + int ref_col; + int this_row_offset; + int this_col_offset; + search_site *ss; + + unsigned char *check_here; + int thissad; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + vp8_clamp_mv(ref_mv, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max); + ref_row = ref_mv->as_mv.row; + ref_col = ref_mv->as_mv.col; + *num00 = 0; + best_mv->as_mv.row = ref_row; + best_mv->as_mv.col = ref_col; + + // Work out the start point for the search + in_what = (unsigned char *)(base_pre + d->offset + (ref_row * pre_stride) + ref_col); + best_address = in_what; + + // Check the starting position + bestsad = fn_ptr->sdf(what, what_stride, in_what, + in_what_stride, 0x7fffffff) + + mvsad_err_cost(best_mv, &fcenter_mv, mvsadcost, sad_per_bit); + + // search_param determines the length of the initial step and hence the number of iterations + // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = (MAX_FIRST_STEP/4) pel... etc. + ss = &x->ss[search_param * x->searches_per_step]; + tot_steps = (x->ss_count / x->searches_per_step) - search_param; + + i = 1; + + for (step = 0; step < tot_steps ; step++) + { + for (j = 0 ; j < x->searches_per_step ; j++) + { + // Trap illegal vectors + this_row_offset = best_mv->as_mv.row + ss[i].mv.row; + this_col_offset = best_mv->as_mv.col + ss[i].mv.col; + + if ((this_col_offset > x->mv_col_min) && (this_col_offset < x->mv_col_max) && + (this_row_offset > x->mv_row_min) && (this_row_offset < x->mv_row_max)) + + { + check_here = ss[i].offset + best_address; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.as_mv.row = this_row_offset; + this_mv.as_mv.col = this_col_offset; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + + i++; + } + + if (best_site != last_site) + { + best_mv->as_mv.row += ss[best_site].mv.row; + best_mv->as_mv.col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + last_site = best_site; + } + else if (best_address == in_what) + (*num00)++; + } + + this_mv.as_mv.row = best_mv->as_mv.row << 3; + this_mv.as_mv.col = best_mv->as_mv.col << 3; + + if (bestsad == INT_MAX) + return INT_MAX; + + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +} + +int vp8_diamond_search_sadx4 +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int_mv *best_mv, + int search_param, + int sad_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvcost[2], + int_mv *center_mv +) +{ + int i, j, step; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int in_what_stride = pre_stride; + unsigned char *best_address; + + int tot_steps; + int_mv this_mv; + + unsigned int bestsad = UINT_MAX; + int best_site = 0; + int last_site = 0; + + int ref_row; + int ref_col; + int this_row_offset; + int this_col_offset; + search_site *ss; + + unsigned char *check_here; + unsigned int thissad; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + vp8_clamp_mv(ref_mv, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max); + ref_row = ref_mv->as_mv.row; + ref_col = ref_mv->as_mv.col; + *num00 = 0; + best_mv->as_mv.row = ref_row; + best_mv->as_mv.col = ref_col; + + // Work out the start point for the search + in_what = (unsigned char *)(base_pre + d->offset + (ref_row * pre_stride) + ref_col); + best_address = in_what; + + // Check the starting position + bestsad = fn_ptr->sdf(what, what_stride, + in_what, in_what_stride, 0x7fffffff) + + mvsad_err_cost(best_mv, &fcenter_mv, mvsadcost, sad_per_bit); + + // search_param determines the length of the initial step and hence the number of iterations + // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = (MAX_FIRST_STEP/4) pel... etc. + ss = &x->ss[search_param * x->searches_per_step]; + tot_steps = (x->ss_count / x->searches_per_step) - search_param; + + i = 1; + + for (step = 0; step < tot_steps ; step++) + { + int all_in = 1, t; + + // To know if all neighbor points are within the bounds, 4 bounds checking are enough instead of + // checking 4 bounds for each points. + all_in &= ((best_mv->as_mv.row + ss[i].mv.row)> x->mv_row_min); + all_in &= ((best_mv->as_mv.row + ss[i+1].mv.row) < x->mv_row_max); + all_in &= ((best_mv->as_mv.col + ss[i+2].mv.col) > x->mv_col_min); + all_in &= ((best_mv->as_mv.col + ss[i+3].mv.col) < x->mv_col_max); + + if (all_in) + { + unsigned int sad_array[4]; + + for (j = 0 ; j < x->searches_per_step ; j += 4) + { + unsigned char *block_offset[4]; + + for (t = 0; t < 4; t++) + block_offset[t] = ss[i+t].offset + best_address; + + fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sad_array); + + for (t = 0; t < 4; t++, i++) + { + if (sad_array[t] < bestsad) + { + this_mv.as_mv.row = best_mv->as_mv.row + ss[i].mv.row; + this_mv.as_mv.col = best_mv->as_mv.col + ss[i].mv.col; + sad_array[t] += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (sad_array[t] < bestsad) + { + bestsad = sad_array[t]; + best_site = i; + } + } + } + } + } + else + { + for (j = 0 ; j < x->searches_per_step ; j++) + { + // Trap illegal vectors + this_row_offset = best_mv->as_mv.row + ss[i].mv.row; + this_col_offset = best_mv->as_mv.col + ss[i].mv.col; + + if ((this_col_offset > x->mv_col_min) && (this_col_offset < x->mv_col_max) && + (this_row_offset > x->mv_row_min) && (this_row_offset < x->mv_row_max)) + { + check_here = ss[i].offset + best_address; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.as_mv.row = this_row_offset; + this_mv.as_mv.col = this_col_offset; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + i++; + } + } + + if (best_site != last_site) + { + best_mv->as_mv.row += ss[best_site].mv.row; + best_mv->as_mv.col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + last_site = best_site; + } + else if (best_address == in_what) + (*num00)++; + } + + this_mv.as_mv.row = best_mv->as_mv.row << 3; + this_mv.as_mv.col = best_mv->as_mv.col << 3; + + if (bestsad == INT_MAX) + return INT_MAX; + + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); +} + +int vp8_full_search_sad_c(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, + int sad_per_bit, int distance, + vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], + int_mv *center_mv) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int in_what_stride = pre_stride; + int mv_stride = pre_stride; + unsigned char *bestaddress; + int_mv *best_mv = &d->bmi.mv; + int_mv this_mv; + int bestsad = INT_MAX; + int r, c; + + unsigned char *check_here; + int thissad; + + int ref_row = ref_mv->as_mv.row; + int ref_col = ref_mv->as_mv.col; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + // Work out the mid point for the search + in_what = base_pre + d->offset; + bestaddress = in_what + (ref_row * pre_stride) + ref_col; + + best_mv->as_mv.row = ref_row; + best_mv->as_mv.col = ref_col; + + // Baseline value at the centre + bestsad = fn_ptr->sdf(what, what_stride, bestaddress, + in_what_stride, 0x7fffffff) + + mvsad_err_cost(best_mv, &fcenter_mv, mvsadcost, sad_per_bit); + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.as_mv.row = r; + check_here = r * mv_stride + in_what + col_min; + + for (c = col_min; c < col_max; c++) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + this_mv.as_mv.col = c; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->as_mv.row = r; + best_mv->as_mv.col = c; + bestaddress = check_here; + } + + check_here++; + } + } + + this_mv.as_mv.row = best_mv->as_mv.row << 3; + this_mv.as_mv.col = best_mv->as_mv.col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); + else + return INT_MAX; +} + +int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, + int sad_per_bit, int distance, + vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], + int_mv *center_mv) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int in_what_stride = pre_stride; + int mv_stride = pre_stride; + unsigned char *bestaddress; + int_mv *best_mv = &d->bmi.mv; + int_mv this_mv; + unsigned int bestsad = UINT_MAX; + int r, c; + + unsigned char *check_here; + unsigned int thissad; + + int ref_row = ref_mv->as_mv.row; + int ref_col = ref_mv->as_mv.col; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + unsigned int sad_array[3]; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + // Work out the mid point for the search + in_what = base_pre + d->offset; + bestaddress = in_what + (ref_row * pre_stride) + ref_col; + + best_mv->as_mv.row = ref_row; + best_mv->as_mv.col = ref_col; + + // Baseline value at the centre + bestsad = fn_ptr->sdf(what, what_stride, + bestaddress, in_what_stride, 0x7fffffff) + + mvsad_err_cost(best_mv, &fcenter_mv, mvsadcost, sad_per_bit); + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.as_mv.row = r; + check_here = r * mv_stride + in_what + col_min; + c = col_min; + + while ((c + 2) < col_max) + { + int i; + + fn_ptr->sdx3f(what, what_stride, check_here , in_what_stride, sad_array); + + for (i = 0; i < 3; i++) + { + thissad = sad_array[i]; + + if (thissad < bestsad) + { + this_mv.as_mv.col = c; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->as_mv.row = r; + best_mv->as_mv.col = c; + bestaddress = check_here; + } + } + + check_here++; + c++; + } + } + + while (c < col_max) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.as_mv.col = c; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->as_mv.row = r; + best_mv->as_mv.col = c; + bestaddress = check_here; + } + } + + check_here ++; + c ++; + } + + } + + this_mv.as_mv.row = best_mv->as_mv.row << 3; + this_mv.as_mv.col = best_mv->as_mv.col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); + else + return INT_MAX; +} + +int vp8_full_search_sadx8(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, + int sad_per_bit, int distance, + vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], + int_mv *center_mv) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + unsigned char *in_what; + int in_what_stride = pre_stride; + int mv_stride = pre_stride; + unsigned char *bestaddress; + int_mv *best_mv = &d->bmi.mv; + int_mv this_mv; + unsigned int bestsad = UINT_MAX; + int r, c; + + unsigned char *check_here; + unsigned int thissad; + + int ref_row = ref_mv->as_mv.row; + int ref_col = ref_mv->as_mv.col; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + DECLARE_ALIGNED_ARRAY(16, unsigned short, sad_array8, 8); + unsigned int sad_array[3]; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + // Work out the mid point for the search + in_what = base_pre + d->offset; + bestaddress = in_what + (ref_row * pre_stride) + ref_col; + + best_mv->as_mv.row = ref_row; + best_mv->as_mv.col = ref_col; + + // Baseline value at the centre + bestsad = fn_ptr->sdf(what, what_stride, + bestaddress, in_what_stride, 0x7fffffff) + + mvsad_err_cost(best_mv, &fcenter_mv, mvsadcost, sad_per_bit); + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.as_mv.row = r; + check_here = r * mv_stride + in_what + col_min; + c = col_min; + + while ((c + 7) < col_max) + { + int i; + + fn_ptr->sdx8f(what, what_stride, check_here , in_what_stride, sad_array8); + + for (i = 0; i < 8; i++) + { + thissad = (unsigned int)sad_array8[i]; + + if (thissad < bestsad) + { + this_mv.as_mv.col = c; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->as_mv.row = r; + best_mv->as_mv.col = c; + bestaddress = check_here; + } + } + + check_here++; + c++; + } + } + + while ((c + 2) < col_max) + { + int i; + + fn_ptr->sdx3f(what, what_stride, check_here , in_what_stride, sad_array); + + for (i = 0; i < 3; i++) + { + thissad = sad_array[i]; + + if (thissad < bestsad) + { + this_mv.as_mv.col = c; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->as_mv.row = r; + best_mv->as_mv.col = c; + bestaddress = check_here; + } + } + + check_here++; + c++; + } + } + + while (c < col_max) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.as_mv.col = c; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, + mvsadcost, sad_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->as_mv.row = r; + best_mv->as_mv.col = c; + bestaddress = check_here; + } + } + + check_here ++; + c ++; + } + } + + this_mv.as_mv.row = best_mv->as_mv.row << 3; + this_mv.as_mv.col = best_mv->as_mv.col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); + else + return INT_MAX; +} + +int vp8_refining_search_sad_c(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *ref_mv, + int error_per_bit, int search_range, + vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], + int_mv *center_mv) +{ + MV neighbors[4] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}}; + int i, j; + short this_row_offset, this_col_offset; + + int what_stride = b->src_stride; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int in_what_stride = pre_stride; + unsigned char *what = (*(b->base_src) + b->src); + unsigned char *best_address = (unsigned char *)(base_pre + d->offset + + (ref_mv->as_mv.row * pre_stride) + ref_mv->as_mv.col); + unsigned char *check_here; + unsigned int thissad; + int_mv this_mv; + unsigned int bestsad = INT_MAX; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + bestsad = fn_ptr->sdf(what, what_stride, best_address, in_what_stride, 0x7fffffff) + mvsad_err_cost(ref_mv, &fcenter_mv, mvsadcost, error_per_bit); + + for (i=0; ias_mv.row + neighbors[j].row; + this_col_offset = ref_mv->as_mv.col + neighbors[j].col; + + if ((this_col_offset > x->mv_col_min) && (this_col_offset < x->mv_col_max) && + (this_row_offset > x->mv_row_min) && (this_row_offset < x->mv_row_max)) + { + check_here = (neighbors[j].row)*in_what_stride + neighbors[j].col + best_address; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.as_mv.row = this_row_offset; + this_mv.as_mv.col = this_col_offset; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = j; + } + } + } + } + + if (best_site == -1) + break; + else + { + ref_mv->as_mv.row += neighbors[best_site].row; + ref_mv->as_mv.col += neighbors[best_site].col; + best_address += (neighbors[best_site].row)*in_what_stride + neighbors[best_site].col; + } + } + + this_mv.as_mv.row = ref_mv->as_mv.row << 3; + this_mv.as_mv.col = ref_mv->as_mv.col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); + else + return INT_MAX; +} + +int vp8_refining_search_sadx4(MACROBLOCK *x, BLOCK *b, BLOCKD *d, + int_mv *ref_mv, int error_per_bit, + int search_range, vp8_variance_fn_ptr_t *fn_ptr, + int *mvcost[2], int_mv *center_mv) +{ + MV neighbors[4] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}}; + int i, j; + short this_row_offset, this_col_offset; + + int what_stride = b->src_stride; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int in_what_stride = pre_stride; + unsigned char *what = (*(b->base_src) + b->src); + unsigned char *best_address = (unsigned char *)(base_pre + d->offset + + (ref_mv->as_mv.row * pre_stride) + ref_mv->as_mv.col); + unsigned char *check_here; + unsigned int thissad; + int_mv this_mv; + unsigned int bestsad = INT_MAX; + + int *mvsadcost[2] = {x->mvsadcost[0], x->mvsadcost[1]}; + int_mv fcenter_mv; + + fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; + fcenter_mv.as_mv.col = center_mv->as_mv.col >> 3; + + bestsad = fn_ptr->sdf(what, what_stride, best_address, in_what_stride, 0x7fffffff) + mvsad_err_cost(ref_mv, &fcenter_mv, mvsadcost, error_per_bit); + + for (i=0; ias_mv.row - 1) > x->mv_row_min); + all_in &= ((ref_mv->as_mv.row + 1) < x->mv_row_max); + all_in &= ((ref_mv->as_mv.col - 1) > x->mv_col_min); + all_in &= ((ref_mv->as_mv.col + 1) < x->mv_col_max); + + if(all_in) + { + unsigned int sad_array[4]; + unsigned char *block_offset[4]; + block_offset[0] = best_address - in_what_stride; + block_offset[1] = best_address - 1; + block_offset[2] = best_address + 1; + block_offset[3] = best_address + in_what_stride; + + fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sad_array); + + for (j = 0; j < 4; j++) + { + if (sad_array[j] < bestsad) + { + this_mv.as_mv.row = ref_mv->as_mv.row + neighbors[j].row; + this_mv.as_mv.col = ref_mv->as_mv.col + neighbors[j].col; + sad_array[j] += mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, error_per_bit); + + if (sad_array[j] < bestsad) + { + bestsad = sad_array[j]; + best_site = j; + } + } + } + } + else + { + for (j = 0 ; j < 4 ; j++) + { + this_row_offset = ref_mv->as_mv.row + neighbors[j].row; + this_col_offset = ref_mv->as_mv.col + neighbors[j].col; + + if ((this_col_offset > x->mv_col_min) && (this_col_offset < x->mv_col_max) && + (this_row_offset > x->mv_row_min) && (this_row_offset < x->mv_row_max)) + { + check_here = (neighbors[j].row)*in_what_stride + neighbors[j].col + best_address; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.as_mv.row = this_row_offset; + this_mv.as_mv.col = this_col_offset; + thissad += mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = j; + } + } + } + } + } + + if (best_site == -1) + break; + else + { + ref_mv->as_mv.row += neighbors[best_site].row; + ref_mv->as_mv.col += neighbors[best_site].col; + best_address += (neighbors[best_site].row)*in_what_stride + neighbors[best_site].col; + } + } + + this_mv.as_mv.row = ref_mv->as_mv.row << 3; + this_mv.as_mv.col = ref_mv->as_mv.col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); + else + return INT_MAX; +} + +#ifdef ENTROPY_STATS +void print_mode_context(void) +{ + FILE *f = fopen("modecont.c", "w"); + int i, j; + + fprintf(f, "#include \"entropy.h\"\n"); + fprintf(f, "const int vp8_mode_contexts[6][4] =\n"); + fprintf(f, "{\n"); + + for (j = 0; j < 6; j++) + { + fprintf(f, " { // %d \n", j); + fprintf(f, " "); + + for (i = 0; i < 4; i++) + { + int overal_prob; + int this_prob; + int count; // = mv_ref_ct[j][i][0]+mv_ref_ct[j][i][1]; + + // Overall probs + count = mv_mode_cts[i][0] + mv_mode_cts[i][1]; + + if (count) + overal_prob = 256 * mv_mode_cts[i][0] / count; + else + overal_prob = 128; + + if (overal_prob == 0) + overal_prob = 1; + + // context probs + count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; + + if (count) + this_prob = 256 * mv_ref_ct[j][i][0] / count; + else + this_prob = 128; + + if (this_prob == 0) + this_prob = 1; + + fprintf(f, "%5d, ", this_prob); + //fprintf(f,"%5d, %5d, %8d,", this_prob, overal_prob, (this_prob << 10)/overal_prob); + //fprintf(f,"%8d, ", (this_prob << 10)/overal_prob); + } + + fprintf(f, " },\n"); + } + + fprintf(f, "};\n"); + fclose(f); +} + +/* MV ref count ENTROPY_STATS stats code */ +#ifdef ENTROPY_STATS +void init_mv_ref_counts() +{ + vpx_memset(mv_ref_ct, 0, sizeof(mv_ref_ct)); + vpx_memset(mv_mode_cts, 0, sizeof(mv_mode_cts)); +} + +void accum_mv_refs(MB_PREDICTION_MODE m, const int ct[4]) +{ + if (m == ZEROMV) + { + ++mv_ref_ct [ct[0]] [0] [0]; + ++mv_mode_cts[0][0]; + } + else + { + ++mv_ref_ct [ct[0]] [0] [1]; + ++mv_mode_cts[0][1]; + + if (m == NEARESTMV) + { + ++mv_ref_ct [ct[1]] [1] [0]; + ++mv_mode_cts[1][0]; + } + else + { + ++mv_ref_ct [ct[1]] [1] [1]; + ++mv_mode_cts[1][1]; + + if (m == NEARMV) + { + ++mv_ref_ct [ct[2]] [2] [0]; + ++mv_mode_cts[2][0]; + } + else + { + ++mv_ref_ct [ct[2]] [2] [1]; + ++mv_mode_cts[2][1]; + + if (m == NEWMV) + { + ++mv_ref_ct [ct[3]] [3] [0]; + ++mv_mode_cts[3][0]; + } + else + { + ++mv_ref_ct [ct[3]] [3] [1]; + ++mv_mode_cts[3][1]; + } + } + } + } +} + +#endif/* END MV ref count ENTROPY_STATS stats code */ + +#endif diff --git a/vp8/encoder/mcomp.h b/vp8/encoder/mcomp.h new file mode 100644 index 0000000..cdb0cb6 --- /dev/null +++ b/vp8/encoder/mcomp.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_MCOMP_H +#define __INC_MCOMP_H + +#include "block.h" +#include "vp8/common/variance.h" + +#ifdef ENTROPY_STATS +extern void init_mv_ref_counts(); +extern void accum_mv_refs(MB_PREDICTION_MODE, const int near_mv_ref_cts[4]); +#endif + + +#define MAX_MVSEARCH_STEPS 8 // The maximum number of steps in a step search given the largest allowed initial step +#define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS)) - 1) // Max full pel mv specified in 1 pel units +#define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS-1)) // Maximum size of the first step in full pel units + +extern void print_mode_context(void); +extern int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight); +extern void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride); +extern void vp8_init3smotion_compensation(MACROBLOCK *x, int stride); + + +extern int vp8_hex_search +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int_mv *best_mv, + int search_param, + int error_per_bit, + const vp8_variance_fn_ptr_t *vf, + int *mvsadcost[2], + int *mvcost[2], + int_mv *center_mv +); + +typedef int (fractional_mv_step_fp) + (MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *bestmv, int_mv *ref_mv, + int error_per_bit, const vp8_variance_fn_ptr_t *vfp, int *mvcost[2], + int *distortion, unsigned int *sse); + +extern fractional_mv_step_fp vp8_find_best_sub_pixel_step_iteratively; +extern fractional_mv_step_fp vp8_find_best_sub_pixel_step; +extern fractional_mv_step_fp vp8_find_best_half_pixel_step; +extern fractional_mv_step_fp vp8_skip_fractional_mv_step; + +typedef int (*vp8_full_search_fn_t) + ( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int sad_per_bit, + int distance, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvcost[2], + int_mv *center_mv + ); + +typedef int (*vp8_refining_search_fn_t) + ( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int sad_per_bit, + int distance, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvcost[2], + int_mv *center_mv + ); + +typedef int (*vp8_diamond_search_fn_t) + ( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + int_mv *ref_mv, + int_mv *best_mv, + int search_param, + int sad_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvcost[2], + int_mv *center_mv + ); + +#endif diff --git a/vp8/encoder/modecosts.c b/vp8/encoder/modecosts.c new file mode 100644 index 0000000..c636c48 --- /dev/null +++ b/vp8/encoder/modecosts.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/blockd.h" +#include "onyx_int.h" +#include "treewriter.h" +#include "vp8/common/entropymode.h" + + +void vp8_init_mode_costs(VP8_COMP *c) +{ + VP8_COMMON *x = &c->common; + { + const vp8_tree_p T = vp8_bmode_tree; + + int i = 0; + + do + { + int j = 0; + + do + { + vp8_cost_tokens((int *)c->mb.bmode_costs[i][j], x->kf_bmode_prob[i][j], T); + } + while (++j < VP8_BINTRAMODES); + } + while (++i < VP8_BINTRAMODES); + + vp8_cost_tokens((int *)c->mb.inter_bmode_costs, x->fc.bmode_prob, T); + } + vp8_cost_tokens((int *)c->mb.inter_bmode_costs, x->fc.sub_mv_ref_prob, vp8_sub_mv_ref_tree); + + vp8_cost_tokens(c->mb.mbmode_cost[1], x->fc.ymode_prob, vp8_ymode_tree); + vp8_cost_tokens(c->mb.mbmode_cost[0], x->kf_ymode_prob, vp8_kf_ymode_tree); + + vp8_cost_tokens(c->mb.intra_uv_mode_cost[1], x->fc.uv_mode_prob, vp8_uv_mode_tree); + vp8_cost_tokens(c->mb.intra_uv_mode_cost[0], x->kf_uv_mode_prob, vp8_uv_mode_tree); +} diff --git a/vp8/encoder/modecosts.h b/vp8/encoder/modecosts.h new file mode 100644 index 0000000..99ef119 --- /dev/null +++ b/vp8/encoder/modecosts.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_MODECOSTS_H +#define __INC_MODECOSTS_H + +void vp8_init_mode_costs(VP8_COMP *x); + +#endif diff --git a/vp8/encoder/mr_dissim.c b/vp8/encoder/mr_dissim.c new file mode 100644 index 0000000..7a62a06 --- /dev/null +++ b/vp8/encoder/mr_dissim.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "vpx_config.h" +#include "onyx_int.h" +#include "mr_dissim.h" +#include "vpx_mem/vpx_mem.h" +#include "rdopt.h" + +void vp8_cal_low_res_mb_cols(VP8_COMP *cpi) +{ + int low_res_w; + + /* Support arbitrary down-sampling factor */ + unsigned int iw = cpi->oxcf.Width*cpi->oxcf.mr_down_sampling_factor.den + + cpi->oxcf.mr_down_sampling_factor.num - 1; + + low_res_w = iw/cpi->oxcf.mr_down_sampling_factor.num; + cpi->mr_low_res_mb_cols = ((low_res_w + 15) >> 4); +} + +#define GET_MV(x) \ +if(x->mbmi.ref_frame !=INTRA_FRAME) \ +{ \ + mvx[cnt] = x->mbmi.mv.as_mv.row; \ + mvy[cnt] = x->mbmi.mv.as_mv.col; \ + cnt++; \ +} + +#define GET_MV_SIGN(x) \ +if(x->mbmi.ref_frame !=INTRA_FRAME) \ +{ \ + mvx[cnt] = x->mbmi.mv.as_mv.row; \ + mvy[cnt] = x->mbmi.mv.as_mv.col; \ + if (cm->ref_frame_sign_bias[x->mbmi.ref_frame] \ + != cm->ref_frame_sign_bias[tmp->mbmi.ref_frame]) \ + { \ + mvx[cnt] *= -1; \ + mvy[cnt] *= -1; \ + } \ + cnt++; \ +} + +void vp8_cal_dissimilarity(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + /* Note: The first row & first column in mip are outside the frame, which + * were initialized to all 0.(ref_frame, mode, mv...) + * Their ref_frame = 0 means they won't be counted in the following + * calculation. + */ + if (cpi->oxcf.mr_total_resolutions >1 + && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1)) + { + /* Store info for show/no-show frames for supporting alt_ref. + * If parent frame is alt_ref, child has one too. + */ + if(cm->frame_type != KEY_FRAME) + { + int mb_row; + int mb_col; + /* Point to beginning of allocated MODE_INFO arrays. */ + MODE_INFO *tmp = cm->mip + cm->mode_info_stride; + LOWER_RES_INFO* store_mode_info + = (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info; + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++) + { + tmp++; + for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++) + { + int dissim = INT_MAX; + + if(tmp->mbmi.ref_frame !=INTRA_FRAME) + { + int mvx[8]; + int mvy[8]; + int mmvx; + int mmvy; + int cnt=0; + const MODE_INFO *here = tmp; + const MODE_INFO *above = here - cm->mode_info_stride; + const MODE_INFO *left = here - 1; + const MODE_INFO *aboveleft = above - 1; + const MODE_INFO *aboveright = NULL; + const MODE_INFO *right = NULL; + const MODE_INFO *belowleft = NULL; + const MODE_INFO *below = NULL; + const MODE_INFO *belowright = NULL; + + /* If alternate reference frame is used, we have to + * check sign of MV. */ + if(cpi->oxcf.play_alternate) + { + /* Gather mv of neighboring MBs */ + GET_MV_SIGN(above) + GET_MV_SIGN(left) + GET_MV_SIGN(aboveleft) + + if(mb_col < (cm->mb_cols-1)) + { + right = here + 1; + aboveright = above + 1; + GET_MV_SIGN(right) + GET_MV_SIGN(aboveright) + } + + if(mb_row < (cm->mb_rows-1)) + { + below = here + cm->mode_info_stride; + belowleft = below - 1; + GET_MV_SIGN(below) + GET_MV_SIGN(belowleft) + } + + if(mb_col < (cm->mb_cols-1) + && mb_row < (cm->mb_rows-1)) + { + belowright = below + 1; + GET_MV_SIGN(belowright) + } + }else + { + /* No alt_ref and gather mv of neighboring MBs */ + GET_MV(above) + GET_MV(left) + GET_MV(aboveleft) + + if(mb_col < (cm->mb_cols-1)) + { + right = here + 1; + aboveright = above + 1; + GET_MV(right) + GET_MV(aboveright) + } + + if(mb_row < (cm->mb_rows-1)) + { + below = here + cm->mode_info_stride; + belowleft = below - 1; + GET_MV(below) + GET_MV(belowleft) + } + + if(mb_col < (cm->mb_cols-1) + && mb_row < (cm->mb_rows-1)) + { + belowright = below + 1; + GET_MV(belowright) + } + } + + if (cnt > 0) + { + int max_mvx = mvx[0]; + int min_mvx = mvx[0]; + int max_mvy = mvy[0]; + int min_mvy = mvy[0]; + int i; + + if (cnt > 1) + { + for (i=1; i< cnt; i++) + { + if (mvx[i] > max_mvx) max_mvx = mvx[i]; + else if (mvx[i] < min_mvx) min_mvx = mvx[i]; + if (mvy[i] > max_mvy) max_mvy = mvy[i]; + else if (mvy[i] < min_mvy) min_mvy = mvy[i]; + } + } + + mmvx = MAX(abs(min_mvx - here->mbmi.mv.as_mv.row), + abs(max_mvx - here->mbmi.mv.as_mv.row)); + mmvy = MAX(abs(min_mvy - here->mbmi.mv.as_mv.col), + abs(max_mvy - here->mbmi.mv.as_mv.col)); + dissim = MAX(mmvx, mmvy); + } + } + + /* Store mode info for next resolution encoding */ + store_mode_info->mode = tmp->mbmi.mode; + store_mode_info->ref_frame = tmp->mbmi.ref_frame; + store_mode_info->mv.as_int = tmp->mbmi.mv.as_int; + store_mode_info->dissim = dissim; + tmp++; + store_mode_info++; + } + } + } + } +} diff --git a/vp8/encoder/mr_dissim.h b/vp8/encoder/mr_dissim.h new file mode 100644 index 0000000..3d2c203 --- /dev/null +++ b/vp8/encoder/mr_dissim.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_MR_DISSIM_H +#define __INC_MR_DISSIM_H +#include "vpx_config.h" + +extern void vp8_cal_low_res_mb_cols(VP8_COMP *cpi); +extern void vp8_cal_dissimilarity(VP8_COMP *cpi); + +#endif diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c new file mode 100644 index 0000000..cee62fa --- /dev/null +++ b/vp8/encoder/onyx_if.c @@ -0,0 +1,5369 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vp8/common/onyxc_int.h" +#include "onyx_int.h" +#include "vp8/common/systemdependent.h" +#include "quantize.h" +#include "vp8/common/alloccommon.h" +#include "mcomp.h" +#include "firstpass.h" +#include "psnr.h" +#include "vpx_scale/vpxscale.h" +#include "vp8/common/extend.h" +#include "ratectrl.h" +#include "vp8/common/quant_common.h" +#include "segmentation.h" +#if CONFIG_POSTPROC +#include "vp8/common/postproc.h" +#endif +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/swapyv12buffer.h" +#include "vp8/common/threading.h" +#include "vpx_ports/vpx_timer.h" +#if ARCH_ARM +#include "vpx_ports/arm.h" +#endif +#if CONFIG_MULTI_RES_ENCODING +#include "mr_dissim.h" +#endif +#include "encodeframe.h" + +#include +#include +#include + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING +extern int vp8_update_coef_context(VP8_COMP *cpi); +extern void vp8_update_coef_probs(VP8_COMP *cpi); +#endif + +extern void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi); +extern void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val); +extern void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi); + +extern void vp8_deblock_frame(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *post, int filt_lvl, int low_var_thresh, int flag); +extern void print_parms(VP8_CONFIG *ocf, char *filenam); +extern unsigned int vp8_get_processor_freq(); +extern void print_tree_update_probs(); +extern void vp8cx_create_encoder_threads(VP8_COMP *cpi); +extern void vp8cx_remove_encoder_threads(VP8_COMP *cpi); +#if HAVE_NEON +extern void vp8_yv12_copy_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); +extern void vp8_yv12_copy_src_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); +#endif + +int vp8_estimate_entropy_savings(VP8_COMP *cpi); + +int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest); + +extern void vp8_temporal_filter_prepare_c(VP8_COMP *cpi, int distance); + +static void set_default_lf_deltas(VP8_COMP *cpi); + +extern const int vp8_gf_interval_table[101]; + +#if CONFIG_INTERNAL_STATS +#include "math.h" + +extern double vp8_calc_ssim +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + int lumamask, + double *weight +); + + +extern double vp8_calc_ssimg +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + double *ssim_y, + double *ssim_u, + double *ssim_v +); + + +#endif + + +#ifdef OUTPUT_YUV_SRC +FILE *yuv_file; +#endif + +#if 0 +FILE *framepsnr; +FILE *kf_list; +FILE *keyfile; +#endif + +#if 0 +extern int skip_true_count; +extern int skip_false_count; +#endif + + +#ifdef ENTROPY_STATS +extern int intra_mode_stats[10][10][10]; +#endif + +#ifdef SPEEDSTATS +unsigned int frames_at_speed[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int tot_pm = 0; +unsigned int cnt_pm = 0; +unsigned int tot_ef = 0; +unsigned int cnt_ef = 0; +#endif + +#ifdef MODE_STATS +extern unsigned __int64 Sectionbits[50]; +extern int y_modes[5] ; +extern int uv_modes[4] ; +extern int b_modes[10] ; + +extern int inter_y_modes[10] ; +extern int inter_uv_modes[4] ; +extern unsigned int inter_b_modes[15]; +#endif + +extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; + +extern const int qrounding_factors[129]; +extern const int qzbin_factors[129]; +extern void vp8cx_init_quantizer(VP8_COMP *cpi); +extern const int vp8cx_base_skip_false_prob[128]; + +// Tables relating active max Q to active min Q +static const unsigned char kf_low_motion_minq[QINDEX_RANGE] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, + 3,3,3,3,3,3,4,4,4,5,5,5,5,5,6,6, + 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11, + 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16, + 16,16,17,17,18,18,18,18,19,20,20,21,21,22,23,23 +}; +static const unsigned char kf_high_motion_minq[QINDEX_RANGE] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3, + 3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6, + 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11, + 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16, + 16,16,17,17,18,18,18,18,19,19,20,20,20,20,21,21, + 21,21,22,22,23,23,24,25,25,26,26,27,28,28,29,30 +}; +static const unsigned char gf_low_motion_minq[QINDEX_RANGE] = +{ + 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, + 3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6, + 7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10, + 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18, + 19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26, + 27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34, + 35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42, + 43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58 +}; +static const unsigned char gf_mid_motion_minq[QINDEX_RANGE] = +{ + 0,0,0,0,1,1,1,1,1,1,2,2,3,3,3,4, + 4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9, + 9,10,10,10,10,11,11,11,12,12,12,12,13,13,13,14, + 14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21, + 22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29, + 30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37, + 38,39,39,40,40,41,41,42,42,43,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64 +}; +static const unsigned char gf_high_motion_minq[QINDEX_RANGE] = +{ + 0,0,0,0,1,1,1,1,1,2,2,2,3,3,3,4, + 4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9, + 9,10,10,10,11,11,12,12,13,13,14,14,15,15,16,16, + 17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24, + 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32, + 33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40, + 41,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54, + 55,56,57,58,59,60,62,64,66,68,70,72,74,76,78,80 +}; +static const unsigned char inter_minq[QINDEX_RANGE] = +{ + 0,0,1,1,2,3,3,4,4,5,6,6,7,8,8,9, + 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,20, + 20,21,22,22,23,24,24,25,26,27,27,28,29,30,30,31, + 32,33,33,34,35,36,36,37,38,39,39,40,41,42,42,43, + 44,45,46,46,47,48,49,50,50,51,52,53,54,55,55,56, + 57,58,59,60,60,61,62,63,64,65,66,67,67,68,69,70, + 71,72,73,74,75,75,76,77,78,79,80,81,82,83,84,85, + 86,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100 +}; + +#ifdef PACKET_TESTING +extern FILE *vpxlogc; +#endif + +static void save_layer_context(VP8_COMP *cpi) +{ + LAYER_CONTEXT *lc = &cpi->layer_context[cpi->current_layer]; + + // Save layer dependent coding state + lc->target_bandwidth = cpi->target_bandwidth; + //lc->target_bandwidth = cpi->oxcf.target_bandwidth; + lc->starting_buffer_level = cpi->oxcf.starting_buffer_level; + lc->optimal_buffer_level = cpi->oxcf.optimal_buffer_level; + lc->maximum_buffer_size = cpi->oxcf.maximum_buffer_size; + lc->starting_buffer_level_in_ms = cpi->oxcf.starting_buffer_level_in_ms; + lc->optimal_buffer_level_in_ms = cpi->oxcf.optimal_buffer_level_in_ms; + lc->maximum_buffer_size_in_ms = cpi->oxcf.maximum_buffer_size_in_ms; + lc->buffer_level = cpi->buffer_level; + lc->bits_off_target = cpi->bits_off_target; + lc->total_actual_bits = cpi->total_actual_bits; + lc->worst_quality = cpi->worst_quality; + lc->active_worst_quality = cpi->active_worst_quality; + lc->best_quality = cpi->best_quality; + lc->active_best_quality = cpi->active_best_quality; + lc->ni_av_qi = cpi->ni_av_qi; + lc->ni_tot_qi = cpi->ni_tot_qi; + lc->ni_frames = cpi->ni_frames; + lc->avg_frame_qindex = cpi->avg_frame_qindex; + lc->rate_correction_factor = cpi->rate_correction_factor; + lc->key_frame_rate_correction_factor = cpi->key_frame_rate_correction_factor; + lc->gf_rate_correction_factor = cpi->gf_rate_correction_factor; + lc->zbin_over_quant = cpi->zbin_over_quant; + lc->inter_frame_target = cpi->inter_frame_target; + lc->total_byte_count = cpi->total_byte_count; + lc->filter_level = cpi->common.filter_level; + + lc->last_frame_percent_intra = cpi->last_frame_percent_intra; + + memcpy (lc->count_mb_ref_frame_usage, + cpi->count_mb_ref_frame_usage, + sizeof(cpi->count_mb_ref_frame_usage)); +} + +static void restore_layer_context(VP8_COMP *cpi, const int layer) +{ + LAYER_CONTEXT *lc = &cpi->layer_context[layer]; + + // Restore layer dependent coding state + cpi->current_layer = layer; + cpi->target_bandwidth = lc->target_bandwidth; + cpi->oxcf.target_bandwidth = lc->target_bandwidth; + cpi->oxcf.starting_buffer_level = lc->starting_buffer_level; + cpi->oxcf.optimal_buffer_level = lc->optimal_buffer_level; + cpi->oxcf.maximum_buffer_size = lc->maximum_buffer_size; + cpi->oxcf.starting_buffer_level_in_ms = lc->starting_buffer_level_in_ms; + cpi->oxcf.optimal_buffer_level_in_ms = lc->optimal_buffer_level_in_ms; + cpi->oxcf.maximum_buffer_size_in_ms = lc->maximum_buffer_size_in_ms; + cpi->buffer_level = lc->buffer_level; + cpi->bits_off_target = lc->bits_off_target; + cpi->total_actual_bits = lc->total_actual_bits; + //cpi->worst_quality = lc->worst_quality; + cpi->active_worst_quality = lc->active_worst_quality; + //cpi->best_quality = lc->best_quality; + cpi->active_best_quality = lc->active_best_quality; + cpi->ni_av_qi = lc->ni_av_qi; + cpi->ni_tot_qi = lc->ni_tot_qi; + cpi->ni_frames = lc->ni_frames; + cpi->avg_frame_qindex = lc->avg_frame_qindex; + cpi->rate_correction_factor = lc->rate_correction_factor; + cpi->key_frame_rate_correction_factor = lc->key_frame_rate_correction_factor; + cpi->gf_rate_correction_factor = lc->gf_rate_correction_factor; + cpi->zbin_over_quant = lc->zbin_over_quant; + cpi->inter_frame_target = lc->inter_frame_target; + cpi->total_byte_count = lc->total_byte_count; + cpi->common.filter_level = lc->filter_level; + + cpi->last_frame_percent_intra = lc->last_frame_percent_intra; + + memcpy (cpi->count_mb_ref_frame_usage, + lc->count_mb_ref_frame_usage, + sizeof(cpi->count_mb_ref_frame_usage)); +} + +static void setup_features(VP8_COMP *cpi) +{ + // Set up default state for MB feature flags + cpi->mb.e_mbd.segmentation_enabled = 0; + cpi->mb.e_mbd.update_mb_segmentation_map = 0; + cpi->mb.e_mbd.update_mb_segmentation_data = 0; + vpx_memset(cpi->mb.e_mbd.mb_segment_tree_probs, 255, sizeof(cpi->mb.e_mbd.mb_segment_tree_probs)); + vpx_memset(cpi->mb.e_mbd.segment_feature_data, 0, sizeof(cpi->mb.e_mbd.segment_feature_data)); + + cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 0; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + vpx_memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); + vpx_memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); + vpx_memset(cpi->mb.e_mbd.last_ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); + vpx_memset(cpi->mb.e_mbd.last_mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); + + set_default_lf_deltas(cpi); + +} + + +static void dealloc_raw_frame_buffers(VP8_COMP *cpi); + + +static void dealloc_compressor_data(VP8_COMP *cpi) +{ + vpx_free(cpi->tplist); + cpi->tplist = NULL; + + // Delete last frame MV storage buffers + vpx_free(cpi->lfmv); + cpi->lfmv = 0; + + vpx_free(cpi->lf_ref_frame_sign_bias); + cpi->lf_ref_frame_sign_bias = 0; + + vpx_free(cpi->lf_ref_frame); + cpi->lf_ref_frame = 0; + + // Delete sementation map + vpx_free(cpi->segmentation_map); + cpi->segmentation_map = 0; + + vpx_free(cpi->active_map); + cpi->active_map = 0; + + vp8_de_alloc_frame_buffers(&cpi->common); + + vp8_yv12_de_alloc_frame_buffer(&cpi->pick_lf_lvl_frame); + vp8_yv12_de_alloc_frame_buffer(&cpi->scaled_source); + dealloc_raw_frame_buffers(cpi); + + vpx_free(cpi->tok); + cpi->tok = 0; + + // Structure used to monitor GF usage + vpx_free(cpi->gf_active_flags); + cpi->gf_active_flags = 0; + + // Activity mask based per mb zbin adjustments + vpx_free(cpi->mb_activity_map); + cpi->mb_activity_map = 0; + vpx_free(cpi->mb_norm_activity_map); + cpi->mb_norm_activity_map = 0; + + vpx_free(cpi->mb.pip); + cpi->mb.pip = 0; +} + +static void enable_segmentation(VP8_COMP *cpi) +{ + // Set the appropriate feature bit + cpi->mb.e_mbd.segmentation_enabled = 1; + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; +} +static void disable_segmentation(VP8_COMP *cpi) +{ + // Clear the appropriate feature bit + cpi->mb.e_mbd.segmentation_enabled = 0; +} + +// Valid values for a segment are 0 to 3 +// Segmentation map is arrange as [Rows][Columns] +static void set_segmentation_map(VP8_COMP *cpi, unsigned char *segmentation_map) +{ + // Copy in the new segmentation map + vpx_memcpy(cpi->segmentation_map, segmentation_map, (cpi->common.mb_rows * cpi->common.mb_cols)); + + // Signal that the map should be updated. + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; +} + +// The values given for each segment can be either deltas (from the default value chosen for the frame) or absolute values. +// +// Valid range for abs values is (0-127 for MB_LVL_ALT_Q) , (0-63 for SEGMENT_ALT_LF) +// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q) , (+/-63 for SEGMENT_ALT_LF) +// +// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use the absolute values given). +// +// +static void set_segment_data(VP8_COMP *cpi, signed char *feature_data, unsigned char abs_delta) +{ + cpi->mb.e_mbd.mb_segement_abs_delta = abs_delta; + vpx_memcpy(cpi->segment_feature_data, feature_data, sizeof(cpi->segment_feature_data)); +} + + +static void segmentation_test_function(VP8_COMP *cpi) +{ + unsigned char *seg_map; + signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + + // Create a temporary map for segmentation data. + CHECK_MEM_ERROR(seg_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + + // MB loop to set local segmentation map + /*for ( i = 0; i < cpi->common.mb_rows; i++ ) + { + for ( j = 0; j < cpi->common.mb_cols; j++ ) + { + //seg_map[(i*cpi->common.mb_cols) + j] = (j % 2) + ((i%2)* 2); + //if ( j < cpi->common.mb_cols/2 ) + + // Segment 1 around the edge else 0 + if ( (i == 0) || (j == 0) || (i == (cpi->common.mb_rows-1)) || (j == (cpi->common.mb_cols-1)) ) + seg_map[(i*cpi->common.mb_cols) + j] = 1; + //else if ( (i < 2) || (j < 2) || (i > (cpi->common.mb_rows-3)) || (j > (cpi->common.mb_cols-3)) ) + // seg_map[(i*cpi->common.mb_cols) + j] = 2; + //else if ( (i < 5) || (j < 5) || (i > (cpi->common.mb_rows-6)) || (j > (cpi->common.mb_cols-6)) ) + // seg_map[(i*cpi->common.mb_cols) + j] = 3; + else + seg_map[(i*cpi->common.mb_cols) + j] = 0; + } + }*/ + + // Set the segmentation Map + set_segmentation_map(cpi, seg_map); + + // Activate segmentation. + enable_segmentation(cpi); + + // Set up the quant segment data + feature_data[MB_LVL_ALT_Q][0] = 0; + feature_data[MB_LVL_ALT_Q][1] = 4; + feature_data[MB_LVL_ALT_Q][2] = 0; + feature_data[MB_LVL_ALT_Q][3] = 0; + // Set up the loop segment data + feature_data[MB_LVL_ALT_LF][0] = 0; + feature_data[MB_LVL_ALT_LF][1] = 0; + feature_data[MB_LVL_ALT_LF][2] = 0; + feature_data[MB_LVL_ALT_LF][3] = 0; + + // Initialise the feature data structure + // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 + set_segment_data(cpi, &feature_data[0][0], SEGMENT_DELTADATA); + + // Delete sementation map + vpx_free(seg_map); + + seg_map = 0; + +} + +// A simple function to cyclically refresh the background at a lower Q +static void cyclic_background_refresh(VP8_COMP *cpi, int Q, int lf_adjustment) +{ + unsigned char *seg_map; + signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + int i; + int block_count = cpi->cyclic_refresh_mode_max_mbs_perframe; + int mbs_in_frame = cpi->common.mb_rows * cpi->common.mb_cols; + + // Create a temporary map for segmentation data. + CHECK_MEM_ERROR(seg_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + + cpi->cyclic_refresh_q = Q; + + for (i = Q; i > 0; i--) + { + if (vp8_bits_per_mb[cpi->common.frame_type][i] >= ((vp8_bits_per_mb[cpi->common.frame_type][Q]*(Q + 128)) / 64)) + //if ( vp8_bits_per_mb[cpi->common.frame_type][i] >= ((vp8_bits_per_mb[cpi->common.frame_type][Q]*((2*Q)+96))/64) ) + { + break; + } + } + + cpi->cyclic_refresh_q = i; + + // Only update for inter frames + if (cpi->common.frame_type != KEY_FRAME) + { + // Cycle through the macro_block rows + // MB loop to set local segmentation map + for (i = cpi->cyclic_refresh_mode_index; i < mbs_in_frame; i++) + { + // If the MB is as a candidate for clean up then mark it for possible boost/refresh (segment 1) + // The segment id may get reset to 0 later if the MB gets coded anything other than last frame 0,0 + // as only (last frame 0,0) MBs are eligable for refresh : that is to say Mbs likely to be background blocks. + if (cpi->cyclic_refresh_map[i] == 0) + { + seg_map[i] = 1; + } + else + { + seg_map[i] = 0; + + // Skip blocks that have been refreshed recently anyway. + if (cpi->cyclic_refresh_map[i] < 0) + //cpi->cyclic_refresh_map[i] = cpi->cyclic_refresh_map[i] / 16; + cpi->cyclic_refresh_map[i]++; + } + + + if (block_count > 0) + block_count--; + else + break; + + } + + // If we have gone through the frame reset to the start + cpi->cyclic_refresh_mode_index = i; + + if (cpi->cyclic_refresh_mode_index >= mbs_in_frame) + cpi->cyclic_refresh_mode_index = 0; + } + + // Set the segmentation Map + set_segmentation_map(cpi, seg_map); + + // Activate segmentation. + enable_segmentation(cpi); + + // Set up the quant segment data + feature_data[MB_LVL_ALT_Q][0] = 0; + feature_data[MB_LVL_ALT_Q][1] = (cpi->cyclic_refresh_q - Q); + feature_data[MB_LVL_ALT_Q][2] = 0; + feature_data[MB_LVL_ALT_Q][3] = 0; + + // Set up the loop segment data + feature_data[MB_LVL_ALT_LF][0] = 0; + feature_data[MB_LVL_ALT_LF][1] = lf_adjustment; + feature_data[MB_LVL_ALT_LF][2] = 0; + feature_data[MB_LVL_ALT_LF][3] = 0; + + // Initialise the feature data structure + // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 + set_segment_data(cpi, &feature_data[0][0], SEGMENT_DELTADATA); + + // Delete sementation map + vpx_free(seg_map); + + seg_map = 0; + +} + +static void set_default_lf_deltas(VP8_COMP *cpi) +{ + cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 1; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 1; + + vpx_memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); + vpx_memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); + + // Test of ref frame deltas + cpi->mb.e_mbd.ref_lf_deltas[INTRA_FRAME] = 2; + cpi->mb.e_mbd.ref_lf_deltas[LAST_FRAME] = 0; + cpi->mb.e_mbd.ref_lf_deltas[GOLDEN_FRAME] = -2; + cpi->mb.e_mbd.ref_lf_deltas[ALTREF_FRAME] = -2; + + cpi->mb.e_mbd.mode_lf_deltas[0] = 4; // BPRED + cpi->mb.e_mbd.mode_lf_deltas[1] = -2; // Zero + cpi->mb.e_mbd.mode_lf_deltas[2] = 2; // New mv + cpi->mb.e_mbd.mode_lf_deltas[3] = 4; // Split mv +} + +/* Convenience macros for mapping speed and mode into a continuous + * range + */ +#define GOOD(x) (x+1) +#define RT(x) (x+7) + +static int speed_map(int speed, const int *map) +{ + int res; + + do + { + res = *map++; + } while(speed >= *map++); + return res; +} + +static const int thresh_mult_map_znn[] = { + /* map common to zero, nearest, and near */ + 0, GOOD(2), 1500, GOOD(3), 2000, RT(0), 1000, RT(2), 2000, INT_MAX +}; + +static const int thresh_mult_map_vhpred[] = { + 1000, GOOD(2), 1500, GOOD(3), 2000, RT(0), 1000, RT(1), 2000, + RT(7), INT_MAX, INT_MAX +}; + +static const int thresh_mult_map_bpred[] = { + 2000, GOOD(0), 2500, GOOD(2), 5000, GOOD(3), 7500, RT(0), 2500, RT(1), 5000, + RT(6), INT_MAX, INT_MAX +}; + +static const int thresh_mult_map_tm[] = { + 1000, GOOD(2), 1500, GOOD(3), 2000, RT(0), 0, RT(1), 1000, RT(2), 2000, + RT(7), INT_MAX, INT_MAX +}; + +static const int thresh_mult_map_new1[] = { + 1000, GOOD(2), 2000, RT(0), 2000, INT_MAX +}; + +static const int thresh_mult_map_new2[] = { + 1000, GOOD(2), 2000, GOOD(3), 2500, GOOD(5), 4000, RT(0), 2000, RT(2), 2500, + RT(5), 4000, INT_MAX +}; + +static const int thresh_mult_map_split1[] = { + 2500, GOOD(0), 1700, GOOD(2), 10000, GOOD(3), 25000, GOOD(4), INT_MAX, + RT(0), 5000, RT(1), 10000, RT(2), 25000, RT(3), INT_MAX, INT_MAX +}; + +static const int thresh_mult_map_split2[] = { + 5000, GOOD(0), 4500, GOOD(2), 20000, GOOD(3), 50000, GOOD(4), INT_MAX, + RT(0), 10000, RT(1), 20000, RT(2), 50000, RT(3), INT_MAX, INT_MAX +}; + +static const int mode_check_freq_map_zn2[] = { + /* {zero,nearest}{2,3} */ + 0, RT(10), 1<<1, RT(11), 1<<2, RT(12), 1<<3, INT_MAX +}; + +static const int mode_check_freq_map_vhbpred[] = { + 0, GOOD(5), 2, RT(0), 0, RT(3), 2, RT(5), 4, INT_MAX +}; + +static const int mode_check_freq_map_near2[] = { + 0, GOOD(5), 2, RT(0), 0, RT(3), 2, RT(10), 1<<2, RT(11), 1<<3, RT(12), 1<<4, + INT_MAX +}; + +static const int mode_check_freq_map_new1[] = { + 0, RT(10), 1<<1, RT(11), 1<<2, RT(12), 1<<3, INT_MAX +}; + +static const int mode_check_freq_map_new2[] = { + 0, GOOD(5), 4, RT(0), 0, RT(3), 4, RT(10), 1<<3, RT(11), 1<<4, RT(12), 1<<5, + INT_MAX +}; + +static const int mode_check_freq_map_split1[] = { + 0, GOOD(2), 2, GOOD(3), 7, RT(1), 2, RT(2), 7, INT_MAX +}; + +static const int mode_check_freq_map_split2[] = { + 0, GOOD(1), 2, GOOD(2), 4, GOOD(3), 15, RT(1), 4, RT(2), 15, INT_MAX +}; + +void vp8_set_speed_features(VP8_COMP *cpi) +{ + SPEED_FEATURES *sf = &cpi->sf; + int Mode = cpi->compressor_speed; + int Speed = cpi->Speed; + int i; + VP8_COMMON *cm = &cpi->common; + int last_improved_quant = sf->improved_quant; + int ref_frames; + + // Initialise default mode frequency sampling variables + for (i = 0; i < MAX_MODES; i ++) + { + cpi->mode_check_freq[i] = 0; + cpi->mode_test_hit_counts[i] = 0; + cpi->mode_chosen_counts[i] = 0; + } + + cpi->mbs_tested_so_far = 0; + + // best quality defaults + sf->RD = 1; + sf->search_method = NSTEP; + sf->improved_quant = 1; + sf->improved_dct = 1; + sf->auto_filter = 1; + sf->recode_loop = 1; + sf->quarter_pixel_search = 1; + sf->half_pixel_search = 1; + sf->iterative_sub_pixel = 1; + sf->optimize_coefficients = 1; + sf->use_fastquant_for_pick = 0; + sf->no_skip_block4x4_search = 1; + + sf->first_step = 0; + sf->max_step_search_steps = MAX_MVSEARCH_STEPS; + sf->improved_mv_pred = 1; + + // default thresholds to 0 + for (i = 0; i < MAX_MODES; i++) + sf->thresh_mult[i] = 0; + + /* Count enabled references */ + ref_frames = 1; + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + ref_frames++; + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + ref_frames++; + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + ref_frames++; + + /* Convert speed to continuous range, with clamping */ + if (Mode == 0) + Speed = 0; + else if (Mode == 2) + Speed = RT(Speed); + else + { + if (Speed > 5) + Speed = 5; + Speed = GOOD(Speed); + } + + sf->thresh_mult[THR_ZERO1] = + sf->thresh_mult[THR_NEAREST1] = + sf->thresh_mult[THR_NEAR1] = + sf->thresh_mult[THR_DC] = 0; /* always */ + + sf->thresh_mult[THR_ZERO2] = + sf->thresh_mult[THR_ZERO3] = + sf->thresh_mult[THR_NEAREST2] = + sf->thresh_mult[THR_NEAREST3] = + sf->thresh_mult[THR_NEAR2] = + sf->thresh_mult[THR_NEAR3] = speed_map(Speed, thresh_mult_map_znn); + + sf->thresh_mult[THR_V_PRED] = + sf->thresh_mult[THR_H_PRED] = speed_map(Speed, thresh_mult_map_vhpred); + sf->thresh_mult[THR_B_PRED] = speed_map(Speed, thresh_mult_map_bpred); + sf->thresh_mult[THR_TM] = speed_map(Speed, thresh_mult_map_tm); + sf->thresh_mult[THR_NEW1] = speed_map(Speed, thresh_mult_map_new1); + sf->thresh_mult[THR_NEW2] = + sf->thresh_mult[THR_NEW3] = speed_map(Speed, thresh_mult_map_new2); + sf->thresh_mult[THR_SPLIT1] = speed_map(Speed, thresh_mult_map_split1); + sf->thresh_mult[THR_SPLIT2] = + sf->thresh_mult[THR_SPLIT3] = speed_map(Speed, thresh_mult_map_split2); + + cpi->mode_check_freq[THR_ZERO1] = + cpi->mode_check_freq[THR_NEAREST1] = + cpi->mode_check_freq[THR_NEAR1] = + cpi->mode_check_freq[THR_TM] = + cpi->mode_check_freq[THR_DC] = 0; /* always */ + + cpi->mode_check_freq[THR_ZERO2] = + cpi->mode_check_freq[THR_ZERO3] = + cpi->mode_check_freq[THR_NEAREST2] = + cpi->mode_check_freq[THR_NEAREST3] = speed_map(Speed, + mode_check_freq_map_zn2); + + cpi->mode_check_freq[THR_NEAR2] = + cpi->mode_check_freq[THR_NEAR3] = speed_map(Speed, + mode_check_freq_map_near2); + + cpi->mode_check_freq[THR_V_PRED] = + cpi->mode_check_freq[THR_H_PRED] = + cpi->mode_check_freq[THR_B_PRED] = speed_map(Speed, + mode_check_freq_map_vhbpred); + cpi->mode_check_freq[THR_NEW1] = speed_map(Speed, + mode_check_freq_map_new1); + cpi->mode_check_freq[THR_NEW2] = + cpi->mode_check_freq[THR_NEW3] = speed_map(Speed, + mode_check_freq_map_new2); + cpi->mode_check_freq[THR_SPLIT1] = speed_map(Speed, + mode_check_freq_map_split1); + cpi->mode_check_freq[THR_SPLIT2] = + cpi->mode_check_freq[THR_SPLIT3] = speed_map(Speed, + mode_check_freq_map_split2); + Speed = cpi->Speed; + switch (Mode) + { +#if !(CONFIG_REALTIME_ONLY) + case 0: // best quality mode + sf->first_step = 0; + sf->max_step_search_steps = MAX_MVSEARCH_STEPS; + break; + case 1: + case 3: + if (Speed > 0) + { + /* Disable coefficient optimization above speed 0 */ + sf->optimize_coefficients = 0; + sf->use_fastquant_for_pick = 1; + sf->no_skip_block4x4_search = 0; + + sf->first_step = 1; + } + + if (Speed > 2) + { + sf->improved_quant = 0; + sf->improved_dct = 0; + + // Only do recode loop on key frames, golden frames and + // alt ref frames + sf->recode_loop = 2; + + } + + if (Speed > 3) + { + sf->auto_filter = 1; + sf->recode_loop = 0; // recode loop off + sf->RD = 0; // Turn rd off + + } + + if (Speed > 4) + { + sf->auto_filter = 0; // Faster selection of loop filter + } + + break; +#endif + case 2: + sf->optimize_coefficients = 0; + sf->recode_loop = 0; + sf->auto_filter = 1; + sf->iterative_sub_pixel = 1; + sf->search_method = NSTEP; + + if (Speed > 0) + { + sf->improved_quant = 0; + sf->improved_dct = 0; + + sf->use_fastquant_for_pick = 1; + sf->no_skip_block4x4_search = 0; + sf->first_step = 1; + } + + if (Speed > 2) + sf->auto_filter = 0; // Faster selection of loop filter + + if (Speed > 3) + { + sf->RD = 0; + sf->auto_filter = 1; + } + + if (Speed > 4) + { + sf->auto_filter = 0; // Faster selection of loop filter + sf->search_method = HEX; + sf->iterative_sub_pixel = 0; + } + + if (Speed > 6) + { + unsigned int sum = 0; + unsigned int total_mbs = cm->MBs; + int i, thresh; + unsigned int total_skip; + + int min = 2000; + + if (cpi->oxcf.encode_breakout > 2000) + min = cpi->oxcf.encode_breakout; + + min >>= 7; + + for (i = 0; i < min; i++) + { + sum += cpi->error_bins[i]; + } + + total_skip = sum; + sum = 0; + + // i starts from 2 to make sure thresh started from 2048 + for (; i < 1024; i++) + { + sum += cpi->error_bins[i]; + + if (10 * sum >= (unsigned int)(cpi->Speed - 6)*(total_mbs - total_skip)) + break; + } + + i--; + thresh = (i << 7); + + if (thresh < 2000) + thresh = 2000; + + if (ref_frames > 1) + { + sf->thresh_mult[THR_NEW1 ] = thresh; + sf->thresh_mult[THR_NEAREST1 ] = thresh >> 1; + sf->thresh_mult[THR_NEAR1 ] = thresh >> 1; + } + + if (ref_frames > 2) + { + sf->thresh_mult[THR_NEW2] = thresh << 1; + sf->thresh_mult[THR_NEAREST2 ] = thresh; + sf->thresh_mult[THR_NEAR2 ] = thresh; + } + + if (ref_frames > 3) + { + sf->thresh_mult[THR_NEW3] = thresh << 1; + sf->thresh_mult[THR_NEAREST3 ] = thresh; + sf->thresh_mult[THR_NEAR3 ] = thresh; + } + + sf->improved_mv_pred = 0; + } + + if (Speed > 8) + sf->quarter_pixel_search = 0; + + if(cm->version == 0) + { + cm->filter_type = NORMAL_LOOPFILTER; + + if (Speed >= 14) + cm->filter_type = SIMPLE_LOOPFILTER; + } + else + { + cm->filter_type = SIMPLE_LOOPFILTER; + } + + // This has a big hit on quality. Last resort + if (Speed >= 15) + sf->half_pixel_search = 0; + + vpx_memset(cpi->error_bins, 0, sizeof(cpi->error_bins)); + + }; /* switch */ + + // Slow quant, dct and trellis not worthwhile for first pass + // so make sure they are always turned off. + if ( cpi->pass == 1 ) + { + sf->improved_quant = 0; + sf->optimize_coefficients = 0; + sf->improved_dct = 0; + } + + if (cpi->sf.search_method == NSTEP) + { + vp8_init3smotion_compensation(&cpi->mb, cm->yv12_fb[cm->lst_fb_idx].y_stride); + } + else if (cpi->sf.search_method == DIAMOND) + { + vp8_init_dsmotion_compensation(&cpi->mb, cm->yv12_fb[cm->lst_fb_idx].y_stride); + } + + if (cpi->sf.improved_dct) + { + cpi->mb.short_fdct8x4 = vp8_short_fdct8x4; + cpi->mb.short_fdct4x4 = vp8_short_fdct4x4; + } + else + { + /* No fast FDCT defined for any platform at this time. */ + cpi->mb.short_fdct8x4 = vp8_short_fdct8x4; + cpi->mb.short_fdct4x4 = vp8_short_fdct4x4; + } + + cpi->mb.short_walsh4x4 = vp8_short_walsh4x4; + + if (cpi->sf.improved_quant) + { + cpi->mb.quantize_b = vp8_regular_quantize_b; + cpi->mb.quantize_b_pair = vp8_regular_quantize_b_pair; + } + else + { + cpi->mb.quantize_b = vp8_fast_quantize_b; + cpi->mb.quantize_b_pair = vp8_fast_quantize_b_pair; + } + if (cpi->sf.improved_quant != last_improved_quant) + vp8cx_init_quantizer(cpi); + + if (cpi->sf.iterative_sub_pixel == 1) + { + cpi->find_fractional_mv_step = vp8_find_best_sub_pixel_step_iteratively; + } + else if (cpi->sf.quarter_pixel_search) + { + cpi->find_fractional_mv_step = vp8_find_best_sub_pixel_step; + } + else if (cpi->sf.half_pixel_search) + { + cpi->find_fractional_mv_step = vp8_find_best_half_pixel_step; + } + else + { + cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step; + } + + if (cpi->sf.optimize_coefficients == 1 && cpi->pass!=1) + cpi->mb.optimize = 1; + else + cpi->mb.optimize = 0; + + if (cpi->common.full_pixel) + cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step; + +#ifdef SPEEDSTATS + frames_at_speed[cpi->Speed]++; +#endif +} +#undef GOOD +#undef RT + +static void alloc_raw_frame_buffers(VP8_COMP *cpi) +{ +#if VP8_TEMPORAL_ALT_REF + int width = (cpi->oxcf.Width + 15) & ~15; + int height = (cpi->oxcf.Height + 15) & ~15; +#endif + + cpi->lookahead = vp8_lookahead_init(cpi->oxcf.Width, cpi->oxcf.Height, + cpi->oxcf.lag_in_frames); + if(!cpi->lookahead) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate lag buffers"); + +#if VP8_TEMPORAL_ALT_REF + + if (vp8_yv12_alloc_frame_buffer(&cpi->alt_ref_buffer, + width, height, VP8BORDERINPIXELS)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate altref buffer"); + +#endif +} + + +static void dealloc_raw_frame_buffers(VP8_COMP *cpi) +{ +#if VP8_TEMPORAL_ALT_REF + vp8_yv12_de_alloc_frame_buffer(&cpi->alt_ref_buffer); +#endif + vp8_lookahead_destroy(cpi->lookahead); +} + + +static int vp8_alloc_partition_data(VP8_COMP *cpi) +{ + vpx_free(cpi->mb.pip); + + cpi->mb.pip = vpx_calloc((cpi->common.mb_cols + 1) * + (cpi->common.mb_rows + 1), + sizeof(PARTITION_INFO)); + if(!cpi->mb.pip) + return 1; + + cpi->mb.pi = cpi->mb.pip + cpi->common.mode_info_stride + 1; + + return 0; +} + +void vp8_alloc_compressor_data(VP8_COMP *cpi) +{ + VP8_COMMON *cm = & cpi->common; + + int width = cm->Width; + int height = cm->Height; + + if (vp8_alloc_frame_buffers(cm, width, height)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate frame buffers"); + + if (vp8_alloc_partition_data(cpi)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate partition data"); + + + if ((width & 0xf) != 0) + width += 16 - (width & 0xf); + + if ((height & 0xf) != 0) + height += 16 - (height & 0xf); + + + if (vp8_yv12_alloc_frame_buffer(&cpi->pick_lf_lvl_frame, + width, height, VP8BORDERINPIXELS)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate last frame buffer"); + + if (vp8_yv12_alloc_frame_buffer(&cpi->scaled_source, + width, height, VP8BORDERINPIXELS)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate scaled source buffer"); + + vpx_free(cpi->tok); + + { +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + unsigned int tokens = 8 * 24 * 16; /* one MB for each thread */ +#else + unsigned int tokens = cm->mb_rows * cm->mb_cols * 24 * 16; +#endif + CHECK_MEM_ERROR(cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok))); + } + + // Data used for real time vc mode to see if gf needs refreshing + cpi->inter_zz_count = 0; + cpi->gf_bad_count = 0; + cpi->gf_update_recommended = 0; + + + // Structures used to minitor GF usage + vpx_free(cpi->gf_active_flags); + CHECK_MEM_ERROR(cpi->gf_active_flags, + vpx_calloc(1, cm->mb_rows * cm->mb_cols)); + cpi->gf_active_count = cm->mb_rows * cm->mb_cols; + + vpx_free(cpi->mb_activity_map); + CHECK_MEM_ERROR(cpi->mb_activity_map, + vpx_calloc(sizeof(unsigned int), + cm->mb_rows * cm->mb_cols)); + + vpx_free(cpi->mb_norm_activity_map); + CHECK_MEM_ERROR(cpi->mb_norm_activity_map, + vpx_calloc(sizeof(unsigned int), + cm->mb_rows * cm->mb_cols)); + +#if CONFIG_MULTITHREAD + if (width < 640) + cpi->mt_sync_range = 1; + else if (width <= 1280) + cpi->mt_sync_range = 4; + else if (width <= 2560) + cpi->mt_sync_range = 8; + else + cpi->mt_sync_range = 16; +#endif + + vpx_free(cpi->tplist); + + CHECK_MEM_ERROR(cpi->tplist, vpx_malloc(sizeof(TOKENLIST) * cpi->common.mb_rows)); +} + + +// Quant MOD +static const int q_trans[] = +{ + 0, 1, 2, 3, 4, 5, 7, 8, + 9, 10, 12, 13, 15, 17, 18, 19, + 20, 21, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, + 59, 61, 64, 67, 70, 73, 76, 79, + 82, 85, 88, 91, 94, 97, 100, 103, + 106, 109, 112, 115, 118, 121, 124, 127, +}; + +int vp8_reverse_trans(int x) +{ + int i; + + for (i = 0; i < 64; i++) + if (q_trans[i] >= x) + return i; + + return 63; +}; +void vp8_new_frame_rate(VP8_COMP *cpi, double framerate) +{ + if(framerate < .1) + framerate = 30; + + cpi->frame_rate = framerate; + cpi->output_frame_rate = framerate; + cpi->per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth / + cpi->output_frame_rate); + cpi->av_per_frame_bandwidth = cpi->per_frame_bandwidth; + cpi->min_frame_bandwidth = (int)(cpi->av_per_frame_bandwidth * + cpi->oxcf.two_pass_vbrmin_section / 100); + + // Set Maximum gf/arf interval + cpi->max_gf_interval = ((int)(cpi->output_frame_rate / 2.0) + 2); + + if(cpi->max_gf_interval < 12) + cpi->max_gf_interval = 12; + + // Extended interval for genuinely static scenes + cpi->twopass.static_scene_max_gf_interval = cpi->key_frame_frequency >> 1; + + // Special conditions when altr ref frame enabled in lagged compress mode + if (cpi->oxcf.play_alternate && cpi->oxcf.lag_in_frames) + { + if (cpi->max_gf_interval > cpi->oxcf.lag_in_frames - 1) + cpi->max_gf_interval = cpi->oxcf.lag_in_frames - 1; + + if (cpi->twopass.static_scene_max_gf_interval > cpi->oxcf.lag_in_frames - 1) + cpi->twopass.static_scene_max_gf_interval = cpi->oxcf.lag_in_frames - 1; + } + + if ( cpi->max_gf_interval > cpi->twopass.static_scene_max_gf_interval ) + cpi->max_gf_interval = cpi->twopass.static_scene_max_gf_interval; +} + + +static int +rescale(int val, int num, int denom) +{ + int64_t llnum = num; + int64_t llden = denom; + int64_t llval = val; + + return llval * llnum / llden; +} + + +static void init_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) +{ + VP8_COMMON *cm = &cpi->common; + + cpi->oxcf = *oxcf; + + cpi->auto_gold = 1; + cpi->auto_adjust_gold_quantizer = 1; + cpi->goldfreq = 7; + + cm->version = oxcf->Version; + vp8_setup_version(cm); + + /* frame rate is not available on the first frame, as it's derived from + * the observed timestamps. The actual value used here doesn't matter + * too much, as it will adapt quickly. If the reciprocal of the timebase + * seems like a reasonable framerate, then use that as a guess, otherwise + * use 30. + */ + cpi->frame_rate = (double)(oxcf->timebase.den) / + (double)(oxcf->timebase.num); + + if (cpi->frame_rate > 180) + cpi->frame_rate = 30; + + cpi->ref_frame_rate = cpi->frame_rate; + + // change includes all joint functionality + vp8_change_config(cpi, oxcf); + + // Initialize active best and worst q and average q values. + cpi->active_worst_quality = cpi->oxcf.worst_allowed_q; + cpi->active_best_quality = cpi->oxcf.best_allowed_q; + cpi->avg_frame_qindex = cpi->oxcf.worst_allowed_q; + + // Initialise the starting buffer levels + cpi->buffer_level = cpi->oxcf.starting_buffer_level; + cpi->bits_off_target = cpi->oxcf.starting_buffer_level; + + cpi->rolling_target_bits = cpi->av_per_frame_bandwidth; + cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth; + cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth; + cpi->long_rolling_actual_bits = cpi->av_per_frame_bandwidth; + + cpi->total_actual_bits = 0; + cpi->total_target_vs_actual = 0; + + // Temporal scalabilty + if (cpi->oxcf.number_of_layers > 1) + { + unsigned int i; + double prev_layer_frame_rate=0; + + for (i=0; ioxcf.number_of_layers; i++) + { + LAYER_CONTEXT *lc = &cpi->layer_context[i]; + + // Layer configuration + lc->frame_rate = + cpi->output_frame_rate / cpi->oxcf.rate_decimator[i]; + lc->target_bandwidth = cpi->oxcf.target_bitrate[i] * 1000; + + lc->starting_buffer_level_in_ms = oxcf->starting_buffer_level; + lc->optimal_buffer_level_in_ms = oxcf->optimal_buffer_level; + lc->maximum_buffer_size_in_ms = oxcf->maximum_buffer_size; + + lc->starting_buffer_level = + rescale(oxcf->starting_buffer_level, + lc->target_bandwidth, 1000); + + if (oxcf->optimal_buffer_level == 0) + lc->optimal_buffer_level = lc->target_bandwidth / 8; + else + lc->optimal_buffer_level = + rescale(oxcf->optimal_buffer_level, + lc->target_bandwidth, 1000); + + if (oxcf->maximum_buffer_size == 0) + lc->maximum_buffer_size = lc->target_bandwidth / 8; + else + lc->maximum_buffer_size = + rescale(oxcf->maximum_buffer_size, + lc->target_bandwidth, 1000); + + // Work out the average size of a frame within this layer + if (i > 0) + lc->avg_frame_size_for_layer = (cpi->oxcf.target_bitrate[i] - + cpi->oxcf.target_bitrate[i-1]) * 1000 / + (lc->frame_rate - prev_layer_frame_rate); + + lc->active_worst_quality = cpi->oxcf.worst_allowed_q; + lc->active_best_quality = cpi->oxcf.best_allowed_q; + lc->avg_frame_qindex = cpi->oxcf.worst_allowed_q; + + lc->buffer_level = lc->starting_buffer_level; + lc->bits_off_target = lc->starting_buffer_level; + + lc->total_actual_bits = 0; + lc->ni_av_qi = 0; + lc->ni_tot_qi = 0; + lc->ni_frames = 0; + lc->rate_correction_factor = 1.0; + lc->key_frame_rate_correction_factor = 1.0; + lc->gf_rate_correction_factor = 1.0; + lc->inter_frame_target = 0.0; + + prev_layer_frame_rate = lc->frame_rate; + } + } + +#if VP8_TEMPORAL_ALT_REF + { + int i; + + cpi->fixed_divide[0] = 0; + + for (i = 1; i < 512; i++) + cpi->fixed_divide[i] = 0x80000 / i; + } +#endif +} + +static void update_layer_contexts (VP8_COMP *cpi) +{ + VP8_CONFIG *oxcf = &cpi->oxcf; + + /* Update snapshots of the layer contexts to reflect new parameters */ + if (oxcf->number_of_layers > 1) + { + unsigned int i; + double prev_layer_frame_rate=0; + + for (i=0; inumber_of_layers; i++) + { + LAYER_CONTEXT *lc = &cpi->layer_context[i]; + + lc->frame_rate = + cpi->ref_frame_rate / oxcf->rate_decimator[i]; + lc->target_bandwidth = oxcf->target_bitrate[i] * 1000; + + lc->starting_buffer_level = rescale( + oxcf->starting_buffer_level_in_ms, + lc->target_bandwidth, 1000); + + if (oxcf->optimal_buffer_level == 0) + lc->optimal_buffer_level = lc->target_bandwidth / 8; + else + lc->optimal_buffer_level = rescale( + oxcf->optimal_buffer_level_in_ms, + lc->target_bandwidth, 1000); + + if (oxcf->maximum_buffer_size == 0) + lc->maximum_buffer_size = lc->target_bandwidth / 8; + else + lc->maximum_buffer_size = rescale( + oxcf->maximum_buffer_size_in_ms, + lc->target_bandwidth, 1000); + + // Work out the average size of a frame within this layer + if (i > 0) + lc->avg_frame_size_for_layer = (oxcf->target_bitrate[i] - + oxcf->target_bitrate[i-1]) * 1000 / + (lc->frame_rate - prev_layer_frame_rate); + + lc->active_worst_quality = oxcf->worst_allowed_q; + lc->active_best_quality = oxcf->best_allowed_q; + lc->avg_frame_qindex = oxcf->worst_allowed_q; + + prev_layer_frame_rate = lc->frame_rate; + } + } +} + +void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) +{ + VP8_COMMON *cm = &cpi->common; + int last_w, last_h; + + if (!cpi) + return; + + if (!oxcf) + return; + +#if CONFIG_MULTITHREAD + /* wait for the last picture loopfilter thread done */ + if (cpi->b_lpf_running) + { + sem_wait(&cpi->h_event_end_lpf); + cpi->b_lpf_running = 0; + } +#endif + + if (cm->version != oxcf->Version) + { + cm->version = oxcf->Version; + vp8_setup_version(cm); + } + + last_w = cpi->oxcf.Width; + last_h = cpi->oxcf.Height; + + cpi->oxcf = *oxcf; + + switch (cpi->oxcf.Mode) + { + + case MODE_REALTIME: + cpi->pass = 0; + cpi->compressor_speed = 2; + + if (cpi->oxcf.cpu_used < -16) + { + cpi->oxcf.cpu_used = -16; + } + + if (cpi->oxcf.cpu_used > 16) + cpi->oxcf.cpu_used = 16; + + break; + + case MODE_GOODQUALITY: + cpi->pass = 0; + cpi->compressor_speed = 1; + + if (cpi->oxcf.cpu_used < -5) + { + cpi->oxcf.cpu_used = -5; + } + + if (cpi->oxcf.cpu_used > 5) + cpi->oxcf.cpu_used = 5; + + break; + + case MODE_BESTQUALITY: + cpi->pass = 0; + cpi->compressor_speed = 0; + break; + + case MODE_FIRSTPASS: + cpi->pass = 1; + cpi->compressor_speed = 1; + break; + case MODE_SECONDPASS: + cpi->pass = 2; + cpi->compressor_speed = 1; + + if (cpi->oxcf.cpu_used < -5) + { + cpi->oxcf.cpu_used = -5; + } + + if (cpi->oxcf.cpu_used > 5) + cpi->oxcf.cpu_used = 5; + + break; + case MODE_SECONDPASS_BEST: + cpi->pass = 2; + cpi->compressor_speed = 0; + break; + } + + if (cpi->pass == 0) + cpi->auto_worst_q = 1; + + cpi->oxcf.worst_allowed_q = q_trans[oxcf->worst_allowed_q]; + cpi->oxcf.best_allowed_q = q_trans[oxcf->best_allowed_q]; + cpi->oxcf.cq_level = q_trans[cpi->oxcf.cq_level]; + + if (oxcf->fixed_q >= 0) + { + if (oxcf->worst_allowed_q < 0) + cpi->oxcf.fixed_q = q_trans[0]; + else + cpi->oxcf.fixed_q = q_trans[oxcf->worst_allowed_q]; + + if (oxcf->alt_q < 0) + cpi->oxcf.alt_q = q_trans[0]; + else + cpi->oxcf.alt_q = q_trans[oxcf->alt_q]; + + if (oxcf->key_q < 0) + cpi->oxcf.key_q = q_trans[0]; + else + cpi->oxcf.key_q = q_trans[oxcf->key_q]; + + if (oxcf->gold_q < 0) + cpi->oxcf.gold_q = q_trans[0]; + else + cpi->oxcf.gold_q = q_trans[oxcf->gold_q]; + + } + + cpi->baseline_gf_interval = + cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL; + + cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; + + //cpi->use_golden_frame_only = 0; + //cpi->use_last_frame_only = 0; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + cm->refresh_entropy_probs = 1; + +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + cpi->oxcf.token_partitions = 3; +#endif + + if (cpi->oxcf.token_partitions >= 0 && cpi->oxcf.token_partitions <= 3) + cm->multi_token_partition = + (TOKEN_PARTITION) cpi->oxcf.token_partitions; + + setup_features(cpi); + + { + int i; + + for (i = 0; i < MAX_MB_SEGMENTS; i++) + cpi->segment_encode_breakout[i] = cpi->oxcf.encode_breakout; + } + + // At the moment the first order values may not be > MAXQ + if (cpi->oxcf.fixed_q > MAXQ) + cpi->oxcf.fixed_q = MAXQ; + + // local file playback mode == really big buffer + if (cpi->oxcf.end_usage == USAGE_LOCAL_FILE_PLAYBACK) + { + cpi->oxcf.starting_buffer_level = 60000; + cpi->oxcf.optimal_buffer_level = 60000; + cpi->oxcf.maximum_buffer_size = 240000; + cpi->oxcf.starting_buffer_level_in_ms = 60000; + cpi->oxcf.optimal_buffer_level_in_ms = 60000; + cpi->oxcf.maximum_buffer_size_in_ms = 240000; + } + + // Convert target bandwidth from Kbit/s to Bit/s + cpi->oxcf.target_bandwidth *= 1000; + + cpi->oxcf.starting_buffer_level = + rescale(cpi->oxcf.starting_buffer_level, + cpi->oxcf.target_bandwidth, 1000); + + // Set or reset optimal and maximum buffer levels. + if (cpi->oxcf.optimal_buffer_level == 0) + cpi->oxcf.optimal_buffer_level = cpi->oxcf.target_bandwidth / 8; + else + cpi->oxcf.optimal_buffer_level = + rescale(cpi->oxcf.optimal_buffer_level, + cpi->oxcf.target_bandwidth, 1000); + + if (cpi->oxcf.maximum_buffer_size == 0) + cpi->oxcf.maximum_buffer_size = cpi->oxcf.target_bandwidth / 8; + else + cpi->oxcf.maximum_buffer_size = + rescale(cpi->oxcf.maximum_buffer_size, + cpi->oxcf.target_bandwidth, 1000); + + // Set up frame rate and related parameters rate control values. + vp8_new_frame_rate(cpi, cpi->frame_rate); + + // Set absolute upper and lower quality limits + cpi->worst_quality = cpi->oxcf.worst_allowed_q; + cpi->best_quality = cpi->oxcf.best_allowed_q; + + // active values should only be modified if out of new range + if (cpi->active_worst_quality > cpi->oxcf.worst_allowed_q) + { + cpi->active_worst_quality = cpi->oxcf.worst_allowed_q; + } + // less likely + else if (cpi->active_worst_quality < cpi->oxcf.best_allowed_q) + { + cpi->active_worst_quality = cpi->oxcf.best_allowed_q; + } + if (cpi->active_best_quality < cpi->oxcf.best_allowed_q) + { + cpi->active_best_quality = cpi->oxcf.best_allowed_q; + } + // less likely + else if (cpi->active_best_quality > cpi->oxcf.worst_allowed_q) + { + cpi->active_best_quality = cpi->oxcf.worst_allowed_q; + } + + cpi->buffered_mode = cpi->oxcf.optimal_buffer_level > 0; + + cpi->cq_target_quality = cpi->oxcf.cq_level; + + // Only allow dropped frames in buffered mode + cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode; + + if (!cm->use_bilinear_mc_filter) + cm->mcomp_filter_type = SIXTAP; + else + cm->mcomp_filter_type = BILINEAR; + + cpi->target_bandwidth = cpi->oxcf.target_bandwidth; + + + cm->Width = cpi->oxcf.Width; + cm->Height = cpi->oxcf.Height; + + /* TODO(jkoleszar): if an internal spatial resampling is active, + * and we downsize the input image, maybe we should clear the + * internal scale immediately rather than waiting for it to + * correct. + */ + + // VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs) + if (cpi->oxcf.Sharpness > 7) + cpi->oxcf.Sharpness = 7; + + cm->sharpness_level = cpi->oxcf.Sharpness; + + if (cm->horiz_scale != NORMAL || cm->vert_scale != NORMAL) + { + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + + // always go to the next whole number + cm->Width = (hs - 1 + cpi->oxcf.Width * hr) / hs; + cm->Height = (vs - 1 + cpi->oxcf.Height * vr) / vs; + } + + if (last_w != cpi->oxcf.Width || last_h != cpi->oxcf.Height) + cpi->force_next_frame_intra = 1; + + if (((cm->Width + 15) & 0xfffffff0) != + cm->yv12_fb[cm->lst_fb_idx].y_width || + ((cm->Height + 15) & 0xfffffff0) != + cm->yv12_fb[cm->lst_fb_idx].y_height || + cm->yv12_fb[cm->lst_fb_idx].y_width == 0) + { + alloc_raw_frame_buffers(cpi); + vp8_alloc_compressor_data(cpi); + } + + if (cpi->oxcf.fixed_q >= 0) + { + cpi->last_q[0] = cpi->oxcf.fixed_q; + cpi->last_q[1] = cpi->oxcf.fixed_q; + } + + cpi->Speed = cpi->oxcf.cpu_used; + + // force to allowlag to 0 if lag_in_frames is 0; + if (cpi->oxcf.lag_in_frames == 0) + { + cpi->oxcf.allow_lag = 0; + } + // Limit on lag buffers as these are not currently dynamically allocated + else if (cpi->oxcf.lag_in_frames > MAX_LAG_BUFFERS) + cpi->oxcf.lag_in_frames = MAX_LAG_BUFFERS; + + // YX Temp + cpi->alt_ref_source = NULL; + cpi->is_src_frame_alt_ref = 0; + +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + if (!cpi->denoiser.yv12_mc_running_avg.buffer_alloc) + { + int width = (cpi->oxcf.Width + 15) & ~15; + int height = (cpi->oxcf.Height + 15) & ~15; + vp8_denoiser_allocate(&cpi->denoiser, width, height); + } + } +#endif + +#if 0 + // Experimental RD Code + cpi->frame_distortion = 0; + cpi->last_frame_distortion = 0; +#endif + +} + +#define M_LOG2_E 0.693147180559945309417 +#define log2f(x) (log (x) / (float) M_LOG2_E) +static void cal_mvsadcosts(int *mvsadcost[2]) +{ + int i = 1; + + mvsadcost [0] [0] = 300; + mvsadcost [1] [0] = 300; + + do + { + double z = 256 * (2 * (log2f(8 * i) + .6)); + mvsadcost [0][i] = (int) z; + mvsadcost [1][i] = (int) z; + mvsadcost [0][-i] = (int) z; + mvsadcost [1][-i] = (int) z; + } + while (++i <= mvfp_max); +} + +struct VP8_COMP* vp8_create_compressor(VP8_CONFIG *oxcf) +{ + int i; + + VP8_COMP *cpi; + VP8_COMMON *cm; + + cpi = vpx_memalign(32, sizeof(VP8_COMP)); + // Check that the CPI instance is valid + if (!cpi) + return 0; + + cm = &cpi->common; + + vpx_memset(cpi, 0, sizeof(VP8_COMP)); + + if (setjmp(cm->error.jmp)) + { + cpi->common.error.setjmp = 0; + vp8_remove_compressor(&cpi); + return 0; + } + + cpi->common.error.setjmp = 1; + + CHECK_MEM_ERROR(cpi->mb.ss, vpx_calloc(sizeof(search_site), (MAX_MVSEARCH_STEPS * 8) + 1)); + + vp8_create_common(&cpi->common); + + init_config(cpi, oxcf); + + memcpy(cpi->base_skip_false_prob, vp8cx_base_skip_false_prob, sizeof(vp8cx_base_skip_false_prob)); + cpi->common.current_video_frame = 0; + cpi->kf_overspend_bits = 0; + cpi->kf_bitrate_adjustment = 0; + cpi->frames_till_gf_update_due = 0; + cpi->gf_overspend_bits = 0; + cpi->non_gf_bitrate_adjustment = 0; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + cpi->prob_intra_coded = 63; + + // Prime the recent reference frame usage counters. + // Hereafter they will be maintained as a sort of moving average + cpi->recent_ref_frame_usage[INTRA_FRAME] = 1; + cpi->recent_ref_frame_usage[LAST_FRAME] = 1; + cpi->recent_ref_frame_usage[GOLDEN_FRAME] = 1; + cpi->recent_ref_frame_usage[ALTREF_FRAME] = 1; + + // Set reference frame sign bias for ALTREF frame to 1 (for now) + cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 1; + + cpi->twopass.gf_decay_rate = 0; + cpi->baseline_gf_interval = DEFAULT_GF_INTERVAL; + + cpi->gold_is_last = 0 ; + cpi->alt_is_last = 0 ; + cpi->gold_is_alt = 0 ; + + // allocate memory for storing last frame's MVs for MV prediction. + CHECK_MEM_ERROR(cpi->lfmv, vpx_calloc((cpi->common.mb_rows+2) * (cpi->common.mb_cols+2), sizeof(int_mv))); + CHECK_MEM_ERROR(cpi->lf_ref_frame_sign_bias, vpx_calloc((cpi->common.mb_rows+2) * (cpi->common.mb_cols+2), sizeof(int))); + CHECK_MEM_ERROR(cpi->lf_ref_frame, vpx_calloc((cpi->common.mb_rows+2) * (cpi->common.mb_cols+2), sizeof(int))); + + // Create the encoder segmentation map and set all entries to 0 + CHECK_MEM_ERROR(cpi->segmentation_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + CHECK_MEM_ERROR(cpi->active_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + vpx_memset(cpi->active_map , 1, (cpi->common.mb_rows * cpi->common.mb_cols)); + cpi->active_map_enabled = 0; + +#if 0 + // Experimental code for lagged and one pass + // Initialise one_pass GF frames stats + // Update stats used for GF selection + if (cpi->pass == 0) + { + cpi->one_pass_frame_index = 0; + + for (i = 0; i < MAX_LAG_BUFFERS; i++) + { + cpi->one_pass_frame_stats[i].frames_so_far = 0; + cpi->one_pass_frame_stats[i].frame_intra_error = 0.0; + cpi->one_pass_frame_stats[i].frame_coded_error = 0.0; + cpi->one_pass_frame_stats[i].frame_pcnt_inter = 0.0; + cpi->one_pass_frame_stats[i].frame_pcnt_motion = 0.0; + cpi->one_pass_frame_stats[i].frame_mvr = 0.0; + cpi->one_pass_frame_stats[i].frame_mvr_abs = 0.0; + cpi->one_pass_frame_stats[i].frame_mvc = 0.0; + cpi->one_pass_frame_stats[i].frame_mvc_abs = 0.0; + } + } +#endif + + // Should we use the cyclic refresh method. + // Currently this is tied to error resilliant mode + cpi->cyclic_refresh_mode_enabled = cpi->oxcf.error_resilient_mode; + cpi->cyclic_refresh_mode_max_mbs_perframe = (cpi->common.mb_rows * cpi->common.mb_cols) / 40; + cpi->cyclic_refresh_mode_index = 0; + cpi->cyclic_refresh_q = 32; + + if (cpi->cyclic_refresh_mode_enabled) + { + CHECK_MEM_ERROR(cpi->cyclic_refresh_map, vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1)); + } + else + cpi->cyclic_refresh_map = (signed char *) NULL; + + // Test function for segmentation + //segmentation_test_function( cpi); + +#ifdef ENTROPY_STATS + init_context_counters(); +#endif + + /*Initialize the feed-forward activity masking.*/ + cpi->activity_avg = 90<<12; + + cpi->frames_since_key = 8; // Give a sensible default for the first frame. + cpi->key_frame_frequency = cpi->oxcf.key_freq; + cpi->this_key_frame_forced = 0; + cpi->next_key_frame_forced = 0; + + cpi->source_alt_ref_pending = 0; + cpi->source_alt_ref_active = 0; + cpi->common.refresh_alt_ref_frame = 0; + + cpi->b_calculate_psnr = CONFIG_INTERNAL_STATS; +#if CONFIG_INTERNAL_STATS + cpi->b_calculate_ssimg = 0; + + cpi->count = 0; + cpi->bytes = 0; + + if (cpi->b_calculate_psnr) + { + cpi->total_sq_error = 0.0; + cpi->total_sq_error2 = 0.0; + cpi->total_y = 0.0; + cpi->total_u = 0.0; + cpi->total_v = 0.0; + cpi->total = 0.0; + cpi->totalp_y = 0.0; + cpi->totalp_u = 0.0; + cpi->totalp_v = 0.0; + cpi->totalp = 0.0; + cpi->tot_recode_hits = 0; + cpi->summed_quality = 0; + cpi->summed_weights = 0; + } + + if (cpi->b_calculate_ssimg) + { + cpi->total_ssimg_y = 0; + cpi->total_ssimg_u = 0; + cpi->total_ssimg_v = 0; + cpi->total_ssimg_all = 0; + } + +#endif + +#ifndef LLONG_MAX +#define LLONG_MAX 9223372036854775807LL +#endif + cpi->first_time_stamp_ever = LLONG_MAX; + + cpi->frames_till_gf_update_due = 0; + cpi->key_frame_count = 1; + + cpi->ni_av_qi = cpi->oxcf.worst_allowed_q; + cpi->ni_tot_qi = 0; + cpi->ni_frames = 0; + cpi->total_byte_count = 0; + + cpi->drop_frame = 0; + cpi->drop_count = 0; + cpi->max_drop_count = 0; + cpi->max_consec_dropped_frames = 4; + + cpi->rate_correction_factor = 1.0; + cpi->key_frame_rate_correction_factor = 1.0; + cpi->gf_rate_correction_factor = 1.0; + cpi->twopass.est_max_qcorrection_factor = 1.0; + + cpi->mb.mvcost[0] = &cpi->mb.mvcosts[0][mv_max+1]; + cpi->mb.mvcost[1] = &cpi->mb.mvcosts[1][mv_max+1]; + cpi->mb.mvsadcost[0] = &cpi->mb.mvsadcosts[0][mvfp_max+1]; + cpi->mb.mvsadcost[1] = &cpi->mb.mvsadcosts[1][mvfp_max+1]; + + cal_mvsadcosts(cpi->mb.mvsadcost); + + for (i = 0; i < KEY_FRAME_CONTEXT; i++) + { + cpi->prior_key_frame_distance[i] = (int)cpi->output_frame_rate; + } + +#ifdef OUTPUT_YUV_SRC + yuv_file = fopen("bd.yuv", "ab"); +#endif + +#if 0 + framepsnr = fopen("framepsnr.stt", "a"); + kf_list = fopen("kf_list.stt", "w"); +#endif + + cpi->output_pkt_list = oxcf->output_pkt_list; + +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 1) + { + vp8_init_first_pass(cpi); + } + else if (cpi->pass == 2) + { + size_t packet_sz = sizeof(FIRSTPASS_STATS); + int packets = oxcf->two_pass_stats_in.sz / packet_sz; + + cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf; + cpi->twopass.stats_in = cpi->twopass.stats_in_start; + cpi->twopass.stats_in_end = (void*)((char *)cpi->twopass.stats_in + + (packets - 1) * packet_sz); + vp8_init_second_pass(cpi); + } + +#endif + + if (cpi->compressor_speed == 2) + { + cpi->cpu_freq = 0; //vp8_get_processor_freq(); + cpi->avg_encode_time = 0; + cpi->avg_pick_mode_time = 0; + } + + vp8_set_speed_features(cpi); + + // Set starting values of RD threshold multipliers (128 = *1) + for (i = 0; i < MAX_MODES; i++) + { + cpi->rd_thresh_mult[i] = 128; + } + +#ifdef ENTROPY_STATS + init_mv_ref_counts(); +#endif + +#if CONFIG_MULTITHREAD + vp8cx_create_encoder_threads(cpi); +#endif + + cpi->fn_ptr[BLOCK_16X16].sdf = vp8_sad16x16; + cpi->fn_ptr[BLOCK_16X16].vf = vp8_variance16x16; + cpi->fn_ptr[BLOCK_16X16].svf = vp8_sub_pixel_variance16x16; + cpi->fn_ptr[BLOCK_16X16].svf_halfpix_h = vp8_variance_halfpixvar16x16_h; + cpi->fn_ptr[BLOCK_16X16].svf_halfpix_v = vp8_variance_halfpixvar16x16_v; + cpi->fn_ptr[BLOCK_16X16].svf_halfpix_hv = vp8_variance_halfpixvar16x16_hv; + cpi->fn_ptr[BLOCK_16X16].sdx3f = vp8_sad16x16x3; + cpi->fn_ptr[BLOCK_16X16].sdx8f = vp8_sad16x16x8; + cpi->fn_ptr[BLOCK_16X16].sdx4df = vp8_sad16x16x4d; + + cpi->fn_ptr[BLOCK_16X8].sdf = vp8_sad16x8; + cpi->fn_ptr[BLOCK_16X8].vf = vp8_variance16x8; + cpi->fn_ptr[BLOCK_16X8].svf = vp8_sub_pixel_variance16x8; + cpi->fn_ptr[BLOCK_16X8].svf_halfpix_h = NULL; + cpi->fn_ptr[BLOCK_16X8].svf_halfpix_v = NULL; + cpi->fn_ptr[BLOCK_16X8].svf_halfpix_hv = NULL; + cpi->fn_ptr[BLOCK_16X8].sdx3f = vp8_sad16x8x3; + cpi->fn_ptr[BLOCK_16X8].sdx8f = vp8_sad16x8x8; + cpi->fn_ptr[BLOCK_16X8].sdx4df = vp8_sad16x8x4d; + + cpi->fn_ptr[BLOCK_8X16].sdf = vp8_sad8x16; + cpi->fn_ptr[BLOCK_8X16].vf = vp8_variance8x16; + cpi->fn_ptr[BLOCK_8X16].svf = vp8_sub_pixel_variance8x16; + cpi->fn_ptr[BLOCK_8X16].svf_halfpix_h = NULL; + cpi->fn_ptr[BLOCK_8X16].svf_halfpix_v = NULL; + cpi->fn_ptr[BLOCK_8X16].svf_halfpix_hv = NULL; + cpi->fn_ptr[BLOCK_8X16].sdx3f = vp8_sad8x16x3; + cpi->fn_ptr[BLOCK_8X16].sdx8f = vp8_sad8x16x8; + cpi->fn_ptr[BLOCK_8X16].sdx4df = vp8_sad8x16x4d; + + cpi->fn_ptr[BLOCK_8X8].sdf = vp8_sad8x8; + cpi->fn_ptr[BLOCK_8X8].vf = vp8_variance8x8; + cpi->fn_ptr[BLOCK_8X8].svf = vp8_sub_pixel_variance8x8; + cpi->fn_ptr[BLOCK_8X8].svf_halfpix_h = NULL; + cpi->fn_ptr[BLOCK_8X8].svf_halfpix_v = NULL; + cpi->fn_ptr[BLOCK_8X8].svf_halfpix_hv = NULL; + cpi->fn_ptr[BLOCK_8X8].sdx3f = vp8_sad8x8x3; + cpi->fn_ptr[BLOCK_8X8].sdx8f = vp8_sad8x8x8; + cpi->fn_ptr[BLOCK_8X8].sdx4df = vp8_sad8x8x4d; + + cpi->fn_ptr[BLOCK_4X4].sdf = vp8_sad4x4; + cpi->fn_ptr[BLOCK_4X4].vf = vp8_variance4x4; + cpi->fn_ptr[BLOCK_4X4].svf = vp8_sub_pixel_variance4x4; + cpi->fn_ptr[BLOCK_4X4].svf_halfpix_h = NULL; + cpi->fn_ptr[BLOCK_4X4].svf_halfpix_v = NULL; + cpi->fn_ptr[BLOCK_4X4].svf_halfpix_hv = NULL; + cpi->fn_ptr[BLOCK_4X4].sdx3f = vp8_sad4x4x3; + cpi->fn_ptr[BLOCK_4X4].sdx8f = vp8_sad4x4x8; + cpi->fn_ptr[BLOCK_4X4].sdx4df = vp8_sad4x4x4d; + +#if ARCH_X86 || ARCH_X86_64 + cpi->fn_ptr[BLOCK_16X16].copymem = vp8_copy32xn; + cpi->fn_ptr[BLOCK_16X8].copymem = vp8_copy32xn; + cpi->fn_ptr[BLOCK_8X16].copymem = vp8_copy32xn; + cpi->fn_ptr[BLOCK_8X8].copymem = vp8_copy32xn; + cpi->fn_ptr[BLOCK_4X4].copymem = vp8_copy32xn; +#endif + + cpi->full_search_sad = vp8_full_search_sad; + cpi->diamond_search_sad = vp8_diamond_search_sad; + cpi->refining_search_sad = vp8_refining_search_sad; + + // make sure frame 1 is okay + cpi->error_bins[0] = cpi->common.MBs; + + //vp8cx_init_quantizer() is first called here. Add check in vp8cx_frame_init_quantizer() so that vp8cx_init_quantizer is only called later + //when needed. This will avoid unnecessary calls of vp8cx_init_quantizer() for every frame. + vp8cx_init_quantizer(cpi); + + vp8_loop_filter_init(cm); + + cpi->common.error.setjmp = 0; + +#if CONFIG_MULTI_RES_ENCODING + /* Calculate # of MBs in a row in lower-resolution level image. */ + if (cpi->oxcf.mr_encoder_id > 0) + vp8_cal_low_res_mb_cols(cpi); +#endif + + return cpi; + +} + + +void vp8_remove_compressor(VP8_COMP **ptr) +{ + VP8_COMP *cpi = *ptr; + + if (!cpi) + return; + + if (cpi && (cpi->common.current_video_frame > 0)) + { +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 2) + { + vp8_end_second_pass(cpi); + } + +#endif + +#ifdef ENTROPY_STATS + print_context_counters(); + print_tree_update_probs(); + print_mode_context(); +#endif + +#if CONFIG_INTERNAL_STATS + + if (cpi->pass != 1) + { + FILE *f = fopen("opsnr.stt", "a"); + double time_encoded = (cpi->last_end_time_stamp_seen + - cpi->first_time_stamp_ever) / 10000000.000; + double total_encode_time = (cpi->time_receive_data + + cpi->time_compress_data) / 1000.000; + double dr = (double)cpi->bytes * 8.0 / 1000.0 / time_encoded; + + if (cpi->b_calculate_psnr) + { + YV12_BUFFER_CONFIG *lst_yv12 = + &cpi->common.yv12_fb[cpi->common.lst_fb_idx]; + + if (cpi->oxcf.number_of_layers > 1) + { + int i; + + fprintf(f, "Layer\tBitrate\tAVGPsnr\tGLBPsnr\tAVPsnrP\t" + "GLPsnrP\tVPXSSIM\t\n"); + for (i=0; ioxcf.number_of_layers; i++) + { + double dr = (double)cpi->bytes_in_layer[i] * + 8.0 / 1000.0 / time_encoded; + double samples = 3.0 / 2 * cpi->frames_in_layer[i] * + lst_yv12->y_width * lst_yv12->y_height; + double total_psnr = vp8_mse2psnr(samples, 255.0, + cpi->total_error2[i]); + double total_psnr2 = vp8_mse2psnr(samples, 255.0, + cpi->total_error2_p[i]); + double total_ssim = 100 * pow(cpi->sum_ssim[i] / + cpi->sum_weights[i], 8.0); + + fprintf(f, "%5d\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t" + "%7.3f\t%7.3f\n", + i, dr, + cpi->sum_psnr[i] / cpi->frames_in_layer[i], + total_psnr, + cpi->sum_psnr_p[i] / cpi->frames_in_layer[i], + total_psnr2, total_ssim); + } + } + else + { + double samples = 3.0 / 2 * cpi->count * + lst_yv12->y_width * lst_yv12->y_height; + double total_psnr = vp8_mse2psnr(samples, 255.0, + cpi->total_sq_error); + double total_psnr2 = vp8_mse2psnr(samples, 255.0, + cpi->total_sq_error2); + double total_ssim = 100 * pow(cpi->summed_quality / + cpi->summed_weights, 8.0); + + fprintf(f, "Bitrate\tAVGPsnr\tGLBPsnr\tAVPsnrP\t" + "GLPsnrP\tVPXSSIM\t Time(us)\n"); + fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t" + "%7.3f\t%8.0f\n", + dr, cpi->total / cpi->count, total_psnr, + cpi->totalp / cpi->count, total_psnr2, + total_ssim, total_encode_time); + } + } + + if (cpi->b_calculate_ssimg) + { + if (cpi->oxcf.number_of_layers > 1) + { + int i; + + fprintf(f, "Layer\tBitRate\tSSIM_Y\tSSIM_U\tSSIM_V\tSSIM_A\t" + "Time(us)\n"); + for (i=0; ioxcf.number_of_layers; i++) + { + double dr = (double)cpi->bytes_in_layer[i] * + 8.0 / 1000.0 / time_encoded; + fprintf(f, "%5d\t%7.3f\t%6.4f\t" + "%6.4f\t%6.4f\t%6.4f\t%8.0f\n", + i, dr, + cpi->total_ssimg_y_in_layer[i] / + cpi->frames_in_layer[i], + cpi->total_ssimg_u_in_layer[i] / + cpi->frames_in_layer[i], + cpi->total_ssimg_v_in_layer[i] / + cpi->frames_in_layer[i], + cpi->total_ssimg_all_in_layer[i] / + cpi->frames_in_layer[i], + total_encode_time); + } + } + else + { + fprintf(f, "BitRate\tSSIM_Y\tSSIM_U\tSSIM_V\tSSIM_A\t" + "Time(us)\n"); + fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f\n", dr, + cpi->total_ssimg_y / cpi->count, + cpi->total_ssimg_u / cpi->count, + cpi->total_ssimg_v / cpi->count, + cpi->total_ssimg_all / cpi->count, total_encode_time); + } + } + + fclose(f); +#if 0 + f = fopen("qskip.stt", "a"); + fprintf(f, "minq:%d -maxq:%d skiptrue:skipfalse = %d:%d\n", cpi->oxcf.best_allowed_q, cpi->oxcf.worst_allowed_q, skiptruecount, skipfalsecount); + fclose(f); +#endif + + } + +#endif + + +#ifdef SPEEDSTATS + + if (cpi->compressor_speed == 2) + { + int i; + FILE *f = fopen("cxspeed.stt", "a"); + cnt_pm /= cpi->common.MBs; + + for (i = 0; i < 16; i++) + fprintf(f, "%5d", frames_at_speed[i]); + + fprintf(f, "\n"); + //fprintf(f, "%10d PM %10d %10d %10d EF %10d %10d %10d\n", cpi->Speed, cpi->avg_pick_mode_time, (tot_pm/cnt_pm), cnt_pm, cpi->avg_encode_time, 0, 0); + fclose(f); + } + +#endif + + +#ifdef MODE_STATS + { + extern int count_mb_seg[4]; + FILE *f = fopen("modes.stt", "a"); + double dr = (double)cpi->frame_rate * (double)bytes * (double)8 / (double)count / (double)1000 ; + fprintf(f, "intra_mode in Intra Frames:\n"); + fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d\n", y_modes[0], y_modes[1], y_modes[2], y_modes[3], y_modes[4]); + fprintf(f, "UV:%8d, %8d, %8d, %8d\n", uv_modes[0], uv_modes[1], uv_modes[2], uv_modes[3]); + fprintf(f, "B: "); + { + int i; + + for (i = 0; i < 10; i++) + fprintf(f, "%8d, ", b_modes[i]); + + fprintf(f, "\n"); + + } + + fprintf(f, "Modes in Inter Frames:\n"); + fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d\n", + inter_y_modes[0], inter_y_modes[1], inter_y_modes[2], inter_y_modes[3], inter_y_modes[4], + inter_y_modes[5], inter_y_modes[6], inter_y_modes[7], inter_y_modes[8], inter_y_modes[9]); + fprintf(f, "UV:%8d, %8d, %8d, %8d\n", inter_uv_modes[0], inter_uv_modes[1], inter_uv_modes[2], inter_uv_modes[3]); + fprintf(f, "B: "); + { + int i; + + for (i = 0; i < 15; i++) + fprintf(f, "%8d, ", inter_b_modes[i]); + + fprintf(f, "\n"); + + } + fprintf(f, "P:%8d, %8d, %8d, %8d\n", count_mb_seg[0], count_mb_seg[1], count_mb_seg[2], count_mb_seg[3]); + fprintf(f, "PB:%8d, %8d, %8d, %8d\n", inter_b_modes[LEFT4X4], inter_b_modes[ABOVE4X4], inter_b_modes[ZERO4X4], inter_b_modes[NEW4X4]); + + + + fclose(f); + } +#endif + +#ifdef ENTROPY_STATS + { + int i, j, k; + FILE *fmode = fopen("modecontext.c", "w"); + + fprintf(fmode, "\n#include \"entropymode.h\"\n\n"); + fprintf(fmode, "const unsigned int vp8_kf_default_bmode_counts "); + fprintf(fmode, "[VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES] =\n{\n"); + + for (i = 0; i < 10; i++) + { + + fprintf(fmode, " { //Above Mode : %d\n", i); + + for (j = 0; j < 10; j++) + { + + fprintf(fmode, " {"); + + for (k = 0; k < 10; k++) + { + if (!intra_mode_stats[i][j][k]) + fprintf(fmode, " %5d, ", 1); + else + fprintf(fmode, " %5d, ", intra_mode_stats[i][j][k]); + } + + fprintf(fmode, "}, // left_mode %d\n", j); + + } + + fprintf(fmode, " },\n"); + + } + + fprintf(fmode, "};\n"); + fclose(fmode); + } +#endif + + +#if defined(SECTIONBITS_OUTPUT) + + if (0) + { + int i; + FILE *f = fopen("tokenbits.stt", "a"); + + for (i = 0; i < 28; i++) + fprintf(f, "%8d", (int)(Sectionbits[i] / 256)); + + fprintf(f, "\n"); + fclose(f); + } + +#endif + +#if 0 + { + printf("\n_pick_loop_filter_level:%d\n", cpi->time_pick_lpf / 1000); + printf("\n_frames recive_data encod_mb_row compress_frame Total\n"); + printf("%6d %10ld %10ld %10ld %10ld\n", cpi->common.current_video_frame, cpi->time_receive_data / 1000, cpi->time_encode_mb_row / 1000, cpi->time_compress_data / 1000, (cpi->time_receive_data + cpi->time_compress_data) / 1000); + } +#endif + + } + +#if CONFIG_MULTITHREAD + vp8cx_remove_encoder_threads(cpi); +#endif + +#if CONFIG_TEMPORAL_DENOISING + vp8_denoiser_free(&cpi->denoiser); +#endif + dealloc_compressor_data(cpi); + vpx_free(cpi->mb.ss); + vpx_free(cpi->tok); + vpx_free(cpi->cyclic_refresh_map); + + vp8_remove_common(&cpi->common); + vpx_free(cpi); + *ptr = 0; + +#ifdef OUTPUT_YUV_SRC + fclose(yuv_file); +#endif + +#if 0 + + if (keyfile) + fclose(keyfile); + + if (framepsnr) + fclose(framepsnr); + + if (kf_list) + fclose(kf_list); + +#endif + +} + + +static uint64_t calc_plane_error(unsigned char *orig, int orig_stride, + unsigned char *recon, int recon_stride, + unsigned int cols, unsigned int rows) +{ + unsigned int row, col; + uint64_t total_sse = 0; + int diff; + + for (row = 0; row + 16 <= rows; row += 16) + { + for (col = 0; col + 16 <= cols; col += 16) + { + unsigned int sse; + + vp8_mse16x16(orig + col, orig_stride, + recon + col, recon_stride, + &sse); + total_sse += sse; + } + + /* Handle odd-sized width */ + if (col < cols) + { + unsigned int border_row, border_col; + unsigned char *border_orig = orig; + unsigned char *border_recon = recon; + + for (border_row = 0; border_row < 16; border_row++) + { + for (border_col = col; border_col < cols; border_col++) + { + diff = border_orig[border_col] - border_recon[border_col]; + total_sse += diff * diff; + } + + border_orig += orig_stride; + border_recon += recon_stride; + } + } + + orig += orig_stride * 16; + recon += recon_stride * 16; + } + + /* Handle odd-sized height */ + for (; row < rows; row++) + { + for (col = 0; col < cols; col++) + { + diff = orig[col] - recon[col]; + total_sse += diff * diff; + } + + orig += orig_stride; + recon += recon_stride; + } + + vp8_clear_system_state(); + return total_sse; +} + + +static void generate_psnr_packet(VP8_COMP *cpi) +{ + YV12_BUFFER_CONFIG *orig = cpi->Source; + YV12_BUFFER_CONFIG *recon = cpi->common.frame_to_show; + struct vpx_codec_cx_pkt pkt; + uint64_t sse; + int i; + unsigned int width = cpi->common.Width; + unsigned int height = cpi->common.Height; + + pkt.kind = VPX_CODEC_PSNR_PKT; + sse = calc_plane_error(orig->y_buffer, orig->y_stride, + recon->y_buffer, recon->y_stride, + width, height); + pkt.data.psnr.sse[0] = sse; + pkt.data.psnr.sse[1] = sse; + pkt.data.psnr.samples[0] = width * height; + pkt.data.psnr.samples[1] = width * height; + + width = (width + 1) / 2; + height = (height + 1) / 2; + + sse = calc_plane_error(orig->u_buffer, orig->uv_stride, + recon->u_buffer, recon->uv_stride, + width, height); + pkt.data.psnr.sse[0] += sse; + pkt.data.psnr.sse[2] = sse; + pkt.data.psnr.samples[0] += width * height; + pkt.data.psnr.samples[2] = width * height; + + sse = calc_plane_error(orig->v_buffer, orig->uv_stride, + recon->v_buffer, recon->uv_stride, + width, height); + pkt.data.psnr.sse[0] += sse; + pkt.data.psnr.sse[3] = sse; + pkt.data.psnr.samples[0] += width * height; + pkt.data.psnr.samples[3] = width * height; + + for (i = 0; i < 4; i++) + pkt.data.psnr.psnr[i] = vp8_mse2psnr(pkt.data.psnr.samples[i], 255.0, + pkt.data.psnr.sse[i]); + + vpx_codec_pkt_list_add(cpi->output_pkt_list, &pkt); +} + + +int vp8_use_as_reference(VP8_COMP *cpi, int ref_frame_flags) +{ + if (ref_frame_flags > 7) + return -1 ; + + cpi->ref_frame_flags = ref_frame_flags; + return 0; +} +int vp8_update_reference(VP8_COMP *cpi, int ref_frame_flags) +{ + if (ref_frame_flags > 7) + return -1 ; + + cpi->common.refresh_golden_frame = 0; + cpi->common.refresh_alt_ref_frame = 0; + cpi->common.refresh_last_frame = 0; + + if (ref_frame_flags & VP8_LAST_FLAG) + cpi->common.refresh_last_frame = 1; + + if (ref_frame_flags & VP8_GOLD_FLAG) + cpi->common.refresh_golden_frame = 1; + + if (ref_frame_flags & VP8_ALT_FLAG) + cpi->common.refresh_alt_ref_frame = 1; + + return 0; +} + +int vp8_get_reference(VP8_COMP *cpi, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8_COMMON *cm = &cpi->common; + int ref_fb_idx; + + if (ref_frame_flag == VP8_LAST_FLAG) + ref_fb_idx = cm->lst_fb_idx; + else if (ref_frame_flag == VP8_GOLD_FLAG) + ref_fb_idx = cm->gld_fb_idx; + else if (ref_frame_flag == VP8_ALT_FLAG) + ref_fb_idx = cm->alt_fb_idx; + else + return -1; + + vp8_yv12_copy_frame(&cm->yv12_fb[ref_fb_idx], sd); + + return 0; +} +int vp8_set_reference(VP8_COMP *cpi, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8_COMMON *cm = &cpi->common; + + int ref_fb_idx; + + if (ref_frame_flag == VP8_LAST_FLAG) + ref_fb_idx = cm->lst_fb_idx; + else if (ref_frame_flag == VP8_GOLD_FLAG) + ref_fb_idx = cm->gld_fb_idx; + else if (ref_frame_flag == VP8_ALT_FLAG) + ref_fb_idx = cm->alt_fb_idx; + else + return -1; + + vp8_yv12_copy_frame(sd, &cm->yv12_fb[ref_fb_idx]); + + return 0; +} +int vp8_update_entropy(VP8_COMP *cpi, int update) +{ + VP8_COMMON *cm = &cpi->common; + cm->refresh_entropy_probs = update; + + return 0; +} + + +#if OUTPUT_YUV_SRC +void vp8_write_yuv_frame(const char *name, YV12_BUFFER_CONFIG *s) +{ + FILE *yuv_file = fopen(name, "ab"); + unsigned char *src = s->y_buffer; + int h = s->y_height; + + do + { + fwrite(src, s->y_width, 1, yuv_file); + src += s->y_stride; + } + while (--h); + + src = s->u_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + src = s->v_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + fclose(yuv_file); +} +#endif + + +static void scale_and_extend_source(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // are we resizing the image + if (cm->horiz_scale != 0 || cm->vert_scale != 0) + { +#if CONFIG_SPATIAL_RESAMPLING + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + int tmp_height; + + if (cm->vert_scale == 3) + tmp_height = 9; + else + tmp_height = 11; + + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + + vp8_scale_frame(sd, &cpi->scaled_source, cm->temp_scale_frame.y_buffer, + tmp_height, hs, hr, vs, vr, 0); + + vp8_yv12_extend_frame_borders(&cpi->scaled_source); + cpi->Source = &cpi->scaled_source; +#endif + } + else + cpi->Source = sd; +} + + +static void resize_key_frame(VP8_COMP *cpi) +{ +#if CONFIG_SPATIAL_RESAMPLING + VP8_COMMON *cm = &cpi->common; + + // Do we need to apply resampling for one pass cbr. + // In one pass this is more limited than in two pass cbr + // The test and any change is only made one per key frame sequence + if (cpi->oxcf.allow_spatial_resampling && (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) + { + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + int new_width, new_height; + + // If we are below the resample DOWN watermark then scale down a notch. + if (cpi->buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100)) + { + cm->horiz_scale = (cm->horiz_scale < ONETWO) ? cm->horiz_scale + 1 : ONETWO; + cm->vert_scale = (cm->vert_scale < ONETWO) ? cm->vert_scale + 1 : ONETWO; + } + // Should we now start scaling back up + else if (cpi->buffer_level > (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100)) + { + cm->horiz_scale = (cm->horiz_scale > NORMAL) ? cm->horiz_scale - 1 : NORMAL; + cm->vert_scale = (cm->vert_scale > NORMAL) ? cm->vert_scale - 1 : NORMAL; + } + + // Get the new hieght and width + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + new_width = ((hs - 1) + (cpi->oxcf.Width * hr)) / hs; + new_height = ((vs - 1) + (cpi->oxcf.Height * vr)) / vs; + + // If the image size has changed we need to reallocate the buffers + // and resample the source image + if ((cm->Width != new_width) || (cm->Height != new_height)) + { + cm->Width = new_width; + cm->Height = new_height; + vp8_alloc_compressor_data(cpi); + scale_and_extend_source(cpi->un_scaled_source, cpi); + } + } + +#endif +} + + +static void update_alt_ref_frame_stats(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // Select an interval before next GF or altref + if (!cpi->auto_gold) + cpi->frames_till_gf_update_due = cpi->goldfreq; + + if ((cpi->pass != 2) && cpi->frames_till_gf_update_due) + { + cpi->current_gf_interval = cpi->frames_till_gf_update_due; + + // Set the bits per frame that we should try and recover in subsequent inter frames + // to account for the extra GF spend... note that his does not apply for GF updates + // that occur coincident with a key frame as the extra cost of key frames is dealt + // with elsewhere. + + cpi->gf_overspend_bits += cpi->projected_frame_size; + cpi->non_gf_bitrate_adjustment = cpi->gf_overspend_bits / cpi->frames_till_gf_update_due; + } + + // Update data structure that monitors level of reference to last GF + vpx_memset(cpi->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cpi->gf_active_count = cm->mb_rows * cm->mb_cols; + + // this frame refreshes means next frames don't unless specified by user + cpi->common.frames_since_golden = 0; + + // Clear the alternate reference update pending flag. + cpi->source_alt_ref_pending = 0; + + // Set the alternate refernce frame active flag + cpi->source_alt_ref_active = 1; + + +} +static void update_golden_frame_stats(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // Update the Golden frame usage counts. + if (cm->refresh_golden_frame) + { + // Select an interval before next GF + if (!cpi->auto_gold) + cpi->frames_till_gf_update_due = cpi->goldfreq; + + if ((cpi->pass != 2) && (cpi->frames_till_gf_update_due > 0)) + { + cpi->current_gf_interval = cpi->frames_till_gf_update_due; + + // Set the bits per frame that we should try and recover in subsequent inter frames + // to account for the extra GF spend... note that his does not apply for GF updates + // that occur coincident with a key frame as the extra cost of key frames is dealt + // with elsewhere. + if ((cm->frame_type != KEY_FRAME) && !cpi->source_alt_ref_active) + { + // Calcluate GF bits to be recovered + // Projected size - av frame bits available for inter frames for clip as a whole + cpi->gf_overspend_bits += (cpi->projected_frame_size - cpi->inter_frame_target); + } + + cpi->non_gf_bitrate_adjustment = cpi->gf_overspend_bits / cpi->frames_till_gf_update_due; + + } + + // Update data structure that monitors level of reference to last GF + vpx_memset(cpi->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cpi->gf_active_count = cm->mb_rows * cm->mb_cols; + + // this frame refreshes means next frames don't unless specified by user + cm->refresh_golden_frame = 0; + cpi->common.frames_since_golden = 0; + + //if ( cm->frame_type == KEY_FRAME ) + //{ + cpi->recent_ref_frame_usage[INTRA_FRAME] = 1; + cpi->recent_ref_frame_usage[LAST_FRAME] = 1; + cpi->recent_ref_frame_usage[GOLDEN_FRAME] = 1; + cpi->recent_ref_frame_usage[ALTREF_FRAME] = 1; + //} + //else + //{ + // // Carry a potrtion of count over to begining of next gf sequence + // cpi->recent_ref_frame_usage[INTRA_FRAME] >>= 5; + // cpi->recent_ref_frame_usage[LAST_FRAME] >>= 5; + // cpi->recent_ref_frame_usage[GOLDEN_FRAME] >>= 5; + // cpi->recent_ref_frame_usage[ALTREF_FRAME] >>= 5; + //} + + // ******** Fixed Q test code only ************ + // If we are going to use the ALT reference for the next group of frames set a flag to say so. + if (cpi->oxcf.fixed_q >= 0 && + cpi->oxcf.play_alternate && !cpi->common.refresh_alt_ref_frame) + { + cpi->source_alt_ref_pending = 1; + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + } + + if (!cpi->source_alt_ref_pending) + cpi->source_alt_ref_active = 0; + + // Decrement count down till next gf + if (cpi->frames_till_gf_update_due > 0) + cpi->frames_till_gf_update_due--; + + } + else if (!cpi->common.refresh_alt_ref_frame) + { + // Decrement count down till next gf + if (cpi->frames_till_gf_update_due > 0) + cpi->frames_till_gf_update_due--; + + if (cpi->common.frames_till_alt_ref_frame) + cpi->common.frames_till_alt_ref_frame --; + + cpi->common.frames_since_golden ++; + + if (cpi->common.frames_since_golden > 1) + { + cpi->recent_ref_frame_usage[INTRA_FRAME] += cpi->count_mb_ref_frame_usage[INTRA_FRAME]; + cpi->recent_ref_frame_usage[LAST_FRAME] += cpi->count_mb_ref_frame_usage[LAST_FRAME]; + cpi->recent_ref_frame_usage[GOLDEN_FRAME] += cpi->count_mb_ref_frame_usage[GOLDEN_FRAME]; + cpi->recent_ref_frame_usage[ALTREF_FRAME] += cpi->count_mb_ref_frame_usage[ALTREF_FRAME]; + } + } +} + +// This function updates the reference frame probability estimates that +// will be used during mode selection +static void update_rd_ref_frame_probs(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + if (cm->frame_type == KEY_FRAME) + { + cpi->prob_intra_coded = 255; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + } + else if (!(rf_intra + rf_inter)) + { + cpi->prob_intra_coded = 63; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + } + + // update reference frame costs since we can do better than what we got last frame. + if (cpi->oxcf.number_of_layers == 1) + { + if (cpi->common.refresh_alt_ref_frame) + { + cpi->prob_intra_coded += 40; + cpi->prob_last_coded = 200; + cpi->prob_gf_coded = 1; + } + else if (cpi->common.frames_since_golden == 0) + { + cpi->prob_last_coded = 214; + } + else if (cpi->common.frames_since_golden == 1) + { + cpi->prob_last_coded = 192; + cpi->prob_gf_coded = 220; + } + else if (cpi->source_alt_ref_active) + { + cpi->prob_gf_coded -= 20; + + if (cpi->prob_gf_coded < 10) + cpi->prob_gf_coded = 10; + } + if (!cpi->source_alt_ref_active) + cpi->prob_gf_coded = 255; + } +} + + +// 1 = key, 0 = inter +static int decide_key_frame(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int code_key_frame = 0; + + cpi->kf_boost = 0; + + if (cpi->Speed > 11) + return 0; + + // Clear down mmx registers + vp8_clear_system_state(); //__asm emms; + + if ((cpi->compressor_speed == 2) && (cpi->Speed >= 5) && (cpi->sf.RD == 0)) + { + double change = 1.0 * abs((int)(cpi->intra_error - cpi->last_intra_error)) / (1 + cpi->last_intra_error); + double change2 = 1.0 * abs((int)(cpi->prediction_error - cpi->last_prediction_error)) / (1 + cpi->last_prediction_error); + double minerror = cm->MBs * 256; + +#if 0 + + if (10 * cpi->intra_error / (1 + cpi->prediction_error) < 15 + && cpi->prediction_error > minerror + && (change > .25 || change2 > .25)) + { + FILE *f = fopen("intra_inter.stt", "a"); + + if (cpi->prediction_error <= 0) + cpi->prediction_error = 1; + + fprintf(f, "%d %d %d %d %14.4f\n", + cm->current_video_frame, + (int) cpi->prediction_error, + (int) cpi->intra_error, + (int)((10 * cpi->intra_error) / cpi->prediction_error), + change); + + fclose(f); + } + +#endif + + cpi->last_intra_error = cpi->intra_error; + cpi->last_prediction_error = cpi->prediction_error; + + if (10 * cpi->intra_error / (1 + cpi->prediction_error) < 15 + && cpi->prediction_error > minerror + && (change > .25 || change2 > .25)) + { + /*(change > 1.4 || change < .75)&& cpi->this_frame_percent_intra > cpi->last_frame_percent_intra + 3*/ + return 1; + } + + return 0; + + } + + // If the following are true we might as well code a key frame + if (((cpi->this_frame_percent_intra == 100) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra + 2))) || + ((cpi->this_frame_percent_intra > 95) && + (cpi->this_frame_percent_intra >= (cpi->last_frame_percent_intra + 5)))) + { + code_key_frame = 1; + } + // in addition if the following are true and this is not a golden frame then code a key frame + // Note that on golden frames there often seems to be a pop in intra useage anyway hence this + // restriction is designed to prevent spurious key frames. The Intra pop needs to be investigated. + else if (((cpi->this_frame_percent_intra > 60) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra * 2))) || + ((cpi->this_frame_percent_intra > 75) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra * 3 / 2))) || + ((cpi->this_frame_percent_intra > 90) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra + 10)))) + { + if (!cm->refresh_golden_frame) + code_key_frame = 1; + } + + return code_key_frame; + +} + +#if !(CONFIG_REALTIME_ONLY) +static void Pass1Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned int *frame_flags) +{ + (void) size; + (void) dest; + (void) frame_flags; + vp8_set_quantizer(cpi, 26); + + vp8_first_pass(cpi); +} +#endif + +#if 0 +void write_cx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) +{ + + // write the frame + FILE *yframe; + int i; + char filename[255]; + + sprintf(filename, "cx\\y%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->y_height; i++) + fwrite(frame->y_buffer + i * frame->y_stride, frame->y_width, 1, yframe); + + fclose(yframe); + sprintf(filename, "cx\\u%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->uv_height; i++) + fwrite(frame->u_buffer + i * frame->uv_stride, frame->uv_width, 1, yframe); + + fclose(yframe); + sprintf(filename, "cx\\v%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->uv_height; i++) + fwrite(frame->v_buffer + i * frame->uv_stride, frame->uv_width, 1, yframe); + + fclose(yframe); +} +#endif +// return of 0 means drop frame + +// Function to test for conditions that indeicate we should loop +// back and recode a frame. +static int recode_loop_test( VP8_COMP *cpi, + int high_limit, int low_limit, + int q, int maxq, int minq ) +{ + int force_recode = 0; + VP8_COMMON *cm = &cpi->common; + + // Is frame recode allowed at all + // Yes if either recode mode 1 is selected or mode two is selcted + // and the frame is a key frame. golden frame or alt_ref_frame + if ( (cpi->sf.recode_loop == 1) || + ( (cpi->sf.recode_loop == 2) && + ( (cm->frame_type == KEY_FRAME) || + cm->refresh_golden_frame || + cm->refresh_alt_ref_frame ) ) ) + { + // General over and under shoot tests + if ( ((cpi->projected_frame_size > high_limit) && (q < maxq)) || + ((cpi->projected_frame_size < low_limit) && (q > minq)) ) + { + force_recode = 1; + } + // Special Constrained quality tests + else if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) + { + // Undershoot and below auto cq level + if ( (q > cpi->cq_target_quality) && + (cpi->projected_frame_size < + ((cpi->this_frame_target * 7) >> 3))) + { + force_recode = 1; + } + // Severe undershoot and between auto and user cq level + else if ( (q > cpi->oxcf.cq_level) && + (cpi->projected_frame_size < cpi->min_frame_bandwidth) && + (cpi->active_best_quality > cpi->oxcf.cq_level)) + { + force_recode = 1; + cpi->active_best_quality = cpi->oxcf.cq_level; + } + } + } + + return force_recode; +} + +static void update_reference_frames(VP8_COMMON *cm) +{ + YV12_BUFFER_CONFIG *yv12_fb = cm->yv12_fb; + + // At this point the new frame has been encoded. + // If any buffer copy / swapping is signaled it should be done here. + + if (cm->frame_type == KEY_FRAME) + { + yv12_fb[cm->new_fb_idx].flags |= VP8_GOLD_FLAG | VP8_ALT_FLAG ; + + yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FLAG; + yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALT_FLAG; + + cm->alt_fb_idx = cm->gld_fb_idx = cm->new_fb_idx; + } + else /* For non key frames */ + { + if (cm->refresh_alt_ref_frame) + { + assert(!cm->copy_buffer_to_arf); + + cm->yv12_fb[cm->new_fb_idx].flags |= VP8_ALT_FLAG; + cm->yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALT_FLAG; + cm->alt_fb_idx = cm->new_fb_idx; + } + else if (cm->copy_buffer_to_arf) + { + assert(!(cm->copy_buffer_to_arf & ~0x3)); + + if (cm->copy_buffer_to_arf == 1) + { + if(cm->alt_fb_idx != cm->lst_fb_idx) + { + yv12_fb[cm->lst_fb_idx].flags |= VP8_ALT_FLAG; + yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALT_FLAG; + cm->alt_fb_idx = cm->lst_fb_idx; + } + } + else /* if (cm->copy_buffer_to_arf == 2) */ + { + if(cm->alt_fb_idx != cm->gld_fb_idx) + { + yv12_fb[cm->gld_fb_idx].flags |= VP8_ALT_FLAG; + yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALT_FLAG; + cm->alt_fb_idx = cm->gld_fb_idx; + } + } + } + + if (cm->refresh_golden_frame) + { + assert(!cm->copy_buffer_to_gf); + + cm->yv12_fb[cm->new_fb_idx].flags |= VP8_GOLD_FLAG; + cm->yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FLAG; + cm->gld_fb_idx = cm->new_fb_idx; + } + else if (cm->copy_buffer_to_gf) + { + assert(!(cm->copy_buffer_to_arf & ~0x3)); + + if (cm->copy_buffer_to_gf == 1) + { + if(cm->gld_fb_idx != cm->lst_fb_idx) + { + yv12_fb[cm->lst_fb_idx].flags |= VP8_GOLD_FLAG; + yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FLAG; + cm->gld_fb_idx = cm->lst_fb_idx; + } + } + else /* if (cm->copy_buffer_to_gf == 2) */ + { + if(cm->alt_fb_idx != cm->gld_fb_idx) + { + yv12_fb[cm->alt_fb_idx].flags |= VP8_GOLD_FLAG; + yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FLAG; + cm->gld_fb_idx = cm->alt_fb_idx; + } + } + } + } + + if (cm->refresh_last_frame) + { + cm->yv12_fb[cm->new_fb_idx].flags |= VP8_LAST_FLAG; + cm->yv12_fb[cm->lst_fb_idx].flags &= ~VP8_LAST_FLAG; + cm->lst_fb_idx = cm->new_fb_idx; + } +} + +void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) +{ + if (cm->no_lpf) + { + cm->filter_level = 0; + } + else + { + struct vpx_usec_timer timer; + + vp8_clear_system_state(); + + vpx_usec_timer_start(&timer); + if (cpi->sf.auto_filter == 0) + vp8cx_pick_filter_level_fast(cpi->Source, cpi); + + else + vp8cx_pick_filter_level(cpi->Source, cpi); + + vpx_usec_timer_mark(&timer); + cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); + } + +#if CONFIG_MULTITHREAD + if (cpi->b_multi_threaded) + sem_post(&cpi->h_event_end_lpf); /* signal that we have set filter_level */ +#endif + + if (cm->filter_level > 0) + { + vp8cx_set_alt_lf_level(cpi, cm->filter_level); + vp8_loop_filter_frame(cm, &cpi->mb.e_mbd); + } + + vp8_yv12_extend_frame_borders(cm->frame_to_show); +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + vp8_yv12_extend_frame_borders(&cpi->denoiser.yv12_running_avg); + } +#endif +} + +static void encode_frame_to_data_rate +( + VP8_COMP *cpi, + unsigned long *size, + unsigned char *dest, + unsigned char* dest_end, + unsigned int *frame_flags +) +{ + int Q; + int frame_over_shoot_limit; + int frame_under_shoot_limit; + + int Loop = 0; + int loop_count; + + VP8_COMMON *cm = &cpi->common; + int active_worst_qchanged = 0; + +#if !(CONFIG_REALTIME_ONLY) + int q_low; + int q_high; + int zbin_oq_high; + int zbin_oq_low = 0; + int top_index; + int bottom_index; + int overshoot_seen = 0; + int undershoot_seen = 0; +#endif + + int drop_mark = cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100; + int drop_mark75 = drop_mark * 2 / 3; + int drop_mark50 = drop_mark / 4; + int drop_mark25 = drop_mark / 8; + + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); + +#if CONFIG_MULTITHREAD + /* wait for the last picture loopfilter thread done */ + if (cpi->b_lpf_running) + { + sem_wait(&cpi->h_event_end_lpf); + cpi->b_lpf_running = 0; + } +#endif + + // Test code for segmentation of gf/arf (0,0) + //segmentation_test_function( cpi); + + if(cpi->force_next_frame_intra) + { + cm->frame_type = KEY_FRAME; /* delayed intra frame */ + cpi->force_next_frame_intra = 0; + } + + // For an alt ref frame in 2 pass we skip the call to the second pass function that sets the target bandwidth +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 2) + { + if (cpi->common.refresh_alt_ref_frame) + { + cpi->per_frame_bandwidth = cpi->twopass.gf_bits; // Per frame bit target for the alt ref frame + cpi->target_bandwidth = cpi->twopass.gf_bits * cpi->output_frame_rate; // per second target bitrate + } + } + else +#endif + cpi->per_frame_bandwidth = (int)(cpi->target_bandwidth / cpi->output_frame_rate); + + // Default turn off buffer to buffer copying + cm->copy_buffer_to_gf = 0; + cm->copy_buffer_to_arf = 0; + + // Clear zbin over-quant value and mode boost values. + cpi->zbin_over_quant = 0; + cpi->zbin_mode_boost = 0; + + // Enable or disable mode based tweaking of the zbin + // For 2 Pass Only used where GF/ARF prediction quality + // is above a threshold + cpi->zbin_mode_boost_enabled = 1; + if (cpi->pass == 2) + { + if ( cpi->gfu_boost <= 400 ) + { + cpi->zbin_mode_boost_enabled = 0; + } + } + + // Current default encoder behaviour for the altref sign bias + if (cpi->source_alt_ref_active) + cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 1; + else + cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 0; + + // Check to see if a key frame is signalled + // For two pass with auto key frame enabled cm->frame_type may already be set, but not for one pass. + if ((cm->current_video_frame == 0) || + (cm->frame_flags & FRAMEFLAGS_KEY) || + (cpi->oxcf.auto_key && (cpi->frames_since_key % cpi->key_frame_frequency == 0))) + { + // Key frame from VFW/auto-keyframe/first frame + cm->frame_type = KEY_FRAME; + } + + // Set default state for segment and mode based loop filter update flags + cpi->mb.e_mbd.update_mb_segmentation_map = 0; + cpi->mb.e_mbd.update_mb_segmentation_data = 0; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + + // Set various flags etc to special state if it is a key frame + if (cm->frame_type == KEY_FRAME) + { + int i; + + // Reset the loop filter deltas and segmentation map + setup_features(cpi); + + // If segmentation is enabled force a map update for key frames + if (cpi->mb.e_mbd.segmentation_enabled) + { + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; + } + + // The alternate reference frame cannot be active for a key frame + cpi->source_alt_ref_active = 0; + + // Reset the RD threshold multipliers to default of * 1 (128) + for (i = 0; i < MAX_MODES; i++) + { + cpi->rd_thresh_mult[i] = 128; + } + } + + // Test code for segmentation + //if ( (cm->frame_type == KEY_FRAME) || ((cm->current_video_frame % 2) == 0)) + //if ( (cm->current_video_frame % 2) == 0 ) + // enable_segmentation(cpi); + //else + // disable_segmentation(cpi); + +#if 0 + // Experimental code for lagged compress and one pass + // Initialise one_pass GF frames stats + // Update stats used for GF selection + //if ( cpi->pass == 0 ) + { + cpi->one_pass_frame_index = cm->current_video_frame % MAX_LAG_BUFFERS; + + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frames_so_far = 0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_intra_error = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_coded_error = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_pcnt_inter = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_pcnt_motion = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvr = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvr_abs = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvc = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvc_abs = 0.0; + } +#endif + + update_rd_ref_frame_probs(cpi); + + if (cpi->drop_frames_allowed) + { + // The reset to decimation 0 is only done here for one pass. + // Once it is set two pass leaves decimation on till the next kf. + if ((cpi->buffer_level > drop_mark) && (cpi->decimation_factor > 0)) + cpi->decimation_factor --; + + if (cpi->buffer_level > drop_mark75 && cpi->decimation_factor > 0) + cpi->decimation_factor = 1; + + else if (cpi->buffer_level < drop_mark25 && (cpi->decimation_factor == 2 || cpi->decimation_factor == 3)) + { + cpi->decimation_factor = 3; + } + else if (cpi->buffer_level < drop_mark50 && (cpi->decimation_factor == 1 || cpi->decimation_factor == 2)) + { + cpi->decimation_factor = 2; + } + else if (cpi->buffer_level < drop_mark75 && (cpi->decimation_factor == 0 || cpi->decimation_factor == 1)) + { + cpi->decimation_factor = 1; + } + //vpx_log("Encoder: Decimation Factor: %d \n",cpi->decimation_factor); + } + + // The following decimates the frame rate according to a regular pattern (i.e. to 1/2 or 2/3 frame rate) + // This can be used to help prevent buffer under-run in CBR mode. Alternatively it might be desirable in + // some situations to drop frame rate but throw more bits at each frame. + // + // Note that dropping a key frame can be problematic if spatial resampling is also active + if (cpi->decimation_factor > 0) + { + switch (cpi->decimation_factor) + { + case 1: + cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 3 / 2; + break; + case 2: + cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 5 / 4; + break; + case 3: + cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 5 / 4; + break; + } + + // Note that we should not throw out a key frame (especially when spatial resampling is enabled). + if ((cm->frame_type == KEY_FRAME)) // && cpi->oxcf.allow_spatial_resampling ) + { + cpi->decimation_count = cpi->decimation_factor; + } + else if (cpi->decimation_count > 0) + { + cpi->decimation_count --; + + cpi->bits_off_target += cpi->av_per_frame_bandwidth; + if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) + cpi->bits_off_target = cpi->oxcf.maximum_buffer_size; + + cm->current_video_frame++; + cpi->frames_since_key++; + +#if CONFIG_INTERNAL_STATS + cpi->count ++; +#endif + + cpi->buffer_level = cpi->bits_off_target; + + if (cpi->oxcf.number_of_layers > 1) + { + unsigned int i; + + // Propagate bits saved by dropping the frame to higher layers + for (i=cpi->current_layer+1; ioxcf.number_of_layers; i++) + { + LAYER_CONTEXT *lc = &cpi->layer_context[i]; + lc->bits_off_target += cpi->av_per_frame_bandwidth; + if (lc->bits_off_target > lc->maximum_buffer_size) + lc->bits_off_target = lc->maximum_buffer_size; + lc->buffer_level = lc->bits_off_target; + } + } + + return; + } + else + cpi->decimation_count = cpi->decimation_factor; + } + + // Decide how big to make the frame + if (!vp8_pick_frame_size(cpi)) + { + cm->current_video_frame++; + cpi->frames_since_key++; + return; + } + + // Reduce active_worst_allowed_q for CBR if our buffer is getting too full. + // This has a knock on effect on active best quality as well. + // For CBR if the buffer reaches its maximum level then we can no longer + // save up bits for later frames so we might as well use them up + // on the current frame. + if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + (cpi->buffer_level >= cpi->oxcf.optimal_buffer_level) && cpi->buffered_mode) + { + int Adjustment = cpi->active_worst_quality / 4; // Max adjustment is 1/4 + + if (Adjustment) + { + int buff_lvl_step; + + if (cpi->buffer_level < cpi->oxcf.maximum_buffer_size) + { + buff_lvl_step = (cpi->oxcf.maximum_buffer_size - cpi->oxcf.optimal_buffer_level) / Adjustment; + + if (buff_lvl_step) + Adjustment = (cpi->buffer_level - cpi->oxcf.optimal_buffer_level) / buff_lvl_step; + else + Adjustment = 0; + } + + cpi->active_worst_quality -= Adjustment; + + if(cpi->active_worst_quality < cpi->active_best_quality) + cpi->active_worst_quality = cpi->active_best_quality; + } + } + + // Set an active best quality and if necessary active worst quality + // There is some odd behavior for one pass here that needs attention. + if ( (cpi->pass == 2) || (cpi->ni_frames > 150)) + { + vp8_clear_system_state(); + + Q = cpi->active_worst_quality; + + if ( cm->frame_type == KEY_FRAME ) + { + if ( cpi->pass == 2 ) + { + if (cpi->gfu_boost > 600) + cpi->active_best_quality = kf_low_motion_minq[Q]; + else + cpi->active_best_quality = kf_high_motion_minq[Q]; + + // Special case for key frames forced because we have reached + // the maximum key frame interval. Here force the Q to a range + // based on the ambient Q to reduce the risk of popping + if ( cpi->this_key_frame_forced ) + { + if ( cpi->active_best_quality > cpi->avg_frame_qindex * 7/8) + cpi->active_best_quality = cpi->avg_frame_qindex * 7/8; + else if ( cpi->active_best_quality < cpi->avg_frame_qindex >> 2 ) + cpi->active_best_quality = cpi->avg_frame_qindex >> 2; + } + } + // One pass more conservative + else + cpi->active_best_quality = kf_high_motion_minq[Q]; + } + + else if (cpi->oxcf.number_of_layers==1 && + (cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame)) + { + // Use the lower of cpi->active_worst_quality and recent + // average Q as basis for GF/ARF Q limit unless last frame was + // a key frame. + if ( (cpi->frames_since_key > 1) && + (cpi->avg_frame_qindex < cpi->active_worst_quality) ) + { + Q = cpi->avg_frame_qindex; + } + + // For constrained quality dont allow Q less than the cq level + if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (Q < cpi->cq_target_quality) ) + { + Q = cpi->cq_target_quality; + } + + if ( cpi->pass == 2 ) + { + if ( cpi->gfu_boost > 1000 ) + cpi->active_best_quality = gf_low_motion_minq[Q]; + else if ( cpi->gfu_boost < 400 ) + cpi->active_best_quality = gf_high_motion_minq[Q]; + else + cpi->active_best_quality = gf_mid_motion_minq[Q]; + + // Constrained quality use slightly lower active best. + if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY ) + { + cpi->active_best_quality = + cpi->active_best_quality * 15/16; + } + } + // One pass more conservative + else + cpi->active_best_quality = gf_high_motion_minq[Q]; + } + else + { + cpi->active_best_quality = inter_minq[Q]; + + // For the constant/constrained quality mode we dont want + // q to fall below the cq level. + if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (cpi->active_best_quality < cpi->cq_target_quality) ) + { + // If we are strongly undershooting the target rate in the last + // frames then use the user passed in cq value not the auto + // cq value. + if ( cpi->rolling_actual_bits < cpi->min_frame_bandwidth ) + cpi->active_best_quality = cpi->oxcf.cq_level; + else + cpi->active_best_quality = cpi->cq_target_quality; + } + } + + // If CBR and the buffer is as full then it is reasonable to allow + // higher quality on the frames to prevent bits just going to waste. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // Note that the use of >= here elliminates the risk of a devide + // by 0 error in the else if clause + if (cpi->buffer_level >= cpi->oxcf.maximum_buffer_size) + cpi->active_best_quality = cpi->best_quality; + + else if (cpi->buffer_level > cpi->oxcf.optimal_buffer_level) + { + int Fraction = ((cpi->buffer_level - cpi->oxcf.optimal_buffer_level) * 128) / (cpi->oxcf.maximum_buffer_size - cpi->oxcf.optimal_buffer_level); + int min_qadjustment = ((cpi->active_best_quality - cpi->best_quality) * Fraction) / 128; + + cpi->active_best_quality -= min_qadjustment; + } + } + } + // Make sure constrained quality mode limits are adhered to for the first + // few frames of one pass encodes + else if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) + { + if ( (cm->frame_type == KEY_FRAME) || + cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame ) + { + cpi->active_best_quality = cpi->best_quality; + } + else if (cpi->active_best_quality < cpi->cq_target_quality) + { + cpi->active_best_quality = cpi->cq_target_quality; + } + } + + // Clip the active best and worst quality values to limits + if (cpi->active_worst_quality > cpi->worst_quality) + cpi->active_worst_quality = cpi->worst_quality; + + if (cpi->active_best_quality < cpi->best_quality) + cpi->active_best_quality = cpi->best_quality; + + if ( cpi->active_worst_quality < cpi->active_best_quality ) + cpi->active_worst_quality = cpi->active_best_quality; + + // Determine initial Q to try + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + +#if !(CONFIG_REALTIME_ONLY) + + // Set highest allowed value for Zbin over quant + if (cm->frame_type == KEY_FRAME) + zbin_oq_high = 0; //ZBIN_OQ_MAX/16 + else if ((cpi->oxcf.number_of_layers == 1) && ((cm->refresh_alt_ref_frame || + (cm->refresh_golden_frame && !cpi->source_alt_ref_active)))) + { + zbin_oq_high = 16; + } + else + zbin_oq_high = ZBIN_OQ_MAX; +#endif + + // Setup background Q adjustment for error resilient mode. + // For multi-layer encodes only enable this for the base layer. + if (cpi->cyclic_refresh_mode_enabled && (cpi->current_layer==0)) + cyclic_background_refresh(cpi, Q, 0); + + vp8_compute_frame_size_bounds(cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); + +#if !(CONFIG_REALTIME_ONLY) + // Limit Q range for the adaptive loop. + bottom_index = cpi->active_best_quality; + top_index = cpi->active_worst_quality; + q_low = cpi->active_best_quality; + q_high = cpi->active_worst_quality; +#endif + + vp8_save_coding_context(cpi); + + loop_count = 0; + + scale_and_extend_source(cpi->un_scaled_source, cpi); + +#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC && !(CONFIG_TEMPORAL_DENOISING) + + if (cpi->oxcf.noise_sensitivity > 0) + { + unsigned char *src; + int l = 0; + + switch (cpi->oxcf.noise_sensitivity) + { + case 1: + l = 20; + break; + case 2: + l = 40; + break; + case 3: + l = 60; + break; + case 4: + l = 80; + break; + case 5: + l = 100; + break; + case 6: + l = 150; + break; + } + + + if (cm->frame_type == KEY_FRAME) + { + vp8_de_noise(cpi->Source, cpi->Source, l , 1, 0); + } + else + { + vp8_de_noise(cpi->Source, cpi->Source, l , 1, 0); + + src = cpi->Source->y_buffer; + + if (cpi->Source->y_stride < 0) + { + src += cpi->Source->y_stride * (cpi->Source->y_height - 1); + } + } + } + +#endif + +#ifdef OUTPUT_YUV_SRC + vp8_write_yuv_frame(cpi->Source); +#endif + + do + { + vp8_clear_system_state(); //__asm emms; + + /* + if(cpi->is_src_frame_alt_ref) + Q = 127; + */ + + vp8_set_quantizer(cpi, Q); + + // setup skip prob for costing in mode/mv decision + if (cpi->common.mb_no_coeff_skip) + { + cpi->prob_skip_false = cpi->base_skip_false_prob[Q]; + + if (cm->frame_type != KEY_FRAME) + { + if (cpi->common.refresh_alt_ref_frame) + { + if (cpi->last_skip_false_probs[2] != 0) + cpi->prob_skip_false = cpi->last_skip_false_probs[2]; + + /* + if(cpi->last_skip_false_probs[2]!=0 && abs(Q- cpi->last_skip_probs_q[2])<=16 ) + cpi->prob_skip_false = cpi->last_skip_false_probs[2]; + else if (cpi->last_skip_false_probs[2]!=0) + cpi->prob_skip_false = (cpi->last_skip_false_probs[2] + cpi->prob_skip_false ) / 2; + */ + } + else if (cpi->common.refresh_golden_frame) + { + if (cpi->last_skip_false_probs[1] != 0) + cpi->prob_skip_false = cpi->last_skip_false_probs[1]; + + /* + if(cpi->last_skip_false_probs[1]!=0 && abs(Q- cpi->last_skip_probs_q[1])<=16 ) + cpi->prob_skip_false = cpi->last_skip_false_probs[1]; + else if (cpi->last_skip_false_probs[1]!=0) + cpi->prob_skip_false = (cpi->last_skip_false_probs[1] + cpi->prob_skip_false ) / 2; + */ + } + else + { + if (cpi->last_skip_false_probs[0] != 0) + cpi->prob_skip_false = cpi->last_skip_false_probs[0]; + + /* + if(cpi->last_skip_false_probs[0]!=0 && abs(Q- cpi->last_skip_probs_q[0])<=16 ) + cpi->prob_skip_false = cpi->last_skip_false_probs[0]; + else if(cpi->last_skip_false_probs[0]!=0) + cpi->prob_skip_false = (cpi->last_skip_false_probs[0] + cpi->prob_skip_false ) / 2; + */ + } + + //as this is for cost estimate, let's make sure it does not go extreme eitehr way + if (cpi->prob_skip_false < 5) + cpi->prob_skip_false = 5; + + if (cpi->prob_skip_false > 250) + cpi->prob_skip_false = 250; + + if (cpi->oxcf.number_of_layers == 1 && cpi->is_src_frame_alt_ref) + cpi->prob_skip_false = 1; + } + +#if 0 + + if (cpi->pass != 1) + { + FILE *f = fopen("skip.stt", "a"); + fprintf(f, "%d, %d, %4d ", cpi->common.refresh_golden_frame, cpi->common.refresh_alt_ref_frame, cpi->prob_skip_false); + fclose(f); + } + +#endif + + } + + if (cm->frame_type == KEY_FRAME) + { + resize_key_frame(cpi); + vp8_setup_key_frame(cpi); + } + + + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + { + if(cpi->oxcf.error_resilient_mode) + cm->refresh_entropy_probs = 0; + + if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS) + { + if (cm->frame_type == KEY_FRAME) + cm->refresh_entropy_probs = 1; + } + + if (cm->refresh_entropy_probs == 0) + { + // save a copy for later refresh + vpx_memcpy(&cm->lfc, &cm->fc, sizeof(cm->fc)); + } + + vp8_update_coef_context(cpi); + + vp8_update_coef_probs(cpi); + + // transform / motion compensation build reconstruction frame + // +pack coef partitions + vp8_encode_frame(cpi); + + /* cpi->projected_frame_size is not needed for RT mode */ + } +#else + // transform / motion compensation build reconstruction frame + vp8_encode_frame(cpi); + + cpi->projected_frame_size -= vp8_estimate_entropy_savings(cpi); + cpi->projected_frame_size = (cpi->projected_frame_size > 0) ? cpi->projected_frame_size : 0; +#endif + vp8_clear_system_state(); //__asm emms; + + // Test to see if the stats generated for this frame indicate that we should have coded a key frame + // (assuming that we didn't)! + if (cpi->pass != 2 && cpi->oxcf.auto_key && cm->frame_type != KEY_FRAME) + { + int key_frame_decision = decide_key_frame(cpi); + + if (cpi->compressor_speed == 2) + { + /* we don't do re-encoding in realtime mode + * if key frame is decided then we force it on next frame */ + cpi->force_next_frame_intra = key_frame_decision; + } +#if !(CONFIG_REALTIME_ONLY) + else if (key_frame_decision) + { + // Reset all our sizing numbers and recode + cm->frame_type = KEY_FRAME; + + vp8_pick_frame_size(cpi); + + // Clear the Alt reference frame active flag when we have a key frame + cpi->source_alt_ref_active = 0; + + // Reset the loop filter deltas and segmentation map + setup_features(cpi); + + // If segmentation is enabled force a map update for key frames + if (cpi->mb.e_mbd.segmentation_enabled) + { + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; + } + + vp8_restore_coding_context(cpi); + + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + + vp8_compute_frame_size_bounds(cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); + + // Limit Q range for the adaptive loop. + bottom_index = cpi->active_best_quality; + top_index = cpi->active_worst_quality; + q_low = cpi->active_best_quality; + q_high = cpi->active_worst_quality; + + loop_count++; + Loop = 1; + + continue; + } +#endif + } + + vp8_clear_system_state(); + + if (frame_over_shoot_limit == 0) + frame_over_shoot_limit = 1; + + // Are we are overshooting and up against the limit of active max Q. + if (((cpi->pass != 2) || (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) && + (Q == cpi->active_worst_quality) && + (cpi->active_worst_quality < cpi->worst_quality) && + (cpi->projected_frame_size > frame_over_shoot_limit)) + { + int over_size_percent = ((cpi->projected_frame_size - frame_over_shoot_limit) * 100) / frame_over_shoot_limit; + + // If so is there any scope for relaxing it + while ((cpi->active_worst_quality < cpi->worst_quality) && (over_size_percent > 0)) + { + cpi->active_worst_quality++; + + over_size_percent = (int)(over_size_percent * 0.96); // Assume 1 qstep = about 4% on frame size. + } +#if !(CONFIG_REALTIME_ONLY) + top_index = cpi->active_worst_quality; +#endif + // If we have updated the active max Q do not call vp8_update_rate_correction_factors() this loop. + active_worst_qchanged = 1; + } + else + active_worst_qchanged = 0; + +#if !(CONFIG_REALTIME_ONLY) + // Special case handling for forced key frames + if ( (cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced ) + { + int last_q = Q; + int kf_err = vp8_calc_ss_err(cpi->Source, + &cm->yv12_fb[cm->new_fb_idx]); + + // The key frame is not good enough + if ( kf_err > ((cpi->ambient_err * 7) >> 3) ) + { + // Lower q_high + q_high = (Q > q_low) ? (Q - 1) : q_low; + + // Adjust Q + Q = (q_high + q_low) >> 1; + } + // The key frame is much better than the previous frame + else if ( kf_err < (cpi->ambient_err >> 1) ) + { + // Raise q_low + q_low = (Q < q_high) ? (Q + 1) : q_high; + + // Adjust Q + Q = (q_high + q_low + 1) >> 1; + } + + // Clamp Q to upper and lower limits: + if (Q > q_high) + Q = q_high; + else if (Q < q_low) + Q = q_low; + + Loop = Q != last_q; + } + + // Is the projected frame size out of range and are we allowed to attempt to recode. + else if ( recode_loop_test( cpi, + frame_over_shoot_limit, frame_under_shoot_limit, + Q, top_index, bottom_index ) ) + { + int last_q = Q; + int Retries = 0; + + // Frame size out of permitted range: + // Update correction factor & compute new Q to try... + + // Frame is too large + if (cpi->projected_frame_size > cpi->this_frame_target) + { + //if ( cpi->zbin_over_quant == 0 ) + q_low = (Q < q_high) ? (Q + 1) : q_high; // Raise Qlow as to at least the current value + + if (cpi->zbin_over_quant > 0) // If we are using over quant do the same for zbin_oq_low + zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high; + + //if ( undershoot_seen || (Q == MAXQ) ) + if (undershoot_seen) + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 1); + + Q = (q_high + q_low + 1) / 2; + + // Adjust cpi->zbin_over_quant (only allowed when Q is max) + if (Q < MAXQ) + cpi->zbin_over_quant = 0; + else + { + zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high; + cpi->zbin_over_quant = (zbin_oq_high + zbin_oq_low) / 2; + } + } + else + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 0); + + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + + while (((Q < q_low) || (cpi->zbin_over_quant < zbin_oq_low)) && (Retries < 10)) + { + vp8_update_rate_correction_factors(cpi, 0); + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + Retries ++; + } + } + + overshoot_seen = 1; + } + // Frame is too small + else + { + if (cpi->zbin_over_quant == 0) + q_high = (Q > q_low) ? (Q - 1) : q_low; // Lower q_high if not using over quant + else // else lower zbin_oq_high + zbin_oq_high = (cpi->zbin_over_quant > zbin_oq_low) ? (cpi->zbin_over_quant - 1) : zbin_oq_low; + + if (overshoot_seen) + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 1); + + Q = (q_high + q_low) / 2; + + // Adjust cpi->zbin_over_quant (only allowed when Q is max) + if (Q < MAXQ) + cpi->zbin_over_quant = 0; + else + cpi->zbin_over_quant = (zbin_oq_high + zbin_oq_low) / 2; + } + else + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 0); + + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + + // Special case reset for qlow for constrained quality. + // This should only trigger where there is very substantial + // undershoot on a frame and the auto cq level is above + // the user passsed in value. + if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (Q < q_low) ) + { + q_low = Q; + } + + while (((Q > q_high) || (cpi->zbin_over_quant > zbin_oq_high)) && (Retries < 10)) + { + vp8_update_rate_correction_factors(cpi, 0); + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + Retries ++; + } + } + + undershoot_seen = 1; + } + + // Clamp Q to upper and lower limits: + if (Q > q_high) + Q = q_high; + else if (Q < q_low) + Q = q_low; + + // Clamp cpi->zbin_over_quant + cpi->zbin_over_quant = (cpi->zbin_over_quant < zbin_oq_low) ? zbin_oq_low : (cpi->zbin_over_quant > zbin_oq_high) ? zbin_oq_high : cpi->zbin_over_quant; + + Loop = Q != last_q; + } + else +#endif + Loop = 0; + + if (cpi->is_src_frame_alt_ref) + Loop = 0; + + if (Loop == 1) + { + vp8_restore_coding_context(cpi); + loop_count++; +#if CONFIG_INTERNAL_STATS + cpi->tot_recode_hits++; +#endif + } + } + while (Loop == 1); + +#if 0 + // Experimental code for lagged and one pass + // Update stats used for one pass GF selection + { + /* + int frames_so_far; + double frame_intra_error; + double frame_coded_error; + double frame_pcnt_inter; + double frame_pcnt_motion; + double frame_mvr; + double frame_mvr_abs; + double frame_mvc; + double frame_mvc_abs; + */ + + cpi->one_pass_frame_stats[cpi->one_pass_frame_index].frame_coded_error = (double)cpi->prediction_error; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index].frame_intra_error = (double)cpi->intra_error; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index].frame_pcnt_inter = (double)(100 - cpi->this_frame_percent_intra) / 100.0; + } +#endif + + // Special case code to reduce pulsing when key frames are forced at a + // fixed interval. Note the reconstruction error if it is the frame before + // the force key frame + if ( cpi->next_key_frame_forced && (cpi->twopass.frames_to_key == 0) ) + { + cpi->ambient_err = vp8_calc_ss_err(cpi->Source, + &cm->yv12_fb[cm->new_fb_idx]); + } + + /* This frame's MVs are saved and will be used in next frame's MV predictor. + * Last frame has one more line(add to bottom) and one more column(add to + * right) than cm->mip. The edge elements are initialized to 0. + */ +#if CONFIG_MULTI_RES_ENCODING + if(!cpi->oxcf.mr_encoder_id && cm->show_frame) +#else + if(cm->show_frame) /* do not save for altref frame */ +#endif + { + int mb_row; + int mb_col; + /* Point to beginning of allocated MODE_INFO arrays. */ + MODE_INFO *tmp = cm->mip; + + if(cm->frame_type != KEY_FRAME) + { + for (mb_row = 0; mb_row < cm->mb_rows+1; mb_row ++) + { + for (mb_col = 0; mb_col < cm->mb_cols+1; mb_col ++) + { + if(tmp->mbmi.ref_frame != INTRA_FRAME) + cpi->lfmv[mb_col + mb_row*(cm->mode_info_stride+1)].as_int = tmp->mbmi.mv.as_int; + + cpi->lf_ref_frame_sign_bias[mb_col + mb_row*(cm->mode_info_stride+1)] = cm->ref_frame_sign_bias[tmp->mbmi.ref_frame]; + cpi->lf_ref_frame[mb_col + mb_row*(cm->mode_info_stride+1)] = tmp->mbmi.ref_frame; + tmp++; + } + } + } + } + +#if CONFIG_MULTI_RES_ENCODING + vp8_cal_dissimilarity(cpi); +#endif + + // Update the GF useage maps. + // This is done after completing the compression of a frame when all + // modes etc. are finalized but before loop filter + if (cpi->oxcf.number_of_layers == 1) + vp8_update_gf_useage_maps(cpi, cm, &cpi->mb); + + if (cm->frame_type == KEY_FRAME) + cm->refresh_last_frame = 1; + +#if 0 + { + FILE *f = fopen("gfactive.stt", "a"); + fprintf(f, "%8d %8d %8d %8d %8d\n", cm->current_video_frame, (100 * cpi->gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols), cpi->this_iiratio, cpi->next_iiratio, cm->refresh_golden_frame); + fclose(f); + } +#endif + + // For inter frames the current default behavior is that when + // cm->refresh_golden_frame is set we copy the old GF over to the ARF buffer + // This is purely an encoder decision at present. + if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame) + cm->copy_buffer_to_arf = 2; + else + cm->copy_buffer_to_arf = 0; + + cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx]; + +#if CONFIG_MULTITHREAD + if (cpi->b_multi_threaded) + { + sem_post(&cpi->h_event_start_lpf); /* start loopfilter in separate thread */ + cpi->b_lpf_running = 1; + } + else +#endif + { + vp8_loopfilter_frame(cpi, cm); + } + + update_reference_frames(cm); + +#if !(CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + if (cpi->oxcf.error_resilient_mode) + { + cm->refresh_entropy_probs = 0; + } +#endif + +#if CONFIG_MULTITHREAD + /* wait that filter_level is picked so that we can continue with stream packing */ + if (cpi->b_multi_threaded) + sem_wait(&cpi->h_event_end_lpf); +#endif + + // build the bitstream + vp8_pack_bitstream(cpi, dest, dest_end, size); + +#if CONFIG_MULTITHREAD + /* if PSNR packets are generated we have to wait for the lpf */ + if (cpi->b_lpf_running && cpi->b_calculate_psnr) + { + sem_wait(&cpi->h_event_end_lpf); + cpi->b_lpf_running = 0; + } +#endif + + /* Move storing frame_type out of the above loop since it is also + * needed in motion search besides loopfilter */ + cm->last_frame_type = cm->frame_type; + + // Update rate control heuristics + cpi->total_byte_count += (*size); + cpi->projected_frame_size = (*size) << 3; + + if (cpi->oxcf.number_of_layers > 1) + { + unsigned int i; + for (i=cpi->current_layer+1; ioxcf.number_of_layers; i++) + cpi->layer_context[i].total_byte_count += (*size); + } + + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 2); + + cpi->last_q[cm->frame_type] = cm->base_qindex; + + if (cm->frame_type == KEY_FRAME) + { + vp8_adjust_key_frame_context(cpi); + } + + // Keep a record of ambient average Q. + if (cm->frame_type != KEY_FRAME) + cpi->avg_frame_qindex = (2 + 3 * cpi->avg_frame_qindex + cm->base_qindex) >> 2; + + // Keep a record from which we can calculate the average Q excluding GF updates and key frames + if ((cm->frame_type != KEY_FRAME) && ((cpi->oxcf.number_of_layers > 1) || + (!cm->refresh_golden_frame && !cm->refresh_alt_ref_frame))) + { + cpi->ni_frames++; + + // Calculate the average Q for normal inter frames (not key or GFU + // frames). + if ( cpi->pass == 2 ) + { + cpi->ni_tot_qi += Q; + cpi->ni_av_qi = (cpi->ni_tot_qi / cpi->ni_frames); + } + else + { + // Damp value for first few frames + if (cpi->ni_frames > 150 ) + { + cpi->ni_tot_qi += Q; + cpi->ni_av_qi = (cpi->ni_tot_qi / cpi->ni_frames); + } + // For one pass, early in the clip ... average the current frame Q + // value with the worstq entered by the user as a dampening measure + else + { + cpi->ni_tot_qi += Q; + cpi->ni_av_qi = ((cpi->ni_tot_qi / cpi->ni_frames) + cpi->worst_quality + 1) / 2; + } + + // If the average Q is higher than what was used in the last frame + // (after going through the recode loop to keep the frame size within range) + // then use the last frame value - 1. + // The -1 is designed to stop Q and hence the data rate, from progressively + // falling away during difficult sections, but at the same time reduce the number of + // itterations around the recode loop. + if (Q > cpi->ni_av_qi) + cpi->ni_av_qi = Q - 1; + } + } + +#if 0 + + // If the frame was massively oversize and we are below optimal buffer level drop next frame + if ((cpi->drop_frames_allowed) && + (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + (cpi->buffer_level < cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100) && + (cpi->projected_frame_size > (4 * cpi->this_frame_target))) + { + cpi->drop_frame = 1; + } + +#endif + + // Set the count for maximum consecutive dropped frames based upon the ratio of + // this frame size to the target average per frame bandwidth. + // (cpi->av_per_frame_bandwidth > 0) is just a sanity check to prevent / 0. + if (cpi->drop_frames_allowed && (cpi->av_per_frame_bandwidth > 0)) + { + cpi->max_drop_count = cpi->projected_frame_size / cpi->av_per_frame_bandwidth; + + if (cpi->max_drop_count > cpi->max_consec_dropped_frames) + cpi->max_drop_count = cpi->max_consec_dropped_frames; + } + + // Update the buffer level variable. + // Non-viewable frames are a special case and are treated as pure overhead. + if ( !cm->show_frame ) + cpi->bits_off_target -= cpi->projected_frame_size; + else + cpi->bits_off_target += cpi->av_per_frame_bandwidth - cpi->projected_frame_size; + + // Clip the buffer level to the maximum specified buffer size + if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) + cpi->bits_off_target = cpi->oxcf.maximum_buffer_size; + + // Rolling monitors of whether we are over or underspending used to help regulate min and Max Q in two pass. + cpi->rolling_target_bits = ((cpi->rolling_target_bits * 3) + cpi->this_frame_target + 2) / 4; + cpi->rolling_actual_bits = ((cpi->rolling_actual_bits * 3) + cpi->projected_frame_size + 2) / 4; + cpi->long_rolling_target_bits = ((cpi->long_rolling_target_bits * 31) + cpi->this_frame_target + 16) / 32; + cpi->long_rolling_actual_bits = ((cpi->long_rolling_actual_bits * 31) + cpi->projected_frame_size + 16) / 32; + + // Actual bits spent + cpi->total_actual_bits += cpi->projected_frame_size; + + // Debug stats + cpi->total_target_vs_actual += (cpi->this_frame_target - cpi->projected_frame_size); + + cpi->buffer_level = cpi->bits_off_target; + + // Propagate values to higher temporal layers + if (cpi->oxcf.number_of_layers > 1) + { + unsigned int i; + + for (i=cpi->current_layer+1; ioxcf.number_of_layers; i++) + { + LAYER_CONTEXT *lc = &cpi->layer_context[i]; + int bits_off_for_this_layer = lc->target_bandwidth / lc->frame_rate + - cpi->projected_frame_size; + + lc->bits_off_target += bits_off_for_this_layer; + + // Clip buffer level to maximum buffer size for the layer + if (lc->bits_off_target > lc->maximum_buffer_size) + lc->bits_off_target = lc->maximum_buffer_size; + + lc->total_actual_bits += cpi->projected_frame_size; + lc->total_target_vs_actual += bits_off_for_this_layer; + lc->buffer_level = lc->bits_off_target; + } + } + + // Update bits left to the kf and gf groups to account for overshoot or undershoot on these frames + if (cm->frame_type == KEY_FRAME) + { + cpi->twopass.kf_group_bits += cpi->this_frame_target - cpi->projected_frame_size; + + if (cpi->twopass.kf_group_bits < 0) + cpi->twopass.kf_group_bits = 0 ; + } + else if (cm->refresh_golden_frame || cm->refresh_alt_ref_frame) + { + cpi->twopass.gf_group_bits += cpi->this_frame_target - cpi->projected_frame_size; + + if (cpi->twopass.gf_group_bits < 0) + cpi->twopass.gf_group_bits = 0 ; + } + + if (cm->frame_type != KEY_FRAME) + { + if (cpi->common.refresh_alt_ref_frame) + { + cpi->last_skip_false_probs[2] = cpi->prob_skip_false; + cpi->last_skip_probs_q[2] = cm->base_qindex; + } + else if (cpi->common.refresh_golden_frame) + { + cpi->last_skip_false_probs[1] = cpi->prob_skip_false; + cpi->last_skip_probs_q[1] = cm->base_qindex; + } + else + { + cpi->last_skip_false_probs[0] = cpi->prob_skip_false; + cpi->last_skip_probs_q[0] = cm->base_qindex; + + //update the baseline + cpi->base_skip_false_prob[cm->base_qindex] = cpi->prob_skip_false; + + } + } + +#if 0 && CONFIG_INTERNAL_STATS + { + FILE *f = fopen("tmp.stt", "a"); + + vp8_clear_system_state(); //__asm emms; + + if (cpi->twopass.total_left_stats.coded_error != 0.0) + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %10d %6d %6d" + "%6d %6d %6d %5d %5d %5d %8d %8.2f %10d %10.3f" + "%10.3f %8d\n", + cpi->common.current_video_frame, cpi->this_frame_target, + cpi->projected_frame_size, + (cpi->projected_frame_size - cpi->this_frame_target), + (int)cpi->total_target_vs_actual, + cpi->buffer_level, + (cpi->oxcf.starting_buffer_level-cpi->bits_off_target), + (int)cpi->total_actual_bits, cm->base_qindex, + cpi->active_best_quality, cpi->active_worst_quality, + cpi->ni_av_qi, cpi->cq_target_quality, + cpi->zbin_over_quant, + //cpi->avg_frame_qindex, cpi->zbin_over_quant, + cm->refresh_golden_frame, cm->refresh_alt_ref_frame, + cm->frame_type, cpi->gfu_boost, + cpi->twopass.est_max_qcorrection_factor, + (int)cpi->twopass.bits_left, + cpi->twopass.total_left_stats.coded_error, + (double)cpi->twopass.bits_left / + cpi->twopass.total_left_stats.coded_error, + cpi->tot_recode_hits); + else + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %10d %6d %6d" + "%6d %6d %6d %5d %5d %5d %8d %8.2f %10d %10.3f" + "%8d\n", + cpi->common.current_video_frame, + cpi->this_frame_target, cpi->projected_frame_size, + (cpi->projected_frame_size - cpi->this_frame_target), + (int)cpi->total_target_vs_actual, + cpi->buffer_level, + (cpi->oxcf.starting_buffer_level-cpi->bits_off_target), + (int)cpi->total_actual_bits, cm->base_qindex, + cpi->active_best_quality, cpi->active_worst_quality, + cpi->ni_av_qi, cpi->cq_target_quality, + cpi->zbin_over_quant, + //cpi->avg_frame_qindex, cpi->zbin_over_quant, + cm->refresh_golden_frame, cm->refresh_alt_ref_frame, + cm->frame_type, cpi->gfu_boost, + cpi->twopass.est_max_qcorrection_factor, + (int)cpi->twopass.bits_left, + cpi->twopass.total_left_stats.coded_error, + cpi->tot_recode_hits); + + fclose(f); + + { + FILE *fmodes = fopen("Modes.stt", "a"); + int i; + + fprintf(fmodes, "%6d:%1d:%1d:%1d ", + cpi->common.current_video_frame, + cm->frame_type, cm->refresh_golden_frame, + cm->refresh_alt_ref_frame); + + for (i = 0; i < MAX_MODES; i++) + fprintf(fmodes, "%5d ", cpi->mode_chosen_counts[i]); + + fprintf(fmodes, "\n"); + + fclose(fmodes); + } + } + +#endif + + // If this was a kf or Gf note the Q + if ((cm->frame_type == KEY_FRAME) || cm->refresh_golden_frame || cm->refresh_alt_ref_frame) + cm->last_kf_gf_q = cm->base_qindex; + + if (cm->refresh_golden_frame == 1) + cm->frame_flags = cm->frame_flags | FRAMEFLAGS_GOLDEN; + else + cm->frame_flags = cm->frame_flags&~FRAMEFLAGS_GOLDEN; + + if (cm->refresh_alt_ref_frame == 1) + cm->frame_flags = cm->frame_flags | FRAMEFLAGS_ALTREF; + else + cm->frame_flags = cm->frame_flags&~FRAMEFLAGS_ALTREF; + + + if (cm->refresh_last_frame & cm->refresh_golden_frame) // both refreshed + cpi->gold_is_last = 1; + else if (cm->refresh_last_frame ^ cm->refresh_golden_frame) // 1 refreshed but not the other + cpi->gold_is_last = 0; + + if (cm->refresh_last_frame & cm->refresh_alt_ref_frame) // both refreshed + cpi->alt_is_last = 1; + else if (cm->refresh_last_frame ^ cm->refresh_alt_ref_frame) // 1 refreshed but not the other + cpi->alt_is_last = 0; + + if (cm->refresh_alt_ref_frame & cm->refresh_golden_frame) // both refreshed + cpi->gold_is_alt = 1; + else if (cm->refresh_alt_ref_frame ^ cm->refresh_golden_frame) // 1 refreshed but not the other + cpi->gold_is_alt = 0; + + cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; + + if (cpi->gold_is_last) + cpi->ref_frame_flags &= ~VP8_GOLD_FLAG; + + if (cpi->alt_is_last) + cpi->ref_frame_flags &= ~VP8_ALT_FLAG; + + if (cpi->gold_is_alt) + cpi->ref_frame_flags &= ~VP8_ALT_FLAG; + + + if (!cpi->oxcf.error_resilient_mode) + { + if (cpi->oxcf.play_alternate && cm->refresh_alt_ref_frame && (cm->frame_type != KEY_FRAME)) + // Update the alternate reference frame stats as appropriate. + update_alt_ref_frame_stats(cpi); + else + // Update the Golden frame stats as appropriate. + update_golden_frame_stats(cpi); + } + + if (cm->frame_type == KEY_FRAME) + { + // Tell the caller that the frame was coded as a key frame + *frame_flags = cm->frame_flags | FRAMEFLAGS_KEY; + + // As this frame is a key frame the next defaults to an inter frame. + cm->frame_type = INTER_FRAME; + + cpi->last_frame_percent_intra = 100; + } + else + { + *frame_flags = cm->frame_flags&~FRAMEFLAGS_KEY; + + cpi->last_frame_percent_intra = cpi->this_frame_percent_intra; + } + + // Clear the one shot update flags for segmentation map and mode/ref loop filter deltas. + cpi->mb.e_mbd.update_mb_segmentation_map = 0; + cpi->mb.e_mbd.update_mb_segmentation_data = 0; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + + + // Dont increment frame counters if this was an altref buffer update not a real frame + if (cm->show_frame) + { + cm->current_video_frame++; + cpi->frames_since_key++; + } + + // reset to normal state now that we are done. + + + +#if 0 + { + char filename[512]; + FILE *recon_file; + sprintf(filename, "enc%04d.yuv", (int) cm->current_video_frame); + recon_file = fopen(filename, "wb"); + fwrite(cm->yv12_fb[cm->lst_fb_idx].buffer_alloc, + cm->yv12_fb[cm->lst_fb_idx].frame_size, 1, recon_file); + fclose(recon_file); + } +#endif + + // DEBUG + //vp8_write_yuv_frame("encoder_recon.yuv", cm->frame_to_show); + + +} + + +static void check_gf_quality(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + int gf_active_pct = (100 * cpi->gf_active_count) / (cm->mb_rows * cm->mb_cols); + int gf_ref_usage_pct = (cpi->count_mb_ref_frame_usage[GOLDEN_FRAME] * 100) / (cm->mb_rows * cm->mb_cols); + int last_ref_zz_useage = (cpi->inter_zz_count * 100) / (cm->mb_rows * cm->mb_cols); + + // Gf refresh is not currently being signalled + if (cpi->gf_update_recommended == 0) + { + if (cpi->common.frames_since_golden > 7) + { + // Low use of gf + if ((gf_active_pct < 10) || ((gf_active_pct + gf_ref_usage_pct) < 15)) + { + // ...but last frame zero zero usage is reasonbable so a new gf might be appropriate + if (last_ref_zz_useage >= 25) + { + cpi->gf_bad_count ++; + + if (cpi->gf_bad_count >= 8) // Check that the condition is stable + { + cpi->gf_update_recommended = 1; + cpi->gf_bad_count = 0; + } + } + else + cpi->gf_bad_count = 0; // Restart count as the background is not stable enough + } + else + cpi->gf_bad_count = 0; // Gf useage has picked up so reset count + } + } + // If the signal is set but has not been read should we cancel it. + else if (last_ref_zz_useage < 15) + { + cpi->gf_update_recommended = 0; + cpi->gf_bad_count = 0; + } + +#if 0 + { + FILE *f = fopen("gfneeded.stt", "a"); + fprintf(f, "%10d %10d %10d %10d %10ld \n", + cm->current_video_frame, + cpi->common.frames_since_golden, + gf_active_pct, gf_ref_usage_pct, + cpi->gf_update_recommended); + fclose(f); + } + +#endif +} + +#if !(CONFIG_REALTIME_ONLY) +static void Pass2Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned char * dest_end, unsigned int *frame_flags) +{ + + if (!cpi->common.refresh_alt_ref_frame) + vp8_second_pass(cpi); + + encode_frame_to_data_rate(cpi, size, dest, dest_end, frame_flags); + cpi->twopass.bits_left -= 8 * *size; + + if (!cpi->common.refresh_alt_ref_frame) + { + double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth + *cpi->oxcf.two_pass_vbrmin_section / 100); + cpi->twopass.bits_left += (int64_t)(two_pass_min_rate / cpi->frame_rate); + } +} +#endif + +//For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us. +#if HAVE_NEON +extern void vp8_push_neon(int64_t *store); +extern void vp8_pop_neon(int64_t *store); +#endif + + +int vp8_receive_raw_frame(VP8_COMP *cpi, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time) +{ +#if HAVE_NEON + int64_t store_reg[8]; +#endif + VP8_COMMON *cm = &cpi->common; + struct vpx_usec_timer timer; + int res = 0; + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_push_neon(store_reg); + } +#endif + + vpx_usec_timer_start(&timer); + + /* Reinit the lookahead buffer if the frame size changes */ + if (sd->y_width != cpi->oxcf.Width || sd->y_height != cpi->oxcf.Height) + { + assert(cpi->oxcf.lag_in_frames < 2); + dealloc_raw_frame_buffers(cpi); + alloc_raw_frame_buffers(cpi); + } + + if(vp8_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, + frame_flags, cpi->active_map_enabled ? cpi->active_map : NULL)) + res = -1; + cm->clr_type = sd->clrtype; + vpx_usec_timer_mark(&timer); + cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(store_reg); + } +#endif + + return res; +} + + +static int frame_is_reference(const VP8_COMP *cpi) +{ + const VP8_COMMON *cm = &cpi->common; + const MACROBLOCKD *xd = &cpi->mb.e_mbd; + + return cm->frame_type == KEY_FRAME || cm->refresh_last_frame + || cm->refresh_golden_frame || cm->refresh_alt_ref_frame + || cm->copy_buffer_to_gf || cm->copy_buffer_to_arf + || cm->refresh_entropy_probs + || xd->mode_ref_lf_delta_update + || xd->update_mb_segmentation_map || xd->update_mb_segmentation_data; +} + + +int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned long *size, unsigned char *dest, unsigned char *dest_end, int64_t *time_stamp, int64_t *time_end, int flush) +{ +#if HAVE_NEON + int64_t store_reg[8]; +#endif + VP8_COMMON *cm; + struct vpx_usec_timer tsctimer; + struct vpx_usec_timer ticktimer; + struct vpx_usec_timer cmptimer; + YV12_BUFFER_CONFIG *force_src_buffer = NULL; + + if (!cpi) + return -1; + + cm = &cpi->common; + + if (setjmp(cpi->common.error.jmp)) + { + cpi->common.error.setjmp = 0; + return VPX_CODEC_CORRUPT_FRAME; + } + + cpi->common.error.setjmp = 1; + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_push_neon(store_reg); + } +#endif + + vpx_usec_timer_start(&cmptimer); + + cpi->source = NULL; + +#if !(CONFIG_REALTIME_ONLY) + // Should we code an alternate reference frame + if (cpi->oxcf.error_resilient_mode == 0 && + cpi->oxcf.play_alternate && + cpi->source_alt_ref_pending) + { + if ((cpi->source = vp8_lookahead_peek(cpi->lookahead, + cpi->frames_till_gf_update_due, + PEEK_FORWARD))) + { + cpi->alt_ref_source = cpi->source; + if (cpi->oxcf.arnr_max_frames > 0) + { + vp8_temporal_filter_prepare_c(cpi, + cpi->frames_till_gf_update_due); + force_src_buffer = &cpi->alt_ref_buffer; + } + cm->frames_till_alt_ref_frame = cpi->frames_till_gf_update_due; + cm->refresh_alt_ref_frame = 1; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 0; + cm->show_frame = 0; + cpi->source_alt_ref_pending = 0; // Clear Pending alt Ref flag. + cpi->is_src_frame_alt_ref = 0; + } + } +#endif + + if (!cpi->source) + { + /* Read last frame source if we are encoding first pass. */ + if (cpi->pass == 1 && cm->current_video_frame > 0) + { + if((cpi->last_source = vp8_lookahead_peek(cpi->lookahead, 1, + PEEK_BACKWARD)) == NULL) + return -1; + } + + + if ((cpi->source = vp8_lookahead_pop(cpi->lookahead, flush))) + { + cm->show_frame = 1; + + cpi->is_src_frame_alt_ref = cpi->alt_ref_source + && (cpi->source == cpi->alt_ref_source); + + if(cpi->is_src_frame_alt_ref) + cpi->alt_ref_source = NULL; + } + } + + if (cpi->source) + { + cpi->Source = force_src_buffer ? force_src_buffer : &cpi->source->img; + cpi->un_scaled_source = cpi->Source; + *time_stamp = cpi->source->ts_start; + *time_end = cpi->source->ts_end; + *frame_flags = cpi->source->flags; + + if (cpi->pass == 1 && cm->current_video_frame > 0) + { + cpi->last_frame_unscaled_source = &cpi->last_source->img; + } + } + else + { + *size = 0; +#if !(CONFIG_REALTIME_ONLY) + + if (flush && cpi->pass == 1 && !cpi->twopass.first_pass_done) + { + vp8_end_first_pass(cpi); /* get last stats packet */ + cpi->twopass.first_pass_done = 1; + } + +#endif + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(store_reg); + } +#endif + return -1; + } + + if (cpi->source->ts_start < cpi->first_time_stamp_ever) + { + cpi->first_time_stamp_ever = cpi->source->ts_start; + cpi->last_end_time_stamp_seen = cpi->source->ts_start; + } + + // adjust frame rates based on timestamps given + if (cm->show_frame) + { + int64_t this_duration; + int step = 0; + + if (cpi->source->ts_start == cpi->first_time_stamp_ever) + { + this_duration = cpi->source->ts_end - cpi->source->ts_start; + step = 1; + } + else + { + int64_t last_duration; + + this_duration = cpi->source->ts_end - cpi->last_end_time_stamp_seen; + last_duration = cpi->last_end_time_stamp_seen + - cpi->last_time_stamp_seen; + // do a step update if the duration changes by 10% + if (last_duration) + step = ((this_duration - last_duration) * 10 / last_duration); + } + + if (this_duration) + { + if (step) + cpi->ref_frame_rate = 10000000.0 / this_duration; + else + { + double avg_duration, interval; + + /* Average this frame's rate into the last second's average + * frame rate. If we haven't seen 1 second yet, then average + * over the whole interval seen. + */ + interval = cpi->source->ts_end - cpi->first_time_stamp_ever; + if(interval > 10000000.0) + interval = 10000000; + + avg_duration = 10000000.0 / cpi->ref_frame_rate; + avg_duration *= (interval - avg_duration + this_duration); + avg_duration /= interval; + + cpi->ref_frame_rate = 10000000.0 / avg_duration; + } + + if (cpi->oxcf.number_of_layers > 1) + { + int i; + + // Update frame rates for each layer + for (i=0; ioxcf.number_of_layers; i++) + { + LAYER_CONTEXT *lc = &cpi->layer_context[i]; + lc->frame_rate = cpi->ref_frame_rate / + cpi->oxcf.rate_decimator[i]; + } + } + else + vp8_new_frame_rate(cpi, cpi->ref_frame_rate); + } + + cpi->last_time_stamp_seen = cpi->source->ts_start; + cpi->last_end_time_stamp_seen = cpi->source->ts_end; + } + + if (cpi->oxcf.number_of_layers > 1) + { + int layer; + + update_layer_contexts (cpi); + + // Restore layer specific context & set frame rate + layer = cpi->oxcf.layer_id[ + cm->current_video_frame % cpi->oxcf.periodicity]; + restore_layer_context (cpi, layer); + vp8_new_frame_rate (cpi, cpi->layer_context[layer].frame_rate); + } + + if (cpi->compressor_speed == 2) + { + if (cpi->oxcf.number_of_layers == 1) + check_gf_quality(cpi); + vpx_usec_timer_start(&tsctimer); + vpx_usec_timer_start(&ticktimer); + } + +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + { + int i; + const int num_part = (1 << cm->multi_token_partition); + /* the available bytes in dest */ + const unsigned long dest_size = dest_end - dest; + const int tok_part_buff_size = (dest_size * 9) / (10 * num_part); + + unsigned char *dp = dest; + + cpi->partition_d[0] = dp; + dp += dest_size/10; /* reserve 1/10 for control partition */ + cpi->partition_d_end[0] = dp; + + for(i = 0; i < num_part; i++) + { + cpi->partition_d[i + 1] = dp; + dp += tok_part_buff_size; + cpi->partition_d_end[i + 1] = dp; + } + } +#endif + + // start with a 0 size frame + *size = 0; + + // Clear down mmx registers + vp8_clear_system_state(); //__asm emms; + + cm->frame_type = INTER_FRAME; + cm->frame_flags = *frame_flags; + +#if 0 + + if (cm->refresh_alt_ref_frame) + { + //cm->refresh_golden_frame = 1; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 0; + } + else + { + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + } + +#endif + /* find a free buffer for the new frame */ + { + int i = 0; + for(; i < NUM_YV12_BUFFERS; i++) + { + if(!cm->yv12_fb[i].flags) + { + cm->new_fb_idx = i; + break; + } + } + + assert(i < NUM_YV12_BUFFERS ); + } +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 1) + { + Pass1Encode(cpi, size, dest, frame_flags); + } + else if (cpi->pass == 2) + { + Pass2Encode(cpi, size, dest, dest_end, frame_flags); + } + else +#endif + encode_frame_to_data_rate(cpi, size, dest, dest_end, frame_flags); + + if (cpi->compressor_speed == 2) + { + unsigned int duration, duration2; + vpx_usec_timer_mark(&tsctimer); + vpx_usec_timer_mark(&ticktimer); + + duration = vpx_usec_timer_elapsed(&ticktimer); + duration2 = (unsigned int)((double)duration / 2); + + if (cm->frame_type != KEY_FRAME) + { + if (cpi->avg_encode_time == 0) + cpi->avg_encode_time = duration; + else + cpi->avg_encode_time = (7 * cpi->avg_encode_time + duration) >> 3; + } + + if (duration2) + { + //if(*frame_flags!=1) + { + + if (cpi->avg_pick_mode_time == 0) + cpi->avg_pick_mode_time = duration2; + else + cpi->avg_pick_mode_time = (7 * cpi->avg_pick_mode_time + duration2) >> 3; + } + } + + } + + if (cm->refresh_entropy_probs == 0) + { + vpx_memcpy(&cm->fc, &cm->lfc, sizeof(cm->fc)); + } + + // Save the contexts separately for alt ref, gold and last. + // (TODO jbb -> Optimize this with pointers to avoid extra copies. ) + if(cm->refresh_alt_ref_frame) + vpx_memcpy(&cpi->lfc_a, &cm->fc, sizeof(cm->fc)); + + if(cm->refresh_golden_frame) + vpx_memcpy(&cpi->lfc_g, &cm->fc, sizeof(cm->fc)); + + if(cm->refresh_last_frame) + vpx_memcpy(&cpi->lfc_n, &cm->fc, sizeof(cm->fc)); + + // if its a dropped frame honor the requests on subsequent frames + if (*size > 0) + { + cpi->droppable = !frame_is_reference(cpi); + + // return to normal state + cm->refresh_entropy_probs = 1; + cm->refresh_alt_ref_frame = 0; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + cm->frame_type = INTER_FRAME; + + } + + // Save layer specific state + if (cpi->oxcf.number_of_layers > 1) + save_layer_context (cpi); + + vpx_usec_timer_mark(&cmptimer); + cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); + + if (cpi->b_calculate_psnr && cpi->pass != 1 && cm->show_frame) + { + generate_psnr_packet(cpi); + } + +#if CONFIG_INTERNAL_STATS + + if (cpi->pass != 1) + { + cpi->bytes += *size; + + if (cm->show_frame) + { + + cpi->count ++; + + if (cpi->b_calculate_psnr) + { + double ye,ue,ve; + double frame_psnr; + YV12_BUFFER_CONFIG *orig = cpi->Source; + YV12_BUFFER_CONFIG *recon = cpi->common.frame_to_show; + int y_samples = orig->y_height * orig->y_width ; + int uv_samples = orig->uv_height * orig->uv_width ; + int t_samples = y_samples + 2 * uv_samples; + int64_t sq_error, sq_error2; + + ye = calc_plane_error(orig->y_buffer, orig->y_stride, + recon->y_buffer, recon->y_stride, orig->y_width, orig->y_height); + + ue = calc_plane_error(orig->u_buffer, orig->uv_stride, + recon->u_buffer, recon->uv_stride, orig->uv_width, orig->uv_height); + + ve = calc_plane_error(orig->v_buffer, orig->uv_stride, + recon->v_buffer, recon->uv_stride, orig->uv_width, orig->uv_height); + + sq_error = ye + ue + ve; + + frame_psnr = vp8_mse2psnr(t_samples, 255.0, sq_error); + + cpi->total_y += vp8_mse2psnr(y_samples, 255.0, ye); + cpi->total_u += vp8_mse2psnr(uv_samples, 255.0, ue); + cpi->total_v += vp8_mse2psnr(uv_samples, 255.0, ve); + cpi->total_sq_error += sq_error; + cpi->total += frame_psnr; +#if CONFIG_POSTPROC + { + YV12_BUFFER_CONFIG *pp = &cm->post_proc_buffer; + double frame_psnr2, frame_ssim2 = 0; + double weight = 0; + + vp8_deblock(cm->frame_to_show, &cm->post_proc_buffer, cm->filter_level * 10 / 6, 1, 0); + vp8_clear_system_state(); + + ye = calc_plane_error(orig->y_buffer, orig->y_stride, + pp->y_buffer, pp->y_stride, orig->y_width, orig->y_height); + + ue = calc_plane_error(orig->u_buffer, orig->uv_stride, + pp->u_buffer, pp->uv_stride, orig->uv_width, orig->uv_height); + + ve = calc_plane_error(orig->v_buffer, orig->uv_stride, + pp->v_buffer, pp->uv_stride, orig->uv_width, orig->uv_height); + + sq_error2 = ye + ue + ve; + + frame_psnr2 = vp8_mse2psnr(t_samples, 255.0, sq_error2); + + cpi->totalp_y += vp8_mse2psnr(y_samples, 255.0, ye); + cpi->totalp_u += vp8_mse2psnr(uv_samples, 255.0, ue); + cpi->totalp_v += vp8_mse2psnr(uv_samples, 255.0, ve); + cpi->total_sq_error2 += sq_error2; + cpi->totalp += frame_psnr2; + + frame_ssim2 = vp8_calc_ssim(cpi->Source, + &cm->post_proc_buffer, 1, &weight); + + cpi->summed_quality += frame_ssim2 * weight; + cpi->summed_weights += weight; + + if (cpi->oxcf.number_of_layers > 1) + { + int i; + + for (i=cpi->current_layer; + ioxcf.number_of_layers; i++) + { + cpi->frames_in_layer[i]++; + + cpi->bytes_in_layer[i] += *size; + cpi->sum_psnr[i] += frame_psnr; + cpi->sum_psnr_p[i] += frame_psnr2; + cpi->total_error2[i] += sq_error; + cpi->total_error2_p[i] += sq_error2; + cpi->sum_ssim[i] += frame_ssim2 * weight; + cpi->sum_weights[i] += weight; + } + } + } +#endif + } + + if (cpi->b_calculate_ssimg) + { + double y, u, v, frame_all; + frame_all = vp8_calc_ssimg(cpi->Source, cm->frame_to_show, + &y, &u, &v); + + if (cpi->oxcf.number_of_layers > 1) + { + int i; + + for (i=cpi->current_layer; + ioxcf.number_of_layers; i++) + { + if (!cpi->b_calculate_psnr) + cpi->frames_in_layer[i]++; + + cpi->total_ssimg_y_in_layer[i] += y; + cpi->total_ssimg_u_in_layer[i] += u; + cpi->total_ssimg_v_in_layer[i] += v; + cpi->total_ssimg_all_in_layer[i] += frame_all; + } + } + else + { + cpi->total_ssimg_y += y; + cpi->total_ssimg_u += u; + cpi->total_ssimg_v += v; + cpi->total_ssimg_all += frame_all; + } + } + + } + } + +#if 0 + + if (cpi->common.frame_type != 0 && cpi->common.base_qindex == cpi->oxcf.worst_allowed_q) + { + skiptruecount += cpi->skip_true_count; + skipfalsecount += cpi->skip_false_count; + } + +#endif +#if 0 + + if (cpi->pass != 1) + { + FILE *f = fopen("skip.stt", "a"); + fprintf(f, "frame:%4d flags:%4x Q:%4d P:%4d Size:%5d\n", cpi->common.current_video_frame, *frame_flags, cpi->common.base_qindex, cpi->prob_skip_false, *size); + + if (cpi->is_src_frame_alt_ref == 1) + fprintf(f, "skipcount: %4d framesize: %d\n", cpi->skip_true_count , *size); + + fclose(f); + } + +#endif +#endif + +#if HAVE_NEON +#if CONFIG_RUNTIME_CPU_DETECT + if (cm->cpu_caps & HAS_NEON) +#endif + { + vp8_pop_neon(store_reg); + } +#endif + + cpi->common.error.setjmp = 0; + + return 0; +} + +int vp8_get_preview_raw_frame(VP8_COMP *cpi, YV12_BUFFER_CONFIG *dest, vp8_ppflags_t *flags) +{ + if (cpi->common.refresh_alt_ref_frame) + return -1; + else + { + int ret; + +#if CONFIG_MULTITHREAD + if(cpi->b_lpf_running) + { + sem_wait(&cpi->h_event_end_lpf); + cpi->b_lpf_running = 0; + } +#endif + +#if CONFIG_POSTPROC + ret = vp8_post_proc_frame(&cpi->common, dest, flags); +#else + + if (cpi->common.frame_to_show) + { + *dest = *cpi->common.frame_to_show; + dest->y_width = cpi->common.Width; + dest->y_height = cpi->common.Height; + dest->uv_height = cpi->common.Height / 2; + ret = 0; + } + else + { + ret = -1; + } + +#endif //!CONFIG_POSTPROC + vp8_clear_system_state(); + return ret; + } +} + +int vp8_set_roimap(VP8_COMP *cpi, unsigned char *map, unsigned int rows, unsigned int cols, int delta_q[4], int delta_lf[4], unsigned int threshold[4]) +{ + signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + + if (cpi->common.mb_rows != rows || cpi->common.mb_cols != cols) + return -1; + + if (!map) + { + disable_segmentation(cpi); + return 0; + } + + // Set the segmentation Map + set_segmentation_map(cpi, map); + + // Activate segmentation. + enable_segmentation(cpi); + + // Set up the quant segment data + feature_data[MB_LVL_ALT_Q][0] = delta_q[0]; + feature_data[MB_LVL_ALT_Q][1] = delta_q[1]; + feature_data[MB_LVL_ALT_Q][2] = delta_q[2]; + feature_data[MB_LVL_ALT_Q][3] = delta_q[3]; + + // Set up the loop segment data s + feature_data[MB_LVL_ALT_LF][0] = delta_lf[0]; + feature_data[MB_LVL_ALT_LF][1] = delta_lf[1]; + feature_data[MB_LVL_ALT_LF][2] = delta_lf[2]; + feature_data[MB_LVL_ALT_LF][3] = delta_lf[3]; + + cpi->segment_encode_breakout[0] = threshold[0]; + cpi->segment_encode_breakout[1] = threshold[1]; + cpi->segment_encode_breakout[2] = threshold[2]; + cpi->segment_encode_breakout[3] = threshold[3]; + + // Initialise the feature data structure + // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 + set_segment_data(cpi, &feature_data[0][0], SEGMENT_DELTADATA); + + return 0; +} + +int vp8_set_active_map(VP8_COMP *cpi, unsigned char *map, unsigned int rows, unsigned int cols) +{ + if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) + { + if (map) + { + vpx_memcpy(cpi->active_map, map, rows * cols); + cpi->active_map_enabled = 1; + } + else + cpi->active_map_enabled = 0; + + return 0; + } + else + { + //cpi->active_map_enabled = 0; + return -1 ; + } +} + +int vp8_set_internal_size(VP8_COMP *cpi, VPX_SCALING horiz_mode, VPX_SCALING vert_mode) +{ + if (horiz_mode <= ONETWO) + cpi->common.horiz_scale = horiz_mode; + else + return -1; + + if (vert_mode <= ONETWO) + cpi->common.vert_scale = vert_mode; + else + return -1; + + return 0; +} + + + +int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest) +{ + int i, j; + int Total = 0; + + unsigned char *src = source->y_buffer; + unsigned char *dst = dest->y_buffer; + + // Loop through the Y plane raw and reconstruction data summing (square differences) + for (i = 0; i < source->y_height; i += 16) + { + for (j = 0; j < source->y_width; j += 16) + { + unsigned int sse; + Total += vp8_mse16x16(src + j, source->y_stride, dst + j, dest->y_stride, &sse); + } + + src += 16 * source->y_stride; + dst += 16 * dest->y_stride; + } + + return Total; +} + + +int vp8_get_quantizer(VP8_COMP *cpi) +{ + return cpi->common.base_qindex; +} diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h new file mode 100644 index 0000000..900141b --- /dev/null +++ b/vp8/encoder/onyx_int.h @@ -0,0 +1,720 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_VP8_INT_H +#define __INC_VP8_INT_H + +#include +#include "vpx_config.h" +#include "vp8/common/onyx.h" +#include "treewriter.h" +#include "tokenize.h" +#include "vp8/common/onyxc_int.h" +#include "vp8/common/variance.h" +#include "encodemb.h" +#include "quantize.h" +#include "vp8/common/entropy.h" +#include "vp8/common/threading.h" +#include "vpx_ports/mem.h" +#include "vpx/internal/vpx_codec_internal.h" +#include "mcomp.h" +#include "vp8/common/findnearmv.h" +#include "lookahead.h" +#if CONFIG_TEMPORAL_DENOISING +#include "vp8/encoder/denoising.h" +#endif + +//#define SPEEDSTATS 1 +#define MIN_GF_INTERVAL 4 +#define DEFAULT_GF_INTERVAL 7 + +#define KEY_FRAME_CONTEXT 5 + +#define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY? 1 : 25) + +#define AF_THRESH 25 +#define AF_THRESH2 100 +#define ARF_DECAY_THRESH 12 +#define MAX_MODES 20 + +#define MIN_THRESHMULT 32 +#define MAX_THRESHMULT 512 + +#define GF_ZEROMV_ZBIN_BOOST 12 +#define LF_ZEROMV_ZBIN_BOOST 6 +#define MV_ZBIN_BOOST 4 +#define ZBIN_OQ_MAX 192 + +#if !(CONFIG_REALTIME_ONLY) +#define VP8_TEMPORAL_ALT_REF 1 +#endif + +#define MAX(x,y) (((x)>(y))?(x):(y)) +#define MIN(x,y) (((x)<(y))?(x):(y)) + +typedef struct +{ + int kf_indicated; + unsigned int frames_since_key; + unsigned int frames_since_golden; + int filter_level; + int frames_till_gf_update_due; + int recent_ref_frame_usage[MAX_REF_FRAMES]; + + MV_CONTEXT mvc[2]; + int mvcosts[2][MVvals+1]; + +#ifdef MODE_STATS + // Stats + int y_modes[5]; + int uv_modes[4]; + int b_modes[10]; + int inter_y_modes[10]; + int inter_uv_modes[4]; + int inter_b_modes[10]; +#endif + + vp8_prob ymode_prob[4], uv_mode_prob[3]; /* interframe intra mode probs */ + vp8_prob kf_ymode_prob[4], kf_uv_mode_prob[3]; /* keyframe "" */ + + int ymode_count[5], uv_mode_count[4]; /* intra MB type cts this frame */ + + int count_mb_ref_frame_usage[MAX_REF_FRAMES]; + + int this_frame_percent_intra; + int last_frame_percent_intra; + + +} CODING_CONTEXT; + +typedef struct +{ + double frame; + double intra_error; + double coded_error; + double ssim_weighted_pred_err; + double pcnt_inter; + double pcnt_motion; + double pcnt_second_ref; + double pcnt_neutral; + double MVr; + double mvr_abs; + double MVc; + double mvc_abs; + double MVrv; + double MVcv; + double mv_in_out_count; + double new_mv_count; + double duration; + double count; +} +FIRSTPASS_STATS; + +typedef struct +{ + int frames_so_far; + double frame_intra_error; + double frame_coded_error; + double frame_pcnt_inter; + double frame_pcnt_motion; + double frame_mvr; + double frame_mvr_abs; + double frame_mvc; + double frame_mvc_abs; + +} ONEPASS_FRAMESTATS; + + +typedef enum +{ + THR_ZERO1 = 0, + THR_DC = 1, + + THR_NEAREST1 = 2, + THR_NEAR1 = 3, + + THR_ZERO2 = 4, + THR_NEAREST2 = 5, + + THR_ZERO3 = 6, + THR_NEAREST3 = 7, + + THR_NEAR2 = 8, + THR_NEAR3 = 9, + + THR_V_PRED = 10, + THR_H_PRED = 11, + THR_TM = 12, + + THR_NEW1 = 13, + THR_NEW2 = 14, + THR_NEW3 = 15, + + THR_SPLIT1 = 16, + THR_SPLIT2 = 17, + THR_SPLIT3 = 18, + + THR_B_PRED = 19 +} +THR_MODES; + +typedef enum +{ + DIAMOND = 0, + NSTEP = 1, + HEX = 2 +} SEARCH_METHODS; + +typedef struct +{ + int RD; + SEARCH_METHODS search_method; + int improved_quant; + int improved_dct; + int auto_filter; + int recode_loop; + int iterative_sub_pixel; + int half_pixel_search; + int quarter_pixel_search; + int thresh_mult[MAX_MODES]; + int max_step_search_steps; + int first_step; + int optimize_coefficients; + + int use_fastquant_for_pick; + int no_skip_block4x4_search; + int improved_mv_pred; + +} SPEED_FEATURES; + +typedef struct +{ + MACROBLOCK mb; + int segment_counts[MAX_MB_SEGMENTS]; + int totalrate; +} MB_ROW_COMP; + +typedef struct +{ + TOKENEXTRA *start; + TOKENEXTRA *stop; +} TOKENLIST; + +typedef struct +{ + int ithread; + void *ptr1; + void *ptr2; +} ENCODETHREAD_DATA; +typedef struct +{ + int ithread; + void *ptr1; +} LPFTHREAD_DATA; + +enum +{ + BLOCK_16X8, + BLOCK_8X16, + BLOCK_8X8, + BLOCK_4X4, + BLOCK_16X16, + BLOCK_MAX_SEGMENTS +}; + +typedef struct +{ + // Layer configuration + double frame_rate; + int target_bandwidth; + + // Layer specific coding parameters + int starting_buffer_level; + int optimal_buffer_level; + int maximum_buffer_size; + int starting_buffer_level_in_ms; + int optimal_buffer_level_in_ms; + int maximum_buffer_size_in_ms; + + int avg_frame_size_for_layer; + + int buffer_level; + int bits_off_target; + + int64_t total_actual_bits; + int total_target_vs_actual; + + int worst_quality; + int active_worst_quality; + int best_quality; + int active_best_quality; + + int ni_av_qi; + int ni_tot_qi; + int ni_frames; + int avg_frame_qindex; + + double rate_correction_factor; + double key_frame_rate_correction_factor; + double gf_rate_correction_factor; + + int zbin_over_quant; + + int inter_frame_target; + int64_t total_byte_count; + + int filter_level; + + int last_frame_percent_intra; + + int count_mb_ref_frame_usage[MAX_REF_FRAMES]; + +} LAYER_CONTEXT; + +typedef struct VP8_COMP +{ + + DECLARE_ALIGNED(16, short, Y1quant[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, unsigned char, Y1quant_shift[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, Y1zbin[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, Y1round[QINDEX_RANGE][16]); + + DECLARE_ALIGNED(16, short, Y2quant[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, unsigned char, Y2quant_shift[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, Y2zbin[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, Y2round[QINDEX_RANGE][16]); + + DECLARE_ALIGNED(16, short, UVquant[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, unsigned char, UVquant_shift[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, UVzbin[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, UVround[QINDEX_RANGE][16]); + + DECLARE_ALIGNED(16, short, zrun_zbin_boost_y1[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, zrun_zbin_boost_y2[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, zrun_zbin_boost_uv[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, Y1quant_fast[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, Y2quant_fast[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, UVquant_fast[QINDEX_RANGE][16]); + + + MACROBLOCK mb; + VP8_COMMON common; + vp8_writer bc[9]; // one boolcoder for each partition + + VP8_CONFIG oxcf; + + struct lookahead_ctx *lookahead; + struct lookahead_entry *source; + struct lookahead_entry *alt_ref_source; + struct lookahead_entry *last_source; + + YV12_BUFFER_CONFIG *Source; + YV12_BUFFER_CONFIG *un_scaled_source; + YV12_BUFFER_CONFIG scaled_source; + YV12_BUFFER_CONFIG *last_frame_unscaled_source; + + int source_alt_ref_pending; // frame in src_buffers has been identified to be encoded as an alt ref + int source_alt_ref_active; // an alt ref frame has been encoded and is usable + + int is_src_frame_alt_ref; // source of frame to encode is an exact copy of an alt ref frame + + int gold_is_last; // golden frame same as last frame ( short circuit gold searches) + int alt_is_last; // Alt reference frame same as last ( short circuit altref search) + int gold_is_alt; // don't do both alt and gold search ( just do gold). + + //int refresh_alt_ref_frame; + YV12_BUFFER_CONFIG pick_lf_lvl_frame; + + TOKENEXTRA *tok; + unsigned int tok_count; + + + unsigned int frames_since_key; + unsigned int key_frame_frequency; + unsigned int this_key_frame_forced; + unsigned int next_key_frame_forced; + + // Ambient reconstruction err target for force key frames + int ambient_err; + + unsigned int mode_check_freq[MAX_MODES]; + unsigned int mode_test_hit_counts[MAX_MODES]; + unsigned int mode_chosen_counts[MAX_MODES]; + unsigned int mbs_tested_so_far; + + int rd_thresh_mult[MAX_MODES]; + int rd_baseline_thresh[MAX_MODES]; + int rd_threshes[MAX_MODES]; + + int RDMULT; + int RDDIV ; + + CODING_CONTEXT coding_context; + + // Rate targetting variables + int64_t prediction_error; + int64_t last_prediction_error; + int64_t intra_error; + int64_t last_intra_error; + + int this_frame_target; + int projected_frame_size; + int last_q[2]; // Separate values for Intra/Inter + + double rate_correction_factor; + double key_frame_rate_correction_factor; + double gf_rate_correction_factor; + + int frames_till_gf_update_due; // Count down till next GF + int current_gf_interval; // GF interval chosen when we coded the last GF + + int gf_overspend_bits; // Total bits overspent becasue of GF boost (cumulative) + + int non_gf_bitrate_adjustment; // Used in the few frames following a GF to recover the extra bits spent in that GF + + int kf_overspend_bits; // Extra bits spent on key frames that need to be recovered on inter frames + int kf_bitrate_adjustment; // Current number of bit s to try and recover on each inter frame. + int max_gf_interval; + int baseline_gf_interval; + int active_arnr_frames; // <= cpi->oxcf.arnr_max_frames + + int64_t key_frame_count; + int prior_key_frame_distance[KEY_FRAME_CONTEXT]; + int per_frame_bandwidth; // Current section per frame bandwidth target + int av_per_frame_bandwidth; // Average frame size target for clip + int min_frame_bandwidth; // Minimum allocation that should be used for any frame + int inter_frame_target; + double output_frame_rate; + int64_t last_time_stamp_seen; + int64_t last_end_time_stamp_seen; + int64_t first_time_stamp_ever; + + int ni_av_qi; + int ni_tot_qi; + int ni_frames; + int avg_frame_qindex; + + int zbin_over_quant; + int zbin_mode_boost; + int zbin_mode_boost_enabled; + int last_zbin_over_quant; + int last_zbin_mode_boost; + + int64_t total_byte_count; + + int buffered_mode; + + double frame_rate; + double ref_frame_rate; + int64_t buffer_level; + int bits_off_target; + + int rolling_target_bits; + int rolling_actual_bits; + + int long_rolling_target_bits; + int long_rolling_actual_bits; + + int64_t total_actual_bits; + int total_target_vs_actual; // debug stats + + int worst_quality; + int active_worst_quality; + int best_quality; + int active_best_quality; + + int cq_target_quality; + + int drop_frames_allowed; // Are we permitted to drop frames? + int drop_frame; // Drop this frame? + int drop_count; // How many frames have we dropped? + int max_drop_count; // How many frames should we drop? + int max_consec_dropped_frames; // Limit number of consecutive frames that can be dropped. + + + int ymode_count [VP8_YMODES]; /* intra MB type cts this frame */ + int uv_mode_count[VP8_UV_MODES]; /* intra MB type cts this frame */ + + unsigned int MVcount [2] [MVvals]; /* (row,col) MV cts this frame */ + + unsigned int coef_counts [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; /* for this frame */ + + //DECLARE_ALIGNED(16, int, coef_counts_backup [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]); //not used any more + //save vp8_tree_probs_from_distribution result for each frame to avoid repeat calculation + vp8_prob frame_coef_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; + char update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES]; + + unsigned int frame_branch_ct [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES][2]; + + int gfu_boost; + int kf_boost; + int last_boost; + + int target_bandwidth; + struct vpx_codec_pkt_list *output_pkt_list; + +#if 0 + // Experimental code for lagged and one pass + ONEPASS_FRAMESTATS one_pass_frame_stats[MAX_LAG_BUFFERS]; + int one_pass_frame_index; +#endif + + int decimation_factor; + int decimation_count; + + // for real time encoding + int avg_encode_time; //microsecond + int avg_pick_mode_time; //microsecond + int Speed; + unsigned int cpu_freq; //Mhz + int compressor_speed; + + int interquantizer; + int auto_gold; + int auto_adjust_gold_quantizer; + int goldfreq; + int auto_worst_q; + int cpu_used; + int pass; + + + int prob_intra_coded; + int prob_last_coded; + int prob_gf_coded; + int prob_skip_false; + int last_skip_false_probs[3]; + int last_skip_probs_q[3]; + int recent_ref_frame_usage[MAX_REF_FRAMES]; + + int count_mb_ref_frame_usage[MAX_REF_FRAMES]; + int this_frame_percent_intra; + int last_frame_percent_intra; + + int ref_frame_flags; + + SPEED_FEATURES sf; + int error_bins[1024]; + + // Data used for real time conferencing mode to help determine if it would be good to update the gf + int inter_zz_count; + int gf_bad_count; + int gf_update_recommended; + int skip_true_count; + + unsigned char *segmentation_map; + signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; // Segment data (can be deltas or absolute values) + int segment_encode_breakout[MAX_MB_SEGMENTS]; // segment threashold for encode breakout + + unsigned char *active_map; + unsigned int active_map_enabled; + // Video conferencing cyclic refresh mode flags etc + // This is a mode designed to clean up the background over time in live encoding scenarious. It uses segmentation + int cyclic_refresh_mode_enabled; + int cyclic_refresh_mode_max_mbs_perframe; + int cyclic_refresh_mode_index; + int cyclic_refresh_q; + signed char *cyclic_refresh_map; + +#if CONFIG_MULTITHREAD + // multithread data + int * mt_current_mb_col; + int mt_sync_range; + int b_multi_threaded; + int encoding_thread_count; + int b_lpf_running; + + pthread_t *h_encoding_thread; + pthread_t h_filter_thread; + + MB_ROW_COMP *mb_row_ei; + ENCODETHREAD_DATA *en_thread_data; + LPFTHREAD_DATA lpf_thread_data; + + //events + sem_t *h_event_start_encoding; + sem_t h_event_end_encoding; + sem_t h_event_start_lpf; + sem_t h_event_end_lpf; +#endif + + TOKENLIST *tplist; + unsigned int partition_sz[MAX_PARTITIONS]; + unsigned char *partition_d[MAX_PARTITIONS]; + unsigned char *partition_d_end[MAX_PARTITIONS]; + // end of multithread data + + + fractional_mv_step_fp *find_fractional_mv_step; + vp8_full_search_fn_t full_search_sad; + vp8_refining_search_fn_t refining_search_sad; + vp8_diamond_search_fn_t diamond_search_sad; + vp8_variance_fn_ptr_t fn_ptr[BLOCK_MAX_SEGMENTS]; + unsigned int time_receive_data; + unsigned int time_compress_data; + unsigned int time_pick_lpf; + unsigned int time_encode_mb_row; + + int base_skip_false_prob[128]; + + FRAME_CONTEXT lfc_n; /* last frame entropy */ + FRAME_CONTEXT lfc_a; /* last alt ref entropy */ + FRAME_CONTEXT lfc_g; /* last gold ref entropy */ + + + struct twopass_rc + { + unsigned int section_intra_rating; + double section_max_qfactor; + unsigned int next_iiratio; + unsigned int this_iiratio; + FIRSTPASS_STATS total_stats; + FIRSTPASS_STATS this_frame_stats; + FIRSTPASS_STATS *stats_in, *stats_in_end, *stats_in_start; + FIRSTPASS_STATS total_left_stats; + int first_pass_done; + int64_t bits_left; + int64_t clip_bits_total; + double avg_iiratio; + double modified_error_total; + double modified_error_used; + double modified_error_left; + double kf_intra_err_min; + double gf_intra_err_min; + int frames_to_key; + int maxq_max_limit; + int maxq_min_limit; + int gf_decay_rate; + int static_scene_max_gf_interval; + int kf_bits; + int gf_group_error_left; // Remaining error from uncoded frames in a gf group. Two pass use only + + // Projected total bits available for a key frame group of frames + int64_t kf_group_bits; + + // Error score of frames still to be coded in kf group + int64_t kf_group_error_left; + + int gf_group_bits; // Projected Bits available for a group of frames including 1 GF or ARF + int gf_bits; // Bits for the golden frame or ARF - 2 pass only + int alt_extra_bits; + double est_max_qcorrection_factor; + } twopass; + +#if VP8_TEMPORAL_ALT_REF + YV12_BUFFER_CONFIG alt_ref_buffer; + YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS]; + int fixed_divide[512]; +#endif + +#if CONFIG_INTERNAL_STATS + int count; + double total_y; + double total_u; + double total_v; + double total ; + double total_sq_error; + double totalp_y; + double totalp_u; + double totalp_v; + double totalp; + double total_sq_error2; + int bytes; + double summed_quality; + double summed_weights; + unsigned int tot_recode_hits; + + + double total_ssimg_y; + double total_ssimg_u; + double total_ssimg_v; + double total_ssimg_all; + + int b_calculate_ssimg; +#endif + int b_calculate_psnr; + + // Per MB activity measurement + unsigned int activity_avg; + unsigned int * mb_activity_map; + int * mb_norm_activity_map; + + // Record of which MBs still refer to last golden frame either + // directly or through 0,0 + unsigned char *gf_active_flags; + int gf_active_count; + + int output_partition; + + //Store last frame's MV info for next frame MV prediction + int_mv *lfmv; + int *lf_ref_frame_sign_bias; + int *lf_ref_frame; + + int force_next_frame_intra; /* force next frame to intra when kf_auto says so */ + + int droppable; + +#if CONFIG_TEMPORAL_DENOISING + VP8_DENOISER denoiser; +#endif + + // Coding layer state variables + unsigned int current_layer; + LAYER_CONTEXT layer_context[VPX_TS_MAX_LAYERS]; + + int64_t frames_in_layer[VPX_TS_MAX_LAYERS]; + int64_t bytes_in_layer[VPX_TS_MAX_LAYERS]; + double sum_psnr[VPX_TS_MAX_LAYERS]; + double sum_psnr_p[VPX_TS_MAX_LAYERS]; + double total_error2[VPX_TS_MAX_LAYERS]; + double total_error2_p[VPX_TS_MAX_LAYERS]; + double sum_ssim[VPX_TS_MAX_LAYERS]; + double sum_weights[VPX_TS_MAX_LAYERS]; + + double total_ssimg_y_in_layer[VPX_TS_MAX_LAYERS]; + double total_ssimg_u_in_layer[VPX_TS_MAX_LAYERS]; + double total_ssimg_v_in_layer[VPX_TS_MAX_LAYERS]; + double total_ssimg_all_in_layer[VPX_TS_MAX_LAYERS]; + +#if CONFIG_MULTI_RES_ENCODING + /* Number of MBs per row at lower-resolution level */ + int mr_low_res_mb_cols; +#endif + +} VP8_COMP; + +void control_data_rate(VP8_COMP *cpi); + +void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned char *dest_end, unsigned long *size); + +int rd_cost_intra_mb(MACROBLOCKD *x); + +void vp8_tokenize_mb(VP8_COMP *, MACROBLOCKD *, TOKENEXTRA **); + +void vp8_set_speed_features(VP8_COMP *cpi); + +#if CONFIG_DEBUG +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval" at %s:%d", \ + __FILE__,__LINE__);\ + } while(0) +#else +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval);\ + } while(0) +#endif +#endif diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c new file mode 100644 index 0000000..dafb645 --- /dev/null +++ b/vp8/encoder/pickinter.c @@ -0,0 +1,1176 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "vpx_config.h" +#include "onyx_int.h" +#include "modecosts.h" +#include "encodeintra.h" +#include "vp8/common/entropymode.h" +#include "pickinter.h" +#include "vp8/common/findnearmv.h" +#include "encodemb.h" +#include "vp8/common/reconinter.h" +#include "vp8/common/reconintra4x4.h" +#include "vp8/common/variance.h" +#include "mcomp.h" +#include "rdopt.h" +#include "vpx_mem/vpx_mem.h" +#if CONFIG_TEMPORAL_DENOISING +#include "denoising.h" +#endif + +extern int VP8_UVSSE(MACROBLOCK *x); + +#ifdef SPEEDSTATS +extern unsigned int cnt_pm; +#endif + +extern const int vp8_ref_frame_order[MAX_MODES]; +extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; + +extern int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]); + + +int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, + int_mv *bestmv, int_mv *ref_mv, + int error_per_bit, + const vp8_variance_fn_ptr_t *vfp, + int *mvcost[2], int *distortion, + unsigned int *sse) +{ + (void) b; + (void) d; + (void) ref_mv; + (void) error_per_bit; + (void) vfp; + (void) mvcost; + (void) distortion; + (void) sse; + bestmv->as_mv.row <<= 3; + bestmv->as_mv.col <<= 3; + return 0; +} + + +static int get_inter_mbpred_error(MACROBLOCK *mb, + const vp8_variance_fn_ptr_t *vfp, + unsigned int *sse, + int_mv this_mv) +{ + + BLOCK *b = &mb->block[0]; + BLOCKD *d = &mb->e_mbd.block[0]; + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + int pre_stride = mb->e_mbd.pre.y_stride; + unsigned char *in_what = mb->e_mbd.pre.y_buffer + d->offset ; + int in_what_stride = pre_stride; + int xoffset = this_mv.as_mv.col & 7; + int yoffset = this_mv.as_mv.row & 7; + + in_what += (this_mv.as_mv.row >> 3) * pre_stride + (this_mv.as_mv.col >> 3); + + if (xoffset | yoffset) + { + return vfp->svf(in_what, in_what_stride, xoffset, yoffset, what, what_stride, sse); + } + else + { + return vfp->vf(what, what_stride, in_what, in_what_stride, sse); + } + +} + + +unsigned int vp8_get4x4sse_cs_c +( + const unsigned char *src_ptr, + int source_stride, + const unsigned char *ref_ptr, + int recon_stride +) +{ + int distortion = 0; + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int diff = src_ptr[c] - ref_ptr[c]; + distortion += diff * diff; + } + + src_ptr += source_stride; + ref_ptr += recon_stride; + } + + return distortion; +} + +static int get_prediction_error(BLOCK *be, BLOCKD *b) +{ + unsigned char *sptr; + unsigned char *dptr; + sptr = (*(be->base_src) + be->src); + dptr = b->predictor; + + return vp8_get4x4sse_cs(sptr, be->src_stride, dptr, 16); + +} + +static int pick_intra4x4block( + MACROBLOCK *x, + int ib, + B_PREDICTION_MODE *best_mode, + unsigned int *mode_costs, + + int *bestrate, + int *bestdistortion) +{ + + BLOCKD *b = &x->e_mbd.block[ib]; + BLOCK *be = &x->block[ib]; + int dst_stride = x->e_mbd.dst.y_stride; + unsigned char *base_dst = x->e_mbd.dst.y_buffer; + B_PREDICTION_MODE mode; + int best_rd = INT_MAX; // 1<<30 + int rate; + int distortion; + + for (mode = B_DC_PRED; mode <= B_HE_PRED /*B_HU_PRED*/; mode++) + { + int this_rd; + + rate = mode_costs[mode]; + vp8_intra4x4_predict + (base_dst + b->offset, dst_stride, + mode, b->predictor, 16); + distortion = get_prediction_error(be, b); + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + *bestrate = rate; + *bestdistortion = distortion; + best_rd = this_rd; + *best_mode = mode; + } + } + + b->bmi.as_mode = (B_PREDICTION_MODE)(*best_mode); + vp8_encode_intra4x4block(x, ib); + return best_rd; +} + + +static int pick_intra4x4mby_modes +( + MACROBLOCK *mb, + int *Rate, + int *best_dist +) +{ + MACROBLOCKD *const xd = &mb->e_mbd; + int i; + int cost = mb->mbmode_cost [xd->frame_type] [B_PRED]; + int error; + int distortion = 0; + unsigned int *bmode_costs; + + intra_prediction_down_copy(xd, xd->dst.y_buffer - xd->dst.y_stride + 16); + + bmode_costs = mb->inter_bmode_costs; + + for (i = 0; i < 16; i++) + { + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); + int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(d); + + if (mb->e_mbd.frame_type == KEY_FRAME) + { + const B_PREDICTION_MODE A = above_block_mode(mic, i, mis); + const B_PREDICTION_MODE L = left_block_mode(mic, i); + + bmode_costs = mb->bmode_costs[A][L]; + } + + + pick_intra4x4block(mb, i, &best_mode, bmode_costs, &r, &d); + + cost += r; + distortion += d; + mic->bmi[i].as_mode = best_mode; + + // Break out case where we have already exceeded best so far value + // that was passed in + if (distortion > *best_dist) + break; + } + + *Rate = cost; + + if (i == 16) + { + *best_dist = distortion; + error = RDCOST(mb->rdmult, mb->rddiv, cost, distortion); + } + else + { + *best_dist = INT_MAX; + error = INT_MAX; + } + + return error; +} + +static void pick_intra_mbuv_mode(MACROBLOCK *mb) +{ + + MACROBLOCKD *x = &mb->e_mbd; + unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; + unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; + unsigned char *usrc_ptr = (mb->block[16].src + *mb->block[16].base_src); + unsigned char *vsrc_ptr = (mb->block[20].src + *mb->block[20].base_src); + int uvsrc_stride = mb->block[16].src_stride; + unsigned char uleft_col[8]; + unsigned char vleft_col[8]; + unsigned char utop_left = uabove_row[-1]; + unsigned char vtop_left = vabove_row[-1]; + int i, j; + int expected_udc; + int expected_vdc; + int shift; + int Uaverage = 0; + int Vaverage = 0; + int diff; + int pred_error[4] = {0, 0, 0, 0}, best_error = INT_MAX; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); + + + for (i = 0; i < 8; i++) + { + uleft_col[i] = x->dst.u_buffer [i* x->dst.uv_stride -1]; + vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; + } + + if (!x->up_available && !x->left_available) + { + expected_udc = 128; + expected_vdc = 128; + } + else + { + shift = 2; + + if (x->up_available) + { + + for (i = 0; i < 8; i++) + { + Uaverage += uabove_row[i]; + Vaverage += vabove_row[i]; + } + + shift ++; + + } + + if (x->left_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uleft_col[i]; + Vaverage += vleft_col[i]; + } + + shift ++; + + } + + expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; + expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; + } + + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + + int predu = uleft_col[i] + uabove_row[j] - utop_left; + int predv = vleft_col[i] + vabove_row[j] - vtop_left; + int u_p, v_p; + + u_p = usrc_ptr[j]; + v_p = vsrc_ptr[j]; + + if (predu < 0) + predu = 0; + + if (predu > 255) + predu = 255; + + if (predv < 0) + predv = 0; + + if (predv > 255) + predv = 255; + + + diff = u_p - expected_udc; + pred_error[DC_PRED] += diff * diff; + diff = v_p - expected_vdc; + pred_error[DC_PRED] += diff * diff; + + + diff = u_p - uabove_row[j]; + pred_error[V_PRED] += diff * diff; + diff = v_p - vabove_row[j]; + pred_error[V_PRED] += diff * diff; + + + diff = u_p - uleft_col[i]; + pred_error[H_PRED] += diff * diff; + diff = v_p - vleft_col[i]; + pred_error[H_PRED] += diff * diff; + + + diff = u_p - predu; + pred_error[TM_PRED] += diff * diff; + diff = v_p - predv; + pred_error[TM_PRED] += diff * diff; + + + } + + usrc_ptr += uvsrc_stride; + vsrc_ptr += uvsrc_stride; + + if (i == 3) + { + usrc_ptr = (mb->block[18].src + *mb->block[18].base_src); + vsrc_ptr = (mb->block[22].src + *mb->block[22].base_src); + } + + + + } + + + for (i = DC_PRED; i <= TM_PRED; i++) + { + if (best_error > pred_error[i]) + { + best_error = pred_error[i]; + best_mode = (MB_PREDICTION_MODE)i; + } + } + + + mb->e_mbd.mode_info_context->mbmi.uv_mode = best_mode; + +} + +static void update_mvcount(VP8_COMP *cpi, MACROBLOCKD *xd, int_mv *best_ref_mv) +{ + /* Split MV modes currently not supported when RD is nopt enabled, + * therefore, only need to modify MVcount in NEWMV mode. */ + if (xd->mode_info_context->mbmi.mode == NEWMV) + { + cpi->MVcount[0][mv_max+((xd->mode_info_context->mbmi.mv.as_mv.row - + best_ref_mv->as_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((xd->mode_info_context->mbmi.mv.as_mv.col - + best_ref_mv->as_mv.col) >> 1)]++; + } +} + + +#if CONFIG_MULTI_RES_ENCODING +static +void get_lower_res_motion_info(VP8_COMP *cpi, MACROBLOCKD *xd, int *dissim, + int *parent_ref_frame, + MB_PREDICTION_MODE *parent_mode, + int_mv *parent_ref_mv, int mb_row, int mb_col) +{ + LOWER_RES_INFO* store_mode_info + = (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info; + unsigned int parent_mb_index; + //unsigned int parent_mb_index = map_640x480_to_320x240[mb_row][mb_col]; + + /* Consider different down_sampling_factor. */ + { + /* TODO: Removed the loop that supports special down_sampling_factor + * such as 2, 4, 8. Will revisit it if needed. + * Should also try using a look-up table to see if it helps + * performance. */ + int parent_mb_row, parent_mb_col; + + parent_mb_row = mb_row*cpi->oxcf.mr_down_sampling_factor.den + /cpi->oxcf.mr_down_sampling_factor.num; + parent_mb_col = mb_col*cpi->oxcf.mr_down_sampling_factor.den + /cpi->oxcf.mr_down_sampling_factor.num; + parent_mb_index = parent_mb_row*cpi->mr_low_res_mb_cols + parent_mb_col; + } + + /* Read lower-resolution mode & motion result from memory.*/ + *parent_ref_frame = store_mode_info[parent_mb_index].ref_frame; + *parent_mode = store_mode_info[parent_mb_index].mode; + *dissim = store_mode_info[parent_mb_index].dissim; + + /* For highest-resolution encoder, adjust dissim value. Lower its quality + * for good performance. */ + if (cpi->oxcf.mr_encoder_id == (cpi->oxcf.mr_total_resolutions - 1)) + *dissim>>=1; + + if(*parent_ref_frame != INTRA_FRAME) + { + /* Consider different down_sampling_factor. + * The result can be rounded to be more precise, but it takes more time. + */ + //int round = cpi->oxcf.mr_down_sampling_factor.den/2; + (*parent_ref_mv).as_mv.row = store_mode_info[parent_mb_index].mv.as_mv.row + *cpi->oxcf.mr_down_sampling_factor.num + /cpi->oxcf.mr_down_sampling_factor.den; + (*parent_ref_mv).as_mv.col = store_mode_info[parent_mb_index].mv.as_mv.col + *cpi->oxcf.mr_down_sampling_factor.num + /cpi->oxcf.mr_down_sampling_factor.den; + + vp8_clamp_mv2(parent_ref_mv, xd); + } +} +#endif + +static void check_for_encode_breakout(unsigned int sse, MACROBLOCK* x) +{ + if (sse < x->encode_breakout) + { + // Check u and v to make sure skip is ok + int sse2 = 0; + + sse2 = VP8_UVSSE(x); + + if (sse2 * 2 < x->encode_breakout) + x->skip = 1; + else + x->skip = 0; + } +} + +static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2, VP8_COMP *cpi, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + int_mv mv = x->e_mbd.mode_info_context->mbmi.mv; + int this_rd; + /* Exit early and don't compute the distortion if this macroblock + * is marked inactive. */ + if (cpi->active_map_enabled && x->active_ptr[0] == 0) + { + *sse = 0; + *distortion2 = 0; + x->skip = 1; + return INT_MAX; + } + + if((this_mode != NEWMV) || + !(cpi->sf.half_pixel_search) || cpi->common.full_pixel==1) + *distortion2 = get_inter_mbpred_error(x, + &cpi->fn_ptr[BLOCK_16X16], + sse, mv); + + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, *distortion2); + + check_for_encode_breakout(*sse, x); + return this_rd; +} + +void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, + int recon_uvoffset, int *returnrate, + int *returndistortion, int *returnintra, int mb_row, + int mb_col) +{ + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO best_mbmode; + + int_mv best_ref_mv_sb[2]; + int_mv mode_mv_sb[2][MB_MODE_COUNT]; + int_mv best_ref_mv; + int_mv *mode_mv; + MB_PREDICTION_MODE this_mode; + int num00; + int mdcounts[4]; + int best_rd = INT_MAX; // 1 << 30; + int best_intra_rd = INT_MAX; + int mode_index; + int rate; + int rate2; + int distortion2; + int bestsme = INT_MAX; + int best_mode_index = 0; + unsigned int sse = INT_MAX, best_rd_sse = INT_MAX; +#if CONFIG_TEMPORAL_DENOISING + unsigned int zero_mv_sse = 0, best_sse = INT_MAX; +#endif + + int_mv mvp; + + int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + int saddone=0; + int sr=0; //search range got from mv_pred(). It uses step_param levels. (0-7) + + unsigned char *plane[4][3]; + int ref_frame_map[4]; + int sign_bias = 0; + +#if CONFIG_MULTI_RES_ENCODING + int dissim = INT_MAX; + int parent_ref_frame = 0; + int_mv parent_ref_mv; + MB_PREDICTION_MODE parent_mode = 0; + + if (cpi->oxcf.mr_encoder_id) + get_lower_res_motion_info(cpi, xd, &dissim, &parent_ref_frame, + &parent_mode, &parent_ref_mv, mb_row, mb_col); +#endif + + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = 0; + vpx_memset(mode_mv_sb, 0, sizeof(mode_mv_sb)); + vpx_memset(&best_mbmode, 0, sizeof(best_mbmode)); + + /* Setup search priorities */ + get_reference_search_order(cpi, ref_frame_map); + + /* Check to see if there is at least 1 valid reference frame that we need + * to calculate near_mvs. + */ + if (ref_frame_map[1] > 0) + { + sign_bias = vp8_find_near_mvs_bias(&x->e_mbd, + x->e_mbd.mode_info_context, + mode_mv_sb, + best_ref_mv_sb, + mdcounts, + ref_frame_map[1], + cpi->common.ref_frame_sign_bias); + + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + } + + get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset); + + cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame + + *returnintra = INT_MAX; + x->skip = 0; + + x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + + // if we encode a new mv this is important + // find the best new motion vector + for (mode_index = 0; mode_index < MAX_MODES; mode_index++) + { + int frame_cost; + int this_rd = INT_MAX; + int this_ref_frame = ref_frame_map[vp8_ref_frame_order[mode_index]]; + + if (best_rd <= cpi->rd_threshes[mode_index]) + continue; + + if (this_ref_frame < 0) + continue; + + x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame; + +#if CONFIG_MULTI_RES_ENCODING + if (cpi->oxcf.mr_encoder_id) + { + /* If parent MB is intra, child MB is intra. */ + if (!parent_ref_frame && this_ref_frame) + continue; + + /* If parent MB is inter, and it is unlikely there are multiple + * objects in parent MB, we use parent ref frame as child MB's + * ref frame. */ + if (parent_ref_frame && dissim < 8 + && parent_ref_frame != this_ref_frame) + continue; + } +#endif + + // everything but intra + if (x->e_mbd.mode_info_context->mbmi.ref_frame) + { + x->e_mbd.pre.y_buffer = plane[this_ref_frame][0]; + x->e_mbd.pre.u_buffer = plane[this_ref_frame][1]; + x->e_mbd.pre.v_buffer = plane[this_ref_frame][2]; + + if (sign_bias != cpi->common.ref_frame_sign_bias[this_ref_frame]) + { + sign_bias = cpi->common.ref_frame_sign_bias[this_ref_frame]; + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + } + +#if CONFIG_MULTI_RES_ENCODING + if (cpi->oxcf.mr_encoder_id) + { + if (vp8_mode_order[mode_index] == NEARESTMV && + mode_mv[NEARESTMV].as_int ==0) + continue; + if (vp8_mode_order[mode_index] == NEARMV && + mode_mv[NEARMV].as_int ==0) + continue; + + if (vp8_mode_order[mode_index] == NEWMV && parent_mode == ZEROMV + && best_ref_mv.as_int==0) //&& dissim==0 + continue; + else if(vp8_mode_order[mode_index] == NEWMV && dissim==0 + && best_ref_mv.as_int==parent_ref_mv.as_int) + continue; + } +#endif + } + + /* Check to see if the testing frequency for this mode is at its max + * If so then prevent it from being tested and increase the threshold + * for its testing */ + if (cpi->mode_test_hit_counts[mode_index] && + (cpi->mode_check_freq[mode_index] > 1)) + { + if (cpi->mbs_tested_so_far <= (cpi->mode_check_freq[mode_index] * + cpi->mode_test_hit_counts[mode_index])) + { + /* Increase the threshold for coding this mode to make it less + * likely to be chosen */ + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = + (cpi->rd_baseline_thresh[mode_index] >> 7) * + cpi->rd_thresh_mult[mode_index]; + continue; + } + } + + /* We have now reached the point where we are going to test the current + * mode so increment the counter for the number of times it has been + * tested */ + cpi->mode_test_hit_counts[mode_index] ++; + + rate2 = 0; + distortion2 = 0; + + this_mode = vp8_mode_order[mode_index]; + + x->e_mbd.mode_info_context->mbmi.mode = this_mode; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + + /* Work out the cost assosciated with selecting the reference frame */ + frame_cost = + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + rate2 += frame_cost; + + /* Only consider ZEROMV/ALTREF_FRAME for alt ref frame, + * unless ARNR filtering is enabled in which case we want + * an unfiltered alternative */ + if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) + { + if (this_mode != ZEROMV || + x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) + continue; + } + + switch (this_mode) + { + case B_PRED: + /* Pass best so far to pick_intra4x4mby_modes to use as breakout */ + distortion2 = best_rd_sse; + pick_intra4x4mby_modes(x, &rate, &distortion2); + + if (distortion2 == INT_MAX) + { + this_rd = INT_MAX; + } + else + { + rate2 += rate; + distortion2 = vp8_variance16x16( + *(b->base_src), b->src_stride, + x->e_mbd.predictor, 16, &sse); + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + + if (this_rd < best_intra_rd) + { + best_intra_rd = this_rd; + *returnintra = distortion2; + } + } + + break; + + case SPLITMV: + + // Split MV modes currently not supported when RD is nopt enabled. + break; + + case DC_PRED: + case V_PRED: + case H_PRED: + case TM_PRED: + vp8_build_intra_predictors_mby_s(xd, + xd->dst.y_buffer - xd->dst.y_stride, + xd->dst.y_buffer - 1, + xd->dst.y_stride, + xd->predictor, + 16); + distortion2 = vp8_variance16x16 + (*(b->base_src), b->src_stride, + x->e_mbd.predictor, 16, &sse); + rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + + if (this_rd < best_intra_rd) + { + best_intra_rd = this_rd; + *returnintra = distortion2; + } + break; + + case NEWMV: + { + int thissme; + int step_param; + int further_steps; + int n = 0; + int sadpb = x->sadperbit16; + int_mv mvp_full; + + int col_min = ((best_ref_mv.as_mv.col+7)>>3) - MAX_FULL_PEL_VAL; + int row_min = ((best_ref_mv.as_mv.row+7)>>3) - MAX_FULL_PEL_VAL; + int col_max = (best_ref_mv.as_mv.col>>3) + + MAX_FULL_PEL_VAL; + int row_max = (best_ref_mv.as_mv.row>>3) + + MAX_FULL_PEL_VAL; + + int tmp_col_min = x->mv_col_min; + int tmp_col_max = x->mv_col_max; + int tmp_row_min = x->mv_row_min; + int tmp_row_max = x->mv_row_max; + + int speed_adjust = (cpi->Speed > 5) ? ((cpi->Speed >= 8)? 3 : 2) : 1; + + // Further step/diamond searches as necessary + step_param = cpi->sf.first_step + speed_adjust; + +#if CONFIG_MULTI_RES_ENCODING + if (cpi->oxcf.mr_encoder_id) + { + // Use parent MV as predictor. Adjust search range accordingly. + mvp.as_int = parent_ref_mv.as_int; + mvp_full.as_mv.col = parent_ref_mv.as_mv.col>>3; + mvp_full.as_mv.row = parent_ref_mv.as_mv.row>>3; + + if(dissim <=32) step_param += 3; + else if(dissim <=128) step_param += 2; + else step_param += 1; + }else +#endif + { + if(cpi->sf.improved_mv_pred) + { + if(!saddone) + { + vp8_cal_sad(cpi,xd,x, recon_yoffset ,&near_sadidx[0] ); + saddone = 1; + } + + vp8_mv_pred(cpi, &x->e_mbd, x->e_mbd.mode_info_context, + &mvp,x->e_mbd.mode_info_context->mbmi.ref_frame, + cpi->common.ref_frame_sign_bias, &sr, + &near_sadidx[0]); + + sr += speed_adjust; + //adjust search range according to sr from mv prediction + if(sr > step_param) + step_param = sr; + + mvp_full.as_mv.col = mvp.as_mv.col>>3; + mvp_full.as_mv.row = mvp.as_mv.row>>3; + }else + { + mvp.as_int = best_ref_mv.as_int; + mvp_full.as_mv.col = best_ref_mv.as_mv.col>>3; + mvp_full.as_mv.row = best_ref_mv.as_mv.row>>3; + } + } + +#if CONFIG_MULTI_RES_ENCODING + if (cpi->oxcf.mr_encoder_id && dissim <= 2 && + MAX(abs(best_ref_mv.as_mv.row - parent_ref_mv.as_mv.row), + abs(best_ref_mv.as_mv.col - parent_ref_mv.as_mv.col)) <= 4) + { + d->bmi.mv.as_int = mvp_full.as_int; + mode_mv[NEWMV].as_int = mvp_full.as_int; + + cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, &best_ref_mv, + x->errorperbit, + &cpi->fn_ptr[BLOCK_16X16], + cpi->mb.mvcost, + &distortion2,&sse); + }else +#endif + { + /* Get intersection of UMV window and valid MV window to + * reduce # of checks in diamond search. */ + if (x->mv_col_min < col_min ) + x->mv_col_min = col_min; + if (x->mv_col_max > col_max ) + x->mv_col_max = col_max; + if (x->mv_row_min < row_min ) + x->mv_row_min = row_min; + if (x->mv_row_max > row_max ) + x->mv_row_max = row_max; + + further_steps = (cpi->Speed >= 8)? + 0: (cpi->sf.max_step_search_steps - 1 - step_param); + + if (cpi->sf.search_method == HEX) + { +#if CONFIG_MULTI_RES_ENCODING + /* TODO: In higher-res pick_inter_mode, step_param is used to + * modify hex search range. Here, set step_param to 0 not to + * change the behavior in lowest-resolution encoder. + * Will improve it later. + */ + if (!cpi->oxcf.mr_encoder_id) + step_param = 0; +#endif + bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv, + step_param, sadpb, + &cpi->fn_ptr[BLOCK_16X16], + x->mvsadcost, x->mvcost, &best_ref_mv); + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + } + else + { + bestsme = cpi->diamond_search_sad(x, b, d, &mvp_full, + &d->bmi.mv, step_param, sadpb, &num00, + &cpi->fn_ptr[BLOCK_16X16], + x->mvcost, &best_ref_mv); + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + + // Further step/diamond searches as necessary + n = 0; + //further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; + + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = + cpi->diamond_search_sad(x, b, d, &mvp_full, + &d->bmi.mv, + step_param + n, + sadpb, &num00, + &cpi->fn_ptr[BLOCK_16X16], + x->mvcost, &best_ref_mv); + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + } + else + { + d->bmi.mv.as_int = mode_mv[NEWMV].as_int; + } + } + } + } + + x->mv_col_min = tmp_col_min; + x->mv_col_max = tmp_col_max; + x->mv_row_min = tmp_row_min; + x->mv_row_max = tmp_row_max; + + if (bestsme < INT_MAX) + cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, + &best_ref_mv, x->errorperbit, + &cpi->fn_ptr[BLOCK_16X16], + cpi->mb.mvcost, + &distortion2,&sse); + } + + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + + // mv cost; + rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, + cpi->mb.mvcost, 128); + } + + case NEARESTMV: + case NEARMV: + + if (mode_mv[this_mode].as_int == 0) + continue; + + case ZEROMV: + + /* Trap vectors that reach beyond the UMV borders + * Note that ALL New MV, Nearest MV Near MV and Zero MV code drops + * through to this point because of the lack of break statements + * in the previous two cases. + */ + if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || + ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || + ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) + continue; + + rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + x->e_mbd.mode_info_context->mbmi.mv.as_int = + mode_mv[this_mode].as_int; + this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x); + + break; + default: + break; + } + +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + // Store for later use by denoiser. + if (this_mode == ZEROMV && + x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME) + { + zero_mv_sse = sse; + } + + // Store the best NEWMV in x for later use in the denoiser. + // We are restricted to the LAST_FRAME since the denoiser only keeps + // one filter state. + if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV && + x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME) + { + best_sse = sse; + x->e_mbd.best_sse_inter_mode = NEWMV; + x->e_mbd.best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv; + x->e_mbd.need_to_clamp_best_mvs = + x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs; + } + } +#endif + + if (this_rd < best_rd || x->skip) + { + // Note index of best mode + best_mode_index = mode_index; + + *returnrate = rate2; + *returndistortion = distortion2; + best_rd_sse = sse; + best_rd = this_rd; + vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, + sizeof(MB_MODE_INFO)); + + /* Testing this mode gave rise to an improvement in best error + * score. Lower threshold a bit for next time + */ + cpi->rd_thresh_mult[mode_index] = + (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? + cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; + cpi->rd_threshes[mode_index] = + (cpi->rd_baseline_thresh[mode_index] >> 7) * + cpi->rd_thresh_mult[mode_index]; + } + + /* If the mode did not help improve the best error case then raise the + * threshold for testing that mode next time around. + */ + else + { + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = + (cpi->rd_baseline_thresh[mode_index] >> 7) * + cpi->rd_thresh_mult[mode_index]; + } + + if (x->skip) + break; + } + + // Reduce the activation RD thresholds for the best choice mode + if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) + { + int best_adjustment = (cpi->rd_thresh_mult[best_mode_index] >> 3); + + cpi->rd_thresh_mult[best_mode_index] = + (cpi->rd_thresh_mult[best_mode_index] + >= (MIN_THRESHMULT + best_adjustment)) ? + cpi->rd_thresh_mult[best_mode_index] - best_adjustment : + MIN_THRESHMULT; + cpi->rd_threshes[best_mode_index] = + (cpi->rd_baseline_thresh[best_mode_index] >> 7) * + cpi->rd_thresh_mult[best_mode_index]; + } + + + { + int this_rdbin = (*returndistortion >> 7); + + if (this_rdbin >= 1024) + { + this_rdbin = 1023; + } + + cpi->error_bins[this_rdbin] ++; + } + +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + if (x->e_mbd.best_sse_inter_mode == DC_PRED) { + // No best MV found. + x->e_mbd.best_sse_inter_mode = best_mbmode.mode; + x->e_mbd.best_sse_mv = best_mbmode.mv; + x->e_mbd.need_to_clamp_best_mvs = best_mbmode.need_to_clamp_mvs; + best_sse = best_rd_sse; + } + vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse, + recon_yoffset, recon_uvoffset); + + // Reevaluate ZEROMV after denoising. + if (best_mbmode.ref_frame == INTRA_FRAME) + { + int this_rd = 0; + rate2 = 0; + distortion2 = 0; + x->e_mbd.mode_info_context->mbmi.ref_frame = LAST_FRAME; + rate2 += x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + this_mode = ZEROMV; + rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + x->e_mbd.mode_info_context->mbmi.mode = this_mode; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x); + + if (this_rd < best_rd || x->skip) + { + vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, + sizeof(MB_MODE_INFO)); + } + } + } +#endif + + if (cpi->is_src_frame_alt_ref && + (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) + { + x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; + x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mb_skip_coeff = + (cpi->common.mb_no_coeff_skip); + x->e_mbd.mode_info_context->mbmi.partitioning = 0; + + return; + } + + /* set to the best mb mode, this copy can be skip if x->skip since it + * already has the right content */ + if (!x->skip) + vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, + sizeof(MB_MODE_INFO)); + + if (best_mbmode.mode <= B_PRED) + { + /* set mode_info_context->mbmi.uv_mode */ + pick_intra_mbuv_mode(x); + } + + if (sign_bias + != cpi->common.ref_frame_sign_bias[xd->mode_info_context->mbmi.ref_frame]) + best_ref_mv.as_int = best_ref_mv_sb[!sign_bias].as_int; + + update_mvcount(cpi, &x->e_mbd, &best_ref_mv); +} + + +void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate_) +{ + int error4x4, error16x16 = INT_MAX; + int rate, best_rate = 0, distortion, best_sse; + MB_PREDICTION_MODE mode, best_mode = DC_PRED; + int this_rd; + unsigned int sse; + BLOCK *b = &x->block[0]; + MACROBLOCKD *xd = &x->e_mbd; + + xd->mode_info_context->mbmi.ref_frame = INTRA_FRAME; + + pick_intra_mbuv_mode(x); + + for (mode = DC_PRED; mode <= TM_PRED; mode ++) + { + xd->mode_info_context->mbmi.mode = mode; + vp8_build_intra_predictors_mby_s(xd, + xd->dst.y_buffer - xd->dst.y_stride, + xd->dst.y_buffer - 1, + xd->dst.y_stride, + xd->predictor, + 16); + distortion = vp8_variance16x16 + (*(b->base_src), b->src_stride, xd->predictor, 16, &sse); + rate = x->mbmode_cost[xd->frame_type][mode]; + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (error16x16 > this_rd) + { + error16x16 = this_rd; + best_mode = mode; + best_sse = sse; + best_rate = rate; + } + } + xd->mode_info_context->mbmi.mode = best_mode; + + error4x4 = pick_intra4x4mby_modes(x, &rate, + &best_sse); + if (error4x4 < error16x16) + { + xd->mode_info_context->mbmi.mode = B_PRED; + best_rate = rate; + } + + *rate_ = best_rate; +} diff --git a/vp8/encoder/pickinter.h b/vp8/encoder/pickinter.h new file mode 100644 index 0000000..3d83782 --- /dev/null +++ b/vp8/encoder/pickinter.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_PICKINTER_H +#define __INC_PICKINTER_H +#include "vpx_config.h" +#include "vp8/common/onyxc_int.h" + +extern void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, + int recon_uvoffset, int *returnrate, + int *returndistortion, int *returnintra, + int mb_row, int mb_col); +extern void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); + +#endif diff --git a/vp8/encoder/picklpf.c b/vp8/encoder/picklpf.c new file mode 100644 index 0000000..21af45a --- /dev/null +++ b/vp8/encoder/picklpf.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/onyxc_int.h" +#include "onyx_int.h" +#include "quantize.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_scale/vpxscale.h" +#include "vp8/common/alloccommon.h" +#include "vp8/common/loopfilter.h" +#if ARCH_ARM +#include "vpx_ports/arm.h" +#endif + +extern int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest); + +void vp8_yv12_copy_partial_frame_c(YV12_BUFFER_CONFIG *src_ybc, + YV12_BUFFER_CONFIG *dst_ybc) +{ + unsigned char *src_y, *dst_y; + int yheight; + int ystride; + int yoffset; + int linestocopy; + + yheight = src_ybc->y_height; + ystride = src_ybc->y_stride; + + /* number of MB rows to use in partial filtering */ + linestocopy = (yheight >> 4) / PARTIAL_FRAME_FRACTION; + linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */ + + /* Copy extra 4 so that full filter context is available if filtering done + * on the copied partial frame and not original. Partial filter does mb + * filtering for top row also, which can modify3 pixels above. + */ + linestocopy += 4; + /* partial image starts at ~middle of frame (macroblock border)*/ + yoffset = ystride * (((yheight >> 5) * 16) - 4); + src_y = src_ybc->y_buffer + yoffset; + dst_y = dst_ybc->y_buffer + yoffset; + + vpx_memcpy(dst_y, src_y, ystride * linestocopy); +} + +static int calc_partial_ssl_err(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest) +{ + int i, j; + int Total = 0; + int srcoffset, dstoffset; + unsigned char *src = source->y_buffer; + unsigned char *dst = dest->y_buffer; + + int linestocopy; + + /* number of MB rows to use in partial filtering */ + linestocopy = (source->y_height >> 4) / PARTIAL_FRAME_FRACTION; + linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */ + + + /* partial image starts at ~middle of frame (macroblock border)*/ + srcoffset = source->y_stride * ((dest->y_height >> 5) * 16); + dstoffset = dest->y_stride * ((dest->y_height >> 5) * 16); + + src += srcoffset; + dst += dstoffset; + + // Loop through the Y plane raw and reconstruction data summing (square differences) + for (i = 0; i < linestocopy; i += 16) + { + for (j = 0; j < source->y_width; j += 16) + { + unsigned int sse; + Total += vp8_mse16x16(src + j, source->y_stride, + dst + j, dest->y_stride, + &sse); + } + + src += 16 * source->y_stride; + dst += 16 * dest->y_stride; + } + + return Total; +} + +// Enforce a minimum filter level based upon baseline Q +static int get_min_filter_level(VP8_COMP *cpi, int base_qindex) +{ + int min_filter_level; + + if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame && + !cpi->common.refresh_alt_ref_frame) + min_filter_level = 0; + else + { + if (base_qindex <= 6) + min_filter_level = 0; + else if (base_qindex <= 16) + min_filter_level = 1; + else + min_filter_level = (base_qindex / 8); + } + + return min_filter_level; +} + +// Enforce a maximum filter level based upon baseline Q +static int get_max_filter_level(VP8_COMP *cpi, int base_qindex) +{ + // PGW August 2006: Highest filter values almost always a bad idea + + // jbb chg: 20100118 - not so any more with this overquant stuff allow high values + // with lots of intra coming in. + int max_filter_level = MAX_LOOP_FILTER ;//* 3 / 4; + (void)base_qindex; + + if (cpi->twopass.section_intra_rating > 8) + max_filter_level = MAX_LOOP_FILTER * 3 / 4; + + return max_filter_level; +} + +void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int best_err = 0; + int filt_err = 0; + int min_filter_level = get_min_filter_level(cpi, cm->base_qindex); + int max_filter_level = get_max_filter_level(cpi, cm->base_qindex); + int filt_val; + int best_filt_val = cm->filter_level; + YV12_BUFFER_CONFIG * saved_frame = cm->frame_to_show; + + /* Replace unfiltered frame buffer with a new one */ + cm->frame_to_show = &cpi->pick_lf_lvl_frame; + + if (cm->frame_type == KEY_FRAME) + cm->sharpness_level = 0; + else + cm->sharpness_level = cpi->oxcf.Sharpness; + + if (cm->sharpness_level != cm->last_sharpness_level) + { + vp8_loop_filter_update_sharpness(&cm->lf_info, cm->sharpness_level); + cm->last_sharpness_level = cm->sharpness_level; + } + + // Start the search at the previous frame filter level unless it is now out of range. + if (cm->filter_level < min_filter_level) + cm->filter_level = min_filter_level; + else if (cm->filter_level > max_filter_level) + cm->filter_level = max_filter_level; + + filt_val = cm->filter_level; + best_filt_val = filt_val; + + // Get the err using the previous frame's filter value. + + /* Copy the unfiltered / processed recon buffer to the new buffer */ + vp8_yv12_copy_partial_frame(saved_frame, cm->frame_to_show); + vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val); + + best_err = calc_partial_ssl_err(sd, cm->frame_to_show); + + filt_val -= 1 + (filt_val > 10); + + // Search lower filter levels + while (filt_val >= min_filter_level) + { + // Apply the loop filter + vp8_yv12_copy_partial_frame(saved_frame, cm->frame_to_show); + vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val); + + // Get the err for filtered frame + filt_err = calc_partial_ssl_err(sd, cm->frame_to_show); + + // Update the best case record or exit loop. + if (filt_err < best_err) + { + best_err = filt_err; + best_filt_val = filt_val; + } + else + break; + + // Adjust filter level + filt_val -= 1 + (filt_val > 10); + } + + // Search up (note that we have already done filt_val = cm->filter_level) + filt_val = cm->filter_level + 1 + (filt_val > 10); + + if (best_filt_val == cm->filter_level) + { + // Resist raising filter level for very small gains + best_err -= (best_err >> 10); + + while (filt_val < max_filter_level) + { + // Apply the loop filter + vp8_yv12_copy_partial_frame(saved_frame, cm->frame_to_show); + + vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val); + + // Get the err for filtered frame + filt_err = calc_partial_ssl_err(sd, cm->frame_to_show); + + // Update the best case record or exit loop. + if (filt_err < best_err) + { + // Do not raise filter level if improvement is < 1 part in 4096 + best_err = filt_err - (filt_err >> 10); + + best_filt_val = filt_val; + } + else + break; + + // Adjust filter level + filt_val += 1 + (filt_val > 10); + } + } + + cm->filter_level = best_filt_val; + + if (cm->filter_level < min_filter_level) + cm->filter_level = min_filter_level; + + if (cm->filter_level > max_filter_level) + cm->filter_level = max_filter_level; + + /* restore unfiltered frame pointer */ + cm->frame_to_show = saved_frame; +} + +// Stub function for now Alt LF not used +void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val) +{ + MACROBLOCKD *mbd = &cpi->mb.e_mbd; + (void) filt_val; + + mbd->segment_feature_data[MB_LVL_ALT_LF][0] = cpi->segment_feature_data[MB_LVL_ALT_LF][0]; + mbd->segment_feature_data[MB_LVL_ALT_LF][1] = cpi->segment_feature_data[MB_LVL_ALT_LF][1]; + mbd->segment_feature_data[MB_LVL_ALT_LF][2] = cpi->segment_feature_data[MB_LVL_ALT_LF][2]; + mbd->segment_feature_data[MB_LVL_ALT_LF][3] = cpi->segment_feature_data[MB_LVL_ALT_LF][3]; +} + +void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int best_err = 0; + int filt_err = 0; + int min_filter_level = get_min_filter_level(cpi, cm->base_qindex); + int max_filter_level = get_max_filter_level(cpi, cm->base_qindex); + + int filter_step; + int filt_high = 0; + int filt_mid = cm->filter_level; // Start search at previous frame filter level + int filt_low = 0; + int filt_best; + int filt_direction = 0; + + int Bias = 0; // Bias against raising loop filter and in favor of lowering it + + int ss_err[MAX_LOOP_FILTER + 1]; + + YV12_BUFFER_CONFIG * saved_frame = cm->frame_to_show; + + vpx_memset(ss_err, 0, sizeof(ss_err)); + + /* Replace unfiltered frame buffer with a new one */ + cm->frame_to_show = &cpi->pick_lf_lvl_frame; + + if (cm->frame_type == KEY_FRAME) + cm->sharpness_level = 0; + else + cm->sharpness_level = cpi->oxcf.Sharpness; + + // Start the search at the previous frame filter level unless it is now out of range. + filt_mid = cm->filter_level; + + if (filt_mid < min_filter_level) + filt_mid = min_filter_level; + else if (filt_mid > max_filter_level) + filt_mid = max_filter_level; + + // Define the initial step size + filter_step = (filt_mid < 16) ? 4 : filt_mid / 4; + + // Get baseline error score + + /* Copy the unfiltered / processed recon buffer to the new buffer */ + vp8_yv12_copy_y(saved_frame, cm->frame_to_show); + + vp8cx_set_alt_lf_level(cpi, filt_mid); + vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_mid); + + best_err = vp8_calc_ss_err(sd, cm->frame_to_show); + + ss_err[filt_mid] = best_err; + + filt_best = filt_mid; + + while (filter_step > 0) + { + Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; //PGW change 12/12/06 for small images + + // jbb chg: 20100118 - in sections with lots of new material coming in don't bias as much to a low filter value + if (cpi->twopass.section_intra_rating < 20) + Bias = Bias * cpi->twopass.section_intra_rating / 20; + + filt_high = ((filt_mid + filter_step) > max_filter_level) ? max_filter_level : (filt_mid + filter_step); + filt_low = ((filt_mid - filter_step) < min_filter_level) ? min_filter_level : (filt_mid - filter_step); + + if ((filt_direction <= 0) && (filt_low != filt_mid)) + { + if(ss_err[filt_low] == 0) + { + // Get Low filter error score + vp8_yv12_copy_y(saved_frame, cm->frame_to_show); + vp8cx_set_alt_lf_level(cpi, filt_low); + vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_low); + + filt_err = vp8_calc_ss_err(sd, cm->frame_to_show); + ss_err[filt_low] = filt_err; + } + else + filt_err = ss_err[filt_low]; + + // If value is close to the best so far then bias towards a lower loop filter value. + if ((filt_err - Bias) < best_err) + { + // Was it actually better than the previous best? + if (filt_err < best_err) + best_err = filt_err; + + filt_best = filt_low; + } + } + + // Now look at filt_high + if ((filt_direction >= 0) && (filt_high != filt_mid)) + { + if(ss_err[filt_high] == 0) + { + vp8_yv12_copy_y(saved_frame, cm->frame_to_show); + vp8cx_set_alt_lf_level(cpi, filt_high); + vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_high); + + filt_err = vp8_calc_ss_err(sd, cm->frame_to_show); + ss_err[filt_high] = filt_err; + } + else + filt_err = ss_err[filt_high]; + + // Was it better than the previous best? + if (filt_err < (best_err - Bias)) + { + best_err = filt_err; + filt_best = filt_high; + } + } + + // Half the step distance if the best filter value was the same as last time + if (filt_best == filt_mid) + { + filter_step = filter_step / 2; + filt_direction = 0; + } + else + { + filt_direction = (filt_best < filt_mid) ? -1 : 1; + filt_mid = filt_best; + } + } + + cm->filter_level = filt_best; + + /* restore unfiltered frame pointer */ + cm->frame_to_show = saved_frame; +} diff --git a/vp8/encoder/ppc/csystemdependent.c b/vp8/encoder/ppc/csystemdependent.c new file mode 100644 index 0000000..63f2357 --- /dev/null +++ b/vp8/encoder/ppc/csystemdependent.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/encoder/variance.h" +#include "vp8/encoder/onyx_int.h" + +SADFunction *vp8_sad16x16; +SADFunction *vp8_sad16x8; +SADFunction *vp8_sad8x16; +SADFunction *vp8_sad8x8; +SADFunction *vp8_sad4x4; + +variance_function *vp8_variance4x4; +variance_function *vp8_variance8x8; +variance_function *vp8_variance8x16; +variance_function *vp8_variance16x8; +variance_function *vp8_variance16x16; + +variance_function *vp8_mse16x16; + +sub_pixel_variance_function *vp8_sub_pixel_variance4x4; +sub_pixel_variance_function *vp8_sub_pixel_variance8x8; +sub_pixel_variance_function *vp8_sub_pixel_variance8x16; +sub_pixel_variance_function *vp8_sub_pixel_variance16x8; +sub_pixel_variance_function *vp8_sub_pixel_variance16x16; + +int (*vp8_block_error)(short *coeff, short *dqcoeff); +int (*vp8_mbblock_error)(MACROBLOCK *mb, int dc); + +int (*vp8_mbuverror)(MACROBLOCK *mb); +unsigned int (*vp8_get_mb_ss)(short *); +void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); +void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); +void (*vp8_fast_fdct4x4)(short *input, short *output, int pitch); +void (*vp8_fast_fdct8x4)(short *input, short *output, int pitch); +void (*short_walsh4x4)(short *input, short *output, int pitch); + +void (*vp8_subtract_b)(BLOCK *be, BLOCKD *bd, int pitch); +void (*vp8_subtract_mby)(short *diff, unsigned char *src, unsigned char *pred, int stride); +void (*vp8_subtract_mbuv)(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +void (*vp8_fast_quantize_b)(BLOCK *b, BLOCKD *d); + +unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + +// c imports +extern int block_error_c(short *coeff, short *dqcoeff); +extern int vp8_mbblock_error_c(MACROBLOCK *mb, int dc); + +extern int vp8_mbuverror_c(MACROBLOCK *mb); +extern unsigned int vp8_get8x8var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern void short_fdct4x4_c(short *input, short *output, int pitch); +extern void short_fdct8x4_c(short *input, short *output, int pitch); +extern void vp8_short_walsh4x4_c(short *input, short *output, int pitch); + +extern void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch); +extern void subtract_mby_c(short *diff, unsigned char *src, unsigned char *pred, int stride); +extern void subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +extern void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d); + +extern SADFunction sad16x16_c; +extern SADFunction sad16x8_c; +extern SADFunction sad8x16_c; +extern SADFunction sad8x8_c; +extern SADFunction sad4x4_c; + +extern variance_function variance16x16_c; +extern variance_function variance8x16_c; +extern variance_function variance16x8_c; +extern variance_function variance8x8_c; +extern variance_function variance4x4_c; +extern variance_function mse16x16_c; + +extern sub_pixel_variance_function sub_pixel_variance4x4_c; +extern sub_pixel_variance_function sub_pixel_variance8x8_c; +extern sub_pixel_variance_function sub_pixel_variance8x16_c; +extern sub_pixel_variance_function sub_pixel_variance16x8_c; +extern sub_pixel_variance_function sub_pixel_variance16x16_c; + +extern unsigned int vp8_get_mb_ss_c(short *); +extern unsigned int vp8_get4x4sse_cs_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + +// ppc +extern int vp8_block_error_ppc(short *coeff, short *dqcoeff); + +extern void vp8_short_fdct4x4_ppc(short *input, short *output, int pitch); +extern void vp8_short_fdct8x4_ppc(short *input, short *output, int pitch); + +extern void vp8_subtract_mby_ppc(short *diff, unsigned char *src, unsigned char *pred, int stride); +extern void vp8_subtract_mbuv_ppc(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); + +extern SADFunction vp8_sad16x16_ppc; +extern SADFunction vp8_sad16x8_ppc; +extern SADFunction vp8_sad8x16_ppc; +extern SADFunction vp8_sad8x8_ppc; +extern SADFunction vp8_sad4x4_ppc; + +extern variance_function vp8_variance16x16_ppc; +extern variance_function vp8_variance8x16_ppc; +extern variance_function vp8_variance16x8_ppc; +extern variance_function vp8_variance8x8_ppc; +extern variance_function vp8_variance4x4_ppc; +extern variance_function vp8_mse16x16_ppc; + +extern sub_pixel_variance_function vp8_sub_pixel_variance4x4_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x8_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x16_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x8_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x16_ppc; + +extern unsigned int vp8_get8x8var_ppc(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get16x16var_ppc(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); + +void vp8_cmachine_specific_config(void) +{ + // Pure C: + vp8_mbuverror = vp8_mbuverror_c; + vp8_fast_quantize_b = vp8_fast_quantize_b_c; + vp8_short_fdct4x4 = vp8_short_fdct4x4_ppc; + vp8_short_fdct8x4 = vp8_short_fdct8x4_ppc; + vp8_fast_fdct4x4 = vp8_short_fdct4x4_ppc; + vp8_fast_fdct8x4 = vp8_short_fdct8x4_ppc; + short_walsh4x4 = vp8_short_walsh4x4_c; + + vp8_variance4x4 = vp8_variance4x4_ppc; + vp8_variance8x8 = vp8_variance8x8_ppc; + vp8_variance8x16 = vp8_variance8x16_ppc; + vp8_variance16x8 = vp8_variance16x8_ppc; + vp8_variance16x16 = vp8_variance16x16_ppc; + vp8_mse16x16 = vp8_mse16x16_ppc; + + vp8_sub_pixel_variance4x4 = vp8_sub_pixel_variance4x4_ppc; + vp8_sub_pixel_variance8x8 = vp8_sub_pixel_variance8x8_ppc; + vp8_sub_pixel_variance8x16 = vp8_sub_pixel_variance8x16_ppc; + vp8_sub_pixel_variance16x8 = vp8_sub_pixel_variance16x8_ppc; + vp8_sub_pixel_variance16x16 = vp8_sub_pixel_variance16x16_ppc; + + vp8_get_mb_ss = vp8_get_mb_ss_c; + vp8_get4x4sse_cs = vp8_get4x4sse_cs_c; + + vp8_sad16x16 = vp8_sad16x16_ppc; + vp8_sad16x8 = vp8_sad16x8_ppc; + vp8_sad8x16 = vp8_sad8x16_ppc; + vp8_sad8x8 = vp8_sad8x8_ppc; + vp8_sad4x4 = vp8_sad4x4_ppc; + + vp8_block_error = vp8_block_error_ppc; + vp8_mbblock_error = vp8_mbblock_error_c; + + vp8_subtract_b = vp8_subtract_b_c; + vp8_subtract_mby = vp8_subtract_mby_ppc; + vp8_subtract_mbuv = vp8_subtract_mbuv_ppc; +} diff --git a/vp8/encoder/ppc/encodemb_altivec.asm b/vp8/encoder/ppc/encodemb_altivec.asm new file mode 100644 index 0000000..6e0099d --- /dev/null +++ b/vp8/encoder/ppc/encodemb_altivec.asm @@ -0,0 +1,153 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl vp8_subtract_mbuv_ppc + .globl vp8_subtract_mby_ppc + +;# r3 short *diff +;# r4 unsigned char *usrc +;# r5 unsigned char *vsrc +;# r6 unsigned char *pred +;# r7 int stride +vp8_subtract_mbuv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf000 + mtspr 256, r12 ;# set VRSAVE + + li r9, 256 + add r3, r3, r9 + add r3, r3, r9 + add r6, r6, r9 + + li r10, 16 + li r9, 4 + mtctr r9 + + vspltisw v0, 0 + +mbu_loop: + lvsl v5, 0, r4 ;# permutate value for alignment + lvx v1, 0, r4 ;# src + lvx v2, 0, r6 ;# pred + + add r4, r4, r7 + addi r6, r6, 16 + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrghb v4, v0, v2 ;# unpack high pred to short + + lvsl v5, 0, r4 ;# permutate value for alignment + lvx v1, 0, r4 ;# src + + add r4, r4, r7 + + vsubshs v3, v3, v4 + + stvx v3, 0, r3 ;# store out diff + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrglb v4, v0, v2 ;# unpack high pred to short + + vsubshs v3, v3, v4 + + stvx v3, r10, r3 ;# store out diff + + addi r3, r3, 32 + + bdnz mbu_loop + + mtctr r9 + +mbv_loop: + lvsl v5, 0, r5 ;# permutate value for alignment + lvx v1, 0, r5 ;# src + lvx v2, 0, r6 ;# pred + + add r5, r5, r7 + addi r6, r6, 16 + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrghb v4, v0, v2 ;# unpack high pred to short + + lvsl v5, 0, r5 ;# permutate value for alignment + lvx v1, 0, r5 ;# src + + add r5, r5, r7 + + vsubshs v3, v3, v4 + + stvx v3, 0, r3 ;# store out diff + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrglb v4, v0, v2 ;# unpack high pred to short + + vsubshs v3, v3, v4 + + stvx v3, r10, r3 ;# store out diff + + addi r3, r3, 32 + + bdnz mbv_loop + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# r3 short *diff +;# r4 unsigned char *src +;# r5 unsigned char *pred +;# r6 int stride +vp8_subtract_mby_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf800 + mtspr 256, r12 ;# set VRSAVE + + li r10, 16 + mtctr r10 + + vspltisw v0, 0 + +mby_loop: + lvx v1, 0, r4 ;# src + lvx v2, 0, r5 ;# pred + + add r4, r4, r6 + addi r5, r5, 16 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrghb v4, v0, v2 ;# unpack high pred to short + + vsubshs v3, v3, v4 + + stvx v3, 0, r3 ;# store out diff + + vmrglb v3, v0, v1 ;# unpack low src to short + vmrglb v4, v0, v2 ;# unpack low pred to short + + vsubshs v3, v3, v4 + + stvx v3, r10, r3 ;# store out diff + + addi r3, r3, 32 + + bdnz mby_loop + + mtspr 256, r11 ;# reset old VRSAVE + + blr diff --git a/vp8/encoder/ppc/fdct_altivec.asm b/vp8/encoder/ppc/fdct_altivec.asm new file mode 100644 index 0000000..935d0cb --- /dev/null +++ b/vp8/encoder/ppc/fdct_altivec.asm @@ -0,0 +1,205 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl vp8_short_fdct4x4_ppc + .globl vp8_short_fdct8x4_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +;# Forward and inverse DCTs are nearly identical; only differences are +;# in normalization (fwd is twice unitary, inv is half unitary) +;# and that they are of course transposes of each other. +;# +;# The following three accomplish most of implementation and +;# are used only by ppc_idct.c and ppc_fdct.c. +.macro prologue + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfffc + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + li r6, 16 + + load_c v0, dct_tab, 0, r9, r10 + lvx v1, r6, r10 + addi r10, r10, 32 + lvx v2, 0, r10 + lvx v3, r6, r10 + + load_c v4, ppc_dctperm_tab, 0, r9, r10 + load_c v5, ppc_dctperm_tab, r6, r9, r10 + + load_c v6, round_tab, 0, r10, r9 +.endm + +.macro epilogue + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE +.endm + +;# Do horiz xf on two rows of coeffs v8 = a0 a1 a2 a3 b0 b1 b2 b3. +;# a/A are the even rows 0,2 b/B are the odd rows 1,3 +;# For fwd transform, indices are horizontal positions, then frequencies. +;# For inverse transform, frequencies then positions. +;# The two resulting A0..A3 B0..B3 are later combined +;# and vertically transformed. + +.macro two_rows_horiz Dst + vperm v9, v8, v8, v4 ;# v9 = a2 a3 a0 a1 b2 b3 b0 b1 + + vmsumshm v10, v0, v8, v6 + vmsumshm v10, v1, v9, v10 + vsraw v10, v10, v7 ;# v10 = A0 A1 B0 B1 + + vmsumshm v11, v2, v8, v6 + vmsumshm v11, v3, v9, v11 + vsraw v11, v11, v7 ;# v11 = A2 A3 B2 B3 + + vpkuwum v10, v10, v11 ;# v10 = A0 A1 B0 B1 A2 A3 B2 B3 + vperm \Dst, v10, v10, v5 ;# Dest = A0 B0 A1 B1 A2 B2 A3 B3 +.endm + +;# Vertical xf on two rows. DCT values in comments are for inverse transform; +;# forward transform uses transpose. + +.macro two_rows_vert Ceven, Codd + vspltw v8, \Ceven, 0 ;# v8 = c00 c10 or c02 c12 four times + vspltw v9, \Codd, 0 ;# v9 = c20 c30 or c22 c32 "" + vmsumshm v8, v8, v12, v6 + vmsumshm v8, v9, v13, v8 + vsraw v10, v8, v7 + + vspltw v8, \Codd, 1 ;# v8 = c01 c11 or c03 c13 + vspltw v9, \Ceven, 1 ;# v9 = c21 c31 or c23 c33 + vmsumshm v8, v8, v12, v6 + vmsumshm v8, v9, v13, v8 + vsraw v8, v8, v7 + + vpkuwum v8, v10, v8 ;# v8 = rows 0,1 or 2,3 +.endm + +.macro two_rows_h Dest + stw r0, 0(r8) + lwz r0, 4(r3) + stw r0, 4(r8) + lwzux r0, r3,r5 + stw r0, 8(r8) + lwz r0, 4(r3) + stw r0, 12(r8) + lvx v8, 0,r8 + two_rows_horiz \Dest +.endm + + .align 2 +;# r3 short *input +;# r4 short *output +;# r5 int pitch +vp8_short_fdct4x4_ppc: + + prologue + + vspltisw v7, 14 ;# == 14, fits in 5 signed bits + addi r8, r1, 0 + + + lwz r0, 0(r3) + two_rows_h v12 ;# v12 = H00 H10 H01 H11 H02 H12 H03 H13 + + lwzux r0, r3, r5 + two_rows_h v13 ;# v13 = H20 H30 H21 H31 H22 H32 H23 H33 + + lvx v6, r6, r9 ;# v6 = Vround + vspltisw v7, -16 ;# == 16 == -16, only low 5 bits matter + + two_rows_vert v0, v1 + stvx v8, 0, r4 + two_rows_vert v2, v3 + stvx v8, r6, r4 + + epilogue + + blr + + .align 2 +;# r3 short *input +;# r4 short *output +;# r5 int pitch +vp8_short_fdct8x4_ppc: + prologue + + vspltisw v7, 14 ;# == 14, fits in 5 signed bits + addi r8, r1, 0 + addi r10, r3, 0 + + lwz r0, 0(r3) + two_rows_h v12 ;# v12 = H00 H10 H01 H11 H02 H12 H03 H13 + + lwzux r0, r3, r5 + two_rows_h v13 ;# v13 = H20 H30 H21 H31 H22 H32 H23 H33 + + lvx v6, r6, r9 ;# v6 = Vround + vspltisw v7, -16 ;# == 16 == -16, only low 5 bits matter + + two_rows_vert v0, v1 + stvx v8, 0, r4 + two_rows_vert v2, v3 + stvx v8, r6, r4 + + ;# Next block + addi r3, r10, 8 + addi r4, r4, 32 + lvx v6, 0, r9 ;# v6 = Hround + + vspltisw v7, 14 ;# == 14, fits in 5 signed bits + addi r8, r1, 0 + + lwz r0, 0(r3) + two_rows_h v12 ;# v12 = H00 H10 H01 H11 H02 H12 H03 H13 + + lwzux r0, r3, r5 + two_rows_h v13 ;# v13 = H20 H30 H21 H31 H22 H32 H23 H33 + + lvx v6, r6, r9 ;# v6 = Vround + vspltisw v7, -16 ;# == 16 == -16, only low 5 bits matter + + two_rows_vert v0, v1 + stvx v8, 0, r4 + two_rows_vert v2, v3 + stvx v8, r6, r4 + + epilogue + + blr + + .data + .align 4 +ppc_dctperm_tab: + .byte 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 + .byte 0,1,4,5, 2,3,6,7, 8,9,12,13, 10,11,14,15 + + .align 4 +dct_tab: + .short 23170, 23170,-12540,-30274, 23170, 23170,-12540,-30274 + .short 23170, 23170, 30274, 12540, 23170, 23170, 30274, 12540 + + .short 23170,-23170, 30274,-12540, 23170,-23170, 30274,-12540 + .short -23170, 23170, 12540,-30274,-23170, 23170, 12540,-30274 + + .align 4 +round_tab: + .long (1 << (14-1)), (1 << (14-1)), (1 << (14-1)), (1 << (14-1)) + .long (1 << (16-1)), (1 << (16-1)), (1 << (16-1)), (1 << (16-1)) diff --git a/vp8/encoder/ppc/rdopt_altivec.asm b/vp8/encoder/ppc/rdopt_altivec.asm new file mode 100644 index 0000000..ba48230 --- /dev/null +++ b/vp8/encoder/ppc/rdopt_altivec.asm @@ -0,0 +1,51 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + .globl vp8_block_error_ppc + + .align 2 +;# r3 short *Coeff +;# r4 short *dqcoeff +vp8_block_error_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf800 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + stw r5, 12(r1) ;# tranfer dc to vector register + + lvx v0, 0, r3 ;# Coeff + lvx v1, 0, r4 ;# dqcoeff + + li r10, 16 + + vspltisw v3, 0 + + vsubshs v0, v0, v1 + + vmsumshm v2, v0, v0, v3 ;# multiply differences + + lvx v0, r10, r3 ;# Coeff + lvx v1, r10, r4 ;# dqcoeff + + vsubshs v0, v0, v1 + + vmsumshm v1, v0, v0, v2 ;# multiply differences + vsumsws v1, v1, v3 ;# sum up + + stvx v1, 0, r1 + lwz r3, 12(r1) ;# return value + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr diff --git a/vp8/encoder/psnr.c b/vp8/encoder/psnr.c new file mode 100644 index 0000000..5119bb8 --- /dev/null +++ b/vp8/encoder/psnr.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +#include "math.h" +#include "vp8/common/systemdependent.h" /* for vp8_clear_system_state() */ + +#define MAX_PSNR 60 + +double vp8_mse2psnr(double Samples, double Peak, double Mse) +{ + double psnr; + + if ((double)Mse > 0.0) + psnr = 10.0 * log10(Peak * Peak * Samples / Mse); + else + psnr = MAX_PSNR; // Limit to prevent / 0 + + if (psnr > MAX_PSNR) + psnr = MAX_PSNR; + + return psnr; +} diff --git a/vp8/encoder/psnr.h b/vp8/encoder/psnr.h new file mode 100644 index 0000000..7f6269a --- /dev/null +++ b/vp8/encoder/psnr.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_PSNR_H +#define __INC_PSNR_H + +extern double vp8_mse2psnr(double Samples, double Peak, double Mse); + +#endif diff --git a/vp8/encoder/quantize.c b/vp8/encoder/quantize.c new file mode 100644 index 0000000..766d2b2 --- /dev/null +++ b/vp8/encoder/quantize.c @@ -0,0 +1,814 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include "vpx_mem/vpx_mem.h" + +#include "onyx_int.h" +#include "quantize.h" +#include "vp8/common/quant_common.h" + +#define EXACT_QUANT + +#ifdef EXACT_FASTQUANT +void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant_fast; + unsigned char *quant_shift_ptr = b->quant_shift; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < 16; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + zbin = zbin_ptr[rc] ; + + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + x += round_ptr[rc]; + y = (((x * quant_ptr[rc]) >> 16) + x) + >> quant_shift_ptr[rc]; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + } + } + } + *d->eob = (char)(eob + 1); +} + +#else + +void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int x, y, z, sz; + short *coeff_ptr = b->coeff; + short *round_ptr = b->round; + short *quant_ptr = b->quant_fast; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + + eob = -1; + for (i = 0; i < 16; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + y = ((x + round_ptr[rc]) * quant_ptr[rc]) >> 16; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + } + } + *d->eob = (char)(eob + 1); +} + +#endif + +#ifdef EXACT_QUANT +void vp8_regular_quantize_b_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *zbin_boost_ptr = b->zrun_zbin_boost; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant; + unsigned char *quant_shift_ptr = b->quant_shift; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + short zbin_oq_value = b->zbin_extra; + + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < 16; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + + zbin = zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value; + + zbin_boost_ptr ++; + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + x += round_ptr[rc]; + y = (((x * quant_ptr[rc]) >> 16) + x) + >> quant_shift_ptr[rc]; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + zbin_boost_ptr = b->zrun_zbin_boost; // reset zero runlength + } + } + } + + *d->eob = (char)(eob + 1); +} + +/* Perform regular quantization, with unbiased rounding and no zero bin. */ +void vp8_strict_quantize_b_c(BLOCK *b, BLOCKD *d) +{ + int i; + int rc; + int eob; + int x; + int y; + int z; + int sz; + short *coeff_ptr; + short *quant_ptr; + unsigned char *quant_shift_ptr; + short *qcoeff_ptr; + short *dqcoeff_ptr; + short *dequant_ptr; + + coeff_ptr = b->coeff; + quant_ptr = b->quant; + quant_shift_ptr = b->quant_shift; + qcoeff_ptr = d->qcoeff; + dqcoeff_ptr = d->dqcoeff; + dequant_ptr = d->dequant; + eob = - 1; + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + for (i = 0; i < 16; i++) + { + int dq; + int round; + + /*TODO: These arrays should be stored in zig-zag order.*/ + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + dq = dequant_ptr[rc]; + round = dq >> 1; + /* Sign of z. */ + sz = -(z < 0); + x = (z + sz) ^ sz; + x += round; + if (x >= dq) + { + /* Quantize x. */ + y = (((x * quant_ptr[rc]) >> 16) + x) >> quant_shift_ptr[rc]; + /* Put the sign back. */ + x = (y + sz) ^ sz; + /* Save the coefficient and its dequantized value. */ + qcoeff_ptr[rc] = x; + dqcoeff_ptr[rc] = x * dq; + /* Remember the last non-zero coefficient. */ + if (y) + eob = i; + } + } + + *d->eob = (char)(eob + 1); +} + +#else + +void vp8_regular_quantize_b_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *zbin_boost_ptr = b->zrun_zbin_boost; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + short zbin_oq_value = b->zbin_extra; + + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < 16; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + + //if ( i == 0 ) + // zbin = zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value/2; + //else + zbin = zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value; + + zbin_boost_ptr ++; + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + y = ((x + round_ptr[rc]) * quant_ptr[rc]) >> 16; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + zbin_boost_ptr = &b->zrun_zbin_boost[0]; // reset zero runlength + } + } + } + + *d->eob = (char)(eob + 1); +} + +#endif + +void vp8_quantize_mby_c(MACROBLOCK *x) +{ + int i; + int has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + + for (i = 0; i < 16; i++) + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + + if(has_2nd_order) + x->quantize_b(&x->block[24], &x->e_mbd.block[24]); +} + +void vp8_quantize_mb_c(MACROBLOCK *x) +{ + int i; + int has_2nd_order=(x->e_mbd.mode_info_context->mbmi.mode != B_PRED + && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV); + + for (i = 0; i < 24+has_2nd_order; i++) + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); +} + + +void vp8_quantize_mbuv_c(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i++) + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); +} + +/* quantize_b_pair function pointer in MACROBLOCK structure is set to one of + * these two C functions if corresponding optimized routine is not available. + * NEON optimized version implements currently the fast quantization for pair + * of blocks. */ +void vp8_regular_quantize_b_pair(BLOCK *b1, BLOCK *b2, BLOCKD *d1, BLOCKD *d2) +{ + vp8_regular_quantize_b(b1, d1); + vp8_regular_quantize_b(b2, d2); +} + +void vp8_fast_quantize_b_pair_c(BLOCK *b1, BLOCK *b2, BLOCKD *d1, BLOCKD *d2) +{ + vp8_fast_quantize_b_c(b1, d1); + vp8_fast_quantize_b_c(b2, d2); +} + + +static const int qrounding_factors[129] = +{ + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48 +}; + + +static const int qzbin_factors[129] = +{ + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80 +}; + + +static const int qrounding_factors_y2[129] = +{ + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48 +}; + + +static const int qzbin_factors_y2[129] = +{ + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80 +}; + + +#define EXACT_QUANT +#ifdef EXACT_QUANT +static void invert_quant(int improved_quant, short *quant, + unsigned char *shift, short d) +{ + if(improved_quant) + { + unsigned t; + int l; + t = d; + for(l = 0; t > 1; l++) + t>>=1; + t = 1 + (1<<(16+l))/d; + *quant = (short)(t - (1<<16)); + *shift = l; + } + else + { + *quant = (1 << 16) / d; + *shift = 0; + } +} + + +void vp8cx_init_quantizer(VP8_COMP *cpi) +{ + int i; + int quant_val; + int Q; + + int zbin_boost[16] = {0, 0, 8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, + 44, 44}; + + for (Q = 0; Q < QINDEX_RANGE; Q++) + { + // dc values + quant_val = vp8_dc_quant(Q, cpi->common.y1dc_delta_q); + cpi->Y1quant_fast[Q][0] = (1 << 16) / quant_val; + invert_quant(cpi->sf.improved_quant, cpi->Y1quant[Q] + 0, + cpi->Y1quant_shift[Q] + 0, quant_val); + cpi->Y1zbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y1round[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y1dequant[Q][0] = quant_val; + cpi->zrun_zbin_boost_y1[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + quant_val = vp8_dc2quant(Q, cpi->common.y2dc_delta_q); + cpi->Y2quant_fast[Q][0] = (1 << 16) / quant_val; + invert_quant(cpi->sf.improved_quant, cpi->Y2quant[Q] + 0, + cpi->Y2quant_shift[Q] + 0, quant_val); + cpi->Y2zbin[Q][0] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; + cpi->Y2round[Q][0] = (qrounding_factors_y2[Q] * quant_val) >> 7; + cpi->common.Y2dequant[Q][0] = quant_val; + cpi->zrun_zbin_boost_y2[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + quant_val = vp8_dc_uv_quant(Q, cpi->common.uvdc_delta_q); + cpi->UVquant_fast[Q][0] = (1 << 16) / quant_val; + invert_quant(cpi->sf.improved_quant, cpi->UVquant[Q] + 0, + cpi->UVquant_shift[Q] + 0, quant_val); + cpi->UVzbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7;; + cpi->UVround[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.UVdequant[Q][0] = quant_val; + cpi->zrun_zbin_boost_uv[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + // all the ac values = ; + quant_val = vp8_ac_yquant(Q); + cpi->Y1quant_fast[Q][1] = (1 << 16) / quant_val; + invert_quant(cpi->sf.improved_quant, cpi->Y1quant[Q] + 1, + cpi->Y1quant_shift[Q] + 1, quant_val); + cpi->Y1zbin[Q][1] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y1round[Q][1] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y1dequant[Q][1] = quant_val; + cpi->zrun_zbin_boost_y1[Q][1] = (quant_val * zbin_boost[1]) >> 7; + + quant_val = vp8_ac2quant(Q, cpi->common.y2ac_delta_q); + cpi->Y2quant_fast[Q][1] = (1 << 16) / quant_val; + invert_quant(cpi->sf.improved_quant, cpi->Y2quant[Q] + 1, + cpi->Y2quant_shift[Q] + 1, quant_val); + cpi->Y2zbin[Q][1] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; + cpi->Y2round[Q][1] = (qrounding_factors_y2[Q] * quant_val) >> 7; + cpi->common.Y2dequant[Q][1] = quant_val; + cpi->zrun_zbin_boost_y2[Q][1] = (quant_val * zbin_boost[1]) >> 7; + + quant_val = vp8_ac_uv_quant(Q, cpi->common.uvac_delta_q); + cpi->UVquant_fast[Q][1] = (1 << 16) / quant_val; + invert_quant(cpi->sf.improved_quant, cpi->UVquant[Q] + 1, + cpi->UVquant_shift[Q] + 1, quant_val); + cpi->UVzbin[Q][1] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->UVround[Q][1] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.UVdequant[Q][1] = quant_val; + cpi->zrun_zbin_boost_uv[Q][1] = (quant_val * zbin_boost[1]) >> 7; + + for (i = 2; i < 16; i++) + { + cpi->Y1quant_fast[Q][i] = cpi->Y1quant_fast[Q][1]; + cpi->Y1quant[Q][i] = cpi->Y1quant[Q][1]; + cpi->Y1quant_shift[Q][i] = cpi->Y1quant_shift[Q][1]; + cpi->Y1zbin[Q][i] = cpi->Y1zbin[Q][1]; + cpi->Y1round[Q][i] = cpi->Y1round[Q][1]; + cpi->zrun_zbin_boost_y1[Q][i] = (cpi->common.Y1dequant[Q][1] * + zbin_boost[i]) >> 7; + + cpi->Y2quant_fast[Q][i] = cpi->Y2quant_fast[Q][1]; + cpi->Y2quant[Q][i] = cpi->Y2quant[Q][1]; + cpi->Y2quant_shift[Q][i] = cpi->Y2quant_shift[Q][1]; + cpi->Y2zbin[Q][i] = cpi->Y2zbin[Q][1]; + cpi->Y2round[Q][i] = cpi->Y2round[Q][1]; + cpi->zrun_zbin_boost_y2[Q][i] = (cpi->common.Y2dequant[Q][1] * + zbin_boost[i]) >> 7; + + cpi->UVquant_fast[Q][i] = cpi->UVquant_fast[Q][1]; + cpi->UVquant[Q][i] = cpi->UVquant[Q][1]; + cpi->UVquant_shift[Q][i] = cpi->UVquant_shift[Q][1]; + cpi->UVzbin[Q][i] = cpi->UVzbin[Q][1]; + cpi->UVround[Q][i] = cpi->UVround[Q][1]; + cpi->zrun_zbin_boost_uv[Q][i] = (cpi->common.UVdequant[Q][1] * + zbin_boost[i]) >> 7; + } + } +} +#else +void vp8cx_init_quantizer(VP8_COMP *cpi) +{ + int i; + int quant_val; + int Q; + + int zbin_boost[16] = {0, 0, 8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 44, 44}; + + for (Q = 0; Q < QINDEX_RANGE; Q++) + { + // dc values + quant_val = vp8_dc_quant(Q, cpi->common.y1dc_delta_q); + cpi->Y1quant[Q][0] = (1 << 16) / quant_val; + cpi->Y1zbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y1round[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y1dequant[Q][0] = quant_val; + cpi->zrun_zbin_boost_y1[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + quant_val = vp8_dc2quant(Q, cpi->common.y2dc_delta_q); + cpi->Y2quant[Q][0] = (1 << 16) / quant_val; + cpi->Y2zbin[Q][0] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; + cpi->Y2round[Q][0] = (qrounding_factors_y2[Q] * quant_val) >> 7; + cpi->common.Y2dequant[Q][0] = quant_val; + cpi->zrun_zbin_boost_y2[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + quant_val = vp8_dc_uv_quant(Q, cpi->common.uvdc_delta_q); + cpi->UVquant[Q][0] = (1 << 16) / quant_val; + cpi->UVzbin[Q][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7;; + cpi->UVround[Q][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.UVdequant[Q][0] = quant_val; + cpi->zrun_zbin_boost_uv[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + // all the ac values = ; + for (i = 1; i < 16; i++) + { + int rc = vp8_default_zig_zag1d[i]; + + quant_val = vp8_ac_yquant(Q); + cpi->Y1quant[Q][rc] = (1 << 16) / quant_val; + cpi->Y1zbin[Q][rc] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y1round[Q][rc] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y1dequant[Q][rc] = quant_val; + cpi->zrun_zbin_boost_y1[Q][i] = (quant_val * zbin_boost[i]) >> 7; + + quant_val = vp8_ac2quant(Q, cpi->common.y2ac_delta_q); + cpi->Y2quant[Q][rc] = (1 << 16) / quant_val; + cpi->Y2zbin[Q][rc] = ((qzbin_factors_y2[Q] * quant_val) + 64) >> 7; + cpi->Y2round[Q][rc] = (qrounding_factors_y2[Q] * quant_val) >> 7; + cpi->common.Y2dequant[Q][rc] = quant_val; + cpi->zrun_zbin_boost_y2[Q][i] = (quant_val * zbin_boost[i]) >> 7; + + quant_val = vp8_ac_uv_quant(Q, cpi->common.uvac_delta_q); + cpi->UVquant[Q][rc] = (1 << 16) / quant_val; + cpi->UVzbin[Q][rc] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->UVround[Q][rc] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.UVdequant[Q][rc] = quant_val; + cpi->zrun_zbin_boost_uv[Q][i] = (quant_val * zbin_boost[i]) >> 7; + } + } +} +#endif + +#define ZBIN_EXTRA_Y \ + (( cpi->common.Y1dequant[QIndex][1] * \ + ( cpi->zbin_over_quant + \ + cpi->zbin_mode_boost + \ + x->act_zbin_adj ) ) >> 7) + +#define ZBIN_EXTRA_UV \ + (( cpi->common.UVdequant[QIndex][1] * \ + ( cpi->zbin_over_quant + \ + cpi->zbin_mode_boost + \ + x->act_zbin_adj ) ) >> 7) + +#define ZBIN_EXTRA_Y2 \ + (( cpi->common.Y2dequant[QIndex][1] * \ + ( (cpi->zbin_over_quant / 2) + \ + cpi->zbin_mode_boost + \ + x->act_zbin_adj ) ) >> 7) + +void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x, int ok_to_skip) +{ + int i; + int QIndex; + MACROBLOCKD *xd = &x->e_mbd; + int zbin_extra; + + // Select the baseline MB Q index. + if (xd->segmentation_enabled) + { + // Abs Value + if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA) + + QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][xd->mode_info_context->mbmi.segment_id]; + // Delta Value + else + { + QIndex = cpi->common.base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][xd->mode_info_context->mbmi.segment_id]; + QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; // Clamp to valid range + } + } + else + QIndex = cpi->common.base_qindex; + + /* This initialization should be called at least once. Use ok_to_skip to + * decide if it is ok to skip. + * Before encoding a frame, this function is always called with ok_to_skip + * =0, which means no skiping of calculations. The "last" values are + * initialized at that time. + */ + if (!ok_to_skip || QIndex != x->q_index) + { + + xd->dequant_y1_dc[0] = 1; + xd->dequant_y1[0] = cpi->common.Y1dequant[QIndex][0]; + xd->dequant_y2[0] = cpi->common.Y2dequant[QIndex][0]; + xd->dequant_uv[0] = cpi->common.UVdequant[QIndex][0]; + + for (i = 1; i < 16; i++) + { + xd->dequant_y1_dc[i] = + xd->dequant_y1[i] = cpi->common.Y1dequant[QIndex][1]; + xd->dequant_y2[i] = cpi->common.Y2dequant[QIndex][1]; + xd->dequant_uv[i] = cpi->common.UVdequant[QIndex][1]; + } +#if 1 + /*TODO: Remove dequant from BLOCKD. This is a temporary solution until + * the quantizer code uses a passed in pointer to the dequant constants. + * This will also require modifications to the x86 and neon assembly. + * */ + for (i = 0; i < 16; i++) + x->e_mbd.block[i].dequant = xd->dequant_y1; //cpi->common.Y1dequant[QIndex]; + for (i = 16; i < 24; i++) + x->e_mbd.block[i].dequant = xd->dequant_uv; //cpi->common.UVdequant[QIndex]; + x->e_mbd.block[24].dequant = xd->dequant_y2; //cpi->common.Y2dequant[QIndex]; +#endif + + // Y + zbin_extra = ZBIN_EXTRA_Y; + + for (i = 0; i < 16; i++) + { + x->block[i].quant = cpi->Y1quant[QIndex]; + x->block[i].quant_fast = cpi->Y1quant_fast[QIndex]; + x->block[i].quant_shift = cpi->Y1quant_shift[QIndex]; + x->block[i].zbin = cpi->Y1zbin[QIndex]; + x->block[i].round = cpi->Y1round[QIndex]; + x->block[i].zrun_zbin_boost = cpi->zrun_zbin_boost_y1[QIndex]; + x->block[i].zbin_extra = (short)zbin_extra; + } + + // UV + zbin_extra = ZBIN_EXTRA_UV; + + for (i = 16; i < 24; i++) + { + x->block[i].quant = cpi->UVquant[QIndex]; + x->block[i].quant_fast = cpi->UVquant_fast[QIndex]; + x->block[i].quant_shift = cpi->UVquant_shift[QIndex]; + x->block[i].zbin = cpi->UVzbin[QIndex]; + x->block[i].round = cpi->UVround[QIndex]; + x->block[i].zrun_zbin_boost = cpi->zrun_zbin_boost_uv[QIndex]; + x->block[i].zbin_extra = (short)zbin_extra; + } + + // Y2 + zbin_extra = ZBIN_EXTRA_Y2; + + x->block[24].quant_fast = cpi->Y2quant_fast[QIndex]; + x->block[24].quant = cpi->Y2quant[QIndex]; + x->block[24].quant_shift = cpi->Y2quant_shift[QIndex]; + x->block[24].zbin = cpi->Y2zbin[QIndex]; + x->block[24].round = cpi->Y2round[QIndex]; + x->block[24].zrun_zbin_boost = cpi->zrun_zbin_boost_y2[QIndex]; + x->block[24].zbin_extra = (short)zbin_extra; + + /* save this macroblock QIndex for vp8_update_zbin_extra() */ + x->q_index = QIndex; + + cpi->last_zbin_over_quant = cpi->zbin_over_quant; + cpi->last_zbin_mode_boost = cpi->zbin_mode_boost; + x->last_act_zbin_adj = x->act_zbin_adj; + + + + } + else if(cpi->last_zbin_over_quant != cpi->zbin_over_quant + || cpi->last_zbin_mode_boost != cpi->zbin_mode_boost + || x->last_act_zbin_adj != x->act_zbin_adj) + { + // Y + zbin_extra = ZBIN_EXTRA_Y; + + for (i = 0; i < 16; i++) + x->block[i].zbin_extra = (short)zbin_extra; + + // UV + zbin_extra = ZBIN_EXTRA_UV; + + for (i = 16; i < 24; i++) + x->block[i].zbin_extra = (short)zbin_extra; + + // Y2 + zbin_extra = ZBIN_EXTRA_Y2; + x->block[24].zbin_extra = (short)zbin_extra; + + cpi->last_zbin_over_quant = cpi->zbin_over_quant; + cpi->last_zbin_mode_boost = cpi->zbin_mode_boost; + x->last_act_zbin_adj = x->act_zbin_adj; + } +} + +void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x) +{ + int i; + int QIndex = x->q_index; + int zbin_extra; + + // Y + zbin_extra = ZBIN_EXTRA_Y; + + for (i = 0; i < 16; i++) + x->block[i].zbin_extra = (short)zbin_extra; + + // UV + zbin_extra = ZBIN_EXTRA_UV; + + for (i = 16; i < 24; i++) + x->block[i].zbin_extra = (short)zbin_extra; + + // Y2 + zbin_extra = ZBIN_EXTRA_Y2; + x->block[24].zbin_extra = (short)zbin_extra; +} +#undef ZBIN_EXTRA_Y +#undef ZBIN_EXTRA_UV +#undef ZBIN_EXTRA_Y2 + +void vp8cx_frame_init_quantizer(VP8_COMP *cpi) +{ + // Clear Zbin mode boost for default case + cpi->zbin_mode_boost = 0; + + // MB level quantizer setup + vp8cx_mb_init_quantizer(cpi, &cpi->mb, 0); +} + + +void vp8_set_quantizer(struct VP8_COMP *cpi, int Q) +{ + VP8_COMMON *cm = &cpi->common; + MACROBLOCKD *mbd = &cpi->mb.e_mbd; + int update = 0; + int new_delta_q; + cm->base_qindex = Q; + + /* if any of the delta_q values are changing update flag has to be set */ + /* currently only y2dc_delta_q may change */ + + cm->y1dc_delta_q = 0; + cm->y2ac_delta_q = 0; + cm->uvdc_delta_q = 0; + cm->uvac_delta_q = 0; + + if (Q < 4) + { + new_delta_q = 4-Q; + } + else + new_delta_q = 0; + + update |= cm->y2dc_delta_q != new_delta_q; + cm->y2dc_delta_q = new_delta_q; + + + // Set Segment specific quatizers + mbd->segment_feature_data[MB_LVL_ALT_Q][0] = cpi->segment_feature_data[MB_LVL_ALT_Q][0]; + mbd->segment_feature_data[MB_LVL_ALT_Q][1] = cpi->segment_feature_data[MB_LVL_ALT_Q][1]; + mbd->segment_feature_data[MB_LVL_ALT_Q][2] = cpi->segment_feature_data[MB_LVL_ALT_Q][2]; + mbd->segment_feature_data[MB_LVL_ALT_Q][3] = cpi->segment_feature_data[MB_LVL_ALT_Q][3]; + + /* quantizer has to be reinitialized for any delta_q changes */ + if(update) + vp8cx_init_quantizer(cpi); + +} diff --git a/vp8/encoder/quantize.h b/vp8/encoder/quantize.h new file mode 100644 index 0000000..d55496c --- /dev/null +++ b/vp8/encoder/quantize.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_QUANTIZE_H +#define __INC_QUANTIZE_H + +struct VP8_COMP; +struct macroblock; +extern void vp8_set_quantizer(struct VP8_COMP *cpi, int Q); +extern void vp8cx_frame_init_quantizer(struct VP8_COMP *cpi); +extern void vp8_update_zbin_extra(struct VP8_COMP *cpi, struct macroblock *x); +extern void vp8cx_mb_init_quantizer(struct VP8_COMP *cpi, struct macroblock *x, int ok_to_skip); +extern void vp8cx_init_quantizer(struct VP8_COMP *cpi); + +#endif diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c new file mode 100644 index 0000000..472e85f --- /dev/null +++ b/vp8/encoder/ratectrl.c @@ -0,0 +1,1569 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include +#include +#include + +#include "math.h" +#include "vp8/common/common.h" +#include "ratectrl.h" +#include "vp8/common/entropymode.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/systemdependent.h" +#include "encodemv.h" + + +#define MIN_BPB_FACTOR 0.01 +#define MAX_BPB_FACTOR 50 + +extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; + + + +#ifdef MODE_STATS +extern int y_modes[5]; +extern int uv_modes[4]; +extern int b_modes[10]; + +extern int inter_y_modes[10]; +extern int inter_uv_modes[4]; +extern int inter_b_modes[10]; +#endif + +// Bits Per MB at different Q (Multiplied by 512) +#define BPER_MB_NORMBITS 9 + +// Work in progress recalibration of baseline rate tables based on +// the assumption that bits per mb is inversely proportional to the +// quantizer value. +const int vp8_bits_per_mb[2][QINDEX_RANGE] = +{ + // Intra case 450000/Qintra + { + 1125000,900000, 750000, 642857, 562500, 500000, 450000, 450000, + 409090, 375000, 346153, 321428, 300000, 281250, 264705, 264705, + 250000, 236842, 225000, 225000, 214285, 214285, 204545, 204545, + 195652, 195652, 187500, 180000, 180000, 173076, 166666, 160714, + 155172, 150000, 145161, 140625, 136363, 132352, 128571, 125000, + 121621, 121621, 118421, 115384, 112500, 109756, 107142, 104651, + 102272, 100000, 97826, 97826, 95744, 93750, 91836, 90000, + 88235, 86538, 84905, 83333, 81818, 80357, 78947, 77586, + 76271, 75000, 73770, 72580, 71428, 70312, 69230, 68181, + 67164, 66176, 65217, 64285, 63380, 62500, 61643, 60810, + 60000, 59210, 59210, 58441, 57692, 56962, 56250, 55555, + 54878, 54216, 53571, 52941, 52325, 51724, 51136, 50561, + 49450, 48387, 47368, 46875, 45918, 45000, 44554, 44117, + 43269, 42452, 41666, 40909, 40178, 39473, 38793, 38135, + 36885, 36290, 35714, 35156, 34615, 34090, 33582, 33088, + 32608, 32142, 31468, 31034, 30405, 29801, 29220, 28662, + }, + // Inter case 285000/Qinter + { + 712500, 570000, 475000, 407142, 356250, 316666, 285000, 259090, + 237500, 219230, 203571, 190000, 178125, 167647, 158333, 150000, + 142500, 135714, 129545, 123913, 118750, 114000, 109615, 105555, + 101785, 98275, 95000, 91935, 89062, 86363, 83823, 81428, + 79166, 77027, 75000, 73076, 71250, 69512, 67857, 66279, + 64772, 63333, 61956, 60638, 59375, 58163, 57000, 55882, + 54807, 53773, 52777, 51818, 50892, 50000, 49137, 47500, + 45967, 44531, 43181, 41911, 40714, 39583, 38513, 37500, + 36538, 35625, 34756, 33928, 33139, 32386, 31666, 30978, + 30319, 29687, 29081, 28500, 27941, 27403, 26886, 26388, + 25909, 25446, 25000, 24568, 23949, 23360, 22800, 22265, + 21755, 21268, 20802, 20357, 19930, 19520, 19127, 18750, + 18387, 18037, 17701, 17378, 17065, 16764, 16473, 16101, + 15745, 15405, 15079, 14766, 14467, 14179, 13902, 13636, + 13380, 13133, 12895, 12666, 12445, 12179, 11924, 11632, + 11445, 11220, 11003, 10795, 10594, 10401, 10215, 10035, + } +}; + +static const int kf_boost_qadjustment[QINDEX_RANGE] = +{ + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 200, 201, 201, 202, 203, 203, 203, + 204, 204, 205, 205, 206, 206, 207, 207, + 208, 208, 209, 209, 210, 210, 211, 211, + 212, 212, 213, 213, 214, 214, 215, 215, + 216, 216, 217, 217, 218, 218, 219, 219, + 220, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 220, +}; + +//#define GFQ_ADJUSTMENT (Q+100) +#define GFQ_ADJUSTMENT vp8_gf_boost_qadjustment[Q] +const int vp8_gf_boost_qadjustment[QINDEX_RANGE] = +{ + 80, 82, 84, 86, 88, 90, 92, 94, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 184, 185, 185, 186, 186, 187, 187, + 188, 188, 189, 189, 190, 190, 191, 191, + 192, 192, 193, 193, 194, 194, 194, 194, + 195, 195, 196, 196, 197, 197, 198, 198 +}; + +/* +const int vp8_gf_boost_qadjustment[QINDEX_RANGE] = +{ + 100,101,102,103,104,105,105,106, + 106,107,107,108,109,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151, + 152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167, + 168,169,170,170,171,171,172,172, + 173,173,173,174,174,174,175,175, + 175,176,176,176,177,177,177,177, + 178,178,179,179,180,180,181,181, + 182,182,183,183,184,184,185,185, + 186,186,187,187,188,188,189,189, + 190,190,191,191,192,192,193,193, +}; +*/ + +static const int kf_gf_boost_qlimits[QINDEX_RANGE] = +{ + 150, 155, 160, 165, 170, 175, 180, 185, + 190, 195, 200, 205, 210, 215, 220, 225, + 230, 235, 240, 245, 250, 255, 260, 265, + 270, 275, 280, 285, 290, 295, 300, 305, + 310, 320, 330, 340, 350, 360, 370, 380, + 390, 400, 410, 420, 430, 440, 450, 460, + 470, 480, 490, 500, 510, 520, 530, 540, + 550, 560, 570, 580, 590, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, +}; + +// % adjustment to target kf size based on seperation from previous frame +static const int kf_boost_seperation_adjustment[16] = +{ + 30, 40, 50, 55, 60, 65, 70, 75, + 80, 85, 90, 95, 100, 100, 100, 100, +}; + + +static const int gf_adjust_table[101] = +{ + 100, + 115, 130, 145, 160, 175, 190, 200, 210, 220, 230, + 240, 260, 270, 280, 290, 300, 310, 320, 330, 340, + 350, 360, 370, 380, 390, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, +}; + +static const int gf_intra_usage_adjustment[20] = +{ + 125, 120, 115, 110, 105, 100, 95, 85, 80, 75, + 70, 65, 60, 55, 50, 50, 50, 50, 50, 50, +}; + +static const int gf_interval_table[101] = +{ + 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +}; + +static const unsigned int prior_key_frame_weight[KEY_FRAME_CONTEXT] = { 1, 2, 3, 4, 5 }; + + +void vp8_save_coding_context(VP8_COMP *cpi) +{ + CODING_CONTEXT *const cc = & cpi->coding_context; + + // Stores a snapshot of key state variables which can subsequently be + // restored with a call to vp8_restore_coding_context. These functions are + // intended for use in a re-code loop in vp8_compress_frame where the + // quantizer value is adjusted between loop iterations. + + cc->frames_since_key = cpi->frames_since_key; + cc->filter_level = cpi->common.filter_level; + cc->frames_till_gf_update_due = cpi->frames_till_gf_update_due; + cc->frames_since_golden = cpi->common.frames_since_golden; + + vp8_copy(cc->mvc, cpi->common.fc.mvc); + vp8_copy(cc->mvcosts, cpi->mb.mvcosts); + + vp8_copy(cc->kf_ymode_prob, cpi->common.kf_ymode_prob); + vp8_copy(cc->ymode_prob, cpi->common.fc.ymode_prob); + vp8_copy(cc->kf_uv_mode_prob, cpi->common.kf_uv_mode_prob); + vp8_copy(cc->uv_mode_prob, cpi->common.fc.uv_mode_prob); + + vp8_copy(cc->ymode_count, cpi->ymode_count); + vp8_copy(cc->uv_mode_count, cpi->uv_mode_count); + + + // Stats +#ifdef MODE_STATS + vp8_copy(cc->y_modes, y_modes); + vp8_copy(cc->uv_modes, uv_modes); + vp8_copy(cc->b_modes, b_modes); + vp8_copy(cc->inter_y_modes, inter_y_modes); + vp8_copy(cc->inter_uv_modes, inter_uv_modes); + vp8_copy(cc->inter_b_modes, inter_b_modes); +#endif + + cc->this_frame_percent_intra = cpi->this_frame_percent_intra; +} + + +void vp8_restore_coding_context(VP8_COMP *cpi) +{ + CODING_CONTEXT *const cc = & cpi->coding_context; + + // Restore key state variables to the snapshot state stored in the + // previous call to vp8_save_coding_context. + + cpi->frames_since_key = cc->frames_since_key; + cpi->common.filter_level = cc->filter_level; + cpi->frames_till_gf_update_due = cc->frames_till_gf_update_due; + cpi->common.frames_since_golden = cc->frames_since_golden; + + vp8_copy(cpi->common.fc.mvc, cc->mvc); + + vp8_copy(cpi->mb.mvcosts, cc->mvcosts); + + vp8_copy(cpi->common.kf_ymode_prob, cc->kf_ymode_prob); + vp8_copy(cpi->common.fc.ymode_prob, cc->ymode_prob); + vp8_copy(cpi->common.kf_uv_mode_prob, cc->kf_uv_mode_prob); + vp8_copy(cpi->common.fc.uv_mode_prob, cc->uv_mode_prob); + + vp8_copy(cpi->ymode_count, cc->ymode_count); + vp8_copy(cpi->uv_mode_count, cc->uv_mode_count); + + // Stats +#ifdef MODE_STATS + vp8_copy(y_modes, cc->y_modes); + vp8_copy(uv_modes, cc->uv_modes); + vp8_copy(b_modes, cc->b_modes); + vp8_copy(inter_y_modes, cc->inter_y_modes); + vp8_copy(inter_uv_modes, cc->inter_uv_modes); + vp8_copy(inter_b_modes, cc->inter_b_modes); +#endif + + + cpi->this_frame_percent_intra = cc->this_frame_percent_intra; +} + + +void vp8_setup_key_frame(VP8_COMP *cpi) +{ + // Setup for Key frame: + + vp8_default_coef_probs(& cpi->common); + + + vp8_kf_default_bmode_probs(cpi->common.kf_bmode_prob); + + vpx_memcpy(cpi->common.fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); + { + int flag[2] = {1, 1}; + vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) cpi->common.fc.mvc, flag); + } + + vpx_memset(cpi->common.fc.pre_mvc, 0, sizeof(cpi->common.fc.pre_mvc)); //initialize pre_mvc to all zero. + + // Make sure we initialize separate contexts for altref,gold, and normal. + // TODO shouldn't need 3 different copies of structure to do this! + vpx_memcpy(&cpi->lfc_a, &cpi->common.fc, sizeof(cpi->common.fc)); + vpx_memcpy(&cpi->lfc_g, &cpi->common.fc, sizeof(cpi->common.fc)); + vpx_memcpy(&cpi->lfc_n, &cpi->common.fc, sizeof(cpi->common.fc)); + + //cpi->common.filter_level = 0; // Reset every key frame. + cpi->common.filter_level = cpi->common.base_qindex * 3 / 8 ; + + // Provisional interval before next GF + if (cpi->auto_gold) + //cpi->frames_till_gf_update_due = DEFAULT_GF_INTERVAL; + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + else + cpi->frames_till_gf_update_due = cpi->goldfreq; + + cpi->common.refresh_golden_frame = 1; + cpi->common.refresh_alt_ref_frame = 1; +} + + +static int estimate_bits_at_q(int frame_kind, int Q, int MBs, + double correction_factor) +{ + int Bpm = (int)(.5 + correction_factor * vp8_bits_per_mb[frame_kind][Q]); + + /* Attempt to retain reasonable accuracy without overflow. The cutoff is + * chosen such that the maximum product of Bpm and MBs fits 31 bits. The + * largest Bpm takes 20 bits. + */ + if (MBs > (1 << 11)) + return (Bpm >> BPER_MB_NORMBITS) * MBs; + else + return (Bpm * MBs) >> BPER_MB_NORMBITS; +} + + +static void calc_iframe_target_size(VP8_COMP *cpi) +{ + // boost defaults to half second + int kf_boost; + int target; + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); //__asm emms; + + if (cpi->oxcf.fixed_q >= 0) + { + int Q = cpi->oxcf.key_q; + + target = estimate_bits_at_q(INTRA_FRAME, Q, cpi->common.MBs, + cpi->key_frame_rate_correction_factor); + } + else if (cpi->pass == 2) + { + // New Two pass RC + target = cpi->per_frame_bandwidth; + } + // First Frame is a special case + else if (cpi->common.current_video_frame == 0) + { + /* 1 Pass there is no information on which to base size so use + * bandwidth per second * fraction of the initial buffer + * level + */ + target = cpi->oxcf.starting_buffer_level / 2; + + if(target > cpi->oxcf.target_bandwidth * 3 / 2) + target = cpi->oxcf.target_bandwidth * 3 / 2; + } + else + { + // if this keyframe was forced, use a more recent Q estimate + int Q = (cpi->common.frame_flags & FRAMEFLAGS_KEY) + ? cpi->avg_frame_qindex : cpi->ni_av_qi; + + int initial_boost = 24; // Corresponds to: |2.5 * per_frame_bandwidth| + // Boost depends somewhat on frame rate: only used for 1 layer case. + if (cpi->oxcf.number_of_layers == 1) { + kf_boost = MAX(initial_boost, (int)(2 * cpi->output_frame_rate - 16)); + } + else { + // Initial factor: set target size to: |2.5 * per_frame_bandwidth|. + kf_boost = initial_boost; + } + + // adjustment up based on q: this factor ranges from ~1.2 to 2.2. + kf_boost = kf_boost * kf_boost_qadjustment[Q] / 100; + + // frame separation adjustment ( down) + if (cpi->frames_since_key < cpi->output_frame_rate / 2) + kf_boost = (int)(kf_boost + * cpi->frames_since_key / (cpi->output_frame_rate / 2)); + + // Minimal target size is |2* per_frame_bandwidth|. + if (kf_boost < 16) + kf_boost = 16; + + target = ((16 + kf_boost) * cpi->per_frame_bandwidth) >> 4; + } + + + if (cpi->oxcf.rc_max_intra_bitrate_pct) + { + unsigned int max_rate = cpi->per_frame_bandwidth + * cpi->oxcf.rc_max_intra_bitrate_pct / 100; + + if (target > max_rate) + target = max_rate; + } + + cpi->this_frame_target = target; + + // TODO: if we separate rate targeting from Q targetting, move this. + // Reset the active worst quality to the baseline value for key frames. + if (cpi->pass != 2) + cpi->active_worst_quality = cpi->worst_quality; + +#if 0 + { + FILE *f; + + f = fopen("kf_boost.stt", "a"); + //fprintf(f, " %8d %10d %10d %10d %10d %10d %10d\n", + // cpi->common.current_video_frame, cpi->target_bandwidth, cpi->frames_to_key, kf_boost_qadjustment[cpi->ni_av_qi], cpi->kf_boost, (cpi->this_frame_target *100 / cpi->per_frame_bandwidth), cpi->this_frame_target ); + + fprintf(f, " %8u %10d %10d %10d\n", + cpi->common.current_video_frame, cpi->gfu_boost, cpi->baseline_gf_interval, cpi->source_alt_ref_pending); + + fclose(f); + } +#endif +} + + +// Do the best we can to define the parameters for the next GF based on what +// information we have available. +static void calc_gf_params(VP8_COMP *cpi) +{ + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int Boost = 0; + + int gf_frame_useage = 0; // Golden frame useage since last GF + int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] + + cpi->recent_ref_frame_usage[LAST_FRAME] + + cpi->recent_ref_frame_usage[GOLDEN_FRAME] + + cpi->recent_ref_frame_usage[ALTREF_FRAME]; + + int pct_gf_active = (100 * cpi->gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols); + + // Reset the last boost indicator + //cpi->last_boost = 100; + + if (tot_mbs) + gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] + cpi->recent_ref_frame_usage[ALTREF_FRAME]) * 100 / tot_mbs; + + if (pct_gf_active > gf_frame_useage) + gf_frame_useage = pct_gf_active; + + // Not two pass + if (cpi->pass != 2) + { + // Single Pass lagged mode: TBD + if (0) + { + } + + // Single Pass compression: Has to use current and historical data + else + { +#if 0 + // Experimental code + int index = cpi->one_pass_frame_index; + int frames_to_scan = (cpi->max_gf_interval <= MAX_LAG_BUFFERS) ? cpi->max_gf_interval : MAX_LAG_BUFFERS; + + /* + // *************** Experimental code - incomplete + double decay_val = 1.0; + double IIAccumulator = 0.0; + double last_iiaccumulator = 0.0; + double IIRatio; + + cpi->one_pass_frame_index = cpi->common.current_video_frame%MAX_LAG_BUFFERS; + + for ( i = 0; i < (frames_to_scan - 1); i++ ) + { + if ( index < 0 ) + index = MAX_LAG_BUFFERS; + index --; + + if ( cpi->one_pass_frame_stats[index].frame_coded_error > 0.0 ) + { + IIRatio = cpi->one_pass_frame_stats[index].frame_intra_error / cpi->one_pass_frame_stats[index].frame_coded_error; + + if ( IIRatio > 30.0 ) + IIRatio = 30.0; + } + else + IIRatio = 30.0; + + IIAccumulator += IIRatio * decay_val; + + decay_val = decay_val * cpi->one_pass_frame_stats[index].frame_pcnt_inter; + + if ( (i > MIN_GF_INTERVAL) && + ((IIAccumulator - last_iiaccumulator) < 2.0) ) + { + break; + } + last_iiaccumulator = IIAccumulator; + } + + Boost = IIAccumulator*100.0/16.0; + cpi->baseline_gf_interval = i; + + */ +#else + + /*************************************************************/ + // OLD code + + // Adjust boost based upon ambient Q + Boost = GFQ_ADJUSTMENT; + + // Adjust based upon most recently measure intra useage + Boost = Boost * gf_intra_usage_adjustment[(cpi->this_frame_percent_intra < 15) ? cpi->this_frame_percent_intra : 14] / 100; + + // Adjust gf boost based upon GF usage since last GF + Boost = Boost * gf_adjust_table[gf_frame_useage] / 100; +#endif + } + + // golden frame boost without recode loop often goes awry. be safe by keeping numbers down. + if (!cpi->sf.recode_loop) + { + if (cpi->compressor_speed == 2) + Boost = Boost / 2; + } + + // Apply an upper limit based on Q for 1 pass encodes + if (Boost > kf_gf_boost_qlimits[Q] && (cpi->pass == 0)) + Boost = kf_gf_boost_qlimits[Q]; + + // Apply lower limits to boost. + else if (Boost < 110) + Boost = 110; + + // Note the boost used + cpi->last_boost = Boost; + + } + + // Estimate next interval + // This is updated once the real frame size/boost is known. + if (cpi->oxcf.fixed_q == -1) + { + if (cpi->pass == 2) // 2 Pass + { + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + } + else // 1 Pass + { + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + + if (cpi->last_boost > 750) + cpi->frames_till_gf_update_due++; + + if (cpi->last_boost > 1000) + cpi->frames_till_gf_update_due++; + + if (cpi->last_boost > 1250) + cpi->frames_till_gf_update_due++; + + if (cpi->last_boost >= 1500) + cpi->frames_till_gf_update_due ++; + + if (gf_interval_table[gf_frame_useage] > cpi->frames_till_gf_update_due) + cpi->frames_till_gf_update_due = gf_interval_table[gf_frame_useage]; + + if (cpi->frames_till_gf_update_due > cpi->max_gf_interval) + cpi->frames_till_gf_update_due = cpi->max_gf_interval; + } + } + else + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + + // ARF on or off + if (cpi->pass != 2) + { + // For now Alt ref is not allowed except in 2 pass modes. + cpi->source_alt_ref_pending = 0; + + /*if ( cpi->oxcf.fixed_q == -1) + { + if ( cpi->oxcf.play_alternate && (cpi->last_boost > (100 + (AF_THRESH*cpi->frames_till_gf_update_due)) ) ) + cpi->source_alt_ref_pending = 1; + else + cpi->source_alt_ref_pending = 0; + }*/ + } +} + + +static void calc_pframe_target_size(VP8_COMP *cpi) +{ + int min_frame_target; + int Adjustment; + int old_per_frame_bandwidth = cpi->per_frame_bandwidth; + + if ( cpi->current_layer > 0) + cpi->per_frame_bandwidth = + cpi->layer_context[cpi->current_layer].avg_frame_size_for_layer; + + min_frame_target = 0; + + if (cpi->pass == 2) + { + min_frame_target = cpi->min_frame_bandwidth; + + if (min_frame_target < (cpi->av_per_frame_bandwidth >> 5)) + min_frame_target = cpi->av_per_frame_bandwidth >> 5; + } + else if (min_frame_target < cpi->per_frame_bandwidth / 4) + min_frame_target = cpi->per_frame_bandwidth / 4; + + + // Special alt reference frame case + if((cpi->common.refresh_alt_ref_frame) && (cpi->oxcf.number_of_layers == 1)) + { + if (cpi->pass == 2) + { + cpi->per_frame_bandwidth = cpi->twopass.gf_bits; // Per frame bit target for the alt ref frame + cpi->this_frame_target = cpi->per_frame_bandwidth; + } + + /* One Pass ??? TBD */ + /*else + { + int frames_in_section; + int allocation_chunks; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int alt_boost; + int max_arf_rate; + + alt_boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); + alt_boost += (cpi->frames_till_gf_update_due * 50); + + // If alt ref is not currently active then we have a pottential double hit with GF and ARF so reduce the boost a bit. + // A similar thing is done on GFs that preceed a arf update. + if ( !cpi->source_alt_ref_active ) + alt_boost = alt_boost * 3 / 4; + + frames_in_section = cpi->frames_till_gf_update_due+1; // Standard frames + GF + allocation_chunks = (frames_in_section * 100) + alt_boost; + + // Normalize Altboost and allocations chunck down to prevent overflow + while ( alt_boost > 1000 ) + { + alt_boost /= 2; + allocation_chunks /= 2; + } + + else + { + int bits_in_section; + + if ( cpi->kf_overspend_bits > 0 ) + { + Adjustment = (cpi->kf_bitrate_adjustment <= cpi->kf_overspend_bits) ? cpi->kf_bitrate_adjustment : cpi->kf_overspend_bits; + + if ( Adjustment > (cpi->per_frame_bandwidth - min_frame_target) ) + Adjustment = (cpi->per_frame_bandwidth - min_frame_target); + + cpi->kf_overspend_bits -= Adjustment; + + // Calculate an inter frame bandwidth target for the next few frames designed to recover + // any extra bits spent on the key frame. + cpi->inter_frame_target = cpi->per_frame_bandwidth - Adjustment; + if ( cpi->inter_frame_target < min_frame_target ) + cpi->inter_frame_target = min_frame_target; + } + else + cpi->inter_frame_target = cpi->per_frame_bandwidth; + + bits_in_section = cpi->inter_frame_target * frames_in_section; + + // Avoid loss of precision but avoid overflow + if ( (bits_in_section>>7) > allocation_chunks ) + cpi->this_frame_target = alt_boost * (bits_in_section / allocation_chunks); + else + cpi->this_frame_target = (alt_boost * bits_in_section) / allocation_chunks; + } + } + */ + } + + // Normal frames (gf,and inter) + else + { + // 2 pass + if (cpi->pass == 2) + { + cpi->this_frame_target = cpi->per_frame_bandwidth; + } + // 1 pass + else + { + // Make rate adjustment to recover bits spent in key frame + // Test to see if the key frame inter data rate correction should still be in force + if (cpi->kf_overspend_bits > 0) + { + Adjustment = (cpi->kf_bitrate_adjustment <= cpi->kf_overspend_bits) ? cpi->kf_bitrate_adjustment : cpi->kf_overspend_bits; + + if (Adjustment > (cpi->per_frame_bandwidth - min_frame_target)) + Adjustment = (cpi->per_frame_bandwidth - min_frame_target); + + cpi->kf_overspend_bits -= Adjustment; + + // Calculate an inter frame bandwidth target for the next few frames designed to recover + // any extra bits spent on the key frame. + cpi->this_frame_target = cpi->per_frame_bandwidth - Adjustment; + + if (cpi->this_frame_target < min_frame_target) + cpi->this_frame_target = min_frame_target; + } + else + cpi->this_frame_target = cpi->per_frame_bandwidth; + + // If appropriate make an adjustment to recover bits spent on a recent GF + if ((cpi->gf_overspend_bits > 0) && (cpi->this_frame_target > min_frame_target)) + { + int Adjustment = (cpi->non_gf_bitrate_adjustment <= cpi->gf_overspend_bits) ? cpi->non_gf_bitrate_adjustment : cpi->gf_overspend_bits; + + if (Adjustment > (cpi->this_frame_target - min_frame_target)) + Adjustment = (cpi->this_frame_target - min_frame_target); + + cpi->gf_overspend_bits -= Adjustment; + cpi->this_frame_target -= Adjustment; + } + + // Apply small + and - boosts for non gf frames + if ((cpi->last_boost > 150) && (cpi->frames_till_gf_update_due > 0) && + (cpi->current_gf_interval >= (MIN_GF_INTERVAL << 1))) + { + // % Adjustment limited to the range 1% to 10% + Adjustment = (cpi->last_boost - 100) >> 5; + + if (Adjustment < 1) + Adjustment = 1; + else if (Adjustment > 10) + Adjustment = 10; + + // Convert to bits + Adjustment = (cpi->this_frame_target * Adjustment) / 100; + + if (Adjustment > (cpi->this_frame_target - min_frame_target)) + Adjustment = (cpi->this_frame_target - min_frame_target); + + if (cpi->common.frames_since_golden == (cpi->current_gf_interval >> 1)) + cpi->this_frame_target += ((cpi->current_gf_interval - 1) * Adjustment); + else + cpi->this_frame_target -= Adjustment; + } + } + } + + // Sanity check that the total sum of adjustments is not above the maximum allowed + // That is that having allowed for KF and GF penalties we have not pushed the + // current interframe target to low. If the adjustment we apply here is not capable of recovering + // all the extra bits we have spent in the KF or GF then the remainder will have to be recovered over + // a longer time span via other buffer / rate control mechanisms. + if (cpi->this_frame_target < min_frame_target) + cpi->this_frame_target = min_frame_target; + + if (!cpi->common.refresh_alt_ref_frame) + // Note the baseline target data rate for this inter frame. + cpi->inter_frame_target = cpi->this_frame_target; + + // One Pass specific code + if (cpi->pass == 0) + { + // Adapt target frame size with respect to any buffering constraints: + if (cpi->buffered_mode) + { + int one_percent_bits = 1 + cpi->oxcf.optimal_buffer_level / 100; + + if ((cpi->buffer_level < cpi->oxcf.optimal_buffer_level) || + (cpi->bits_off_target < cpi->oxcf.optimal_buffer_level)) + { + int percent_low = 0; + + // Decide whether or not we need to adjust the frame data rate target. + // + // If we are are below the optimal buffer fullness level and adherence + // to buffering constraints is important to the end usage then adjust + // the per frame target. + if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + (cpi->buffer_level < cpi->oxcf.optimal_buffer_level)) + { + percent_low = + (cpi->oxcf.optimal_buffer_level - cpi->buffer_level) / + one_percent_bits; + } + // Are we overshooting the long term clip data rate... + else if (cpi->bits_off_target < 0) + { + // Adjust per frame data target downwards to compensate. + percent_low = (int)(100 * -cpi->bits_off_target / + (cpi->total_byte_count * 8)); + } + + if (percent_low > cpi->oxcf.under_shoot_pct) + percent_low = cpi->oxcf.under_shoot_pct; + else if (percent_low < 0) + percent_low = 0; + + // lower the target bandwidth for this frame. + cpi->this_frame_target -= + (cpi->this_frame_target * percent_low) / 200; + + // Are we using allowing control of active_worst_allowed_q + // according to buffer level. + if (cpi->auto_worst_q && cpi->ni_frames > 150) + { + int critical_buffer_level; + + // For streaming applications the most important factor is + // cpi->buffer_level as this takes into account the + // specified short term buffering constraints. However, + // hitting the long term clip data rate target is also + // important. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // Take the smaller of cpi->buffer_level and + // cpi->bits_off_target + critical_buffer_level = + (cpi->buffer_level < cpi->bits_off_target) + ? cpi->buffer_level : cpi->bits_off_target; + } + // For local file playback short term buffering constraints + // are less of an issue + else + { + // Consider only how we are doing for the clip as a + // whole + critical_buffer_level = cpi->bits_off_target; + } + + // Set the active worst quality based upon the selected + // buffer fullness number. + if (critical_buffer_level < cpi->oxcf.optimal_buffer_level) + { + if ( critical_buffer_level > + (cpi->oxcf.optimal_buffer_level >> 2) ) + { + int64_t qadjustment_range = + cpi->worst_quality - cpi->ni_av_qi; + int64_t above_base = + (critical_buffer_level - + (cpi->oxcf.optimal_buffer_level >> 2)); + + // Step active worst quality down from + // cpi->ni_av_qi when (critical_buffer_level == + // cpi->optimal_buffer_level) to + // cpi->worst_quality when + // (critical_buffer_level == + // cpi->optimal_buffer_level >> 2) + cpi->active_worst_quality = + cpi->worst_quality - + ((qadjustment_range * above_base) / + (cpi->oxcf.optimal_buffer_level*3>>2)); + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + } + } + else + { + cpi->active_worst_quality = cpi->ni_av_qi; + } + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + } + } + else + { + int percent_high = 0; + + if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + && (cpi->buffer_level > cpi->oxcf.optimal_buffer_level)) + { + percent_high = (cpi->buffer_level + - cpi->oxcf.optimal_buffer_level) + / one_percent_bits; + } + else if (cpi->bits_off_target > cpi->oxcf.optimal_buffer_level) + { + percent_high = (int)((100 * cpi->bits_off_target) + / (cpi->total_byte_count * 8)); + } + + if (percent_high > cpi->oxcf.over_shoot_pct) + percent_high = cpi->oxcf.over_shoot_pct; + else if (percent_high < 0) + percent_high = 0; + + cpi->this_frame_target += (cpi->this_frame_target * + percent_high) / 200; + + // Are we allowing control of active_worst_allowed_q according + // to buffer level. + if (cpi->auto_worst_q && cpi->ni_frames > 150) + { + // When using the relaxed buffer model stick to the user specified value + cpi->active_worst_quality = cpi->ni_av_qi; + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + } + } + + // Set active_best_quality to prevent quality rising too high + cpi->active_best_quality = cpi->best_quality; + + // Worst quality obviously must not be better than best quality + if (cpi->active_worst_quality <= cpi->active_best_quality) + cpi->active_worst_quality = cpi->active_best_quality + 1; + + if(cpi->active_worst_quality > 127) + cpi->active_worst_quality = 127; + } + // Unbuffered mode (eg. video conferencing) + else + { + // Set the active worst quality + cpi->active_worst_quality = cpi->worst_quality; + } + + // Special trap for constrained quality mode + // "active_worst_quality" may never drop below cq level + // for any frame type. + if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY && + cpi->active_worst_quality < cpi->cq_target_quality) + { + cpi->active_worst_quality = cpi->cq_target_quality; + } + } + + // Test to see if we have to drop a frame + // The auto-drop frame code is only used in buffered mode. + // In unbufferd mode (eg vide conferencing) the descision to + // code or drop a frame is made outside the codec in response to real + // world comms or buffer considerations. + if (cpi->drop_frames_allowed && cpi->buffered_mode && + (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + ((cpi->common.frame_type != KEY_FRAME))) //|| !cpi->oxcf.allow_spatial_resampling) ) + { + // Check for a buffer underun-crisis in which case we have to drop a frame + if ((cpi->buffer_level < 0)) + { +#if 0 + FILE *f = fopen("dec.stt", "a"); + fprintf(f, "%10d %10d %10d %10d ***** BUFFER EMPTY\n", + (int) cpi->common.current_video_frame, + cpi->decimation_factor, cpi->common.horiz_scale, + (cpi->buffer_level * 100) / cpi->oxcf.optimal_buffer_level); + fclose(f); +#endif + //vpx_log("Decoder: Drop frame due to bandwidth: %d \n",cpi->buffer_level, cpi->av_per_frame_bandwidth); + + cpi->drop_frame = 1; + } + +#if 0 + // Check for other drop frame crtieria (Note 2 pass cbr uses decimation on whole KF sections) + else if ((cpi->buffer_level < cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100) && + (cpi->drop_count < cpi->max_drop_count) && (cpi->pass == 0)) + { + cpi->drop_frame = 1; + } + +#endif + + if (cpi->drop_frame) + { + // Update the buffer level variable. + cpi->bits_off_target += cpi->av_per_frame_bandwidth; + if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size) + cpi->bits_off_target = cpi->oxcf.maximum_buffer_size; + cpi->buffer_level = cpi->bits_off_target; + } + else + cpi->drop_count = 0; + } + + // Adjust target frame size for Golden Frames: + if (cpi->oxcf.error_resilient_mode == 0 && + (cpi->frames_till_gf_update_due == 0) && !cpi->drop_frame) + { + //int Boost = 0; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + + int gf_frame_useage = 0; // Golden frame useage since last GF + int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] + + cpi->recent_ref_frame_usage[LAST_FRAME] + + cpi->recent_ref_frame_usage[GOLDEN_FRAME] + + cpi->recent_ref_frame_usage[ALTREF_FRAME]; + + int pct_gf_active = (100 * cpi->gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols); + + // Reset the last boost indicator + //cpi->last_boost = 100; + + if (tot_mbs) + gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] + cpi->recent_ref_frame_usage[ALTREF_FRAME]) * 100 / tot_mbs; + + if (pct_gf_active > gf_frame_useage) + gf_frame_useage = pct_gf_active; + + // Is a fixed manual GF frequency being used + if (cpi->auto_gold) + { + // For one pass throw a GF if recent frame intra useage is low or the GF useage is high + if ((cpi->pass == 0) && (cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) + cpi->common.refresh_golden_frame = 1; + + // Two pass GF descision + else if (cpi->pass == 2) + cpi->common.refresh_golden_frame = 1; + } + +#if 0 + + // Debug stats + if (0) + { + FILE *f; + + f = fopen("gf_useaget.stt", "a"); + fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n", + cpi->common.current_video_frame, cpi->gfu_boost, GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage); + fclose(f); + } + +#endif + + if (cpi->common.refresh_golden_frame == 1) + { +#if 0 + + if (0) // p_gw + { + FILE *f; + + f = fopen("GFexit.stt", "a"); + fprintf(f, "%8ld GF coded\n", cpi->common.current_video_frame); + fclose(f); + } + +#endif + + if (cpi->auto_adjust_gold_quantizer) + { + calc_gf_params(cpi); + } + + // If we are using alternate ref instead of gf then do not apply the boost + // It will instead be applied to the altref update + // Jims modified boost + if (!cpi->source_alt_ref_active) + { + if (cpi->oxcf.fixed_q < 0) + { + if (cpi->pass == 2) + { + cpi->this_frame_target = cpi->per_frame_bandwidth; // The spend on the GF is defined in the two pass code for two pass encodes + } + else + { + int Boost = cpi->last_boost; + int frames_in_section = cpi->frames_till_gf_update_due + 1; + int allocation_chunks = (frames_in_section * 100) + (Boost - 100); + int bits_in_section = cpi->inter_frame_target * frames_in_section; + + // Normalize Altboost and allocations chunck down to prevent overflow + while (Boost > 1000) + { + Boost /= 2; + allocation_chunks /= 2; + } + + // Avoid loss of precision but avoid overflow + if ((bits_in_section >> 7) > allocation_chunks) + cpi->this_frame_target = Boost * (bits_in_section / allocation_chunks); + else + cpi->this_frame_target = (Boost * bits_in_section) / allocation_chunks; + } + } + else + cpi->this_frame_target = + (estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) + * cpi->last_boost) / 100; + + } + // If there is an active ARF at this location use the minimum + // bits on this frame even if it is a contructed arf. + // The active maximum quantizer insures that an appropriate + // number of bits will be spent if needed for contstructed ARFs. + else + { + cpi->this_frame_target = 0; + } + + cpi->current_gf_interval = cpi->frames_till_gf_update_due; + + } + } + + cpi->per_frame_bandwidth = old_per_frame_bandwidth; +} + + +void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var) +{ + int Q = cpi->common.base_qindex; + int correction_factor = 100; + double rate_correction_factor; + double adjustment_limit; + + int projected_size_based_on_q = 0; + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); //__asm emms; + + if (cpi->common.frame_type == KEY_FRAME) + { + rate_correction_factor = cpi->key_frame_rate_correction_factor; + } + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + rate_correction_factor = cpi->gf_rate_correction_factor; + else + rate_correction_factor = cpi->rate_correction_factor; + } + + // Work out how big we would have expected the frame to be at this Q given the current correction factor. + // Stay in double to avoid int overflow when values are large + //projected_size_based_on_q = ((int)(.5 + rate_correction_factor * vp8_bits_per_mb[cpi->common.frame_type][Q]) * cpi->common.MBs) >> BPER_MB_NORMBITS; + projected_size_based_on_q = (int)(((.5 + rate_correction_factor * vp8_bits_per_mb[cpi->common.frame_type][Q]) * cpi->common.MBs) / (1 << BPER_MB_NORMBITS)); + + // Make some allowance for cpi->zbin_over_quant + if (cpi->zbin_over_quant > 0) + { + int Z = cpi->zbin_over_quant; + double Factor = 0.99; + double factor_adjustment = 0.01 / 256.0; //(double)ZBIN_OQ_MAX; + + while (Z > 0) + { + Z --; + projected_size_based_on_q = + (int)(Factor * projected_size_based_on_q); + Factor += factor_adjustment; + + if (Factor >= 0.999) + Factor = 0.999; + } + } + + // Work out a size correction factor. + //if ( cpi->this_frame_target > 0 ) + // correction_factor = (100 * cpi->projected_frame_size) / cpi->this_frame_target; + if (projected_size_based_on_q > 0) + correction_factor = (100 * cpi->projected_frame_size) / projected_size_based_on_q; + + // More heavily damped adjustment used if we have been oscillating either side of target + switch (damp_var) + { + case 0: + adjustment_limit = 0.75; + break; + case 1: + adjustment_limit = 0.375; + break; + case 2: + default: + adjustment_limit = 0.25; + break; + } + + //if ( (correction_factor > 102) && (Q < cpi->active_worst_quality) ) + if (correction_factor > 102) + { + // We are not already at the worst allowable quality + correction_factor = (int)(100.5 + ((correction_factor - 100) * adjustment_limit)); + rate_correction_factor = ((rate_correction_factor * correction_factor) / 100); + + // Keep rate_correction_factor within limits + if (rate_correction_factor > MAX_BPB_FACTOR) + rate_correction_factor = MAX_BPB_FACTOR; + } + //else if ( (correction_factor < 99) && (Q > cpi->active_best_quality) ) + else if (correction_factor < 99) + { + // We are not already at the best allowable quality + correction_factor = (int)(100.5 - ((100 - correction_factor) * adjustment_limit)); + rate_correction_factor = ((rate_correction_factor * correction_factor) / 100); + + // Keep rate_correction_factor within limits + if (rate_correction_factor < MIN_BPB_FACTOR) + rate_correction_factor = MIN_BPB_FACTOR; + } + + if (cpi->common.frame_type == KEY_FRAME) + cpi->key_frame_rate_correction_factor = rate_correction_factor; + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + cpi->gf_rate_correction_factor = rate_correction_factor; + else + cpi->rate_correction_factor = rate_correction_factor; + } +} + + +int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) +{ + int Q = cpi->active_worst_quality; + + // Reset Zbin OQ value + cpi->zbin_over_quant = 0; + + if (cpi->oxcf.fixed_q >= 0) + { + Q = cpi->oxcf.fixed_q; + + if (cpi->common.frame_type == KEY_FRAME) + { + Q = cpi->oxcf.key_q; + } + else if (cpi->common.refresh_alt_ref_frame) + { + Q = cpi->oxcf.alt_q; + } + else if (cpi->common.refresh_golden_frame) + { + Q = cpi->oxcf.gold_q; + } + + } + else + { + int i; + int last_error = INT_MAX; + int target_bits_per_mb; + int bits_per_mb_at_this_q; + double correction_factor; + + // Select the appropriate correction factor based upon type of frame. + if (cpi->common.frame_type == KEY_FRAME) + correction_factor = cpi->key_frame_rate_correction_factor; + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + correction_factor = cpi->gf_rate_correction_factor; + else + correction_factor = cpi->rate_correction_factor; + } + + // Calculate required scaling factor based on target frame size and size of frame produced using previous Q + if (target_bits_per_frame >= (INT_MAX >> BPER_MB_NORMBITS)) + target_bits_per_mb = (target_bits_per_frame / cpi->common.MBs) << BPER_MB_NORMBITS; // Case where we would overflow int + else + target_bits_per_mb = (target_bits_per_frame << BPER_MB_NORMBITS) / cpi->common.MBs; + + i = cpi->active_best_quality; + + do + { + bits_per_mb_at_this_q = (int)(.5 + correction_factor * vp8_bits_per_mb[cpi->common.frame_type][i]); + + if (bits_per_mb_at_this_q <= target_bits_per_mb) + { + if ((target_bits_per_mb - bits_per_mb_at_this_q) <= last_error) + Q = i; + else + Q = i - 1; + + break; + } + else + last_error = bits_per_mb_at_this_q - target_bits_per_mb; + } + while (++i <= cpi->active_worst_quality); + + + // If we are at MAXQ then enable Q over-run which seeks to claw back additional bits through things like + // the RD multiplier and zero bin size. + if (Q >= MAXQ) + { + int zbin_oqmax; + + double Factor = 0.99; + double factor_adjustment = 0.01 / 256.0; //(double)ZBIN_OQ_MAX; + + if (cpi->common.frame_type == KEY_FRAME) + zbin_oqmax = 0; //ZBIN_OQ_MAX/16 + else if (cpi->common.refresh_alt_ref_frame || (cpi->common.refresh_golden_frame && !cpi->source_alt_ref_active)) + zbin_oqmax = 16; + else + zbin_oqmax = ZBIN_OQ_MAX; + + /*{ + double Factor = (double)target_bits_per_mb/(double)bits_per_mb_at_this_q; + double Oq; + + Factor = Factor/1.2683; + + Oq = pow( Factor, (1.0/-0.165) ); + + if ( Oq > zbin_oqmax ) + Oq = zbin_oqmax; + + cpi->zbin_over_quant = (int)Oq; + }*/ + + // Each incrment in the zbin is assumed to have a fixed effect on bitrate. This is not of course true. + // The effect will be highly clip dependent and may well have sudden steps. + // The idea here is to acheive higher effective quantizers than the normal maximum by expanding the zero + // bin and hence decreasing the number of low magnitude non zero coefficients. + while (cpi->zbin_over_quant < zbin_oqmax) + { + cpi->zbin_over_quant ++; + + if (cpi->zbin_over_quant > zbin_oqmax) + cpi->zbin_over_quant = zbin_oqmax; + + // Adjust bits_per_mb_at_this_q estimate + bits_per_mb_at_this_q = (int)(Factor * bits_per_mb_at_this_q); + Factor += factor_adjustment; + + if (Factor >= 0.999) + Factor = 0.999; + + if (bits_per_mb_at_this_q <= target_bits_per_mb) // Break out if we get down to the target rate + break; + } + + } + } + + return Q; +} + + +static int estimate_keyframe_frequency(VP8_COMP *cpi) +{ + int i; + + // Average key frame frequency + int av_key_frame_frequency = 0; + + /* First key frame at start of sequence is a special case. We have no + * frequency data. + */ + if (cpi->key_frame_count == 1) + { + /* Assume a default of 1 kf every 2 seconds, or the max kf interval, + * whichever is smaller. + */ + int key_freq = cpi->oxcf.key_freq>0 ? cpi->oxcf.key_freq : 1; + av_key_frame_frequency = (int)cpi->output_frame_rate * 2; + + if (cpi->oxcf.auto_key && av_key_frame_frequency > key_freq) + av_key_frame_frequency = cpi->oxcf.key_freq; + + cpi->prior_key_frame_distance[KEY_FRAME_CONTEXT - 1] + = av_key_frame_frequency; + } + else + { + unsigned int total_weight = 0; + int last_kf_interval = + (cpi->frames_since_key > 0) ? cpi->frames_since_key : 1; + + /* reset keyframe context and calculate weighted average of last + * KEY_FRAME_CONTEXT keyframes + */ + for (i = 0; i < KEY_FRAME_CONTEXT; i++) + { + if (i < KEY_FRAME_CONTEXT - 1) + cpi->prior_key_frame_distance[i] + = cpi->prior_key_frame_distance[i+1]; + else + cpi->prior_key_frame_distance[i] = last_kf_interval; + + av_key_frame_frequency += prior_key_frame_weight[i] + * cpi->prior_key_frame_distance[i]; + total_weight += prior_key_frame_weight[i]; + } + + av_key_frame_frequency /= total_weight; + + } + return av_key_frame_frequency; +} + + +void vp8_adjust_key_frame_context(VP8_COMP *cpi) +{ + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); + + // Do we have any key frame overspend to recover? + // Two-pass overspend handled elsewhere. + if ((cpi->pass != 2) + && (cpi->projected_frame_size > cpi->per_frame_bandwidth)) + { + int overspend; + + /* Update the count of key frame overspend to be recovered in + * subsequent frames. A portion of the KF overspend is treated as gf + * overspend (and hence recovered more quickly) as the kf is also a + * gf. Otherwise the few frames following each kf tend to get more + * bits allocated than those following other gfs. + */ + overspend = (cpi->projected_frame_size - cpi->per_frame_bandwidth); + + if (cpi->oxcf.number_of_layers > 1) + cpi->kf_overspend_bits += overspend; + else + { + cpi->kf_overspend_bits += overspend * 7 / 8; + cpi->gf_overspend_bits += overspend * 1 / 8; + } + + /* Work out how much to try and recover per frame. */ + cpi->kf_bitrate_adjustment = cpi->kf_overspend_bits + / estimate_keyframe_frequency(cpi); + } + + cpi->frames_since_key = 0; + cpi->key_frame_count++; +} + + +void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, int *frame_over_shoot_limit) +{ + // Set-up bounds on acceptable frame size: + if (cpi->oxcf.fixed_q >= 0) + { + // Fixed Q scenario: frame size never outranges target (there is no target!) + *frame_under_shoot_limit = 0; + *frame_over_shoot_limit = INT_MAX; + } + else + { + if (cpi->common.frame_type == KEY_FRAME) + { + *frame_over_shoot_limit = cpi->this_frame_target * 9 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 7 / 8; + } + else + { + if (cpi->oxcf.number_of_layers > 1 || + cpi->common.refresh_alt_ref_frame || + cpi->common.refresh_golden_frame) + { + *frame_over_shoot_limit = cpi->this_frame_target * 9 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 7 / 8; + } + else + { + // For CBR take buffer fullness into account + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + if (cpi->buffer_level >= ((cpi->oxcf.optimal_buffer_level + cpi->oxcf.maximum_buffer_size) >> 1)) + { + // Buffer is too full so relax overshoot and tighten undershoot + *frame_over_shoot_limit = cpi->this_frame_target * 12 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 6 / 8; + } + else if (cpi->buffer_level <= (cpi->oxcf.optimal_buffer_level >> 1)) + { + // Buffer is too low so relax undershoot and tighten overshoot + *frame_over_shoot_limit = cpi->this_frame_target * 10 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 4 / 8; + } + else + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; + } + } + // VBR and CQ mode + // Note that tighter restrictions here can help quality but hurt encode speed + else + { + // Stron overshoot limit for constrained quality + if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 2 / 8; + } + else + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; + } + } + } + } + + // For very small rate targets where the fractional adjustment + // (eg * 7/8) may be tiny make sure there is at least a minimum + // range. + *frame_over_shoot_limit += 200; + *frame_under_shoot_limit -= 200; + if ( *frame_under_shoot_limit < 0 ) + *frame_under_shoot_limit = 0; + + } +} + + +// return of 0 means drop frame +int vp8_pick_frame_size(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + if (cm->frame_type == KEY_FRAME) + calc_iframe_target_size(cpi); + else + { + calc_pframe_target_size(cpi); + + // Check if we're dropping the frame: + if (cpi->drop_frame) + { + cpi->drop_frame = 0; + cpi->drop_count++; + return 0; + } + } + return 1; +} diff --git a/vp8/encoder/ratectrl.h b/vp8/encoder/ratectrl.h new file mode 100644 index 0000000..d4f7796 --- /dev/null +++ b/vp8/encoder/ratectrl.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#if !defined __INC_RATECTRL_H + +#include "onyx_int.h" + +extern void vp8_save_coding_context(VP8_COMP *cpi); +extern void vp8_restore_coding_context(VP8_COMP *cpi); + +extern void vp8_setup_key_frame(VP8_COMP *cpi); +extern void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var); +extern int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame); +extern void vp8_adjust_key_frame_context(VP8_COMP *cpi); +extern void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, int *frame_over_shoot_limit); + +// return of 0 means drop frame +extern int vp8_pick_frame_size(VP8_COMP *cpi); + +#endif diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c new file mode 100644 index 0000000..2b706ba --- /dev/null +++ b/vp8/encoder/rdopt.c @@ -0,0 +1,2576 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include +#include +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vp8/common/pragmas.h" +#include "tokenize.h" +#include "treewriter.h" +#include "onyx_int.h" +#include "modecosts.h" +#include "encodeintra.h" +#include "vp8/common/entropymode.h" +#include "vp8/common/reconinter.h" +#include "vp8/common/reconintra4x4.h" +#include "vp8/common/findnearmv.h" +#include "vp8/common/quant_common.h" +#include "encodemb.h" +#include "quantize.h" +#include "vp8/common/variance.h" +#include "mcomp.h" +#include "rdopt.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/systemdependent.h" +#if CONFIG_TEMPORAL_DENOISING +#include "denoising.h" +#endif + +extern void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x); + +#define MAXF(a,b) (((a) > (b)) ? (a) : (b)) + +typedef struct rate_distortion_struct +{ + int rate2; + int rate_y; + int rate_uv; + int distortion2; + int distortion_uv; +} RATE_DISTORTION; + +typedef struct best_mode_struct +{ + int yrd; + int rd; + int intra_rd; + MB_MODE_INFO mbmode; + union b_mode_info bmodes[16]; + PARTITION_INFO partition; +} BEST_MODE; + +static const int auto_speed_thresh[17] = +{ + 1000, + 200, + 150, + 130, + 150, + 125, + 120, + 115, + 115, + 115, + 115, + 115, + 115, + 115, + 115, + 115, + 105 +}; + +const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES] = +{ + ZEROMV, + DC_PRED, + + NEARESTMV, + NEARMV, + + ZEROMV, + NEARESTMV, + + ZEROMV, + NEARESTMV, + + NEARMV, + NEARMV, + + V_PRED, + H_PRED, + TM_PRED, + + NEWMV, + NEWMV, + NEWMV, + + SPLITMV, + SPLITMV, + SPLITMV, + + B_PRED, +}; + +/* This table determines the search order in reference frame priority order, + * which may not necessarily match INTRA,LAST,GOLDEN,ARF + */ +const int vp8_ref_frame_order[MAX_MODES] = +{ + 1, + 0, + + 1, + 1, + + 2, + 2, + + 3, + 3, + + 2, + 3, + + 0, + 0, + 0, + + 1, + 2, + 3, + + 1, + 2, + 3, + + 0, +}; + +static void fill_token_costs( + unsigned int c [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS], + const vp8_prob p [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES] +) +{ + int i, j, k; + + + for (i = 0; i < BLOCK_TYPES; i++) + for (j = 0; j < COEF_BANDS; j++) + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + // check for pt=0 and band > 1 if block type 0 and 0 if blocktype 1 + if(k==0 && j>(i==0) ) + vp8_cost_tokens2((int *)(c [i][j][k]), p [i][j][k], vp8_coef_tree,2); + else + vp8_cost_tokens((int *)(c [i][j][k]), p [i][j][k], vp8_coef_tree); +} + +static int rd_iifactor [ 32 ] = { 4, 4, 3, 2, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + +/* values are now correlated to quantizer */ +static int sad_per_bit16lut[QINDEX_RANGE] = +{ + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 10, + 10, 10, 10, 10, 10, 10, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 14, 14 +}; +static int sad_per_bit4lut[QINDEX_RANGE] = +{ + 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, 17, 18, + 18, 18, 19, 19, 19, 20, 20, 20, +}; + +void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex) +{ + cpi->mb.sadperbit16 = sad_per_bit16lut[QIndex]; + cpi->mb.sadperbit4 = sad_per_bit4lut[QIndex]; +} + +void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue) +{ + int q; + int i; + double capped_q = (Qvalue < 160) ? (double)Qvalue : 160.0; + double rdconst = 2.80; + + vp8_clear_system_state(); //__asm emms; + + // Further tests required to see if optimum is different + // for key frames, golden frames and arf frames. + // if (cpi->common.refresh_golden_frame || + // cpi->common.refresh_alt_ref_frame) + cpi->RDMULT = (int)(rdconst * (capped_q * capped_q)); + + // Extend rate multiplier along side quantizer zbin increases + if (cpi->zbin_over_quant > 0) + { + double oq_factor; + double modq; + + // Experimental code using the same basic equation as used for Q above + // The units of cpi->zbin_over_quant are 1/128 of Q bin size + oq_factor = 1.0 + ((double)0.0015625 * cpi->zbin_over_quant); + modq = (int)((double)capped_q * oq_factor); + cpi->RDMULT = (int)(rdconst * (modq * modq)); + } + + if (cpi->pass == 2 && (cpi->common.frame_type != KEY_FRAME)) + { + if (cpi->twopass.next_iiratio > 31) + cpi->RDMULT += (cpi->RDMULT * rd_iifactor[31]) >> 4; + else + cpi->RDMULT += + (cpi->RDMULT * rd_iifactor[cpi->twopass.next_iiratio]) >> 4; + } + + cpi->mb.errorperbit = (cpi->RDMULT / 110); + cpi->mb.errorperbit += (cpi->mb.errorperbit==0); + + vp8_set_speed_features(cpi); + + q = (int)pow(Qvalue, 1.25); + + if (q < 8) + q = 8; + + if (cpi->RDMULT > 1000) + { + cpi->RDDIV = 1; + cpi->RDMULT /= 100; + + for (i = 0; i < MAX_MODES; i++) + { + if (cpi->sf.thresh_mult[i] < INT_MAX) + { + cpi->rd_threshes[i] = cpi->sf.thresh_mult[i] * q / 100; + } + else + { + cpi->rd_threshes[i] = INT_MAX; + } + + cpi->rd_baseline_thresh[i] = cpi->rd_threshes[i]; + } + } + else + { + cpi->RDDIV = 100; + + for (i = 0; i < MAX_MODES; i++) + { + if (cpi->sf.thresh_mult[i] < (INT_MAX / q)) + { + cpi->rd_threshes[i] = cpi->sf.thresh_mult[i] * q; + } + else + { + cpi->rd_threshes[i] = INT_MAX; + } + + cpi->rd_baseline_thresh[i] = cpi->rd_threshes[i]; + } + } + + { + // build token cost array for the type of frame we have now + FRAME_CONTEXT *l = &cpi->lfc_n; + + if(cpi->common.refresh_alt_ref_frame) + l = &cpi->lfc_a; + else if(cpi->common.refresh_golden_frame) + l = &cpi->lfc_g; + + fill_token_costs( + cpi->mb.token_costs, + (const vp8_prob( *)[8][3][11]) l->coef_probs + ); + /* + fill_token_costs( + cpi->mb.token_costs, + (const vp8_prob( *)[8][3][11]) cpi->common.fc.coef_probs); + */ + + + // TODO make these mode costs depend on last,alt or gold too. (jbb) + vp8_init_mode_costs(cpi); + + // TODO figure onnnnuut why making mv cost frame type dependent didn't help (jbb) + //vp8_build_component_cost_table(cpi->mb.mvcost, (const MV_CONTEXT *) l->mvc, flags); + + } + +} + +void vp8_auto_select_speed(VP8_COMP *cpi) +{ + int milliseconds_for_compress = (int)(1000000 / cpi->frame_rate); + + milliseconds_for_compress = milliseconds_for_compress * (16 - cpi->oxcf.cpu_used) / 16; + +#if 0 + + if (0) + { + FILE *f; + + f = fopen("speed.stt", "a"); + fprintf(f, " %8ld %10ld %10ld %10ld\n", + cpi->common.current_video_frame, cpi->Speed, milliseconds_for_compress, cpi->avg_pick_mode_time); + fclose(f); + } + +#endif + + /* + // this is done during parameter valid check + if( cpi->oxcf.cpu_used > 16) + cpi->oxcf.cpu_used = 16; + if( cpi->oxcf.cpu_used < -16) + cpi->oxcf.cpu_used = -16; + */ + + if (cpi->avg_pick_mode_time < milliseconds_for_compress && (cpi->avg_encode_time - cpi->avg_pick_mode_time) < milliseconds_for_compress) + { + if (cpi->avg_pick_mode_time == 0) + { + cpi->Speed = 4; + } + else + { + if (milliseconds_for_compress * 100 < cpi->avg_encode_time * 95) + { + cpi->Speed += 2; + cpi->avg_pick_mode_time = 0; + cpi->avg_encode_time = 0; + + if (cpi->Speed > 16) + { + cpi->Speed = 16; + } + } + + if (milliseconds_for_compress * 100 > cpi->avg_encode_time * auto_speed_thresh[cpi->Speed]) + { + cpi->Speed -= 1; + cpi->avg_pick_mode_time = 0; + cpi->avg_encode_time = 0; + + // In real-time mode, cpi->speed is in [4, 16]. + if (cpi->Speed < 4) //if ( cpi->Speed < 0 ) + { + cpi->Speed = 4; //cpi->Speed = 0; + } + } + } + } + else + { + cpi->Speed += 4; + + if (cpi->Speed > 16) + cpi->Speed = 16; + + + cpi->avg_pick_mode_time = 0; + cpi->avg_encode_time = 0; + } +} + +int vp8_block_error_c(short *coeff, short *dqcoeff) +{ + int i; + int error = 0; + + for (i = 0; i < 16; i++) + { + int this_diff = coeff[i] - dqcoeff[i]; + error += this_diff * this_diff; + } + + return error; +} + +int vp8_mbblock_error_c(MACROBLOCK *mb, int dc) +{ + BLOCK *be; + BLOCKD *bd; + int i, j; + int berror, error = 0; + + for (i = 0; i < 16; i++) + { + be = &mb->block[i]; + bd = &mb->e_mbd.block[i]; + + berror = 0; + + for (j = dc; j < 16; j++) + { + int this_diff = be->coeff[j] - bd->dqcoeff[j]; + berror += this_diff * this_diff; + } + + error += berror; + } + + return error; +} + +int vp8_mbuverror_c(MACROBLOCK *mb) +{ + + BLOCK *be; + BLOCKD *bd; + + + int i; + int error = 0; + + for (i = 16; i < 24; i++) + { + be = &mb->block[i]; + bd = &mb->e_mbd.block[i]; + + error += vp8_block_error_c(be->coeff, bd->dqcoeff); + } + + return error; +} + +int VP8_UVSSE(MACROBLOCK *x) +{ + unsigned char *uptr, *vptr; + unsigned char *upred_ptr = (*(x->block[16].base_src) + x->block[16].src); + unsigned char *vpred_ptr = (*(x->block[20].base_src) + x->block[20].src); + int uv_stride = x->block[16].src_stride; + + unsigned int sse1 = 0; + unsigned int sse2 = 0; + int mv_row = x->e_mbd.mode_info_context->mbmi.mv.as_mv.row; + int mv_col = x->e_mbd.mode_info_context->mbmi.mv.as_mv.col; + int offset; + int pre_stride = x->e_mbd.pre.uv_stride; + + if (mv_row < 0) + mv_row -= 1; + else + mv_row += 1; + + if (mv_col < 0) + mv_col -= 1; + else + mv_col += 1; + + mv_row /= 2; + mv_col /= 2; + + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->e_mbd.pre.u_buffer + offset; + vptr = x->e_mbd.pre.v_buffer + offset; + + if ((mv_row | mv_col) & 7) + { + vp8_sub_pixel_variance8x8(uptr, pre_stride, + mv_col & 7, mv_row & 7, upred_ptr, uv_stride, &sse2); + vp8_sub_pixel_variance8x8(vptr, pre_stride, + mv_col & 7, mv_row & 7, vpred_ptr, uv_stride, &sse1); + sse2 += sse1; + } + else + { + vp8_variance8x8(uptr, pre_stride, + upred_ptr, uv_stride, &sse2); + vp8_variance8x8(vptr, pre_stride, + vpred_ptr, uv_stride, &sse1); + sse2 += sse1; + } + return sse2; + +} + +static int cost_coeffs(MACROBLOCK *mb, BLOCKD *b, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int c = !type; /* start at coef 0, unless Y with Y2 */ + int eob = (int)(*b->eob); + int pt ; /* surrounding block/prev coef predictor */ + int cost = 0; + short *qcoeff_ptr = b->qcoeff; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + +# define QC( I) ( qcoeff_ptr [vp8_default_zig_zag1d[I]] ) + + for (; c < eob; c++) + { + int v = QC(c); + int t = vp8_dct_value_tokens_ptr[v].Token; + cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [t]; + cost += vp8_dct_value_cost_ptr[v]; + pt = vp8_prev_token_class[t]; + } + +# undef QC + + if (c < 16) + cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [DCT_EOB_TOKEN]; + + pt = (c != !type); // is eob first coefficient; + *a = *l = pt; + + return cost; +} + +static int vp8_rdcost_mby(MACROBLOCK *mb) +{ + int cost = 0; + int b; + MACROBLOCKD *x = &mb->e_mbd; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + vpx_memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + for (b = 0; b < 16; b++) + cost += cost_coeffs(mb, x->block + b, PLANE_TYPE_Y_NO_DC, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + + cost += cost_coeffs(mb, x->block + 24, PLANE_TYPE_Y2, + ta + vp8_block2above[24], tl + vp8_block2left[24]); + + return cost; +} + +static void macro_block_yrd( MACROBLOCK *mb, + int *Rate, + int *Distortion) +{ + int b; + MACROBLOCKD *const x = &mb->e_mbd; + BLOCK *const mb_y2 = mb->block + 24; + BLOCKD *const x_y2 = x->block + 24; + short *Y2DCPtr = mb_y2->src_diff; + BLOCK *beptr; + int d; + + vp8_subtract_mby( mb->src_diff, *(mb->block[0].base_src), + mb->block[0].src_stride, mb->e_mbd.predictor, 16); + + // Fdct and building the 2nd order block + for (beptr = mb->block; beptr < mb->block + 16; beptr += 2) + { + mb->short_fdct8x4(beptr->src_diff, beptr->coeff, 32); + *Y2DCPtr++ = beptr->coeff[0]; + *Y2DCPtr++ = beptr->coeff[16]; + } + + // 2nd order fdct + mb->short_walsh4x4(mb_y2->src_diff, mb_y2->coeff, 8); + + // Quantization + for (b = 0; b < 16; b++) + { + mb->quantize_b(&mb->block[b], &mb->e_mbd.block[b]); + } + + // DC predication and Quantization of 2nd Order block + mb->quantize_b(mb_y2, x_y2); + + // Distortion + d = vp8_mbblock_error(mb, 1) << 2; + d += vp8_block_error(mb_y2->coeff, x_y2->dqcoeff); + + *Distortion = (d >> 4); + + // rate + *Rate = vp8_rdcost_mby(mb); +} + +static void copy_predictor(unsigned char *dst, const unsigned char *predictor) +{ + const unsigned int *p = (const unsigned int *)predictor; + unsigned int *d = (unsigned int *)dst; + d[0] = p[0]; + d[4] = p[4]; + d[8] = p[8]; + d[12] = p[12]; +} +static int rd_pick_intra4x4block( + VP8_COMP *cpi, + MACROBLOCK *x, + BLOCK *be, + BLOCKD *b, + B_PREDICTION_MODE *best_mode, + unsigned int *bmode_costs, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + + int *bestrate, + int *bestratey, + int *bestdistortion) +{ + B_PREDICTION_MODE mode; + int best_rd = INT_MAX; + int rate = 0; + int distortion; + + ENTROPY_CONTEXT ta = *a, tempa = *a; + ENTROPY_CONTEXT tl = *l, templ = *l; + /* + * The predictor buffer is a 2d buffer with a stride of 16. Create + * a temp buffer that meets the stride requirements, but we are only + * interested in the left 4x4 block + * */ + DECLARE_ALIGNED_ARRAY(16, unsigned char, best_predictor, 16*4); + DECLARE_ALIGNED_ARRAY(16, short, best_dqcoeff, 16); + int dst_stride = x->e_mbd.dst.y_stride; + unsigned char *base_dst = x->e_mbd.dst.y_buffer; + + for (mode = B_DC_PRED; mode <= B_HU_PRED; mode++) + { + int this_rd; + int ratey; + + rate = bmode_costs[mode]; + + vp8_intra4x4_predict(base_dst + b->offset, dst_stride, mode, + b->predictor, 16); + vp8_subtract_b(be, b, 16); + x->short_fdct4x4(be->src_diff, be->coeff, 32); + x->quantize_b(be, b); + + tempa = ta; + templ = tl; + + ratey = cost_coeffs(x, b, PLANE_TYPE_Y_WITH_DC, &tempa, &templ); + rate += ratey; + distortion = vp8_block_error(be->coeff, b->dqcoeff) >> 2; + + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + *bestrate = rate; + *bestratey = ratey; + *bestdistortion = distortion; + best_rd = this_rd; + *best_mode = mode; + *a = tempa; + *l = templ; + copy_predictor(best_predictor, b->predictor); + vpx_memcpy(best_dqcoeff, b->dqcoeff, 32); + } + } + b->bmi.as_mode = (B_PREDICTION_MODE)(*best_mode); + + vp8_short_idct4x4llm(best_dqcoeff, best_predictor, 16, base_dst + b->offset, + dst_stride); + + return best_rd; +} + +static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, + int *rate_y, int *Distortion, int best_rd) +{ + MACROBLOCKD *const xd = &mb->e_mbd; + int i; + int cost = mb->mbmode_cost [xd->frame_type] [B_PRED]; + int distortion = 0; + int tot_rate_y = 0; + int64_t total_rd = 0; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + unsigned int *bmode_costs; + + vpx_memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + intra_prediction_down_copy(xd, xd->dst.y_buffer - xd->dst.y_stride + 16); + + bmode_costs = mb->inter_bmode_costs; + + for (i = 0; i < 16; i++) + { + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); + int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(ry), UNINITIALIZED_IS_SAFE(d); + + if (mb->e_mbd.frame_type == KEY_FRAME) + { + const B_PREDICTION_MODE A = above_block_mode(mic, i, mis); + const B_PREDICTION_MODE L = left_block_mode(mic, i); + + bmode_costs = mb->bmode_costs[A][L]; + } + + total_rd += rd_pick_intra4x4block( + cpi, mb, mb->block + i, xd->block + i, &best_mode, bmode_costs, + ta + vp8_block2above[i], + tl + vp8_block2left[i], &r, &ry, &d); + + cost += r; + distortion += d; + tot_rate_y += ry; + + mic->bmi[i].as_mode = best_mode; + + if(total_rd >= (int64_t)best_rd) + break; + } + + if(total_rd >= (int64_t)best_rd) + return INT_MAX; + + *Rate = cost; + *rate_y = tot_rate_y; + *Distortion = distortion; + + return RDCOST(mb->rdmult, mb->rddiv, cost, distortion); +} + + +static int rd_pick_intra16x16mby_mode(VP8_COMP *cpi, + MACROBLOCK *x, + int *Rate, + int *rate_y, + int *Distortion) +{ + MB_PREDICTION_MODE mode; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); + int rate, ratey; + int distortion; + int best_rd = INT_MAX; + int this_rd; + MACROBLOCKD *xd = &x->e_mbd; + + //Y Search for 16x16 intra prediction mode + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { + xd->mode_info_context->mbmi.mode = mode; + + vp8_build_intra_predictors_mby_s(xd, + xd->dst.y_buffer - xd->dst.y_stride, + xd->dst.y_buffer - 1, + xd->dst.y_stride, + xd->predictor, + 16); + + macro_block_yrd(x, &ratey, &distortion); + rate = ratey + x->mbmode_cost[xd->frame_type] + [xd->mode_info_context->mbmi.mode]; + + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + mode_selected = mode; + best_rd = this_rd; + *Rate = rate; + *rate_y = ratey; + *Distortion = distortion; + } + } + + xd->mode_info_context->mbmi.mode = mode_selected; + return best_rd; +} + +static int rd_cost_mbuv(MACROBLOCK *mb) +{ + int b; + int cost = 0; + MACROBLOCKD *x = &mb->e_mbd; + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + + vpx_memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + + for (b = 16; b < 24; b++) + cost += cost_coeffs(mb, x->block + b, PLANE_TYPE_UV, + ta + vp8_block2above[b], tl + vp8_block2left[b]); + + return cost; +} + + +static int rd_inter16x16_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, + int *distortion, int fullpixel) +{ + vp8_build_inter16x16_predictors_mbuv(&x->e_mbd); + vp8_subtract_mbuv(x->src_diff, + x->src.u_buffer, x->src.v_buffer, x->src.uv_stride, + &x->e_mbd.predictor[256], &x->e_mbd.predictor[320], 8); + + vp8_transform_mbuv(x); + vp8_quantize_mbuv(x); + + *rate = rd_cost_mbuv(x); + *distortion = vp8_mbuverror(x) / 4; + + return RDCOST(x->rdmult, x->rddiv, *rate, *distortion); +} + +static int rd_inter4x4_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, + int *distortion, int fullpixel) +{ + vp8_build_inter4x4_predictors_mbuv(&x->e_mbd); + vp8_subtract_mbuv(x->src_diff, + x->src.u_buffer, x->src.v_buffer, x->src.uv_stride, + &x->e_mbd.predictor[256], &x->e_mbd.predictor[320], 8); + + vp8_transform_mbuv(x); + vp8_quantize_mbuv(x); + + *rate = rd_cost_mbuv(x); + *distortion = vp8_mbuverror(x) / 4; + + return RDCOST(x->rdmult, x->rddiv, *rate, *distortion); +} + +static void rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *rate_tokenonly, int *distortion) +{ + MB_PREDICTION_MODE mode; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); + int best_rd = INT_MAX; + int UNINITIALIZED_IS_SAFE(d), UNINITIALIZED_IS_SAFE(r); + int rate_to; + MACROBLOCKD *xd = &x->e_mbd; + + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { + int rate; + int distortion; + int this_rd; + + xd->mode_info_context->mbmi.uv_mode = mode; + + vp8_build_intra_predictors_mbuv_s(xd, + xd->dst.u_buffer - xd->dst.uv_stride, + xd->dst.v_buffer - xd->dst.uv_stride, + xd->dst.u_buffer - 1, + xd->dst.v_buffer - 1, + xd->dst.uv_stride, + &xd->predictor[256], &xd->predictor[320], + 8); + + + vp8_subtract_mbuv(x->src_diff, + x->src.u_buffer, x->src.v_buffer, x->src.uv_stride, + &xd->predictor[256], &xd->predictor[320], 8); + vp8_transform_mbuv(x); + vp8_quantize_mbuv(x); + + rate_to = rd_cost_mbuv(x); + rate = rate_to + x->intra_uv_mode_cost[xd->frame_type][xd->mode_info_context->mbmi.uv_mode]; + + distortion = vp8_mbuverror(x) / 4; + + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + best_rd = this_rd; + d = distortion; + r = rate; + *rate_tokenonly = rate_to; + mode_selected = mode; + } + } + + *rate = r; + *distortion = d; + + xd->mode_info_context->mbmi.uv_mode = mode_selected; +} + +int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]) +{ + vp8_prob p [VP8_MVREFS-1]; + assert(NEARESTMV <= m && m <= SPLITMV); + vp8_mv_ref_probs(p, near_mv_ref_ct); + return vp8_cost_token(vp8_mv_ref_tree, p, + vp8_mv_ref_encoding_array - NEARESTMV + m); +} + +void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, int_mv *mv) +{ + x->e_mbd.mode_info_context->mbmi.mode = mb; + x->e_mbd.mode_info_context->mbmi.mv.as_int = mv->as_int; +} + +static int labels2mode( + MACROBLOCK *x, + int const *labelings, int which_label, + B_PREDICTION_MODE this_mode, + int_mv *this_mv, int_mv *best_ref_mv, + int *mvcost[2] +) +{ + MACROBLOCKD *const xd = & x->e_mbd; + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + + int cost = 0; + int thismvcost = 0; + + /* We have to be careful retrieving previously-encoded motion vectors. + Ones from this macroblock have to be pulled from the BLOCKD array + as they have not yet made it to the bmi array in our MB_MODE_INFO. */ + + int i = 0; + + do + { + BLOCKD *const d = xd->block + i; + const int row = i >> 2, col = i & 3; + + B_PREDICTION_MODE m; + + if (labelings[i] != which_label) + continue; + + if (col && labelings[i] == labelings[i-1]) + m = LEFT4X4; + else if (row && labelings[i] == labelings[i-4]) + m = ABOVE4X4; + else + { + // the only time we should do costing for new motion vector or mode + // is when we are on a new label (jbb May 08, 2007) + switch (m = this_mode) + { + case NEW4X4 : + thismvcost = vp8_mv_bit_cost(this_mv, best_ref_mv, mvcost, 102); + break; + case LEFT4X4: + this_mv->as_int = col ? d[-1].bmi.mv.as_int : left_block_mv(mic, i); + break; + case ABOVE4X4: + this_mv->as_int = row ? d[-4].bmi.mv.as_int : above_block_mv(mic, i, mis); + break; + case ZERO4X4: + this_mv->as_int = 0; + break; + default: + break; + } + + if (m == ABOVE4X4) // replace above with left if same + { + int_mv left_mv; + + left_mv.as_int = col ? d[-1].bmi.mv.as_int : + left_block_mv(mic, i); + + if (left_mv.as_int == this_mv->as_int) + m = LEFT4X4; + } + + cost = x->inter_bmode_costs[ m]; + } + + d->bmi.mv.as_int = this_mv->as_int; + + x->partition_info->bmi[i].mode = m; + x->partition_info->bmi[i].mv.as_int = this_mv->as_int; + + } + while (++i < 16); + + cost += thismvcost ; + return cost; +} + +static int rdcost_mbsegment_y(MACROBLOCK *mb, const int *labels, + int which_label, ENTROPY_CONTEXT *ta, + ENTROPY_CONTEXT *tl) +{ + int cost = 0; + int b; + MACROBLOCKD *x = &mb->e_mbd; + + for (b = 0; b < 16; b++) + if (labels[ b] == which_label) + cost += cost_coeffs(mb, x->block + b, PLANE_TYPE_Y_WITH_DC, + ta + vp8_block2above[b], + tl + vp8_block2left[b]); + + return cost; + +} +static unsigned int vp8_encode_inter_mb_segment(MACROBLOCK *x, int const *labels, int which_label) +{ + int i; + unsigned int distortion = 0; + int pre_stride = x->e_mbd.pre.y_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + + + for (i = 0; i < 16; i++) + { + if (labels[i] == which_label) + { + BLOCKD *bd = &x->e_mbd.block[i]; + BLOCK *be = &x->block[i]; + + vp8_build_inter_predictors_b(bd, 16, base_pre, pre_stride, x->e_mbd.subpixel_predict); + vp8_subtract_b(be, bd, 16); + x->short_fdct4x4(be->src_diff, be->coeff, 32); + + // set to 0 no way to account for 2nd order DC so discount + //be->coeff[0] = 0; + x->quantize_b(be, bd); + + distortion += vp8_block_error(be->coeff, bd->dqcoeff); + } + } + + return distortion; +} + + +static const unsigned int segmentation_to_sseshift[4] = {3, 3, 2, 0}; + + +typedef struct +{ + int_mv *ref_mv; + int_mv mvp; + + int segment_rd; + int segment_num; + int r; + int d; + int segment_yrate; + B_PREDICTION_MODE modes[16]; + int_mv mvs[16]; + unsigned char eobs[16]; + + int mvthresh; + int *mdcounts; + + int_mv sv_mvp[4]; // save 4 mvp from 8x8 + int sv_istep[2]; // save 2 initial step_param for 16x8/8x16 + +} BEST_SEG_INFO; + + +static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, + BEST_SEG_INFO *bsi, unsigned int segmentation) +{ + int i; + int const *labels; + int br = 0; + int bd = 0; + B_PREDICTION_MODE this_mode; + + + int label_count; + int this_segment_rd = 0; + int label_mv_thresh; + int rate = 0; + int sbr = 0; + int sbd = 0; + int segmentyrate = 0; + + vp8_variance_fn_ptr_t *v_fn_ptr; + + ENTROPY_CONTEXT_PLANES t_above, t_left; + ENTROPY_CONTEXT *ta; + ENTROPY_CONTEXT *tl; + ENTROPY_CONTEXT_PLANES t_above_b, t_left_b; + ENTROPY_CONTEXT *ta_b; + ENTROPY_CONTEXT *tl_b; + + vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta = (ENTROPY_CONTEXT *)&t_above; + tl = (ENTROPY_CONTEXT *)&t_left; + ta_b = (ENTROPY_CONTEXT *)&t_above_b; + tl_b = (ENTROPY_CONTEXT *)&t_left_b; + + br = 0; + bd = 0; + + v_fn_ptr = &cpi->fn_ptr[segmentation]; + labels = vp8_mbsplits[segmentation]; + label_count = vp8_mbsplit_count[segmentation]; + + // 64 makes this threshold really big effectively + // making it so that we very rarely check mvs on + // segments. setting this to 1 would make mv thresh + // roughly equal to what it is for macroblocks + label_mv_thresh = 1 * bsi->mvthresh / label_count ; + + // Segmentation method overheads + rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation); + rate += vp8_cost_mv_ref(SPLITMV, bsi->mdcounts); + this_segment_rd += RDCOST(x->rdmult, x->rddiv, rate, 0); + br += rate; + + for (i = 0; i < label_count; i++) + { + int_mv mode_mv[B_MODE_COUNT]; + int best_label_rd = INT_MAX; + B_PREDICTION_MODE mode_selected = ZERO4X4; + int bestlabelyrate = 0; + + // search for the best motion vector on this segment + for (this_mode = LEFT4X4; this_mode <= NEW4X4 ; this_mode ++) + { + int this_rd; + int distortion; + int labelyrate; + ENTROPY_CONTEXT_PLANES t_above_s, t_left_s; + ENTROPY_CONTEXT *ta_s; + ENTROPY_CONTEXT *tl_s; + + vpx_memcpy(&t_above_s, &t_above, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(&t_left_s, &t_left, sizeof(ENTROPY_CONTEXT_PLANES)); + + ta_s = (ENTROPY_CONTEXT *)&t_above_s; + tl_s = (ENTROPY_CONTEXT *)&t_left_s; + + if (this_mode == NEW4X4) + { + int sseshift; + int num00; + int step_param = 0; + int further_steps; + int n; + int thissme; + int bestsme = INT_MAX; + int_mv temp_mv; + BLOCK *c; + BLOCKD *e; + + // Is the best so far sufficiently good that we cant justify doing and new motion search. + if (best_label_rd < label_mv_thresh) + break; + + if(cpi->compressor_speed) + { + if (segmentation == BLOCK_8X16 || segmentation == BLOCK_16X8) + { + bsi->mvp.as_int = bsi->sv_mvp[i].as_int; + if (i==1 && segmentation == BLOCK_16X8) + bsi->mvp.as_int = bsi->sv_mvp[2].as_int; + + step_param = bsi->sv_istep[i]; + } + + // use previous block's result as next block's MV predictor. + if (segmentation == BLOCK_4X4 && i>0) + { + bsi->mvp.as_int = x->e_mbd.block[i-1].bmi.mv.as_int; + if (i==4 || i==8 || i==12) + bsi->mvp.as_int = x->e_mbd.block[i-4].bmi.mv.as_int; + step_param = 2; + } + } + + further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param; + + { + int sadpb = x->sadperbit4; + int_mv mvp_full; + + mvp_full.as_mv.row = bsi->mvp.as_mv.row >>3; + mvp_full.as_mv.col = bsi->mvp.as_mv.col >>3; + + // find first label + n = vp8_mbsplit_offset[segmentation][i]; + + c = &x->block[n]; + e = &x->e_mbd.block[n]; + + { + bestsme = cpi->diamond_search_sad(x, c, e, &mvp_full, + &mode_mv[NEW4X4], step_param, + sadpb, &num00, v_fn_ptr, + x->mvcost, bsi->ref_mv); + + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = cpi->diamond_search_sad(x, c, e, + &mvp_full, &temp_mv, + step_param + n, sadpb, + &num00, v_fn_ptr, + x->mvcost, bsi->ref_mv); + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEW4X4].as_int = temp_mv.as_int; + } + } + } + } + + sseshift = segmentation_to_sseshift[segmentation]; + + // Should we do a full search (best quality only) + if ((cpi->compressor_speed == 0) && (bestsme >> sseshift) > 4000) + { + /* Check if mvp_full is within the range. */ + vp8_clamp_mv(&mvp_full, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max); + + thissme = cpi->full_search_sad(x, c, e, &mvp_full, + sadpb, 16, v_fn_ptr, + x->mvcost, bsi->ref_mv); + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEW4X4].as_int = e->bmi.mv.as_int; + } + else + { + // The full search result is actually worse so re-instate the previous best vector + e->bmi.mv.as_int = mode_mv[NEW4X4].as_int; + } + } + } + + if (bestsme < INT_MAX) + { + int distortion; + unsigned int sse; + cpi->find_fractional_mv_step(x, c, e, &mode_mv[NEW4X4], + bsi->ref_mv, x->errorperbit, v_fn_ptr, x->mvcost, + &distortion, &sse); + + } + } /* NEW4X4 */ + + rate = labels2mode(x, labels, i, this_mode, &mode_mv[this_mode], + bsi->ref_mv, x->mvcost); + + // Trap vectors that reach beyond the UMV borders + if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) + { + continue; + } + + distortion = vp8_encode_inter_mb_segment(x, labels, i) / 4; + + labelyrate = rdcost_mbsegment_y(x, labels, i, ta_s, tl_s); + rate += labelyrate; + + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_label_rd) + { + sbr = rate; + sbd = distortion; + bestlabelyrate = labelyrate; + mode_selected = this_mode; + best_label_rd = this_rd; + + vpx_memcpy(ta_b, ta_s, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(tl_b, tl_s, sizeof(ENTROPY_CONTEXT_PLANES)); + + } + } /*for each 4x4 mode*/ + + vpx_memcpy(ta, ta_b, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memcpy(tl, tl_b, sizeof(ENTROPY_CONTEXT_PLANES)); + + labels2mode(x, labels, i, mode_selected, &mode_mv[mode_selected], + bsi->ref_mv, x->mvcost); + + br += sbr; + bd += sbd; + segmentyrate += bestlabelyrate; + this_segment_rd += best_label_rd; + + if (this_segment_rd >= bsi->segment_rd) + break; + + } /* for each label */ + + if (this_segment_rd < bsi->segment_rd) + { + bsi->r = br; + bsi->d = bd; + bsi->segment_yrate = segmentyrate; + bsi->segment_rd = this_segment_rd; + bsi->segment_num = segmentation; + + // store everything needed to come back to this!! + for (i = 0; i < 16; i++) + { + bsi->mvs[i].as_mv = x->partition_info->bmi[i].mv.as_mv; + bsi->modes[i] = x->partition_info->bmi[i].mode; + bsi->eobs[i] = x->e_mbd.eobs[i]; + } + } +} + +static +void vp8_cal_step_param(int sr, int *sp) +{ + int step = 0; + + if (sr > MAX_FIRST_STEP) sr = MAX_FIRST_STEP; + else if (sr < 1) sr = 1; + + while (sr>>=1) + step++; + + *sp = MAX_MVSEARCH_STEPS - 1 - step; +} + +static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x, + int_mv *best_ref_mv, int best_rd, + int *mdcounts, int *returntotrate, + int *returnyrate, int *returndistortion, + int mvthresh) +{ + int i; + BEST_SEG_INFO bsi; + + vpx_memset(&bsi, 0, sizeof(bsi)); + + bsi.segment_rd = best_rd; + bsi.ref_mv = best_ref_mv; + bsi.mvp.as_int = best_ref_mv->as_int; + bsi.mvthresh = mvthresh; + bsi.mdcounts = mdcounts; + + for(i = 0; i < 16; i++) + { + bsi.modes[i] = ZERO4X4; + } + + if(cpi->compressor_speed == 0) + { + /* for now, we will keep the original segmentation order + when in best quality mode */ + rd_check_segment(cpi, x, &bsi, BLOCK_16X8); + rd_check_segment(cpi, x, &bsi, BLOCK_8X16); + rd_check_segment(cpi, x, &bsi, BLOCK_8X8); + rd_check_segment(cpi, x, &bsi, BLOCK_4X4); + } + else + { + int sr; + + rd_check_segment(cpi, x, &bsi, BLOCK_8X8); + + if (bsi.segment_rd < best_rd) + { + int col_min = ((best_ref_mv->as_mv.col+7)>>3) - MAX_FULL_PEL_VAL; + int row_min = ((best_ref_mv->as_mv.row+7)>>3) - MAX_FULL_PEL_VAL; + int col_max = (best_ref_mv->as_mv.col>>3) + MAX_FULL_PEL_VAL; + int row_max = (best_ref_mv->as_mv.row>>3) + MAX_FULL_PEL_VAL; + + int tmp_col_min = x->mv_col_min; + int tmp_col_max = x->mv_col_max; + int tmp_row_min = x->mv_row_min; + int tmp_row_max = x->mv_row_max; + + /* Get intersection of UMV window and valid MV window to reduce # of checks in diamond search. */ + if (x->mv_col_min < col_min ) + x->mv_col_min = col_min; + if (x->mv_col_max > col_max ) + x->mv_col_max = col_max; + if (x->mv_row_min < row_min ) + x->mv_row_min = row_min; + if (x->mv_row_max > row_max ) + x->mv_row_max = row_max; + + /* Get 8x8 result */ + bsi.sv_mvp[0].as_int = bsi.mvs[0].as_int; + bsi.sv_mvp[1].as_int = bsi.mvs[2].as_int; + bsi.sv_mvp[2].as_int = bsi.mvs[8].as_int; + bsi.sv_mvp[3].as_int = bsi.mvs[10].as_int; + + /* Use 8x8 result as 16x8/8x16's predictor MV. Adjust search range according to the closeness of 2 MV. */ + /* block 8X16 */ + { + sr = MAXF((abs(bsi.sv_mvp[0].as_mv.row - bsi.sv_mvp[2].as_mv.row))>>3, (abs(bsi.sv_mvp[0].as_mv.col - bsi.sv_mvp[2].as_mv.col))>>3); + vp8_cal_step_param(sr, &bsi.sv_istep[0]); + + sr = MAXF((abs(bsi.sv_mvp[1].as_mv.row - bsi.sv_mvp[3].as_mv.row))>>3, (abs(bsi.sv_mvp[1].as_mv.col - bsi.sv_mvp[3].as_mv.col))>>3); + vp8_cal_step_param(sr, &bsi.sv_istep[1]); + + rd_check_segment(cpi, x, &bsi, BLOCK_8X16); + } + + /* block 16X8 */ + { + sr = MAXF((abs(bsi.sv_mvp[0].as_mv.row - bsi.sv_mvp[1].as_mv.row))>>3, (abs(bsi.sv_mvp[0].as_mv.col - bsi.sv_mvp[1].as_mv.col))>>3); + vp8_cal_step_param(sr, &bsi.sv_istep[0]); + + sr = MAXF((abs(bsi.sv_mvp[2].as_mv.row - bsi.sv_mvp[3].as_mv.row))>>3, (abs(bsi.sv_mvp[2].as_mv.col - bsi.sv_mvp[3].as_mv.col))>>3); + vp8_cal_step_param(sr, &bsi.sv_istep[1]); + + rd_check_segment(cpi, x, &bsi, BLOCK_16X8); + } + + /* If 8x8 is better than 16x8/8x16, then do 4x4 search */ + /* Not skip 4x4 if speed=0 (good quality) */ + if (cpi->sf.no_skip_block4x4_search || bsi.segment_num == BLOCK_8X8) /* || (sv_segment_rd8x8-bsi.segment_rd) < sv_segment_rd8x8>>5) */ + { + bsi.mvp.as_int = bsi.sv_mvp[0].as_int; + rd_check_segment(cpi, x, &bsi, BLOCK_4X4); + } + + /* restore UMV window */ + x->mv_col_min = tmp_col_min; + x->mv_col_max = tmp_col_max; + x->mv_row_min = tmp_row_min; + x->mv_row_max = tmp_row_max; + } + } + + /* set it to the best */ + for (i = 0; i < 16; i++) + { + BLOCKD *bd = &x->e_mbd.block[i]; + + bd->bmi.mv.as_int = bsi.mvs[i].as_int; + *bd->eob = bsi.eobs[i]; + } + + *returntotrate = bsi.r; + *returndistortion = bsi.d; + *returnyrate = bsi.segment_yrate; + + /* save partitions */ + x->e_mbd.mode_info_context->mbmi.partitioning = bsi.segment_num; + x->partition_info->count = vp8_mbsplit_count[bsi.segment_num]; + + for (i = 0; i < x->partition_info->count; i++) + { + int j; + + j = vp8_mbsplit_offset[bsi.segment_num][i]; + + x->partition_info->bmi[i].mode = bsi.modes[j]; + x->partition_info->bmi[i].mv.as_mv = bsi.mvs[j].as_mv; + } + /* + * used to set x->e_mbd.mode_info_context->mbmi.mv.as_int + */ + x->partition_info->bmi[15].mv.as_int = bsi.mvs[15].as_int; + + return bsi.segment_rd; +} + +//The improved MV prediction +void vp8_mv_pred +( + VP8_COMP *cpi, + MACROBLOCKD *xd, + const MODE_INFO *here, + int_mv *mvp, + int refframe, + int *ref_frame_sign_bias, + int *sr, + int near_sadidx[] +) +{ + const MODE_INFO *above = here - xd->mode_info_stride; + const MODE_INFO *left = here - 1; + const MODE_INFO *aboveleft = above - 1; + int_mv near_mvs[8]; + int near_ref[8]; + int_mv mv; + int vcnt=0; + int find=0; + int mb_offset; + + int mvx[8]; + int mvy[8]; + int i; + + mv.as_int = 0; + + if(here->mbmi.ref_frame != INTRA_FRAME) + { + near_mvs[0].as_int = near_mvs[1].as_int = near_mvs[2].as_int = near_mvs[3].as_int = near_mvs[4].as_int = near_mvs[5].as_int = near_mvs[6].as_int = near_mvs[7].as_int = 0; + near_ref[0] = near_ref[1] = near_ref[2] = near_ref[3] = near_ref[4] = near_ref[5] = near_ref[6] = near_ref[7] = 0; + + // read in 3 nearby block's MVs from current frame as prediction candidates. + if (above->mbmi.ref_frame != INTRA_FRAME) + { + near_mvs[vcnt].as_int = above->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[above->mbmi.ref_frame], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = above->mbmi.ref_frame; + } + vcnt++; + if (left->mbmi.ref_frame != INTRA_FRAME) + { + near_mvs[vcnt].as_int = left->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[left->mbmi.ref_frame], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = left->mbmi.ref_frame; + } + vcnt++; + if (aboveleft->mbmi.ref_frame != INTRA_FRAME) + { + near_mvs[vcnt].as_int = aboveleft->mbmi.mv.as_int; + mv_bias(ref_frame_sign_bias[aboveleft->mbmi.ref_frame], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = aboveleft->mbmi.ref_frame; + } + vcnt++; + + // read in 5 nearby block's MVs from last frame. + if(cpi->common.last_frame_type != KEY_FRAME) + { + mb_offset = (-xd->mb_to_top_edge/128 + 1) * (xd->mode_info_stride +1) + (-xd->mb_to_left_edge/128 +1) ; + + // current in last frame + if (cpi->lf_ref_frame[mb_offset] != INTRA_FRAME) + { + near_mvs[vcnt].as_int = cpi->lfmv[mb_offset].as_int; + mv_bias(cpi->lf_ref_frame_sign_bias[mb_offset], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = cpi->lf_ref_frame[mb_offset]; + } + vcnt++; + + // above in last frame + if (cpi->lf_ref_frame[mb_offset - xd->mode_info_stride-1] != INTRA_FRAME) + { + near_mvs[vcnt].as_int = cpi->lfmv[mb_offset - xd->mode_info_stride-1].as_int; + mv_bias(cpi->lf_ref_frame_sign_bias[mb_offset - xd->mode_info_stride-1], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = cpi->lf_ref_frame[mb_offset - xd->mode_info_stride-1]; + } + vcnt++; + + // left in last frame + if (cpi->lf_ref_frame[mb_offset-1] != INTRA_FRAME) + { + near_mvs[vcnt].as_int = cpi->lfmv[mb_offset -1].as_int; + mv_bias(cpi->lf_ref_frame_sign_bias[mb_offset -1], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = cpi->lf_ref_frame[mb_offset - 1]; + } + vcnt++; + + // right in last frame + if (cpi->lf_ref_frame[mb_offset +1] != INTRA_FRAME) + { + near_mvs[vcnt].as_int = cpi->lfmv[mb_offset +1].as_int; + mv_bias(cpi->lf_ref_frame_sign_bias[mb_offset +1], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = cpi->lf_ref_frame[mb_offset +1]; + } + vcnt++; + + // below in last frame + if (cpi->lf_ref_frame[mb_offset + xd->mode_info_stride +1] != INTRA_FRAME) + { + near_mvs[vcnt].as_int = cpi->lfmv[mb_offset + xd->mode_info_stride +1].as_int; + mv_bias(cpi->lf_ref_frame_sign_bias[mb_offset + xd->mode_info_stride +1], refframe, &near_mvs[vcnt], ref_frame_sign_bias); + near_ref[vcnt] = cpi->lf_ref_frame[mb_offset + xd->mode_info_stride +1]; + } + vcnt++; + } + + for(i=0; i< vcnt; i++) + { + if(near_ref[near_sadidx[i]] != INTRA_FRAME) + { + if(here->mbmi.ref_frame == near_ref[near_sadidx[i]]) + { + mv.as_int = near_mvs[near_sadidx[i]].as_int; + find = 1; + if (i < 3) + *sr = 3; + else + *sr = 2; + break; + } + } + } + + if(!find) + { + for(i=0; ias_int = mv.as_int; + vp8_clamp_mv2(mvp, xd); +} + +void vp8_cal_sad(VP8_COMP *cpi, MACROBLOCKD *xd, MACROBLOCK *x, int recon_yoffset, int near_sadidx[]) +{ + + int near_sad[8] = {0}; // 0-cf above, 1-cf left, 2-cf aboveleft, 3-lf current, 4-lf above, 5-lf left, 6-lf right, 7-lf below + BLOCK *b = &x->block[0]; + unsigned char *src_y_ptr = *(b->base_src); + + //calculate sad for current frame 3 nearby MBs. + if( xd->mb_to_top_edge==0 && xd->mb_to_left_edge ==0) + { + near_sad[0] = near_sad[1] = near_sad[2] = INT_MAX; + }else if(xd->mb_to_top_edge==0) + { //only has left MB for sad calculation. + near_sad[0] = near_sad[2] = INT_MAX; + near_sad[1] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, xd->dst.y_buffer - 16,xd->dst.y_stride, 0x7fffffff); + }else if(xd->mb_to_left_edge ==0) + { //only has left MB for sad calculation. + near_sad[1] = near_sad[2] = INT_MAX; + near_sad[0] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, xd->dst.y_buffer - xd->dst.y_stride *16,xd->dst.y_stride, 0x7fffffff); + }else + { + near_sad[0] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, xd->dst.y_buffer - xd->dst.y_stride *16,xd->dst.y_stride, 0x7fffffff); + near_sad[1] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, xd->dst.y_buffer - 16,xd->dst.y_stride, 0x7fffffff); + near_sad[2] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, xd->dst.y_buffer - xd->dst.y_stride *16 -16,xd->dst.y_stride, 0x7fffffff); + } + + if(cpi->common.last_frame_type != KEY_FRAME) + { + //calculate sad for last frame 5 nearby MBs. + unsigned char *pre_y_buffer = cpi->common.yv12_fb[cpi->common.lst_fb_idx].y_buffer + recon_yoffset; + int pre_y_stride = cpi->common.yv12_fb[cpi->common.lst_fb_idx].y_stride; + + if(xd->mb_to_top_edge==0) near_sad[4] = INT_MAX; + if(xd->mb_to_left_edge ==0) near_sad[5] = INT_MAX; + if(xd->mb_to_right_edge ==0) near_sad[6] = INT_MAX; + if(xd->mb_to_bottom_edge==0) near_sad[7] = INT_MAX; + + if(near_sad[4] != INT_MAX) + near_sad[4] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, pre_y_buffer - pre_y_stride *16, pre_y_stride, 0x7fffffff); + if(near_sad[5] != INT_MAX) + near_sad[5] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, pre_y_buffer - 16, pre_y_stride, 0x7fffffff); + near_sad[3] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, pre_y_buffer, pre_y_stride, 0x7fffffff); + if(near_sad[6] != INT_MAX) + near_sad[6] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, pre_y_buffer + 16, pre_y_stride, 0x7fffffff); + if(near_sad[7] != INT_MAX) + near_sad[7] = cpi->fn_ptr[BLOCK_16X16].sdf(src_y_ptr, b->src_stride, pre_y_buffer + pre_y_stride *16, pre_y_stride, 0x7fffffff); + } + + if(cpi->common.last_frame_type != KEY_FRAME) + { + insertsortsad(near_sad, near_sadidx, 8); + }else + { + insertsortsad(near_sad, near_sadidx, 3); + } +} + +static void rd_update_mvcount(VP8_COMP *cpi, MACROBLOCK *x, int_mv *best_ref_mv) +{ + if (x->e_mbd.mode_info_context->mbmi.mode == SPLITMV) + { + int i; + + for (i = 0; i < x->partition_info->count; i++) + { + if (x->partition_info->bmi[i].mode == NEW4X4) + { + cpi->MVcount[0][mv_max+((x->partition_info->bmi[i].mv.as_mv.row + - best_ref_mv->as_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((x->partition_info->bmi[i].mv.as_mv.col + - best_ref_mv->as_mv.col) >> 1)]++; + } + } + } + else if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV) + { + cpi->MVcount[0][mv_max+((x->e_mbd.mode_info_context->mbmi.mv.as_mv.row + - best_ref_mv->as_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((x->e_mbd.mode_info_context->mbmi.mv.as_mv.col + - best_ref_mv->as_mv.col) >> 1)]++; + } +} + +static int evaluate_inter_mode_rd(int mdcounts[4], + RATE_DISTORTION* rd, + int* disable_skip, + VP8_COMP *cpi, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + BLOCK *b = &x->block[0]; + MACROBLOCKD *xd = &x->e_mbd; + int distortion; + vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16); + + if (cpi->active_map_enabled && x->active_ptr[0] == 0) { + x->skip = 1; + } + else if (x->encode_breakout) + { + unsigned int sse; + unsigned int var; + int threshold = (xd->block[0].dequant[1] + * xd->block[0].dequant[1] >>4); + + if(threshold < x->encode_breakout) + threshold = x->encode_breakout; + + var = vp8_variance16x16 + (*(b->base_src), b->src_stride, + x->e_mbd.predictor, 16, &sse); + + if (sse < threshold) + { + unsigned int q2dc = xd->block[24].dequant[0]; + /* If theres is no codeable 2nd order dc + or a very small uniform pixel change change */ + if ((sse - var < q2dc * q2dc >>4) || + (sse /2 > var && sse-var < 64)) + { + // Check u and v to make sure skip is ok + int sse2= VP8_UVSSE(x); + if (sse2 * 2 < threshold) + { + x->skip = 1; + rd->distortion2 = sse + sse2; + rd->rate2 = 500; + + /* for best_yrd calculation */ + rd->rate_uv = 0; + rd->distortion_uv = sse2; + + *disable_skip = 1; + return RDCOST(x->rdmult, x->rddiv, rd->rate2, + rd->distortion2); + } + } + } + } + + + //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code + + // Add in the Mv/mode cost + rd->rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + + // Y cost and distortion + macro_block_yrd(x, &rd->rate_y, &distortion); + rd->rate2 += rd->rate_y; + rd->distortion2 += distortion; + + // UV cost and distortion + rd_inter16x16_uv(cpi, x, &rd->rate_uv, &rd->distortion_uv, + cpi->common.full_pixel); + rd->rate2 += rd->rate_uv; + rd->distortion2 += rd->distortion_uv; + return INT_MAX; +} + +static int calculate_final_rd_costs(int this_rd, + RATE_DISTORTION* rd, + int* other_cost, + int disable_skip, + int uv_intra_tteob, + int intra_rd_penalty, + VP8_COMP *cpi, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + // Where skip is allowable add in the default per mb cost for the no skip case. + // where we then decide to skip we have to delete this and replace it with the + // cost of signallying a skip + if (cpi->common.mb_no_coeff_skip) + { + *other_cost += vp8_cost_bit(cpi->prob_skip_false, 0); + rd->rate2 += *other_cost; + } + + /* Estimate the reference frame signaling cost and add it + * to the rolling cost variable. + */ + rd->rate2 += + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + if (!disable_skip) + { + // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate + if (cpi->common.mb_no_coeff_skip) + { + int i; + int tteob; + int has_y2_block = (this_mode!=SPLITMV && this_mode!=B_PRED); + + tteob = 0; + if(has_y2_block) + tteob += x->e_mbd.eobs[24]; + + for (i = 0; i < 16; i++) + tteob += (x->e_mbd.eobs[i] > has_y2_block); + + if (x->e_mbd.mode_info_context->mbmi.ref_frame) + { + for (i = 16; i < 24; i++) + tteob += x->e_mbd.eobs[i]; + } + else + tteob += uv_intra_tteob; + + if (tteob == 0) + { + rd->rate2 -= (rd->rate_y + rd->rate_uv); + //for best_yrd calculation + rd->rate_uv = 0; + + // Back out no skip flag costing and add in skip flag costing + if (cpi->prob_skip_false) + { + int prob_skip_cost; + + prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1); + prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0); + rd->rate2 += prob_skip_cost; + *other_cost += prob_skip_cost; + } + } + } + // Calculate the final RD estimate for this mode + this_rd = RDCOST(x->rdmult, x->rddiv, rd->rate2, rd->distortion2); + if (this_rd < INT_MAX && x->e_mbd.mode_info_context->mbmi.ref_frame + == INTRA_FRAME) + this_rd += intra_rd_penalty; + } + return this_rd; +} + +static void update_best_mode(BEST_MODE* best_mode, int this_rd, + RATE_DISTORTION* rd, int other_cost, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + + other_cost += + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + /* Calculate the final y RD estimate for this mode */ + best_mode->yrd = RDCOST(x->rdmult, x->rddiv, (rd->rate2-rd->rate_uv-other_cost), + (rd->distortion2-rd->distortion_uv)); + + best_mode->rd = this_rd; + vpx_memcpy(&best_mode->mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); + vpx_memcpy(&best_mode->partition, x->partition_info, sizeof(PARTITION_INFO)); + + if ((this_mode == B_PRED) || (this_mode == SPLITMV)) + { + int i; + for (i = 0; i < 16; i++) + { + best_mode->bmodes[i] = x->e_mbd.block[i].bmi; + } + } +} + +void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, + int recon_uvoffset, int *returnrate, + int *returndistortion, int *returnintra) +{ + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + MACROBLOCKD *xd = &x->e_mbd; + int_mv best_ref_mv_sb[2]; + int_mv mode_mv_sb[2][MB_MODE_COUNT]; + int_mv best_ref_mv; + int_mv *mode_mv; + MB_PREDICTION_MODE this_mode; + int num00; + int best_mode_index = 0; + BEST_MODE best_mode; + + int i; + int mode_index; + int mdcounts[4]; + int rate; + RATE_DISTORTION rd; + int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly; + int uv_intra_tteob = 0; + int uv_intra_done = 0; + + MB_PREDICTION_MODE uv_intra_mode = 0; + int_mv mvp; + int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + int saddone=0; + int sr=0; //search range got from mv_pred(). It uses step_param levels. (0-7) + + unsigned char *plane[4][3]; + int ref_frame_map[4]; + int sign_bias = 0; + + int intra_rd_penalty = 10* vp8_dc_quant(cpi->common.base_qindex, + cpi->common.y1dc_delta_q); + + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = 0; + best_mode.rd = INT_MAX; + best_mode.yrd = INT_MAX; + best_mode.intra_rd = INT_MAX; + vpx_memset(mode_mv_sb, 0, sizeof(mode_mv_sb)); + vpx_memset(&best_mode.mbmode, 0, sizeof(best_mode.mbmode)); + vpx_memset(&best_mode.bmodes, 0, sizeof(best_mode.bmodes)); + + /* Setup search priorities */ + get_reference_search_order(cpi, ref_frame_map); + + /* Check to see if there is at least 1 valid reference frame that we need + * to calculate near_mvs. + */ + if (ref_frame_map[1] > 0) + { + sign_bias = vp8_find_near_mvs_bias(&x->e_mbd, + x->e_mbd.mode_info_context, + mode_mv_sb, + best_ref_mv_sb, + mdcounts, + ref_frame_map[1], + cpi->common.ref_frame_sign_bias); + + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + } + + get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset); + + *returnintra = INT_MAX; + cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame + + x->skip = 0; + + for (mode_index = 0; mode_index < MAX_MODES; mode_index++) + { + int this_rd = INT_MAX; + int disable_skip = 0; + int other_cost = 0; + int this_ref_frame = ref_frame_map[vp8_ref_frame_order[mode_index]]; + + // Test best rd so far against threshold for trying this mode. + if (best_mode.rd <= cpi->rd_threshes[mode_index]) + continue; + + if (this_ref_frame < 0) + continue; + + // These variables hold are rolling total cost and distortion for this mode + rd.rate2 = 0; + rd.distortion2 = 0; + + this_mode = vp8_mode_order[mode_index]; + + x->e_mbd.mode_info_context->mbmi.mode = this_mode; + x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame; + + // Only consider ZEROMV/ALTREF_FRAME for alt ref frame, + // unless ARNR filtering is enabled in which case we want + // an unfiltered alternative + if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) + { + if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) + continue; + } + + /* everything but intra */ + if (x->e_mbd.mode_info_context->mbmi.ref_frame) + { + x->e_mbd.pre.y_buffer = plane[this_ref_frame][0]; + x->e_mbd.pre.u_buffer = plane[this_ref_frame][1]; + x->e_mbd.pre.v_buffer = plane[this_ref_frame][2]; + + if (sign_bias != cpi->common.ref_frame_sign_bias[this_ref_frame]) + { + sign_bias = cpi->common.ref_frame_sign_bias[this_ref_frame]; + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + } + } + + // Check to see if the testing frequency for this mode is at its max + // If so then prevent it from being tested and increase the threshold for its testing + if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1)) + { + if (cpi->mbs_tested_so_far <= cpi->mode_check_freq[mode_index] * cpi->mode_test_hit_counts[mode_index]) + { + // Increase the threshold for coding this mode to make it less likely to be chosen + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + + continue; + } + } + + // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested + cpi->mode_test_hit_counts[mode_index] ++; + + // Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise + if (cpi->zbin_mode_boost_enabled) + { + if ( this_ref_frame == INTRA_FRAME ) + cpi->zbin_mode_boost = 0; + else + { + if (vp8_mode_order[mode_index] == ZEROMV) + { + if (this_ref_frame != LAST_FRAME) + cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST; + else + cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST; + } + else if (vp8_mode_order[mode_index] == SPLITMV) + cpi->zbin_mode_boost = 0; + else + cpi->zbin_mode_boost = MV_ZBIN_BOOST; + } + + vp8_update_zbin_extra(cpi, x); + } + + if(!uv_intra_done && this_ref_frame == INTRA_FRAME) + { + rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, + &uv_intra_rate_tokenonly, + &uv_intra_distortion); + uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode; + + /* + * Total of the eobs is used later to further adjust rate2. Since uv + * block's intra eobs will be overwritten when we check inter modes, + * we need to save uv_intra_tteob here. + */ + for (i = 16; i < 24; i++) + uv_intra_tteob += x->e_mbd.eobs[i]; + + uv_intra_done = 1; + } + + switch (this_mode) + { + case B_PRED: + { + int tmp_rd; + + // Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED]; + int distortion; + tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rd.rate_y, &distortion, best_mode.yrd); + rd.rate2 += rate; + rd.distortion2 += distortion; + + if(tmp_rd < best_mode.yrd) + { + rd.rate2 += uv_intra_rate; + rd.rate_uv = uv_intra_rate_tokenonly; + rd.distortion2 += uv_intra_distortion; + rd.distortion_uv = uv_intra_distortion; + } + else + { + this_rd = INT_MAX; + disable_skip = 1; + } + } + break; + + case SPLITMV: + { + int tmp_rd; + int this_rd_thresh; + int distortion; + + this_rd_thresh = (vp8_ref_frame_order[mode_index] == 1) ? cpi->rd_threshes[THR_NEW1] : cpi->rd_threshes[THR_NEW3]; + this_rd_thresh = (vp8_ref_frame_order[mode_index] == 2) ? cpi->rd_threshes[THR_NEW2] : this_rd_thresh; + + tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv, + best_mode.yrd, mdcounts, + &rate, &rd.rate_y, &distortion, this_rd_thresh) ; + + rd.rate2 += rate; + rd.distortion2 += distortion; + + // If even the 'Y' rd value of split is higher than best so far then dont bother looking at UV + if (tmp_rd < best_mode.yrd) + { + // Now work out UV cost and add it in + rd_inter4x4_uv(cpi, x, &rd.rate_uv, &rd.distortion_uv, cpi->common.full_pixel); + rd.rate2 += rd.rate_uv; + rd.distortion2 += rd.distortion_uv; + } + else + { + this_rd = INT_MAX; + disable_skip = 1; + } + } + break; + case DC_PRED: + case V_PRED: + case H_PRED: + case TM_PRED: + { + int distortion; + x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + + vp8_build_intra_predictors_mby_s(xd, + xd->dst.y_buffer - xd->dst.y_stride, + xd->dst.y_buffer - 1, + xd->dst.y_stride, + xd->predictor, + 16); + macro_block_yrd(x, &rd.rate_y, &distortion) ; + rd.rate2 += rd.rate_y; + rd.distortion2 += distortion; + rd.rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; + rd.rate2 += uv_intra_rate; + rd.rate_uv = uv_intra_rate_tokenonly; + rd.distortion2 += uv_intra_distortion; + rd.distortion_uv = uv_intra_distortion; + } + break; + + case NEWMV: + { + int thissme; + int bestsme = INT_MAX; + int step_param = cpi->sf.first_step; + int further_steps; + int n; + int do_refine=1; /* If last step (1-away) of n-step search doesn't pick the center point as the best match, + we will do a final 1-away diamond refining search */ + + int sadpb = x->sadperbit16; + int_mv mvp_full; + + int col_min = ((best_ref_mv.as_mv.col+7)>>3) - MAX_FULL_PEL_VAL; + int row_min = ((best_ref_mv.as_mv.row+7)>>3) - MAX_FULL_PEL_VAL; + int col_max = (best_ref_mv.as_mv.col>>3) + MAX_FULL_PEL_VAL; + int row_max = (best_ref_mv.as_mv.row>>3) + MAX_FULL_PEL_VAL; + + int tmp_col_min = x->mv_col_min; + int tmp_col_max = x->mv_col_max; + int tmp_row_min = x->mv_row_min; + int tmp_row_max = x->mv_row_max; + + if(!saddone) + { + vp8_cal_sad(cpi,xd,x, recon_yoffset ,&near_sadidx[0] ); + saddone = 1; + } + + vp8_mv_pred(cpi, &x->e_mbd, x->e_mbd.mode_info_context, &mvp, + x->e_mbd.mode_info_context->mbmi.ref_frame, cpi->common.ref_frame_sign_bias, &sr, &near_sadidx[0]); + + mvp_full.as_mv.col = mvp.as_mv.col>>3; + mvp_full.as_mv.row = mvp.as_mv.row>>3; + + // Get intersection of UMV window and valid MV window to reduce # of checks in diamond search. + if (x->mv_col_min < col_min ) + x->mv_col_min = col_min; + if (x->mv_col_max > col_max ) + x->mv_col_max = col_max; + if (x->mv_row_min < row_min ) + x->mv_row_min = row_min; + if (x->mv_row_max > row_max ) + x->mv_row_max = row_max; + + //adjust search range according to sr from mv prediction + if(sr > step_param) + step_param = sr; + + // Initial step/diamond search + { + bestsme = cpi->diamond_search_sad(x, b, d, &mvp_full, &d->bmi.mv, + step_param, sadpb, &num00, + &cpi->fn_ptr[BLOCK_16X16], + x->mvcost, &best_ref_mv); + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + + // Further step/diamond searches as necessary + n = 0; + further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; + + n = num00; + num00 = 0; + + /* If there won't be more n-step search, check to see if refining search is needed. */ + if (n > further_steps) + do_refine = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = cpi->diamond_search_sad(x, b, d, &mvp_full, + &d->bmi.mv, step_param + n, sadpb, &num00, + &cpi->fn_ptr[BLOCK_16X16], x->mvcost, + &best_ref_mv); + + /* check to see if refining search is needed. */ + if (num00 > (further_steps-n)) + do_refine = 0; + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + } + else + { + d->bmi.mv.as_int = mode_mv[NEWMV].as_int; + } + } + } + } + + /* final 1-away diamond refining search */ + if (do_refine == 1) + { + int search_range; + + //It seems not a good way to set search_range. Need further investigation. + //search_range = MAXF(abs((mvp.row>>3) - d->bmi.mv.as_mv.row), abs((mvp.col>>3) - d->bmi.mv.as_mv.col)); + search_range = 8; + + //thissme = cpi->full_search_sad(x, b, d, &d->bmi.mv.as_mv, sadpb, search_range, &cpi->fn_ptr[BLOCK_16X16], x->mvcost, &best_ref_mv); + thissme = cpi->refining_search_sad(x, b, d, &d->bmi.mv, sadpb, + search_range, &cpi->fn_ptr[BLOCK_16X16], + x->mvcost, &best_ref_mv); + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + } + else + { + d->bmi.mv.as_int = mode_mv[NEWMV].as_int; + } + } + + x->mv_col_min = tmp_col_min; + x->mv_col_max = tmp_col_max; + x->mv_row_min = tmp_row_min; + x->mv_row_max = tmp_row_max; + + if (bestsme < INT_MAX) + { + int dis; /* TODO: use dis in distortion calculation later. */ + unsigned int sse; + cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, &best_ref_mv, + x->errorperbit, + &cpi->fn_ptr[BLOCK_16X16], + x->mvcost, &dis, &sse); + } + + mode_mv[NEWMV].as_int = d->bmi.mv.as_int; + + // Add the new motion vector cost to our rolling cost variable + rd.rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96); + } + + case NEARESTMV: + case NEARMV: + // Clip "next_nearest" so that it does not extend to far out of image + vp8_clamp_mv2(&mode_mv[this_mode], xd); + + // Do not bother proceeding if the vector (from newmv,nearest or near) is 0,0 as this should then be coded using the zeromv mode. + if (((this_mode == NEARMV) || (this_mode == NEARESTMV)) && (mode_mv[this_mode].as_int == 0)) + continue; + + case ZEROMV: + + // Trap vectors that reach beyond the UMV borders + // Note that ALL New MV, Nearest MV Near MV and Zero MV code drops through to this point + // because of the lack of break statements in the previous two cases. + if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) + continue; + + vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]); + this_rd = evaluate_inter_mode_rd(mdcounts, &rd, + &disable_skip, cpi, x); + break; + + default: + break; + } + + this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost, + disable_skip, uv_intra_tteob, + intra_rd_penalty, cpi, x); + + // Keep record of best intra distortion + if ((x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) && + (this_rd < best_mode.intra_rd) ) + { + best_mode.intra_rd = this_rd; + *returnintra = rd.distortion2 ; + } + +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + // Store the best NEWMV in x for later use in the denoiser. + // We are restricted to the LAST_FRAME since the denoiser only keeps + // one filter state. + if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV && + x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME) + { + x->e_mbd.best_sse_inter_mode = NEWMV; + x->e_mbd.best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv; + x->e_mbd.need_to_clamp_best_mvs = + x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs; + } + } +#endif + + // Did this mode help.. i.i is it the new best mode + if (this_rd < best_mode.rd || x->skip) + { + // Note index of best mode so far + best_mode_index = mode_index; + *returnrate = rd.rate2; + *returndistortion = rd.distortion2; + if (this_mode <= B_PRED) + { + x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode; + /* required for left and above block mv */ + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + } + update_best_mode(&best_mode, this_rd, &rd, other_cost, x); + + + // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time + cpi->rd_thresh_mult[mode_index] = (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + } + + // If the mode did not help improve the best error case then raise the threshold for testing that mode next time around. + else + { + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + } + + if (x->skip) + break; + + } + + // Reduce the activation RD thresholds for the best choice mode + if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) + { + int best_adjustment = (cpi->rd_thresh_mult[best_mode_index] >> 2); + + cpi->rd_thresh_mult[best_mode_index] = (cpi->rd_thresh_mult[best_mode_index] >= (MIN_THRESHMULT + best_adjustment)) ? cpi->rd_thresh_mult[best_mode_index] - best_adjustment : MIN_THRESHMULT; + cpi->rd_threshes[best_mode_index] = (cpi->rd_baseline_thresh[best_mode_index] >> 7) * cpi->rd_thresh_mult[best_mode_index]; + + // If we chose a split mode then reset the new MV thresholds as well + /*if ( vp8_mode_order[best_mode_index] == SPLITMV ) + { + best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWMV] >> 4); + cpi->rd_thresh_mult[THR_NEWMV] = (cpi->rd_thresh_mult[THR_NEWMV] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWMV]-best_adjustment: MIN_THRESHMULT; + cpi->rd_threshes[THR_NEWMV] = (cpi->rd_baseline_thresh[THR_NEWMV] >> 7) * cpi->rd_thresh_mult[THR_NEWMV]; + + best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWG] >> 4); + cpi->rd_thresh_mult[THR_NEWG] = (cpi->rd_thresh_mult[THR_NEWG] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWG]-best_adjustment: MIN_THRESHMULT; + cpi->rd_threshes[THR_NEWG] = (cpi->rd_baseline_thresh[THR_NEWG] >> 7) * cpi->rd_thresh_mult[THR_NEWG]; + + best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWA] >> 4); + cpi->rd_thresh_mult[THR_NEWA] = (cpi->rd_thresh_mult[THR_NEWA] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWA]-best_adjustment: MIN_THRESHMULT; + cpi->rd_threshes[THR_NEWA] = (cpi->rd_baseline_thresh[THR_NEWA] >> 7) * cpi->rd_thresh_mult[THR_NEWA]; + }*/ + + } + + // Note how often each mode chosen as best + cpi->mode_chosen_counts[best_mode_index] ++; + +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + if (x->e_mbd.best_sse_inter_mode == DC_PRED) { + // No best MV found. + x->e_mbd.best_sse_inter_mode = best_mode.mbmode.mode; + x->e_mbd.best_sse_mv = best_mode.mbmode.mv; + x->e_mbd.need_to_clamp_best_mvs = best_mode.mbmode.need_to_clamp_mvs; + } + + // TODO(holmer): No SSEs are calculated in rdopt.c. What else can be used? + vp8_denoiser_denoise_mb(&cpi->denoiser, x, 0, 0, + recon_yoffset, recon_uvoffset); + // Reevalute ZEROMV if the current mode is INTRA. + if (best_mode.mbmode.ref_frame == INTRA_FRAME) + { + int this_rd = INT_MAX; + int disable_skip = 0; + int other_cost = 0; + vpx_memset(&rd, 0, sizeof(rd)); + x->e_mbd.mode_info_context->mbmi.ref_frame = LAST_FRAME; + rd.rate2 += x->ref_frame_cost[LAST_FRAME]; + rd.rate2 += vp8_cost_mv_ref(ZEROMV, mdcounts); + x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + this_rd = evaluate_inter_mode_rd(mdcounts, &rd, &disable_skip, cpi, x); + this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost, + disable_skip, uv_intra_tteob, + intra_rd_penalty, cpi, x); + if (this_rd < best_mode.rd || x->skip) + { + // Note index of best mode so far + best_mode_index = mode_index; + *returnrate = rd.rate2; + *returndistortion = rd.distortion2; + update_best_mode(&best_mode, this_rd, &rd, other_cost, x); + } + } + } +#endif + + if (cpi->is_src_frame_alt_ref && + (best_mode.mbmode.mode != ZEROMV || best_mode.mbmode.ref_frame != ALTREF_FRAME)) + { + x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; + x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mb_skip_coeff = + (cpi->common.mb_no_coeff_skip); + x->e_mbd.mode_info_context->mbmi.partitioning = 0; + return; + } + + + // macroblock modes + vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mode.mbmode, sizeof(MB_MODE_INFO)); + + if (best_mode.mbmode.mode == B_PRED) + { + for (i = 0; i < 16; i++) + xd->mode_info_context->bmi[i].as_mode = best_mode.bmodes[i].as_mode; + } + + if (best_mode.mbmode.mode == SPLITMV) + { + for (i = 0; i < 16; i++) + xd->mode_info_context->bmi[i].mv.as_int = best_mode.bmodes[i].mv.as_int; + + vpx_memcpy(x->partition_info, &best_mode.partition, sizeof(PARTITION_INFO)); + + x->e_mbd.mode_info_context->mbmi.mv.as_int = + x->partition_info->bmi[15].mv.as_int; + } + + if (sign_bias + != cpi->common.ref_frame_sign_bias[xd->mode_info_context->mbmi.ref_frame]) + best_ref_mv.as_int = best_ref_mv_sb[!sign_bias].as_int; + + rd_update_mvcount(cpi, x, &best_ref_mv); +} + +void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate_) +{ + int error4x4, error16x16; + int rate4x4, rate16x16 = 0, rateuv; + int dist4x4, dist16x16, distuv; + int rate; + int rate4x4_tokenonly = 0; + int rate16x16_tokenonly = 0; + int rateuv_tokenonly = 0; + + x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + + rd_pick_intra_mbuv_mode(cpi, x, &rateuv, &rateuv_tokenonly, &distuv); + rate = rateuv; + + error16x16 = rd_pick_intra16x16mby_mode(cpi, x, + &rate16x16, &rate16x16_tokenonly, + &dist16x16); + + error4x4 = rd_pick_intra4x4mby_modes(cpi, x, + &rate4x4, &rate4x4_tokenonly, + &dist4x4, error16x16); + + if (error4x4 < error16x16) + { + x->e_mbd.mode_info_context->mbmi.mode = B_PRED; + rate += rate4x4; + } + else + { + rate += rate16x16; + } + + *rate_ = rate; +} diff --git a/vp8/encoder/rdopt.h b/vp8/encoder/rdopt.h new file mode 100644 index 0000000..db939f9 --- /dev/null +++ b/vp8/encoder/rdopt.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_RDOPT_H +#define __INC_RDOPT_H + +#define RDCOST(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) + +static void insertsortmv(int arr[], int len) +{ + int i, j, k; + + for ( i = 1 ; i <= len-1 ; i++ ) + { + for ( j = 0 ; j < i ; j++ ) + { + if ( arr[j] > arr[i] ) + { + int temp; + + temp = arr[i]; + + for ( k = i; k >j; k--) + arr[k] = arr[k - 1] ; + + arr[j] = temp ; + } + } + } +} + +static void insertsortsad(int arr[],int idx[], int len) +{ + int i, j, k; + + for ( i = 1 ; i <= len-1 ; i++ ) + { + for ( j = 0 ; j < i ; j++ ) + { + if ( arr[j] > arr[i] ) + { + int temp, tempi; + + temp = arr[i]; + tempi = idx[i]; + + for ( k = i; k >j; k--) + { + arr[k] = arr[k - 1] ; + idx[k] = idx[k - 1]; + } + + arr[j] = temp ; + idx[j] = tempi; + } + } + } +} + +extern void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue); +extern void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); +extern void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); + + +static void get_plane_pointers(const YV12_BUFFER_CONFIG *fb, + unsigned char *plane[3], + unsigned int recon_yoffset, + unsigned int recon_uvoffset) +{ + plane[0] = fb->y_buffer + recon_yoffset; + plane[1] = fb->u_buffer + recon_uvoffset; + plane[2] = fb->v_buffer + recon_uvoffset; +} + + +static void get_predictor_pointers(const VP8_COMP *cpi, + unsigned char *plane[4][3], + unsigned int recon_yoffset, + unsigned int recon_uvoffset) +{ + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + get_plane_pointers(&cpi->common.yv12_fb[cpi->common.lst_fb_idx], + plane[LAST_FRAME], recon_yoffset, recon_uvoffset); + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + get_plane_pointers(&cpi->common.yv12_fb[cpi->common.gld_fb_idx], + plane[GOLDEN_FRAME], recon_yoffset, recon_uvoffset); + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + get_plane_pointers(&cpi->common.yv12_fb[cpi->common.alt_fb_idx], + plane[ALTREF_FRAME], recon_yoffset, recon_uvoffset); +} + + +static void get_reference_search_order(const VP8_COMP *cpi, + int ref_frame_map[4]) +{ + int i=0; + + ref_frame_map[i++] = INTRA_FRAME; + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + ref_frame_map[i++] = LAST_FRAME; + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + ref_frame_map[i++] = GOLDEN_FRAME; + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + ref_frame_map[i++] = ALTREF_FRAME; + for(; i<4; i++) + ref_frame_map[i] = -1; +} + + +extern void vp8_mv_pred +( + VP8_COMP *cpi, + MACROBLOCKD *xd, + const MODE_INFO *here, + int_mv *mvp, + int refframe, + int *ref_frame_sign_bias, + int *sr, + int near_sadidx[] +); +void vp8_cal_sad(VP8_COMP *cpi, MACROBLOCKD *xd, MACROBLOCK *x, int recon_yoffset, int near_sadidx[]); + +#endif diff --git a/vp8/encoder/segmentation.c b/vp8/encoder/segmentation.c new file mode 100644 index 0000000..fc0967d --- /dev/null +++ b/vp8/encoder/segmentation.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "segmentation.h" +#include "vpx_mem/vpx_mem.h" + +void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x) +{ + int mb_row, mb_col; + + MODE_INFO *this_mb_mode_info = cm->mi; + + x->gf_active_ptr = (signed char *)cpi->gf_active_flags; + + if ((cm->frame_type == KEY_FRAME) || (cm->refresh_golden_frame)) + { + // Reset Gf useage monitors + vpx_memset(cpi->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cpi->gf_active_count = cm->mb_rows * cm->mb_cols; + } + else + { + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + + // If using golden then set GF active flag if not already set. + // If using last frame 0,0 mode then leave flag as it is + // else if using non 0,0 motion or intra modes then clear flag if it is currently set + if ((this_mb_mode_info->mbmi.ref_frame == GOLDEN_FRAME) || (this_mb_mode_info->mbmi.ref_frame == ALTREF_FRAME)) + { + if (*(x->gf_active_ptr) == 0) + { + *(x->gf_active_ptr) = 1; + cpi->gf_active_count ++; + } + } + else if ((this_mb_mode_info->mbmi.mode != ZEROMV) && *(x->gf_active_ptr)) + { + *(x->gf_active_ptr) = 0; + cpi->gf_active_count--; + } + + x->gf_active_ptr++; // Step onto next entry + this_mb_mode_info++; // skip to next mb + + } + + // this is to account for the border + this_mb_mode_info++; + } + } +} diff --git a/vp8/encoder/segmentation.h b/vp8/encoder/segmentation.h new file mode 100644 index 0000000..12815b0 --- /dev/null +++ b/vp8/encoder/segmentation.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "string.h" +#include "vp8/common/blockd.h" +#include "onyx_int.h" + +extern void vp8_update_gf_useage_maps(VP8_COMP *cpi, VP8_COMMON *cm, MACROBLOCK *x); diff --git a/vp8/encoder/ssim.c b/vp8/encoder/ssim.c new file mode 100644 index 0000000..e751608 --- /dev/null +++ b/vp8/encoder/ssim.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "onyx_int.h" + +void vp8_ssim_parms_16x16_c +( + unsigned char *s, + int sp, + unsigned char *r, + int rp, + unsigned long *sum_s, + unsigned long *sum_r, + unsigned long *sum_sq_s, + unsigned long *sum_sq_r, + unsigned long *sum_sxr +) +{ + int i,j; + for(i=0;i<16;i++,s+=sp,r+=rp) + { + for(j=0;j<16;j++) + { + *sum_s += s[j]; + *sum_r += r[j]; + *sum_sq_s += s[j] * s[j]; + *sum_sq_r += r[j] * r[j]; + *sum_sxr += s[j] * r[j]; + } + } +} +void vp8_ssim_parms_8x8_c +( + unsigned char *s, + int sp, + unsigned char *r, + int rp, + unsigned long *sum_s, + unsigned long *sum_r, + unsigned long *sum_sq_s, + unsigned long *sum_sq_r, + unsigned long *sum_sxr +) +{ + int i,j; + for(i=0;i<8;i++,s+=sp,r+=rp) + { + for(j=0;j<8;j++) + { + *sum_s += s[j]; + *sum_r += r[j]; + *sum_sq_s += s[j] * s[j]; + *sum_sq_r += r[j] * r[j]; + *sum_sxr += s[j] * r[j]; + } + } +} + +const static int64_t cc1 = 26634; // (64^2*(.01*255)^2 +const static int64_t cc2 = 239708; // (64^2*(.03*255)^2 + +static double similarity +( + unsigned long sum_s, + unsigned long sum_r, + unsigned long sum_sq_s, + unsigned long sum_sq_r, + unsigned long sum_sxr, + int count +) +{ + int64_t ssim_n, ssim_d; + int64_t c1, c2; + + //scale the constants by number of pixels + c1 = (cc1*count*count)>>12; + c2 = (cc2*count*count)>>12; + + ssim_n = (2*sum_s*sum_r+ c1)*((int64_t) 2*count*sum_sxr- + (int64_t) 2*sum_s*sum_r+c2); + + ssim_d = (sum_s*sum_s +sum_r*sum_r+c1)* + ((int64_t)count*sum_sq_s-(int64_t)sum_s*sum_s + + (int64_t)count*sum_sq_r-(int64_t) sum_r*sum_r +c2) ; + + return ssim_n * 1.0 / ssim_d; +} + +static double ssim_16x16(unsigned char *s,int sp, unsigned char *r,int rp) +{ + unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; + vp8_ssim_parms_16x16(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); + return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 256); +} +static double ssim_8x8(unsigned char *s,int sp, unsigned char *r,int rp) +{ + unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; + vp8_ssim_parms_8x8(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); + return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64); +} + +// TODO: (jbb) tried to scale this function such that we may be able to use it +// for distortion metric in mode selection code ( provided we do a reconstruction) +long dssim(unsigned char *s,int sp, unsigned char *r,int rp) +{ + unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; + int64_t ssim3; + int64_t ssim_n1,ssim_n2; + int64_t ssim_d1,ssim_d2; + int64_t ssim_t1,ssim_t2; + int64_t c1, c2; + + // normalize by 256/64 + c1 = cc1*16; + c2 = cc2*16; + + vp8_ssim_parms_16x16(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); + ssim_n1 = (2*sum_s*sum_r+ c1); + + ssim_n2 =((int64_t) 2*256*sum_sxr-(int64_t) 2*sum_s*sum_r+c2); + + ssim_d1 =((int64_t)sum_s*sum_s +(int64_t)sum_r*sum_r+c1); + + ssim_d2 = (256 * (int64_t) sum_sq_s-(int64_t) sum_s*sum_s + + (int64_t) 256*sum_sq_r-(int64_t) sum_r*sum_r +c2) ; + + ssim_t1 = 256 - 256 * ssim_n1 / ssim_d1; + ssim_t2 = 256 - 256 * ssim_n2 / ssim_d2; + + ssim3 = 256 *ssim_t1 * ssim_t2; + if(ssim3 <0 ) + ssim3=0; + return (long)( ssim3 ); +} + +// We are using a 8x8 moving window with starting location of each 8x8 window +// on the 4x4 pixel grid. Such arrangement allows the windows to overlap +// block boundaries to penalize blocking artifacts. +double vp8_ssim2 +( + unsigned char *img1, + unsigned char *img2, + int stride_img1, + int stride_img2, + int width, + int height +) +{ + int i,j; + int samples =0; + double ssim_total=0; + + // sample point start with each 4x4 location + for(i=0; i < height-8; i+=4, img1 += stride_img1*4, img2 += stride_img2*4) + { + for(j=0; j < width-8; j+=4 ) + { + double v = ssim_8x8(img1+j, stride_img1, img2+j, stride_img2); + ssim_total += v; + samples++; + } + } + ssim_total /= samples; + return ssim_total; +} +double vp8_calc_ssim +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + int lumamask, + double *weight +) +{ + double a, b, c; + double ssimv; + + a = vp8_ssim2(source->y_buffer, dest->y_buffer, + source->y_stride, dest->y_stride, source->y_width, + source->y_height); + + b = vp8_ssim2(source->u_buffer, dest->u_buffer, + source->uv_stride, dest->uv_stride, source->uv_width, + source->uv_height); + + c = vp8_ssim2(source->v_buffer, dest->v_buffer, + source->uv_stride, dest->uv_stride, source->uv_width, + source->uv_height); + + ssimv = a * .8 + .1 * (b + c); + + *weight = 1; + + return ssimv; +} + +double vp8_calc_ssimg +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + double *ssim_y, + double *ssim_u, + double *ssim_v +) +{ + double ssim_all = 0; + double a, b, c; + + a = vp8_ssim2(source->y_buffer, dest->y_buffer, + source->y_stride, dest->y_stride, source->y_width, + source->y_height); + + b = vp8_ssim2(source->u_buffer, dest->u_buffer, + source->uv_stride, dest->uv_stride, source->uv_width, + source->uv_height); + + c = vp8_ssim2(source->v_buffer, dest->v_buffer, + source->uv_stride, dest->uv_stride, source->uv_width, + source->uv_height); + *ssim_y = a; + *ssim_u = b; + *ssim_v = c; + ssim_all = (a * 4 + b + c) /6; + + return ssim_all; +} diff --git a/vp8/encoder/temporal_filter.c b/vp8/encoder/temporal_filter.c new file mode 100644 index 0000000..6c61b36 --- /dev/null +++ b/vp8/encoder/temporal_filter.c @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8/common/onyxc_int.h" +#include "onyx_int.h" +#include "vp8/common/systemdependent.h" +#include "quantize.h" +#include "vp8/common/alloccommon.h" +#include "mcomp.h" +#include "firstpass.h" +#include "psnr.h" +#include "vpx_scale/vpxscale.h" +#include "vp8/common/extend.h" +#include "ratectrl.h" +#include "vp8/common/quant_common.h" +#include "segmentation.h" +#include "vpx_mem/vpx_mem.h" +#include "vp8/common/swapyv12buffer.h" +#include "vp8/common/threading.h" +#include "vpx_ports/vpx_timer.h" + +#include +#include + +#define ALT_REF_MC_ENABLED 1 // dis/enable MC in AltRef filtering +#define ALT_REF_SUBPEL_ENABLED 1 // dis/enable subpel in MC AltRef filtering + +#if VP8_TEMPORAL_ALT_REF + +static void vp8_temporal_filter_predictors_mb_c +( + MACROBLOCKD *x, + unsigned char *y_mb_ptr, + unsigned char *u_mb_ptr, + unsigned char *v_mb_ptr, + int stride, + int mv_row, + int mv_col, + unsigned char *pred +) +{ + int offset; + unsigned char *yptr, *uptr, *vptr; + + // Y + yptr = y_mb_ptr + (mv_row >> 3) * stride + (mv_col >> 3); + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict16x16(yptr, stride, + mv_col & 7, mv_row & 7, &pred[0], 16); + } + else + { + vp8_copy_mem16x16(yptr, stride, &pred[0], 16); + } + + // U & V + mv_row >>= 1; + mv_col >>= 1; + stride = (stride + 1) >> 1; + offset = (mv_row >> 3) * stride + (mv_col >> 3); + uptr = u_mb_ptr + offset; + vptr = v_mb_ptr + offset; + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict8x8(uptr, stride, + mv_col & 7, mv_row & 7, &pred[256], 8); + x->subpixel_predict8x8(vptr, stride, + mv_col & 7, mv_row & 7, &pred[320], 8); + } + else + { + vp8_copy_mem8x8(uptr, stride, &pred[256], 8); + vp8_copy_mem8x8(vptr, stride, &pred[320], 8); + } +} +void vp8_temporal_filter_apply_c +( + unsigned char *frame1, + unsigned int stride, + unsigned char *frame2, + unsigned int block_size, + int strength, + int filter_weight, + unsigned int *accumulator, + unsigned short *count +) +{ + unsigned int i, j, k; + int modifier; + int byte = 0; + + for (i = 0,k = 0; i < block_size; i++) + { + for (j = 0; j < block_size; j++, k++) + { + + int src_byte = frame1[byte]; + int pixel_value = *frame2++; + + modifier = src_byte - pixel_value; + // This is an integer approximation of: + // float coeff = (3.0 * modifer * modifier) / pow(2, strength); + // modifier = (int)roundf(coeff > 16 ? 0 : 16-coeff); + modifier *= modifier; + modifier *= 3; + modifier += 1 << (strength - 1); + modifier >>= strength; + + if (modifier > 16) + modifier = 16; + + modifier = 16 - modifier; + modifier *= filter_weight; + + count[k] += modifier; + accumulator[k] += modifier * pixel_value; + + byte++; + } + + byte += stride - block_size; + } +} + +#if ALT_REF_MC_ENABLED +static int dummy_cost[2*mv_max+1]; + +static int vp8_temporal_filter_find_matching_mb_c +( + VP8_COMP *cpi, + YV12_BUFFER_CONFIG *arf_frame, + YV12_BUFFER_CONFIG *frame_ptr, + int mb_offset, + int error_thresh +) +{ + MACROBLOCK *x = &cpi->mb; + int step_param; + int sadpb = x->sadperbit16; + int bestsme = INT_MAX; + + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + int_mv best_ref_mv1; + int_mv best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */ + + int *mvcost[2] = { &dummy_cost[mv_max+1], &dummy_cost[mv_max+1] }; + int *mvsadcost[2] = { &dummy_cost[mv_max+1], &dummy_cost[mv_max+1] }; + + // Save input state + unsigned char **base_src = b->base_src; + int src = b->src; + int src_stride = b->src_stride; + unsigned char *base_pre = x->e_mbd.pre.y_buffer; + int pre = d->offset; + int pre_stride = x->e_mbd.pre.y_stride; + + best_ref_mv1.as_int = 0; + best_ref_mv1_full.as_mv.col = best_ref_mv1.as_mv.col >>3; + best_ref_mv1_full.as_mv.row = best_ref_mv1.as_mv.row >>3; + + // Setup frame pointers + b->base_src = &arf_frame->y_buffer; + b->src_stride = arf_frame->y_stride; + b->src = mb_offset; + + x->e_mbd.pre.y_buffer = frame_ptr->y_buffer; + x->e_mbd.pre.y_stride = frame_ptr->y_stride; + d->offset = mb_offset; + + // Further step/diamond searches as necessary + if (cpi->Speed < 8) + { + step_param = cpi->sf.first_step + (cpi->Speed > 5); + } + else + { + step_param = cpi->sf.first_step + 2; + } + + /*cpi->sf.search_method == HEX*/ + // TODO Check that the 16x16 vf & sdf are selected here + bestsme = vp8_hex_search(x, b, d, + &best_ref_mv1_full, &d->bmi.mv, + step_param, + sadpb, + &cpi->fn_ptr[BLOCK_16X16], + mvsadcost, mvcost, &best_ref_mv1); + +#if ALT_REF_SUBPEL_ENABLED + // Try sub-pixel MC? + //if (bestsme > error_thresh && bestsme < INT_MAX) + { + int distortion; + unsigned int sse; + bestsme = cpi->find_fractional_mv_step(x, b, d, + &d->bmi.mv, &best_ref_mv1, + x->errorperbit, &cpi->fn_ptr[BLOCK_16X16], + mvcost, &distortion, &sse); + } +#endif + + // Save input state + b->base_src = base_src; + b->src = src; + b->src_stride = src_stride; + x->e_mbd.pre.y_buffer = base_pre; + d->offset = pre; + x->e_mbd.pre.y_stride = pre_stride; + + return bestsme; +} +#endif + +static void vp8_temporal_filter_iterate_c +( + VP8_COMP *cpi, + int frame_count, + int alt_ref_index, + int strength +) +{ + int byte; + int frame; + int mb_col, mb_row; + unsigned int filter_weight; + int mb_cols = cpi->common.mb_cols; + int mb_rows = cpi->common.mb_rows; + int mb_y_offset = 0; + int mb_uv_offset = 0; + DECLARE_ALIGNED_ARRAY(16, unsigned int, accumulator, 16*16 + 8*8 + 8*8); + DECLARE_ALIGNED_ARRAY(16, unsigned short, count, 16*16 + 8*8 + 8*8); + MACROBLOCKD *mbd = &cpi->mb.e_mbd; + YV12_BUFFER_CONFIG *f = cpi->frames[alt_ref_index]; + unsigned char *dst1, *dst2; + DECLARE_ALIGNED_ARRAY(16, unsigned char, predictor, 16*16 + 8*8 + 8*8); + + // Save input state + unsigned char *y_buffer = mbd->pre.y_buffer; + unsigned char *u_buffer = mbd->pre.u_buffer; + unsigned char *v_buffer = mbd->pre.v_buffer; + + for (mb_row = 0; mb_row < mb_rows; mb_row++) + { +#if ALT_REF_MC_ENABLED + // Source frames are extended to 16 pixels. This is different than + // L/A/G reference frames that have a border of 32 (VP8BORDERINPIXELS) + // A 6 tap filter is used for motion search. This requires 2 pixels + // before and 3 pixels after. So the largest Y mv on a border would + // then be 16 - 3. The UV blocks are half the size of the Y and + // therefore only extended by 8. The largest mv that a UV block + // can support is 8 - 3. A UV mv is half of a Y mv. + // (16 - 3) >> 1 == 6 which is greater than 8 - 3. + // To keep the mv in play for both Y and UV planes the max that it + // can be on a border is therefore 16 - 5. + cpi->mb.mv_row_min = -((mb_row * 16) + (16 - 5)); + cpi->mb.mv_row_max = ((cpi->common.mb_rows - 1 - mb_row) * 16) + + (16 - 5); +#endif + + for (mb_col = 0; mb_col < mb_cols; mb_col++) + { + int i, j, k; + int stride; + + vpx_memset(accumulator, 0, 384*sizeof(unsigned int)); + vpx_memset(count, 0, 384*sizeof(unsigned short)); + +#if ALT_REF_MC_ENABLED + cpi->mb.mv_col_min = -((mb_col * 16) + (16 - 5)); + cpi->mb.mv_col_max = ((cpi->common.mb_cols - 1 - mb_col) * 16) + + (16 - 5); +#endif + + for (frame = 0; frame < frame_count; frame++) + { + int err = 0; + + if (cpi->frames[frame] == NULL) + continue; + + mbd->block[0].bmi.mv.as_mv.row = 0; + mbd->block[0].bmi.mv.as_mv.col = 0; + +#if ALT_REF_MC_ENABLED +#define THRESH_LOW 10000 +#define THRESH_HIGH 20000 + + // Find best match in this frame by MC + err = vp8_temporal_filter_find_matching_mb_c + (cpi, + cpi->frames[alt_ref_index], + cpi->frames[frame], + mb_y_offset, + THRESH_LOW); + +#endif + // Assign higher weight to matching MB if it's error + // score is lower. If not applying MC default behavior + // is to weight all MBs equal. + filter_weight = errframes[frame]->y_buffer + mb_y_offset, + cpi->frames[frame]->u_buffer + mb_uv_offset, + cpi->frames[frame]->v_buffer + mb_uv_offset, + cpi->frames[frame]->y_stride, + mbd->block[0].bmi.mv.as_mv.row, + mbd->block[0].bmi.mv.as_mv.col, + predictor); + + // Apply the filter (YUV) + vp8_temporal_filter_apply + (f->y_buffer + mb_y_offset, + f->y_stride, + predictor, + 16, + strength, + filter_weight, + accumulator, + count); + + vp8_temporal_filter_apply + (f->u_buffer + mb_uv_offset, + f->uv_stride, + predictor + 256, + 8, + strength, + filter_weight, + accumulator + 256, + count + 256); + + vp8_temporal_filter_apply + (f->v_buffer + mb_uv_offset, + f->uv_stride, + predictor + 320, + 8, + strength, + filter_weight, + accumulator + 320, + count + 320); + } + } + + // Normalize filter output to produce AltRef frame + dst1 = cpi->alt_ref_buffer.y_buffer; + stride = cpi->alt_ref_buffer.y_stride; + byte = mb_y_offset; + for (i = 0,k = 0; i < 16; i++) + { + for (j = 0; j < 16; j++, k++) + { + unsigned int pval = accumulator[k] + (count[k] >> 1); + pval *= cpi->fixed_divide[count[k]]; + pval >>= 19; + + dst1[byte] = (unsigned char)pval; + + // move to next pixel + byte++; + } + + byte += stride - 16; + } + + dst1 = cpi->alt_ref_buffer.u_buffer; + dst2 = cpi->alt_ref_buffer.v_buffer; + stride = cpi->alt_ref_buffer.uv_stride; + byte = mb_uv_offset; + for (i = 0,k = 256; i < 8; i++) + { + for (j = 0; j < 8; j++, k++) + { + int m=k+64; + + // U + unsigned int pval = accumulator[k] + (count[k] >> 1); + pval *= cpi->fixed_divide[count[k]]; + pval >>= 19; + dst1[byte] = (unsigned char)pval; + + // V + pval = accumulator[m] + (count[m] >> 1); + pval *= cpi->fixed_divide[count[m]]; + pval >>= 19; + dst2[byte] = (unsigned char)pval; + + // move to next pixel + byte++; + } + + byte += stride - 8; + } + + mb_y_offset += 16; + mb_uv_offset += 8; + } + + mb_y_offset += 16*(f->y_stride-mb_cols); + mb_uv_offset += 8*(f->uv_stride-mb_cols); + } + + // Restore input state + mbd->pre.y_buffer = y_buffer; + mbd->pre.u_buffer = u_buffer; + mbd->pre.v_buffer = v_buffer; +} + +void vp8_temporal_filter_prepare_c +( + VP8_COMP *cpi, + int distance +) +{ + int frame = 0; + + int num_frames_backward = 0; + int num_frames_forward = 0; + int frames_to_blur_backward = 0; + int frames_to_blur_forward = 0; + int frames_to_blur = 0; + int start_frame = 0; + + int strength = cpi->oxcf.arnr_strength; + + int blur_type = cpi->oxcf.arnr_type; + + int max_frames = cpi->active_arnr_frames; + + num_frames_backward = distance; + num_frames_forward = vp8_lookahead_depth(cpi->lookahead) + - (num_frames_backward + 1); + + switch (blur_type) + { + case 1: + ///////////////////////////////////////// + // Backward Blur + + frames_to_blur_backward = num_frames_backward; + + if (frames_to_blur_backward >= max_frames) + frames_to_blur_backward = max_frames - 1; + + frames_to_blur = frames_to_blur_backward + 1; + break; + + case 2: + ///////////////////////////////////////// + // Forward Blur + + frames_to_blur_forward = num_frames_forward; + + if (frames_to_blur_forward >= max_frames) + frames_to_blur_forward = max_frames - 1; + + frames_to_blur = frames_to_blur_forward + 1; + break; + + case 3: + default: + ///////////////////////////////////////// + // Center Blur + frames_to_blur_forward = num_frames_forward; + frames_to_blur_backward = num_frames_backward; + + if (frames_to_blur_forward > frames_to_blur_backward) + frames_to_blur_forward = frames_to_blur_backward; + + if (frames_to_blur_backward > frames_to_blur_forward) + frames_to_blur_backward = frames_to_blur_forward; + + // When max_frames is even we have 1 more frame backward than forward + if (frames_to_blur_forward > (max_frames - 1) / 2) + frames_to_blur_forward = ((max_frames - 1) / 2); + + if (frames_to_blur_backward > (max_frames / 2)) + frames_to_blur_backward = (max_frames / 2); + + frames_to_blur = frames_to_blur_backward + frames_to_blur_forward + 1; + break; + } + + start_frame = distance + frames_to_blur_forward; + +#ifdef DEBUGFWG + // DEBUG FWG + printf("max:%d FBCK:%d FFWD:%d ftb:%d ftbbck:%d ftbfwd:%d sei:%d lasei:%d start:%d" + , max_frames + , num_frames_backward + , num_frames_forward + , frames_to_blur + , frames_to_blur_backward + , frames_to_blur_forward + , cpi->source_encode_index + , cpi->last_alt_ref_sei + , start_frame); +#endif + + // Setup frame pointers, NULL indicates frame not included in filter + vpx_memset(cpi->frames, 0, max_frames*sizeof(YV12_BUFFER_CONFIG *)); + for (frame = 0; frame < frames_to_blur; frame++) + { + int which_buffer = start_frame - frame; + struct lookahead_entry* buf = vp8_lookahead_peek(cpi->lookahead, + which_buffer, + PEEK_FORWARD); + cpi->frames[frames_to_blur-1-frame] = &buf->img; + } + + vp8_temporal_filter_iterate_c ( + cpi, + frames_to_blur, + frames_to_blur_backward, + strength ); +} +#endif diff --git a/vp8/encoder/tokenize.c b/vp8/encoder/tokenize.c new file mode 100644 index 0000000..ef41fa8 --- /dev/null +++ b/vp8/encoder/tokenize.c @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include +#include +#include "onyx_int.h" +#include "tokenize.h" +#include "vpx_mem/vpx_mem.h" + +/* Global event counters used for accumulating statistics across several + compressions, then generating context.c = initial stats. */ + +#ifdef ENTROPY_STATS +_int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; +#endif +void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; +void vp8_fix_contexts(MACROBLOCKD *x); + +#include "dct_value_tokens.h" +#include "dct_value_cost.h" + +const TOKENVALUE *const vp8_dct_value_tokens_ptr = dct_value_tokens + + DCT_MAX_VALUE; +const short *const vp8_dct_value_cost_ptr = dct_value_cost + DCT_MAX_VALUE; + +#if 0 +int skip_true_count = 0; +int skip_false_count = 0; +#endif + +/* function used to generate dct_value_tokens and dct_value_cost tables */ +/* +static void fill_value_tokens() +{ + + TOKENVALUE *t = dct_value_tokens + DCT_MAX_VALUE; + const vp8_extra_bit_struct *e = vp8_extra_bits; + + int i = -DCT_MAX_VALUE; + int sign = 1; + + do + { + if (!i) + sign = 0; + + { + const int a = sign ? -i : i; + int eb = sign; + + if (a > 4) + { + int j = 4; + + while (++j < 11 && e[j].base_val <= a) {} + + t[i].Token = --j; + eb |= (a - e[j].base_val) << 1; + } + else + t[i].Token = a; + + t[i].Extra = eb; + } + + // initialize the cost for extra bits for all possible coefficient value. + { + int cost = 0; + const vp8_extra_bit_struct *p = vp8_extra_bits + t[i].Token; + + if (p->base_val) + { + const int extra = t[i].Extra; + const int Length = p->Len; + + if (Length) + cost += vp8_treed_cost(p->tree, p->prob, extra >> 1, Length); + + cost += vp8_cost_bit(vp8_prob_half, extra & 1); // sign + dct_value_cost[i + DCT_MAX_VALUE] = cost; + } + + } + + } + while (++i < DCT_MAX_VALUE); + + vp8_dct_value_tokens_ptr = dct_value_tokens + DCT_MAX_VALUE; + vp8_dct_value_cost_ptr = dct_value_cost + DCT_MAX_VALUE; +} +*/ + +static void tokenize2nd_order_b +( + MACROBLOCKD *x, + TOKENEXTRA **tp, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + int c; /* start at DC */ + TOKENEXTRA *t = *tp;/* store tokens starting here */ + const BLOCKD *b; + const short *qcoeff_ptr; + ENTROPY_CONTEXT * a; + ENTROPY_CONTEXT * l; + int band, rc, v, token; + int eob; + + b = x->block + 24; + qcoeff_ptr = b->qcoeff; + a = (ENTROPY_CONTEXT *)x->above_context + 8; + l = (ENTROPY_CONTEXT *)x->left_context + 8; + eob = x->eobs[24]; + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + if(!eob) + { + /* c = band for this case */ + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; + t->skip_eob_node = 0; + + ++cpi->coef_counts [1] [0] [pt] [DCT_EOB_TOKEN]; + t++; + *tp = t; + *a = *l = 0; + return; + } + + v = qcoeff_ptr[0]; + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + token = vp8_dct_value_tokens_ptr[v].Token; + t->Token = token; + + t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; + t->skip_eob_node = 0; + ++cpi->coef_counts [1] [0] [pt] [token]; + pt = vp8_prev_token_class[token]; + t++; + c = 1; + + for (; c < eob; c++) + { + rc = vp8_default_zig_zag1d[c]; + band = vp8_coef_bands[c]; + v = qcoeff_ptr[rc]; + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + token = vp8_dct_value_tokens_ptr[v].Token; + + t->Token = token; + t->context_tree = cpi->common.fc.coef_probs [1] [band] [pt]; + + t->skip_eob_node = ((pt == 0)); + + ++cpi->coef_counts [1] [band] [pt] [token]; + + pt = vp8_prev_token_class[token]; + t++; + } + if (c < 16) + { + band = vp8_coef_bands[c]; + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [1] [band] [pt]; + + t->skip_eob_node = 0; + + ++cpi->coef_counts [1] [band] [pt] [DCT_EOB_TOKEN]; + + t++; + } + + *tp = t; + *a = *l = 1; + +} + +static void tokenize1st_order_b +( + MACROBLOCKD *x, + TOKENEXTRA **tp, + int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + VP8_COMP *cpi +) +{ + unsigned int block; + const BLOCKD *b; + int pt; /* near block/prev token context index */ + int c; + int token; + TOKENEXTRA *t = *tp;/* store tokens starting here */ + const short *qcoeff_ptr; + ENTROPY_CONTEXT * a; + ENTROPY_CONTEXT * l; + int band, rc, v; + int tmp1, tmp2; + + b = x->block; + /* Luma */ + for (block = 0; block < 16; block++, b++) + { + tmp1 = vp8_block2above[block]; + tmp2 = vp8_block2left[block]; + qcoeff_ptr = b->qcoeff; + a = (ENTROPY_CONTEXT *)x->above_context + tmp1; + l = (ENTROPY_CONTEXT *)x->left_context + tmp2; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + c = type ? 0 : 1; + + if(c >= *b->eob) + { + /* c = band for this case */ + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [type] [c] [pt]; + t->skip_eob_node = 0; + + ++cpi->coef_counts [type] [c] [pt] [DCT_EOB_TOKEN]; + t++; + *tp = t; + *a = *l = 0; + continue; + } + + v = qcoeff_ptr[c]; + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + token = vp8_dct_value_tokens_ptr[v].Token; + t->Token = token; + + t->context_tree = cpi->common.fc.coef_probs [type] [c] [pt]; + t->skip_eob_node = 0; + ++cpi->coef_counts [type] [c] [pt] [token]; + pt = vp8_prev_token_class[token]; + t++; + c++; + + for (; c < *b->eob; c++) + { + rc = vp8_default_zig_zag1d[c]; + band = vp8_coef_bands[c]; + v = qcoeff_ptr[rc]; + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + token = vp8_dct_value_tokens_ptr[v].Token; + + t->Token = token; + t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; + + t->skip_eob_node = (pt == 0); + ++cpi->coef_counts [type] [band] [pt] [token]; + + pt = vp8_prev_token_class[token]; + t++; + } + if (c < 16) + { + band = vp8_coef_bands[c]; + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; + + t->skip_eob_node = 0; + ++cpi->coef_counts [type] [band] [pt] [DCT_EOB_TOKEN]; + + t++; + } + *tp = t; + *a = *l = 1; + } + + /* Chroma */ + for (block = 16; block < 24; block++, b++) + { + tmp1 = vp8_block2above[block]; + tmp2 = vp8_block2left[block]; + qcoeff_ptr = b->qcoeff; + a = (ENTROPY_CONTEXT *)x->above_context + tmp1; + l = (ENTROPY_CONTEXT *)x->left_context + tmp2; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + if(!(*b->eob)) + { + /* c = band for this case */ + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; + t->skip_eob_node = 0; + + ++cpi->coef_counts [2] [0] [pt] [DCT_EOB_TOKEN]; + t++; + *tp = t; + *a = *l = 0; + continue; + } + + v = qcoeff_ptr[0]; + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + token = vp8_dct_value_tokens_ptr[v].Token; + t->Token = token; + + t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; + t->skip_eob_node = 0; + ++cpi->coef_counts [2] [0] [pt] [token]; + pt = vp8_prev_token_class[token]; + t++; + c = 1; + + for (; c < *b->eob; c++) + { + rc = vp8_default_zig_zag1d[c]; + band = vp8_coef_bands[c]; + v = qcoeff_ptr[rc]; + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + token = vp8_dct_value_tokens_ptr[v].Token; + + t->Token = token; + t->context_tree = cpi->common.fc.coef_probs [2] [band] [pt]; + + t->skip_eob_node = (pt == 0); + + ++cpi->coef_counts [2] [band] [pt] [token]; + + pt = vp8_prev_token_class[token]; + t++; + } + if (c < 16) + { + band = vp8_coef_bands[c]; + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [2] [band] [pt]; + + t->skip_eob_node = 0; + + ++cpi->coef_counts [2] [band] [pt] [DCT_EOB_TOKEN]; + + t++; + } + *tp = t; + *a = *l = 1; + } +} + + +static int mb_is_skippable(MACROBLOCKD *x, int has_y2_block) +{ + int skip = 1; + int i = 0; + + if (has_y2_block) + { + for (i = 0; i < 16; i++) + skip &= (x->eobs[i] < 2); + } + + for (; i < 24 + has_y2_block; i++) + skip &= (!x->eobs[i]); + + return skip; +} + + +void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) +{ + int plane_type; + int has_y2_block; + + has_y2_block = (x->mode_info_context->mbmi.mode != B_PRED + && x->mode_info_context->mbmi.mode != SPLITMV); + + x->mode_info_context->mbmi.mb_skip_coeff = mb_is_skippable(x, has_y2_block); + if (x->mode_info_context->mbmi.mb_skip_coeff) + { + if (!cpi->common.mb_no_coeff_skip) + { + vp8_stuff_mb(cpi, x, t); + } + else + { + vp8_fix_contexts(x); + cpi->skip_true_count++; + } + + return; + } + + plane_type = 3; + if(has_y2_block) + { + tokenize2nd_order_b(x, t, cpi); + plane_type = 0; + } + + tokenize1st_order_b(x, t, plane_type, cpi); +} + + +#ifdef ENTROPY_STATS + +void init_context_counters(void) +{ + vpx_memset(context_counters, 0, sizeof(context_counters)); +} + +void print_context_counters() +{ + + int type, band, pt, t; + + FILE *const f = fopen("context.c", "w"); + + fprintf(f, "#include \"entropy.h\"\n"); + + fprintf(f, "\n/* *** GENERATED FILE: DO NOT EDIT *** */\n\n"); + + fprintf(f, "int Contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS];\n\n"); + + fprintf(f, "const int default_contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS] = {"); + +# define Comma( X) (X? ",":"") + + type = 0; + + do + { + fprintf(f, "%s\n { /* block Type %d */", Comma(type), type); + + band = 0; + + do + { + fprintf(f, "%s\n { /* Coeff Band %d */", Comma(band), band); + + pt = 0; + + do + { + fprintf(f, "%s\n {", Comma(pt)); + + t = 0; + + do + { + const _int64 x = context_counters [type] [band] [pt] [t]; + const int y = (int) x; + + assert(x == (_int64) y); /* no overflow handling yet */ + fprintf(f, "%s %d", Comma(t), y); + + } + while (++t < MAX_ENTROPY_TOKENS); + + fprintf(f, "}"); + } + while (++pt < PREV_COEF_CONTEXTS); + + fprintf(f, "\n }"); + + } + while (++band < COEF_BANDS); + + fprintf(f, "\n }"); + } + while (++type < BLOCK_TYPES); + + fprintf(f, "\n};\n"); + fclose(f); +} +#endif + + +static void stuff2nd_order_b +( + TOKENEXTRA **tp, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; + t->skip_eob_node = 0; + ++cpi->coef_counts [1] [0] [pt] [DCT_EOB_TOKEN]; + ++t; + + *tp = t; + pt = 0; + *a = *l = pt; + +} + +static void stuff1st_order_b +( + TOKENEXTRA **tp, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + int type, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + int band; + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + band = type ? 0 : 1; + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; + t->skip_eob_node = 0; + ++cpi->coef_counts [type] [band] [pt] [DCT_EOB_TOKEN]; + ++t; + *tp = t; + pt = 0; /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} +static +void stuff1st_order_buv +( + TOKENEXTRA **tp, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; + t->skip_eob_node = 0; + ++cpi->coef_counts[2] [0] [pt] [DCT_EOB_TOKEN]; + ++t; + *tp = t; + pt = 0; /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} + +void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) +{ + ENTROPY_CONTEXT * A = (ENTROPY_CONTEXT *)x->above_context; + ENTROPY_CONTEXT * L = (ENTROPY_CONTEXT *)x->left_context; + int plane_type; + int b; + plane_type = 3; + if((x->mode_info_context->mbmi.mode != B_PRED + && x->mode_info_context->mbmi.mode != SPLITMV)) + { + stuff2nd_order_b(t, + A + vp8_block2above[24], L + vp8_block2left[24], cpi); + plane_type = 0; + } + + for (b = 0; b < 16; b++) + stuff1st_order_b(t, + A + vp8_block2above[b], + L + vp8_block2left[b], plane_type, cpi); + + for (b = 16; b < 24; b++) + stuff1st_order_buv(t, + A + vp8_block2above[b], + L + vp8_block2left[b], cpi); + +} +void vp8_fix_contexts(MACROBLOCKD *x) +{ + /* Clear entropy contexts for Y2 blocks */ + if (x->mode_info_context->mbmi.mode != B_PRED && x->mode_info_context->mbmi.mode != SPLITMV) + { + vpx_memset(x->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); + vpx_memset(x->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); + } + else + { + vpx_memset(x->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)-1); + vpx_memset(x->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)-1); + } + +} diff --git a/vp8/encoder/tokenize.h b/vp8/encoder/tokenize.h new file mode 100644 index 0000000..c2d1438 --- /dev/null +++ b/vp8/encoder/tokenize.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef tokenize_h +#define tokenize_h + +#include "vp8/common/entropy.h" +#include "block.h" + +void vp8_tokenize_initialize(); + +typedef struct +{ + short Token; + short Extra; +} TOKENVALUE; + +typedef struct +{ + const vp8_prob *context_tree; + short Extra; + unsigned char Token; + unsigned char skip_eob_node; +} TOKENEXTRA; + +int rd_cost_mby(MACROBLOCKD *); + +#ifdef ENTROPY_STATS +void init_context_counters(); +void print_context_counters(); + +extern _int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; +#endif + +extern const short *const vp8_dct_value_cost_ptr; +/* TODO: The Token field should be broken out into a separate char array to + * improve cache locality, since it's needed for costing when the rest of the + * fields are not. + */ +extern const TOKENVALUE *const vp8_dct_value_tokens_ptr; + +#endif /* tokenize_h */ diff --git a/vp8/encoder/treewriter.c b/vp8/encoder/treewriter.c new file mode 100644 index 0000000..ef25f67 --- /dev/null +++ b/vp8/encoder/treewriter.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "treewriter.h" + +static void cost( + int *const C, + vp8_tree T, + const vp8_prob *const P, + int i, + int c +) +{ + const vp8_prob p = P [i>>1]; + + do + { + const vp8_tree_index j = T[i]; + const int d = c + vp8_cost_bit(p, i & 1); + + if (j <= 0) + C[-j] = d; + else + cost(C, T, P, j, d); + } + while (++i & 1); +} +void vp8_cost_tokens(int *c, const vp8_prob *p, vp8_tree t) +{ + cost(c, t, p, 0, 0); +} +void vp8_cost_tokens2(int *c, const vp8_prob *p, vp8_tree t,int start) +{ + cost(c, t, p, start, 0); +} diff --git a/vp8/encoder/treewriter.h b/vp8/encoder/treewriter.h new file mode 100644 index 0000000..48574f3 --- /dev/null +++ b/vp8/encoder/treewriter.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __INC_TREEWRITER_H +#define __INC_TREEWRITER_H + +/* Trees map alphabets into huffman-like codes suitable for an arithmetic + bit coder. Timothy S Murphy 11 October 2004 */ + +#include "vp8/common/treecoder.h" + +#include "boolhuff.h" /* for now */ + +typedef BOOL_CODER vp8_writer; + +#define vp8_write vp8_encode_bool +#define vp8_write_literal vp8_encode_value +#define vp8_write_bit( W, V) vp8_write( W, V, vp8_prob_half) + +#define vp8bc_write vp8bc_write_bool +#define vp8bc_write_literal vp8bc_write_bits +#define vp8bc_write_bit( W, V) vp8bc_write_bits( W, V, 1) + + +/* Approximate length of an encoded bool in 256ths of a bit at given prob */ + +#define vp8_cost_zero( x) ( vp8_prob_cost[x]) +#define vp8_cost_one( x) vp8_cost_zero( vp8_complement(x)) + +#define vp8_cost_bit( x, b) vp8_cost_zero( (b)? vp8_complement(x) : (x) ) + +/* VP8BC version is scaled by 2^20 rather than 2^8; see bool_coder.h */ + + +/* Both of these return bits, not scaled bits. */ + +static unsigned int vp8_cost_branch(const unsigned int ct[2], vp8_prob p) +{ + /* Imitate existing calculation */ + + return ((ct[0] * vp8_cost_zero(p)) + + (ct[1] * vp8_cost_one(p))) >> 8; +} + +/* Small functions to write explicit values and tokens, as well as + estimate their lengths. */ + +static void vp8_treed_write +( + vp8_writer *const w, + vp8_tree t, + const vp8_prob *const p, + int v, + int n /* number of bits in v, assumed nonzero */ +) +{ + vp8_tree_index i = 0; + + do + { + const int b = (v >> --n) & 1; + vp8_write(w, b, p[i>>1]); + i = t[i+b]; + } + while (n); +} +static void vp8_write_token +( + vp8_writer *const w, + vp8_tree t, + const vp8_prob *const p, + vp8_token *const x +) +{ + vp8_treed_write(w, t, p, x->value, x->Len); +} + +static int vp8_treed_cost( + vp8_tree t, + const vp8_prob *const p, + int v, + int n /* number of bits in v, assumed nonzero */ +) +{ + int c = 0; + vp8_tree_index i = 0; + + do + { + const int b = (v >> --n) & 1; + c += vp8_cost_bit(p[i>>1], b); + i = t[i+b]; + } + while (n); + + return c; +} +static int vp8_cost_token +( + vp8_tree t, + const vp8_prob *const p, + vp8_token *const x +) +{ + return vp8_treed_cost(t, p, x->value, x->Len); +} + +/* Fill array of costs for all possible token values. */ + +void vp8_cost_tokens( + int *Costs, const vp8_prob *, vp8_tree +); + +void vp8_cost_tokens2( + int *Costs, const vp8_prob *, vp8_tree, int +); + +#endif diff --git a/vp8/encoder/x86/dct_mmx.asm b/vp8/encoder/x86/dct_mmx.asm new file mode 100644 index 0000000..f07b030 --- /dev/null +++ b/vp8/encoder/x86/dct_mmx.asm @@ -0,0 +1,241 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_fdct4x4_mmx(short *input, short *output, int pitch) +global sym(vp8_short_fdct4x4_mmx) +sym(vp8_short_fdct4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ; input + mov rdi, arg(1) ; output + + movsxd rax, dword ptr arg(2) ;pitch + + lea rcx, [rsi + rax*2] + ; read the input data + movq mm0, [rsi] + movq mm1, [rsi + rax] + + movq mm2, [rcx] + movq mm4, [rcx + rax] + + ; transpose for the first stage + movq mm3, mm0 ; 00 01 02 03 + movq mm5, mm2 ; 20 21 22 23 + + punpcklwd mm0, mm1 ; 00 10 01 11 + punpckhwd mm3, mm1 ; 02 12 03 13 + + punpcklwd mm2, mm4 ; 20 30 21 31 + punpckhwd mm5, mm4 ; 22 32 23 33 + + movq mm1, mm0 ; 00 10 01 11 + punpckldq mm0, mm2 ; 00 10 20 30 + + punpckhdq mm1, mm2 ; 01 11 21 31 + + movq mm2, mm3 ; 02 12 03 13 + punpckldq mm2, mm5 ; 02 12 22 32 + + punpckhdq mm3, mm5 ; 03 13 23 33 + + ; mm0 0 + ; mm1 1 + ; mm2 2 + ; mm3 3 + + ; first stage + movq mm5, mm0 + movq mm4, mm1 + + paddw mm0, mm3 ; a1 = 0 + 3 + paddw mm1, mm2 ; b1 = 1 + 2 + + psubw mm4, mm2 ; c1 = 1 - 2 + psubw mm5, mm3 ; d1 = 0 - 3 + + psllw mm5, 3 + psllw mm4, 3 + + psllw mm0, 3 + psllw mm1, 3 + + ; output 0 and 2 + movq mm2, mm0 ; a1 + + paddw mm0, mm1 ; op[0] = a1 + b1 + psubw mm2, mm1 ; op[2] = a1 - b1 + + ; output 1 and 3 + ; interleave c1, d1 + movq mm1, mm5 ; d1 + punpcklwd mm1, mm4 ; c1 d1 + punpckhwd mm5, mm4 ; c1 d1 + + movq mm3, mm1 + movq mm4, mm5 + + pmaddwd mm1, MMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + pmaddwd mm4, MMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + + pmaddwd mm3, MMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + pmaddwd mm5, MMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + + paddd mm1, MMWORD PTR[GLOBAL(_14500)] + paddd mm4, MMWORD PTR[GLOBAL(_14500)] + paddd mm3, MMWORD PTR[GLOBAL(_7500)] + paddd mm5, MMWORD PTR[GLOBAL(_7500)] + + psrad mm1, 12 ; (c1 * 2217 + d1 * 5352 + 14500)>>12 + psrad mm4, 12 ; (c1 * 2217 + d1 * 5352 + 14500)>>12 + psrad mm3, 12 ; (d1 * 2217 - c1 * 5352 + 7500)>>12 + psrad mm5, 12 ; (d1 * 2217 - c1 * 5352 + 7500)>>12 + + packssdw mm1, mm4 ; op[1] + packssdw mm3, mm5 ; op[3] + + ; done with vertical + ; transpose for the second stage + movq mm4, mm0 ; 00 10 20 30 + movq mm5, mm2 ; 02 12 22 32 + + punpcklwd mm0, mm1 ; 00 01 10 11 + punpckhwd mm4, mm1 ; 20 21 30 31 + + punpcklwd mm2, mm3 ; 02 03 12 13 + punpckhwd mm5, mm3 ; 22 23 32 33 + + movq mm1, mm0 ; 00 01 10 11 + punpckldq mm0, mm2 ; 00 01 02 03 + + punpckhdq mm1, mm2 ; 01 22 12 13 + + movq mm2, mm4 ; 20 31 30 31 + punpckldq mm2, mm5 ; 20 21 22 23 + + punpckhdq mm4, mm5 ; 30 31 32 33 + + ; mm0 0 + ; mm1 1 + ; mm2 2 + ; mm3 4 + + movq mm5, mm0 + movq mm3, mm1 + + paddw mm0, mm4 ; a1 = 0 + 3 + paddw mm1, mm2 ; b1 = 1 + 2 + + psubw mm3, mm2 ; c1 = 1 - 2 + psubw mm5, mm4 ; d1 = 0 - 3 + + pxor mm6, mm6 ; zero out for compare + + pcmpeqw mm6, mm5 ; d1 != 0 + + pandn mm6, MMWORD PTR[GLOBAL(_cmp_mask)] ; clear upper, + ; and keep bit 0 of lower + + ; output 0 and 2 + movq mm2, mm0 ; a1 + + paddw mm0, mm1 ; a1 + b1 + psubw mm2, mm1 ; a1 - b1 + + paddw mm0, MMWORD PTR[GLOBAL(_7w)] + paddw mm2, MMWORD PTR[GLOBAL(_7w)] + + psraw mm0, 4 ; op[0] = (a1 + b1 + 7)>>4 + psraw mm2, 4 ; op[8] = (a1 - b1 + 7)>>4 + + movq MMWORD PTR[rdi + 0 ], mm0 + movq MMWORD PTR[rdi + 16], mm2 + + ; output 1 and 3 + ; interleave c1, d1 + movq mm1, mm5 ; d1 + punpcklwd mm1, mm3 ; c1 d1 + punpckhwd mm5, mm3 ; c1 d1 + + movq mm3, mm1 + movq mm4, mm5 + + pmaddwd mm1, MMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + pmaddwd mm4, MMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + + pmaddwd mm3, MMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + pmaddwd mm5, MMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + + paddd mm1, MMWORD PTR[GLOBAL(_12000)] + paddd mm4, MMWORD PTR[GLOBAL(_12000)] + paddd mm3, MMWORD PTR[GLOBAL(_51000)] + paddd mm5, MMWORD PTR[GLOBAL(_51000)] + + psrad mm1, 16 ; (c1 * 2217 + d1 * 5352 + 14500)>>16 + psrad mm4, 16 ; (c1 * 2217 + d1 * 5352 + 14500)>>16 + psrad mm3, 16 ; (d1 * 2217 - c1 * 5352 + 7500)>>16 + psrad mm5, 16 ; (d1 * 2217 - c1 * 5352 + 7500)>>16 + + packssdw mm1, mm4 ; op[4] + packssdw mm3, mm5 ; op[12] + + paddw mm1, mm6 ; op[4] += (d1!=0) + + movq MMWORD PTR[rdi + 8 ], mm1 + movq MMWORD PTR[rdi + 24], mm3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 8 +_5352_2217: + dw 5352 + dw 2217 + dw 5352 + dw 2217 +align 8 +_2217_neg5352: + dw 2217 + dw -5352 + dw 2217 + dw -5352 +align 8 +_cmp_mask: + times 4 dw 1 +align 8 +_7w: + times 4 dw 7 +align 8 +_14500: + times 2 dd 14500 +align 8 +_7500: + times 2 dd 7500 +align 8 +_12000: + times 2 dd 12000 +align 8 +_51000: + times 2 dd 51000 diff --git a/vp8/encoder/x86/dct_sse2.asm b/vp8/encoder/x86/dct_sse2.asm new file mode 100644 index 0000000..3d52a5d --- /dev/null +++ b/vp8/encoder/x86/dct_sse2.asm @@ -0,0 +1,432 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%macro STACK_FRAME_CREATE 0 +%if ABI_IS_32BIT + %define input rsi + %define output rdi + %define pitch rax + push rbp + mov rbp, rsp + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) + mov rdi, arg(1) + + movsxd rax, dword ptr arg(2) + lea rcx, [rsi + rax*2] +%else + %ifidn __OUTPUT_FORMAT__,x64 + %define input rcx + %define output rdx + %define pitch r8 + SAVE_XMM 7, u + %else + %define input rdi + %define output rsi + %define pitch rdx + %endif +%endif +%endmacro + +%macro STACK_FRAME_DESTROY 0 + %define input + %define output + %define pitch + +%if ABI_IS_32BIT + pop rdi + pop rsi + RESTORE_GOT + pop rbp +%else + %ifidn __OUTPUT_FORMAT__,x64 + RESTORE_XMM + %endif +%endif + ret +%endmacro + +;void vp8_short_fdct4x4_sse2(short *input, short *output, int pitch) +global sym(vp8_short_fdct4x4_sse2) +sym(vp8_short_fdct4x4_sse2): + + STACK_FRAME_CREATE + + movq xmm0, MMWORD PTR[input ] ;03 02 01 00 + movq xmm2, MMWORD PTR[input+ pitch] ;13 12 11 10 + lea input, [input+2*pitch] + movq xmm1, MMWORD PTR[input ] ;23 22 21 20 + movq xmm3, MMWORD PTR[input+ pitch] ;33 32 31 30 + + punpcklqdq xmm0, xmm2 ;13 12 11 10 03 02 01 00 + punpcklqdq xmm1, xmm3 ;33 32 31 30 23 22 21 20 + + movdqa xmm2, xmm0 + punpckldq xmm0, xmm1 ;23 22 03 02 21 20 01 00 + punpckhdq xmm2, xmm1 ;33 32 13 12 31 30 11 10 + movdqa xmm1, xmm0 + punpckldq xmm0, xmm2 ;31 21 30 20 11 10 01 00 + pshufhw xmm1, xmm1, 0b1h ;22 23 02 03 xx xx xx xx + pshufhw xmm2, xmm2, 0b1h ;32 33 12 13 xx xx xx xx + + punpckhdq xmm1, xmm2 ;32 33 22 23 12 13 02 03 + movdqa xmm3, xmm0 + paddw xmm0, xmm1 ;b1 a1 b1 a1 b1 a1 b1 a1 + psubw xmm3, xmm1 ;c1 d1 c1 d1 c1 d1 c1 d1 + psllw xmm0, 3 ;b1 <<= 3 a1 <<= 3 + psllw xmm3, 3 ;c1 <<= 3 d1 <<= 3 + + movdqa xmm1, xmm0 + pmaddwd xmm0, XMMWORD PTR[GLOBAL(_mult_add)] ;a1 + b1 + pmaddwd xmm1, XMMWORD PTR[GLOBAL(_mult_sub)] ;a1 - b1 + movdqa xmm4, xmm3 + pmaddwd xmm3, XMMWORD PTR[GLOBAL(_5352_2217)] ;c1*2217 + d1*5352 + pmaddwd xmm4, XMMWORD PTR[GLOBAL(_2217_neg5352)];d1*2217 - c1*5352 + + paddd xmm3, XMMWORD PTR[GLOBAL(_14500)] + paddd xmm4, XMMWORD PTR[GLOBAL(_7500)] + psrad xmm3, 12 ;(c1 * 2217 + d1 * 5352 + 14500)>>12 + psrad xmm4, 12 ;(d1 * 2217 - c1 * 5352 + 7500)>>12 + + packssdw xmm0, xmm1 ;op[2] op[0] + packssdw xmm3, xmm4 ;op[3] op[1] + ; 23 22 21 20 03 02 01 00 + ; + ; 33 32 31 30 13 12 11 10 + ; + movdqa xmm2, xmm0 + punpcklqdq xmm0, xmm3 ;13 12 11 10 03 02 01 00 + punpckhqdq xmm2, xmm3 ;23 22 21 20 33 32 31 30 + + movdqa xmm3, xmm0 + punpcklwd xmm0, xmm2 ;32 30 22 20 12 10 02 00 + punpckhwd xmm3, xmm2 ;33 31 23 21 13 11 03 01 + movdqa xmm2, xmm0 + punpcklwd xmm0, xmm3 ;13 12 11 10 03 02 01 00 + punpckhwd xmm2, xmm3 ;33 32 31 30 23 22 21 20 + + movdqa xmm5, XMMWORD PTR[GLOBAL(_7)] + pshufd xmm2, xmm2, 04eh + movdqa xmm3, xmm0 + paddw xmm0, xmm2 ;b1 b1 b1 b1 a1 a1 a1 a1 + psubw xmm3, xmm2 ;c1 c1 c1 c1 d1 d1 d1 d1 + + pshufd xmm0, xmm0, 0d8h ;b1 b1 a1 a1 b1 b1 a1 a1 + movdqa xmm2, xmm3 ;save d1 for compare + pshufd xmm3, xmm3, 0d8h ;c1 c1 d1 d1 c1 c1 d1 d1 + pshuflw xmm0, xmm0, 0d8h ;b1 b1 a1 a1 b1 a1 b1 a1 + pshuflw xmm3, xmm3, 0d8h ;c1 c1 d1 d1 c1 d1 c1 d1 + pshufhw xmm0, xmm0, 0d8h ;b1 a1 b1 a1 b1 a1 b1 a1 + pshufhw xmm3, xmm3, 0d8h ;c1 d1 c1 d1 c1 d1 c1 d1 + movdqa xmm1, xmm0 + pmaddwd xmm0, XMMWORD PTR[GLOBAL(_mult_add)] ;a1 + b1 + pmaddwd xmm1, XMMWORD PTR[GLOBAL(_mult_sub)] ;a1 - b1 + + pxor xmm4, xmm4 ;zero out for compare + paddd xmm0, xmm5 + paddd xmm1, xmm5 + pcmpeqw xmm2, xmm4 + psrad xmm0, 4 ;(a1 + b1 + 7)>>4 + psrad xmm1, 4 ;(a1 - b1 + 7)>>4 + pandn xmm2, XMMWORD PTR[GLOBAL(_cmp_mask)] ;clear upper, + ;and keep bit 0 of lower + + movdqa xmm4, xmm3 + pmaddwd xmm3, XMMWORD PTR[GLOBAL(_5352_2217)] ;c1*2217 + d1*5352 + pmaddwd xmm4, XMMWORD PTR[GLOBAL(_2217_neg5352)] ;d1*2217 - c1*5352 + paddd xmm3, XMMWORD PTR[GLOBAL(_12000)] + paddd xmm4, XMMWORD PTR[GLOBAL(_51000)] + packssdw xmm0, xmm1 ;op[8] op[0] + psrad xmm3, 16 ;(c1 * 2217 + d1 * 5352 + 12000)>>16 + psrad xmm4, 16 ;(d1 * 2217 - c1 * 5352 + 51000)>>16 + + packssdw xmm3, xmm4 ;op[12] op[4] + movdqa xmm1, xmm0 + paddw xmm3, xmm2 ;op[4] += (d1!=0) + punpcklqdq xmm0, xmm3 ;op[4] op[0] + punpckhqdq xmm1, xmm3 ;op[12] op[8] + + movdqa XMMWORD PTR[output + 0], xmm0 + movdqa XMMWORD PTR[output + 16], xmm1 + + STACK_FRAME_DESTROY + +;void vp8_short_fdct8x4_sse2(short *input, short *output, int pitch) +global sym(vp8_short_fdct8x4_sse2) +sym(vp8_short_fdct8x4_sse2): + + STACK_FRAME_CREATE + + ; read the input data + movdqa xmm0, [input ] + movdqa xmm2, [input+ pitch] + lea input, [input+2*pitch] + movdqa xmm4, [input ] + movdqa xmm3, [input+ pitch] + + ; transpose for the first stage + movdqa xmm1, xmm0 ; 00 01 02 03 04 05 06 07 + movdqa xmm5, xmm4 ; 20 21 22 23 24 25 26 27 + + punpcklwd xmm0, xmm2 ; 00 10 01 11 02 12 03 13 + punpckhwd xmm1, xmm2 ; 04 14 05 15 06 16 07 17 + + punpcklwd xmm4, xmm3 ; 20 30 21 31 22 32 23 33 + punpckhwd xmm5, xmm3 ; 24 34 25 35 26 36 27 37 + + movdqa xmm2, xmm0 ; 00 10 01 11 02 12 03 13 + punpckldq xmm0, xmm4 ; 00 10 20 30 01 11 21 31 + + punpckhdq xmm2, xmm4 ; 02 12 22 32 03 13 23 33 + + movdqa xmm4, xmm1 ; 04 14 05 15 06 16 07 17 + punpckldq xmm4, xmm5 ; 04 14 24 34 05 15 25 35 + + punpckhdq xmm1, xmm5 ; 06 16 26 36 07 17 27 37 + movdqa xmm3, xmm2 ; 02 12 22 32 03 13 23 33 + + punpckhqdq xmm3, xmm1 ; 03 13 23 33 07 17 27 37 + punpcklqdq xmm2, xmm1 ; 02 12 22 32 06 16 26 36 + + movdqa xmm1, xmm0 ; 00 10 20 30 01 11 21 31 + punpcklqdq xmm0, xmm4 ; 00 10 20 30 04 14 24 34 + + punpckhqdq xmm1, xmm4 ; 01 11 21 32 05 15 25 35 + + ; xmm0 0 + ; xmm1 1 + ; xmm2 2 + ; xmm3 3 + + ; first stage + movdqa xmm5, xmm0 + movdqa xmm4, xmm1 + + paddw xmm0, xmm3 ; a1 = 0 + 3 + paddw xmm1, xmm2 ; b1 = 1 + 2 + + psubw xmm4, xmm2 ; c1 = 1 - 2 + psubw xmm5, xmm3 ; d1 = 0 - 3 + + psllw xmm5, 3 + psllw xmm4, 3 + + psllw xmm0, 3 + psllw xmm1, 3 + + ; output 0 and 2 + movdqa xmm2, xmm0 ; a1 + + paddw xmm0, xmm1 ; op[0] = a1 + b1 + psubw xmm2, xmm1 ; op[2] = a1 - b1 + + ; output 1 and 3 + ; interleave c1, d1 + movdqa xmm1, xmm5 ; d1 + punpcklwd xmm1, xmm4 ; c1 d1 + punpckhwd xmm5, xmm4 ; c1 d1 + + movdqa xmm3, xmm1 + movdqa xmm4, xmm5 + + pmaddwd xmm1, XMMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + pmaddwd xmm4, XMMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + + pmaddwd xmm3, XMMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + pmaddwd xmm5, XMMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + + paddd xmm1, XMMWORD PTR[GLOBAL(_14500)] + paddd xmm4, XMMWORD PTR[GLOBAL(_14500)] + paddd xmm3, XMMWORD PTR[GLOBAL(_7500)] + paddd xmm5, XMMWORD PTR[GLOBAL(_7500)] + + psrad xmm1, 12 ; (c1 * 2217 + d1 * 5352 + 14500)>>12 + psrad xmm4, 12 ; (c1 * 2217 + d1 * 5352 + 14500)>>12 + psrad xmm3, 12 ; (d1 * 2217 - c1 * 5352 + 7500)>>12 + psrad xmm5, 12 ; (d1 * 2217 - c1 * 5352 + 7500)>>12 + + packssdw xmm1, xmm4 ; op[1] + packssdw xmm3, xmm5 ; op[3] + + ; done with vertical + ; transpose for the second stage + movdqa xmm4, xmm0 ; 00 10 20 30 04 14 24 34 + movdqa xmm5, xmm2 ; 02 12 22 32 06 16 26 36 + + punpcklwd xmm0, xmm1 ; 00 01 10 11 20 21 30 31 + punpckhwd xmm4, xmm1 ; 04 05 14 15 24 25 34 35 + + punpcklwd xmm2, xmm3 ; 02 03 12 13 22 23 32 33 + punpckhwd xmm5, xmm3 ; 06 07 16 17 26 27 36 37 + + movdqa xmm1, xmm0 ; 00 01 10 11 20 21 30 31 + punpckldq xmm0, xmm2 ; 00 01 02 03 10 11 12 13 + + punpckhdq xmm1, xmm2 ; 20 21 22 23 30 31 32 33 + + movdqa xmm2, xmm4 ; 04 05 14 15 24 25 34 35 + punpckldq xmm2, xmm5 ; 04 05 06 07 14 15 16 17 + + punpckhdq xmm4, xmm5 ; 24 25 26 27 34 35 36 37 + movdqa xmm3, xmm1 ; 20 21 22 23 30 31 32 33 + + punpckhqdq xmm3, xmm4 ; 30 31 32 33 34 35 36 37 + punpcklqdq xmm1, xmm4 ; 20 21 22 23 24 25 26 27 + + movdqa xmm4, xmm0 ; 00 01 02 03 10 11 12 13 + punpcklqdq xmm0, xmm2 ; 00 01 02 03 04 05 06 07 + + punpckhqdq xmm4, xmm2 ; 10 11 12 13 14 15 16 17 + + ; xmm0 0 + ; xmm1 4 + ; xmm2 1 + ; xmm3 3 + + movdqa xmm5, xmm0 + movdqa xmm2, xmm1 + + paddw xmm0, xmm3 ; a1 = 0 + 3 + paddw xmm1, xmm4 ; b1 = 1 + 2 + + psubw xmm4, xmm2 ; c1 = 1 - 2 + psubw xmm5, xmm3 ; d1 = 0 - 3 + + pxor xmm6, xmm6 ; zero out for compare + + pcmpeqw xmm6, xmm5 ; d1 != 0 + + pandn xmm6, XMMWORD PTR[GLOBAL(_cmp_mask8x4)] ; clear upper, + ; and keep bit 0 of lower + + ; output 0 and 2 + movdqa xmm2, xmm0 ; a1 + + paddw xmm0, xmm1 ; a1 + b1 + psubw xmm2, xmm1 ; a1 - b1 + + paddw xmm0, XMMWORD PTR[GLOBAL(_7w)] + paddw xmm2, XMMWORD PTR[GLOBAL(_7w)] + + psraw xmm0, 4 ; op[0] = (a1 + b1 + 7)>>4 + psraw xmm2, 4 ; op[8] = (a1 - b1 + 7)>>4 + + ; output 1 and 3 + ; interleave c1, d1 + movdqa xmm1, xmm5 ; d1 + punpcklwd xmm1, xmm4 ; c1 d1 + punpckhwd xmm5, xmm4 ; c1 d1 + + movdqa xmm3, xmm1 + movdqa xmm4, xmm5 + + pmaddwd xmm1, XMMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + pmaddwd xmm4, XMMWORD PTR[GLOBAL (_5352_2217)] ; c1*2217 + d1*5352 + + pmaddwd xmm3, XMMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + pmaddwd xmm5, XMMWORD PTR[GLOBAL(_2217_neg5352)] ; d1*2217 - c1*5352 + + paddd xmm1, XMMWORD PTR[GLOBAL(_12000)] + paddd xmm4, XMMWORD PTR[GLOBAL(_12000)] + paddd xmm3, XMMWORD PTR[GLOBAL(_51000)] + paddd xmm5, XMMWORD PTR[GLOBAL(_51000)] + + psrad xmm1, 16 ; (c1 * 2217 + d1 * 5352 + 14500)>>16 + psrad xmm4, 16 ; (c1 * 2217 + d1 * 5352 + 14500)>>16 + psrad xmm3, 16 ; (d1 * 2217 - c1 * 5352 + 7500)>>16 + psrad xmm5, 16 ; (d1 * 2217 - c1 * 5352 + 7500)>>16 + + packssdw xmm1, xmm4 ; op[4] + packssdw xmm3, xmm5 ; op[12] + + paddw xmm1, xmm6 ; op[4] += (d1!=0) + + movdqa xmm4, xmm0 + movdqa xmm5, xmm2 + + punpcklqdq xmm0, xmm1 + punpckhqdq xmm4, xmm1 + + punpcklqdq xmm2, xmm3 + punpckhqdq xmm5, xmm3 + + movdqa XMMWORD PTR[output + 0 ], xmm0 + movdqa XMMWORD PTR[output + 16], xmm2 + movdqa XMMWORD PTR[output + 32], xmm4 + movdqa XMMWORD PTR[output + 48], xmm5 + + STACK_FRAME_DESTROY + +SECTION_RODATA +align 16 +_5352_2217: + dw 5352 + dw 2217 + dw 5352 + dw 2217 + dw 5352 + dw 2217 + dw 5352 + dw 2217 +align 16 +_2217_neg5352: + dw 2217 + dw -5352 + dw 2217 + dw -5352 + dw 2217 + dw -5352 + dw 2217 + dw -5352 +align 16 +_mult_add: + times 8 dw 1 +align 16 +_cmp_mask: + times 4 dw 1 + times 4 dw 0 +align 16 +_cmp_mask8x4: + times 8 dw 1 +align 16 +_mult_sub: + dw 1 + dw -1 + dw 1 + dw -1 + dw 1 + dw -1 + dw 1 + dw -1 +align 16 +_7: + times 4 dd 7 +align 16 +_7w: + times 8 dw 7 +align 16 +_14500: + times 4 dd 14500 +align 16 +_7500: + times 4 dd 7500 +align 16 +_12000: + times 4 dd 12000 +align 16 +_51000: + times 4 dd 51000 diff --git a/vp8/encoder/x86/encodeopt.asm b/vp8/encoder/x86/encodeopt.asm new file mode 100644 index 0000000..7ec7d60 --- /dev/null +++ b/vp8/encoder/x86/encodeopt.asm @@ -0,0 +1,386 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;int vp8_block_error_xmm(short *coeff_ptr, short *dcoef_ptr) +global sym(vp8_block_error_xmm) +sym(vp8_block_error_xmm): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prologue + + mov rsi, arg(0) ;coeff_ptr + mov rdi, arg(1) ;dcoef_ptr + + movdqa xmm0, [rsi] + movdqa xmm1, [rdi] + + movdqa xmm2, [rsi+16] + movdqa xmm3, [rdi+16] + + psubw xmm0, xmm1 + psubw xmm2, xmm3 + + pmaddwd xmm0, xmm0 + pmaddwd xmm2, xmm2 + + paddd xmm0, xmm2 + + pxor xmm5, xmm5 + movdqa xmm1, xmm0 + + punpckldq xmm0, xmm5 + punpckhdq xmm1, xmm5 + + paddd xmm0, xmm1 + movdqa xmm1, xmm0 + + psrldq xmm0, 8 + paddd xmm0, xmm1 + + movq rax, xmm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + +;int vp8_block_error_mmx(short *coeff_ptr, short *dcoef_ptr) +global sym(vp8_block_error_mmx) +sym(vp8_block_error_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor mm7, mm7 + + mov rdi, arg(1) ;dcoef_ptr + movq mm3, [rsi] + + movq mm4, [rdi] + movq mm5, [rsi+8] + + movq mm6, [rdi+8] + pxor mm1, mm1 ; from movd mm1, dc ; dc =0 + + movq mm2, mm7 + psubw mm5, mm6 + + por mm1, mm2 + pmaddwd mm5, mm5 + + pcmpeqw mm1, mm7 + psubw mm3, mm4 + + pand mm1, mm3 + pmaddwd mm1, mm1 + + paddd mm1, mm5 + movq mm3, [rsi+16] + + movq mm4, [rdi+16] + movq mm5, [rsi+24] + + movq mm6, [rdi+24] + psubw mm5, mm6 + + pmaddwd mm5, mm5 + psubw mm3, mm4 + + pmaddwd mm3, mm3 + paddd mm3, mm5 + + paddd mm1, mm3 + movq mm0, mm1 + + psrlq mm1, 32 + paddd mm0, mm1 + + movq rax, mm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbblock_error_mmx_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +global sym(vp8_mbblock_error_mmx_impl) +sym(vp8_mbblock_error_mmx_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor mm7, mm7 + + mov rdi, arg(1) ;dcoef_ptr + pxor mm2, mm2 + + movd mm1, dword ptr arg(2) ;dc + por mm1, mm2 + + pcmpeqw mm1, mm7 + mov rcx, 16 + +.mberror_loop_mmx: + movq mm3, [rsi] + movq mm4, [rdi] + + movq mm5, [rsi+8] + movq mm6, [rdi+8] + + + psubw mm5, mm6 + pmaddwd mm5, mm5 + + psubw mm3, mm4 + pand mm3, mm1 + + pmaddwd mm3, mm3 + paddd mm2, mm5 + + paddd mm2, mm3 + movq mm3, [rsi+16] + + movq mm4, [rdi+16] + movq mm5, [rsi+24] + + movq mm6, [rdi+24] + psubw mm5, mm6 + + pmaddwd mm5, mm5 + psubw mm3, mm4 + + pmaddwd mm3, mm3 + paddd mm2, mm5 + + paddd mm2, mm3 + add rsi, 32 + + add rdi, 32 + sub rcx, 1 + + jnz .mberror_loop_mmx + + movq mm0, mm2 + psrlq mm2, 32 + + paddd mm0, mm2 + movq rax, mm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbblock_error_xmm_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +global sym(vp8_mbblock_error_xmm_impl) +sym(vp8_mbblock_error_xmm_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + SAVE_XMM 6 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor xmm6, xmm6 + + mov rdi, arg(1) ;dcoef_ptr + pxor xmm4, xmm4 + + movd xmm5, dword ptr arg(2) ;dc + por xmm5, xmm4 + + pcmpeqw xmm5, xmm6 + mov rcx, 16 + +.mberror_loop: + movdqa xmm0, [rsi] + movdqa xmm1, [rdi] + + movdqa xmm2, [rsi+16] + movdqa xmm3, [rdi+16] + + + psubw xmm2, xmm3 + pmaddwd xmm2, xmm2 + + psubw xmm0, xmm1 + pand xmm0, xmm5 + + pmaddwd xmm0, xmm0 + add rsi, 32 + + add rdi, 32 + + sub rcx, 1 + paddd xmm4, xmm2 + + paddd xmm4, xmm0 + jnz .mberror_loop + + movdqa xmm0, xmm4 + punpckldq xmm0, xmm6 + + punpckhdq xmm4, xmm6 + paddd xmm0, xmm4 + + movdqa xmm1, xmm0 + psrldq xmm0, 8 + + paddd xmm0, xmm1 + movq rax, xmm0 + + pop rdi + pop rsi + ; begin epilog + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbuverror_mmx_impl(short *s_ptr, short *d_ptr); +global sym(vp8_mbuverror_mmx_impl) +sym(vp8_mbuverror_mmx_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;s_ptr + mov rdi, arg(1) ;d_ptr + + mov rcx, 16 + pxor mm7, mm7 + +.mbuverror_loop_mmx: + + movq mm1, [rsi] + movq mm2, [rdi] + + psubw mm1, mm2 + pmaddwd mm1, mm1 + + + movq mm3, [rsi+8] + movq mm4, [rdi+8] + + psubw mm3, mm4 + pmaddwd mm3, mm3 + + + paddd mm7, mm1 + paddd mm7, mm3 + + + add rsi, 16 + add rdi, 16 + + dec rcx + jnz .mbuverror_loop_mmx + + movq mm0, mm7 + psrlq mm7, 32 + + paddd mm0, mm7 + movq rax, mm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbuverror_xmm_impl(short *s_ptr, short *d_ptr); +global sym(vp8_mbuverror_xmm_impl) +sym(vp8_mbuverror_xmm_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;s_ptr + mov rdi, arg(1) ;d_ptr + + mov rcx, 16 + pxor xmm3, xmm3 + +.mbuverror_loop: + + movdqa xmm1, [rsi] + movdqa xmm2, [rdi] + + psubw xmm1, xmm2 + pmaddwd xmm1, xmm1 + + paddd xmm3, xmm1 + + add rsi, 16 + add rdi, 16 + + dec rcx + jnz .mbuverror_loop + + pxor xmm0, xmm0 + movdqa xmm1, xmm3 + + movdqa xmm2, xmm1 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + paddd xmm1, xmm2 + + movdqa xmm2, xmm1 + + psrldq xmm1, 8 + paddd xmm1, xmm2 + + movq rax, xmm1 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/encoder/x86/fwalsh_sse2.asm b/vp8/encoder/x86/fwalsh_sse2.asm new file mode 100644 index 0000000..71efd56 --- /dev/null +++ b/vp8/encoder/x86/fwalsh_sse2.asm @@ -0,0 +1,164 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_walsh4x4_sse2(short *input, short *output, int pitch) +global sym(vp8_short_walsh4x4_sse2) +sym(vp8_short_walsh4x4_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ; input + mov rdi, arg(1) ; output + movsxd rdx, dword ptr arg(2) ; pitch + + ; first for loop + movq xmm0, MMWORD PTR [rsi] ; load input + movq xmm1, MMWORD PTR [rsi + rdx] + lea rsi, [rsi + rdx*2] + movq xmm2, MMWORD PTR [rsi] + movq xmm3, MMWORD PTR [rsi + rdx] + + punpcklwd xmm0, xmm1 + punpcklwd xmm2, xmm3 + + movdqa xmm1, xmm0 + punpckldq xmm0, xmm2 ; ip[1] ip[0] + punpckhdq xmm1, xmm2 ; ip[3] ip[2] + + movdqa xmm2, xmm0 + paddw xmm0, xmm1 + psubw xmm2, xmm1 + + psllw xmm0, 2 ; d1 a1 + psllw xmm2, 2 ; c1 b1 + + movdqa xmm1, xmm0 + punpcklqdq xmm0, xmm2 ; b1 a1 + punpckhqdq xmm1, xmm2 ; c1 d1 + + pxor xmm6, xmm6 + movq xmm6, xmm0 + pxor xmm7, xmm7 + pcmpeqw xmm7, xmm6 + paddw xmm7, [GLOBAL(c1)] + + movdqa xmm2, xmm0 + paddw xmm0, xmm1 ; b1+c1 a1+d1 + psubw xmm2, xmm1 ; b1-c1 a1-d1 + paddw xmm0, xmm7 ; b1+c1 a1+d1+(a1!=0) + + ; second for loop + ; input: 13 9 5 1 12 8 4 0 (xmm0) + ; 14 10 6 2 15 11 7 3 (xmm2) + ; after shuffle: + ; 13 5 9 1 12 4 8 0 (xmm0) + ; 14 6 10 2 15 7 11 3 (xmm1) + pshuflw xmm3, xmm0, 0xd8 + pshufhw xmm0, xmm3, 0xd8 + pshuflw xmm3, xmm2, 0xd8 + pshufhw xmm1, xmm3, 0xd8 + + movdqa xmm2, xmm0 + pmaddwd xmm0, [GLOBAL(c1)] ; d11 a11 d10 a10 + pmaddwd xmm2, [GLOBAL(cn1)] ; c11 b11 c10 b10 + movdqa xmm3, xmm1 + pmaddwd xmm1, [GLOBAL(c1)] ; d12 a12 d13 a13 + pmaddwd xmm3, [GLOBAL(cn1)] ; c12 b12 c13 b13 + + pshufd xmm4, xmm0, 0xd8 ; d11 d10 a11 a10 + pshufd xmm5, xmm2, 0xd8 ; c11 c10 b11 b10 + pshufd xmm6, xmm1, 0x72 ; d13 d12 a13 a12 + pshufd xmm7, xmm3, 0x72 ; c13 c12 b13 b12 + + movdqa xmm0, xmm4 + punpcklqdq xmm0, xmm5 ; b11 b10 a11 a10 + punpckhqdq xmm4, xmm5 ; c11 c10 d11 d10 + movdqa xmm1, xmm6 + punpcklqdq xmm1, xmm7 ; b13 b12 a13 a12 + punpckhqdq xmm6, xmm7 ; c13 c12 d13 d12 + + movdqa xmm2, xmm0 + paddd xmm0, xmm4 ; b21 b20 a21 a20 + psubd xmm2, xmm4 ; c21 c20 d21 d20 + movdqa xmm3, xmm1 + paddd xmm1, xmm6 ; b23 b22 a23 a22 + psubd xmm3, xmm6 ; c23 c22 d23 d22 + + pxor xmm4, xmm4 + movdqa xmm5, xmm4 + pcmpgtd xmm4, xmm0 + pcmpgtd xmm5, xmm2 + pand xmm4, [GLOBAL(cd1)] + pand xmm5, [GLOBAL(cd1)] + + pxor xmm6, xmm6 + movdqa xmm7, xmm6 + pcmpgtd xmm6, xmm1 + pcmpgtd xmm7, xmm3 + pand xmm6, [GLOBAL(cd1)] + pand xmm7, [GLOBAL(cd1)] + + paddd xmm0, xmm4 + paddd xmm2, xmm5 + paddd xmm0, [GLOBAL(cd3)] + paddd xmm2, [GLOBAL(cd3)] + paddd xmm1, xmm6 + paddd xmm3, xmm7 + paddd xmm1, [GLOBAL(cd3)] + paddd xmm3, [GLOBAL(cd3)] + + psrad xmm0, 3 + psrad xmm1, 3 + psrad xmm2, 3 + psrad xmm3, 3 + movdqa xmm4, xmm0 + punpcklqdq xmm0, xmm1 ; a23 a22 a21 a20 + punpckhqdq xmm4, xmm1 ; b23 b22 b21 b20 + movdqa xmm5, xmm2 + punpckhqdq xmm2, xmm3 ; c23 c22 c21 c20 + punpcklqdq xmm5, xmm3 ; d23 d22 d21 d20 + + packssdw xmm0, xmm4 ; b23 b22 b21 b20 a23 a22 a21 a20 + packssdw xmm2, xmm5 ; d23 d22 d21 d20 c23 c22 c21 c20 + + movdqa XMMWORD PTR [rdi], xmm0 + movdqa XMMWORD PTR [rdi + 16], xmm2 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +c1: + dw 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 +align 16 +cn1: + dw 0x0001, 0xffff, 0x0001, 0xffff, 0x0001, 0xffff, 0x0001, 0xffff +align 16 +cd1: + dd 0x00000001, 0x00000001, 0x00000001, 0x00000001 +align 16 +cd3: + dd 0x00000003, 0x00000003, 0x00000003, 0x00000003 diff --git a/vp8/encoder/x86/quantize_mmx.asm b/vp8/encoder/x86/quantize_mmx.asm new file mode 100644 index 0000000..f29a54e --- /dev/null +++ b/vp8/encoder/x86/quantize_mmx.asm @@ -0,0 +1,286 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;int vp8_fast_quantize_b_impl_mmx(short *coeff_ptr, short *zbin_ptr, +; short *qcoeff_ptr,short *dequant_ptr, +; short *scan_mask, short *round_ptr, +; short *quant_ptr, short *dqcoeff_ptr); +global sym(vp8_fast_quantize_b_impl_mmx) +sym(vp8_fast_quantize_b_impl_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + movq mm0, [rsi] + + mov rax, arg(1) ;zbin_ptr + movq mm1, [rax] + + movq mm3, mm0 + psraw mm0, 15 + + pxor mm3, mm0 + psubw mm3, mm0 ; abs + + movq mm2, mm3 + pcmpgtw mm1, mm2 + + pandn mm1, mm2 + movq mm3, mm1 + + mov rdx, arg(6) ;quant_ptr + movq mm1, [rdx] + + mov rcx, arg(5) ;round_ptr + movq mm2, [rcx] + + paddw mm3, mm2 + pmulhuw mm3, mm1 + + pxor mm3, mm0 + psubw mm3, mm0 ;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + movq mm0, mm3 + + movq [rdi], mm3 + + mov rax, arg(3) ;dequant_ptr + movq mm2, [rax] + + pmullw mm3, mm2 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax], mm3 + + ; next 8 + movq mm4, [rsi+8] + + mov rax, arg(1) ;zbin_ptr + movq mm5, [rax+8] + + movq mm7, mm4 + psraw mm4, 15 + + pxor mm7, mm4 + psubw mm7, mm4 ; abs + + movq mm6, mm7 + pcmpgtw mm5, mm6 + + pandn mm5, mm6 + movq mm7, mm5 + + movq mm5, [rdx+8] + movq mm6, [rcx+8] + + paddw mm7, mm6 + pmulhuw mm7, mm5 + + pxor mm7, mm4 + psubw mm7, mm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movq mm1, mm7 + movq [rdi+8], mm7 + + mov rax, arg(3) ;dequant_ptr + movq mm6, [rax+8] + + pmullw mm7, mm6 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax+8], mm7 + + + ; next 8 + movq mm4, [rsi+16] + + mov rax, arg(1) ;zbin_ptr + movq mm5, [rax+16] + + movq mm7, mm4 + psraw mm4, 15 + + pxor mm7, mm4 + psubw mm7, mm4 ; abs + + movq mm6, mm7 + pcmpgtw mm5, mm6 + + pandn mm5, mm6 + movq mm7, mm5 + + movq mm5, [rdx+16] + movq mm6, [rcx+16] + + paddw mm7, mm6 + pmulhuw mm7, mm5 + + pxor mm7, mm4 + psubw mm7, mm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movq mm1, mm7 + movq [rdi+16], mm7 + + mov rax, arg(3) ;dequant_ptr + movq mm6, [rax+16] + + pmullw mm7, mm6 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax+16], mm7 + + + ; next 8 + movq mm4, [rsi+24] + + mov rax, arg(1) ;zbin_ptr + movq mm5, [rax+24] + + movq mm7, mm4 + psraw mm4, 15 + + pxor mm7, mm4 + psubw mm7, mm4 ; abs + + movq mm6, mm7 + pcmpgtw mm5, mm6 + + pandn mm5, mm6 + movq mm7, mm5 + + movq mm5, [rdx+24] + movq mm6, [rcx+24] + + paddw mm7, mm6 + pmulhuw mm7, mm5 + + pxor mm7, mm4 + psubw mm7, mm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movq mm1, mm7 + movq [rdi+24], mm7 + + mov rax, arg(3) ;dequant_ptr + movq mm6, [rax+24] + + pmullw mm7, mm6 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax+24], mm7 + + + + mov rdi, arg(4) ;scan_mask + mov rsi, arg(2) ;qcoeff_ptr + + pxor mm5, mm5 + pxor mm7, mm7 + + movq mm0, [rsi] + movq mm1, [rsi+8] + + movq mm2, [rdi] + movq mm3, [rdi+8]; + + pcmpeqw mm0, mm7 + pcmpeqw mm1, mm7 + + pcmpeqw mm6, mm6 + pxor mm0, mm6 + + pxor mm1, mm6 + psrlw mm0, 15 + + psrlw mm1, 15 + pmaddwd mm0, mm2 + + pmaddwd mm1, mm3 + movq mm5, mm0 + + paddd mm5, mm1 + + movq mm0, [rsi+16] + movq mm1, [rsi+24] + + movq mm2, [rdi+16] + movq mm3, [rdi+24]; + + pcmpeqw mm0, mm7 + pcmpeqw mm1, mm7 + + pcmpeqw mm6, mm6 + pxor mm0, mm6 + + pxor mm1, mm6 + psrlw mm0, 15 + + psrlw mm1, 15 + pmaddwd mm0, mm2 + + pmaddwd mm1, mm3 + paddd mm5, mm0 + + paddd mm5, mm1 + movq mm0, mm5 + + psrlq mm5, 32 + paddd mm0, mm5 + + ; eob adjustment begins here + movq rcx, mm0 + and rcx, 0xffff + + xor rdx, rdx + sub rdx, rcx ; rdx=-rcx + + bsr rax, rcx + inc rax + + sar rdx, 31 + and rax, rdx + ; Substitute the sse assembly for the old mmx mixed assembly/C. The + ; following is kept as reference + ; movq rcx, mm0 + ; bsr rax, rcx + ; + ; mov eob, rax + ; mov eee, rcx + ; + ;if(eee==0) + ;{ + ; eob=-1; + ;} + ;else if(eee<0) + ;{ + ; eob=15; + ;} + ;d->eob = eob+1; + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/encoder/x86/quantize_sse2.asm b/vp8/encoder/x86/quantize_sse2.asm new file mode 100644 index 0000000..7c249ff --- /dev/null +++ b/vp8/encoder/x86/quantize_sse2.asm @@ -0,0 +1,386 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +%include "asm_enc_offsets.asm" + + +; void vp8_regular_quantize_b_sse2 | arg +; (BLOCK *b, | 0 +; BLOCKD *d) | 1 + +global sym(vp8_regular_quantize_b_sse2) +sym(vp8_regular_quantize_b_sse2): + push rbp + mov rbp, rsp + SAVE_XMM 7 + GET_GOT rbx + +%if ABI_IS_32BIT + push rdi + push rsi +%else + %ifidn __OUTPUT_FORMAT__,x64 + push rdi + push rsi + %endif +%endif + + ALIGN_STACK 16, rax + %define zrun_zbin_boost 0 ; 8 + %define abs_minus_zbin 8 ; 32 + %define temp_qcoeff 40 ; 32 + %define qcoeff 72 ; 32 + %define stack_size 104 + sub rsp, stack_size + ; end prolog + +%if ABI_IS_32BIT + mov rdi, arg(0) ; BLOCK *b + mov rsi, arg(1) ; BLOCKD *d +%else + %ifidn __OUTPUT_FORMAT__,x64 + mov rdi, rcx ; BLOCK *b + mov rsi, rdx ; BLOCKD *d + %else + ;mov rdi, rdi ; BLOCK *b + ;mov rsi, rsi ; BLOCKD *d + %endif +%endif + + mov rdx, [rdi + vp8_block_coeff] ; coeff_ptr + mov rcx, [rdi + vp8_block_zbin] ; zbin_ptr + movd xmm7, [rdi + vp8_block_zbin_extra] ; zbin_oq_value + + ; z + movdqa xmm0, [rdx] + movdqa xmm4, [rdx + 16] + mov rdx, [rdi + vp8_block_round] ; round_ptr + + pshuflw xmm7, xmm7, 0 + punpcklwd xmm7, xmm7 ; duplicated zbin_oq_value + + movdqa xmm1, xmm0 + movdqa xmm5, xmm4 + + ; sz + psraw xmm0, 15 + psraw xmm4, 15 + + ; (z ^ sz) + pxor xmm1, xmm0 + pxor xmm5, xmm4 + + ; x = abs(z) + psubw xmm1, xmm0 + psubw xmm5, xmm4 + + movdqa xmm2, [rcx] + movdqa xmm3, [rcx + 16] + mov rcx, [rdi + vp8_block_quant] ; quant_ptr + + ; *zbin_ptr + zbin_oq_value + paddw xmm2, xmm7 + paddw xmm3, xmm7 + + ; x - (*zbin_ptr + zbin_oq_value) + psubw xmm1, xmm2 + psubw xmm5, xmm3 + movdqa [rsp + abs_minus_zbin], xmm1 + movdqa [rsp + abs_minus_zbin + 16], xmm5 + + ; add (zbin_ptr + zbin_oq_value) back + paddw xmm1, xmm2 + paddw xmm5, xmm3 + + movdqa xmm2, [rdx] + movdqa xmm6, [rdx + 16] + + movdqa xmm3, [rcx] + movdqa xmm7, [rcx + 16] + + ; x + round + paddw xmm1, xmm2 + paddw xmm5, xmm6 + + ; y = x * quant_ptr >> 16 + pmulhw xmm3, xmm1 + pmulhw xmm7, xmm5 + + ; y += x + paddw xmm1, xmm3 + paddw xmm5, xmm7 + + movdqa [rsp + temp_qcoeff], xmm1 + movdqa [rsp + temp_qcoeff + 16], xmm5 + + pxor xmm6, xmm6 + ; zero qcoeff + movdqa [rsp + qcoeff], xmm6 + movdqa [rsp + qcoeff + 16], xmm6 + + mov rdx, [rdi + vp8_block_zrun_zbin_boost] ; zbin_boost_ptr + mov rax, [rdi + vp8_block_quant_shift] ; quant_shift_ptr + mov [rsp + zrun_zbin_boost], rdx + +%macro ZIGZAG_LOOP 1 + ; x + movsx ecx, WORD PTR[rsp + abs_minus_zbin + %1 * 2] + + ; if (x >= zbin) + sub cx, WORD PTR[rdx] ; x - zbin + lea rdx, [rdx + 2] ; zbin_boost_ptr++ + jl .rq_zigzag_loop_%1 ; x < zbin + + movsx edi, WORD PTR[rsp + temp_qcoeff + %1 * 2] + + ; downshift by quant_shift[rc] + movsx cx, BYTE PTR[rax + %1] ; quant_shift_ptr[rc] + sar edi, cl ; also sets Z bit + je .rq_zigzag_loop_%1 ; !y + mov WORD PTR[rsp + qcoeff + %1 * 2], di ;qcoeff_ptr[rc] = temp_qcoeff[rc] + mov rdx, [rsp + zrun_zbin_boost] ; reset to b->zrun_zbin_boost +.rq_zigzag_loop_%1: +%endmacro +; in vp8_default_zig_zag1d order: see vp8/common/entropy.c +ZIGZAG_LOOP 0 +ZIGZAG_LOOP 1 +ZIGZAG_LOOP 4 +ZIGZAG_LOOP 8 +ZIGZAG_LOOP 5 +ZIGZAG_LOOP 2 +ZIGZAG_LOOP 3 +ZIGZAG_LOOP 6 +ZIGZAG_LOOP 9 +ZIGZAG_LOOP 12 +ZIGZAG_LOOP 13 +ZIGZAG_LOOP 10 +ZIGZAG_LOOP 7 +ZIGZAG_LOOP 11 +ZIGZAG_LOOP 14 +ZIGZAG_LOOP 15 + + movdqa xmm2, [rsp + qcoeff] + movdqa xmm3, [rsp + qcoeff + 16] + + mov rcx, [rsi + vp8_blockd_dequant] ; dequant_ptr + mov rdi, [rsi + vp8_blockd_dqcoeff] ; dqcoeff_ptr + + ; y ^ sz + pxor xmm2, xmm0 + pxor xmm3, xmm4 + ; x = (y ^ sz) - sz + psubw xmm2, xmm0 + psubw xmm3, xmm4 + + ; dequant + movdqa xmm0, [rcx] + movdqa xmm1, [rcx + 16] + + mov rcx, [rsi + vp8_blockd_qcoeff] ; qcoeff_ptr + + pmullw xmm0, xmm2 + pmullw xmm1, xmm3 + + movdqa [rcx], xmm2 ; store qcoeff + movdqa [rcx + 16], xmm3 + movdqa [rdi], xmm0 ; store dqcoeff + movdqa [rdi + 16], xmm1 + + mov rcx, [rsi + vp8_blockd_eob] + + ; select the last value (in zig_zag order) for EOB + pcmpeqw xmm2, xmm6 + pcmpeqw xmm3, xmm6 + ; ! + pcmpeqw xmm6, xmm6 + pxor xmm2, xmm6 + pxor xmm3, xmm6 + ; mask inv_zig_zag + pand xmm2, [GLOBAL(inv_zig_zag)] + pand xmm3, [GLOBAL(inv_zig_zag + 16)] + ; select the max value + pmaxsw xmm2, xmm3 + pshufd xmm3, xmm2, 00001110b + pmaxsw xmm2, xmm3 + pshuflw xmm3, xmm2, 00001110b + pmaxsw xmm2, xmm3 + pshuflw xmm3, xmm2, 00000001b + pmaxsw xmm2, xmm3 + movd eax, xmm2 + and eax, 0xff + + mov BYTE PTR [rcx], al ; store eob + + ; begin epilog + add rsp, stack_size + pop rsp +%if ABI_IS_32BIT + pop rsi + pop rdi +%else + %ifidn __OUTPUT_FORMAT__,x64 + pop rsi + pop rdi + %endif +%endif + RESTORE_GOT + RESTORE_XMM + pop rbp + ret + +; void vp8_fast_quantize_b_sse2 | arg +; (BLOCK *b, | 0 +; BLOCKD *d) | 1 + +global sym(vp8_fast_quantize_b_sse2) +sym(vp8_fast_quantize_b_sse2): + push rbp + mov rbp, rsp + GET_GOT rbx + +%if ABI_IS_32BIT + push rdi + push rsi +%else + %ifidn __OUTPUT_FORMAT__,x64 + push rdi + push rsi + %else + ; these registers are used for passing arguments + %endif +%endif + + ; end prolog + +%if ABI_IS_32BIT + mov rdi, arg(0) ; BLOCK *b + mov rsi, arg(1) ; BLOCKD *d +%else + %ifidn __OUTPUT_FORMAT__,x64 + mov rdi, rcx ; BLOCK *b + mov rsi, rdx ; BLOCKD *d + %else + ;mov rdi, rdi ; BLOCK *b + ;mov rsi, rsi ; BLOCKD *d + %endif +%endif + + mov rax, [rdi + vp8_block_coeff] + mov rcx, [rdi + vp8_block_round] + mov rdx, [rdi + vp8_block_quant_fast] + + ; z = coeff + movdqa xmm0, [rax] + movdqa xmm4, [rax + 16] + + ; dup z so we can save sz + movdqa xmm1, xmm0 + movdqa xmm5, xmm4 + + ; sz = z >> 15 + psraw xmm0, 15 + psraw xmm4, 15 + + ; x = abs(z) = (z ^ sz) - sz + pxor xmm1, xmm0 + pxor xmm5, xmm4 + psubw xmm1, xmm0 + psubw xmm5, xmm4 + + ; x += round + paddw xmm1, [rcx] + paddw xmm5, [rcx + 16] + + mov rax, [rsi + vp8_blockd_qcoeff] + mov rcx, [rsi + vp8_blockd_dequant] + mov rdi, [rsi + vp8_blockd_dqcoeff] + + ; y = x * quant >> 16 + pmulhw xmm1, [rdx] + pmulhw xmm5, [rdx + 16] + + ; x = (y ^ sz) - sz + pxor xmm1, xmm0 + pxor xmm5, xmm4 + psubw xmm1, xmm0 + psubw xmm5, xmm4 + + ; qcoeff = x + movdqa [rax], xmm1 + movdqa [rax + 16], xmm5 + + ; x * dequant + movdqa xmm2, xmm1 + movdqa xmm3, xmm5 + pmullw xmm2, [rcx] + pmullw xmm3, [rcx + 16] + + ; dqcoeff = x * dequant + movdqa [rdi], xmm2 + movdqa [rdi + 16], xmm3 + + pxor xmm4, xmm4 ;clear all bits + pcmpeqw xmm1, xmm4 + pcmpeqw xmm5, xmm4 + + pcmpeqw xmm4, xmm4 ;set all bits + pxor xmm1, xmm4 + pxor xmm5, xmm4 + + pand xmm1, [GLOBAL(inv_zig_zag)] + pand xmm5, [GLOBAL(inv_zig_zag + 16)] + + pmaxsw xmm1, xmm5 + + mov rcx, [rsi + vp8_blockd_eob] + + ; now down to 8 + pshufd xmm5, xmm1, 00001110b + + pmaxsw xmm1, xmm5 + + ; only 4 left + pshuflw xmm5, xmm1, 00001110b + + pmaxsw xmm1, xmm5 + + ; okay, just 2! + pshuflw xmm5, xmm1, 00000001b + + pmaxsw xmm1, xmm5 + + movd eax, xmm1 + and eax, 0xff + + mov BYTE PTR [rcx], al ; store eob + + ; begin epilog +%if ABI_IS_32BIT + pop rsi + pop rdi +%else + %ifidn __OUTPUT_FORMAT__,x64 + pop rsi + pop rdi + %endif +%endif + + RESTORE_GOT + pop rbp + ret + +SECTION_RODATA +align 16 +inv_zig_zag: + dw 0x0001, 0x0002, 0x0006, 0x0007 + dw 0x0003, 0x0005, 0x0008, 0x000d + dw 0x0004, 0x0009, 0x000c, 0x000e + dw 0x000a, 0x000b, 0x000f, 0x0010 diff --git a/vp8/encoder/x86/quantize_sse4.asm b/vp8/encoder/x86/quantize_sse4.asm new file mode 100644 index 0000000..70eac0c --- /dev/null +++ b/vp8/encoder/x86/quantize_sse4.asm @@ -0,0 +1,256 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +%include "asm_enc_offsets.asm" + + +; void vp8_regular_quantize_b_sse4 | arg +; (BLOCK *b, | 0 +; BLOCKD *d) | 1 + +global sym(vp8_regular_quantize_b_sse4) +sym(vp8_regular_quantize_b_sse4): + +%if ABI_IS_32BIT + push rbp + mov rbp, rsp + GET_GOT rbx + push rdi + push rsi + + ALIGN_STACK 16, rax + %define qcoeff 0 ; 32 + %define stack_size 32 + sub rsp, stack_size +%else + %ifidn __OUTPUT_FORMAT__,x64 + SAVE_XMM 8, u + push rdi + push rsi + %endif +%endif + ; end prolog + +%if ABI_IS_32BIT + mov rdi, arg(0) ; BLOCK *b + mov rsi, arg(1) ; BLOCKD *d +%else + %ifidn __OUTPUT_FORMAT__,x64 + mov rdi, rcx ; BLOCK *b + mov rsi, rdx ; BLOCKD *d + %else + ;mov rdi, rdi ; BLOCK *b + ;mov rsi, rsi ; BLOCKD *d + %endif +%endif + + mov rax, [rdi + vp8_block_coeff] + mov rcx, [rdi + vp8_block_zbin] + mov rdx, [rdi + vp8_block_round] + movd xmm7, [rdi + vp8_block_zbin_extra] + + ; z + movdqa xmm0, [rax] + movdqa xmm1, [rax + 16] + + ; duplicate zbin_oq_value + pshuflw xmm7, xmm7, 0 + punpcklwd xmm7, xmm7 + + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + ; sz + psraw xmm0, 15 + psraw xmm1, 15 + + ; (z ^ sz) + pxor xmm2, xmm0 + pxor xmm3, xmm1 + + ; x = abs(z) + psubw xmm2, xmm0 + psubw xmm3, xmm1 + + ; zbin + movdqa xmm4, [rcx] + movdqa xmm5, [rcx + 16] + + ; *zbin_ptr + zbin_oq_value + paddw xmm4, xmm7 + paddw xmm5, xmm7 + + movdqa xmm6, xmm2 + movdqa xmm7, xmm3 + + ; x - (*zbin_ptr + zbin_oq_value) + psubw xmm6, xmm4 + psubw xmm7, xmm5 + + ; round + movdqa xmm4, [rdx] + movdqa xmm5, [rdx + 16] + + mov rax, [rdi + vp8_block_quant_shift] + mov rcx, [rdi + vp8_block_quant] + mov rdx, [rdi + vp8_block_zrun_zbin_boost] + + ; x + round + paddw xmm2, xmm4 + paddw xmm3, xmm5 + + ; quant + movdqa xmm4, [rcx] + movdqa xmm5, [rcx + 16] + + ; y = x * quant_ptr >> 16 + pmulhw xmm4, xmm2 + pmulhw xmm5, xmm3 + + ; y += x + paddw xmm2, xmm4 + paddw xmm3, xmm5 + + pxor xmm4, xmm4 +%if ABI_IS_32BIT + movdqa [rsp + qcoeff], xmm4 + movdqa [rsp + qcoeff + 16], xmm4 +%else + pxor xmm8, xmm8 +%endif + + ; quant_shift + movdqa xmm5, [rax] + + ; zrun_zbin_boost + mov rax, rdx + +%macro ZIGZAG_LOOP 5 + ; x + pextrw ecx, %4, %2 + + ; if (x >= zbin) + sub cx, WORD PTR[rdx] ; x - zbin + lea rdx, [rdx + 2] ; zbin_boost_ptr++ + jl .rq_zigzag_loop_%1 ; x < zbin + + pextrw edi, %3, %2 ; y + + ; downshift by quant_shift[rc] + pextrb ecx, xmm5, %1 ; quant_shift[rc] + sar edi, cl ; also sets Z bit + je .rq_zigzag_loop_%1 ; !y +%if ABI_IS_32BIT + mov WORD PTR[rsp + qcoeff + %1 *2], di +%else + pinsrw %5, edi, %2 ; qcoeff[rc] +%endif + mov rdx, rax ; reset to b->zrun_zbin_boost +.rq_zigzag_loop_%1: +%endmacro +; in vp8_default_zig_zag1d order: see vp8/common/entropy.c +ZIGZAG_LOOP 0, 0, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 1, 1, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 4, 4, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 8, 0, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 5, 5, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 2, 2, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 3, 3, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 6, 6, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 9, 1, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 12, 4, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 13, 5, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 10, 2, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 7, 7, xmm2, xmm6, xmm4 +ZIGZAG_LOOP 11, 3, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 14, 6, xmm3, xmm7, xmm8 +ZIGZAG_LOOP 15, 7, xmm3, xmm7, xmm8 + + mov rcx, [rsi + vp8_blockd_dequant] + mov rdi, [rsi + vp8_blockd_dqcoeff] + +%if ABI_IS_32BIT + movdqa xmm4, [rsp + qcoeff] + movdqa xmm5, [rsp + qcoeff + 16] +%else + %define xmm5 xmm8 +%endif + + ; y ^ sz + pxor xmm4, xmm0 + pxor xmm5, xmm1 + ; x = (y ^ sz) - sz + psubw xmm4, xmm0 + psubw xmm5, xmm1 + + ; dequant + movdqa xmm0, [rcx] + movdqa xmm1, [rcx + 16] + + mov rcx, [rsi + vp8_blockd_qcoeff] + + pmullw xmm0, xmm4 + pmullw xmm1, xmm5 + + ; store qcoeff + movdqa [rcx], xmm4 + movdqa [rcx + 16], xmm5 + + ; store dqcoeff + movdqa [rdi], xmm0 + movdqa [rdi + 16], xmm1 + + mov rcx, [rsi + vp8_blockd_eob] + + ; select the last value (in zig_zag order) for EOB + pxor xmm6, xmm6 + pcmpeqw xmm4, xmm6 + pcmpeqw xmm5, xmm6 + + packsswb xmm4, xmm5 + pshufb xmm4, [GLOBAL(zig_zag1d)] + pmovmskb edx, xmm4 + xor rdi, rdi + mov eax, -1 + xor dx, ax + bsr eax, edx + sub edi, edx + sar edi, 31 + add eax, 1 + and eax, edi + + mov BYTE PTR [rcx], al ; store eob + + ; begin epilog +%if ABI_IS_32BIT + add rsp, stack_size + pop rsp + + pop rsi + pop rdi + RESTORE_GOT + pop rbp +%else + %undef xmm5 + %ifidn __OUTPUT_FORMAT__,x64 + pop rsi + pop rdi + RESTORE_XMM + %endif +%endif + + ret + +SECTION_RODATA +align 16 +; vp8/common/entropy.c: vp8_default_zig_zag1d +zig_zag1d: + db 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 diff --git a/vp8/encoder/x86/quantize_ssse3.asm b/vp8/encoder/x86/quantize_ssse3.asm new file mode 100644 index 0000000..e698e90 --- /dev/null +++ b/vp8/encoder/x86/quantize_ssse3.asm @@ -0,0 +1,138 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +%include "asm_enc_offsets.asm" + + +; void vp8_fast_quantize_b_ssse3 | arg +; (BLOCK *b, | 0 +; BLOCKD *d) | 1 +; + +global sym(vp8_fast_quantize_b_ssse3) +sym(vp8_fast_quantize_b_ssse3): + push rbp + mov rbp, rsp + GET_GOT rbx + +%if ABI_IS_32BIT + push rdi + push rsi +%else + %ifidn __OUTPUT_FORMAT__,x64 + push rdi + push rsi + %endif +%endif + ; end prolog + +%if ABI_IS_32BIT + mov rdi, arg(0) ; BLOCK *b + mov rsi, arg(1) ; BLOCKD *d +%else + %ifidn __OUTPUT_FORMAT__,x64 + mov rdi, rcx ; BLOCK *b + mov rsi, rdx ; BLOCKD *d + %else + ;mov rdi, rdi ; BLOCK *b + ;mov rsi, rsi ; BLOCKD *d + %endif +%endif + + mov rax, [rdi + vp8_block_coeff] + mov rcx, [rdi + vp8_block_round] + mov rdx, [rdi + vp8_block_quant_fast] + + ; coeff + movdqa xmm0, [rax] + movdqa xmm4, [rax + 16] + + ; round + movdqa xmm2, [rcx] + movdqa xmm3, [rcx + 16] + + movdqa xmm1, xmm0 + movdqa xmm5, xmm4 + + ; sz = z >> 15 + psraw xmm0, 15 + psraw xmm4, 15 + + pabsw xmm1, xmm1 + pabsw xmm5, xmm5 + + paddw xmm1, xmm2 + paddw xmm5, xmm3 + + ; quant_fast + pmulhw xmm1, [rdx] + pmulhw xmm5, [rdx + 16] + + mov rax, [rsi + vp8_blockd_qcoeff] + mov rdi, [rsi + vp8_blockd_dequant] + mov rcx, [rsi + vp8_blockd_dqcoeff] + + movdqa xmm2, xmm1 ;store y for getting eob + movdqa xmm3, xmm5 + + pxor xmm1, xmm0 + pxor xmm5, xmm4 + psubw xmm1, xmm0 + psubw xmm5, xmm4 + + movdqa [rax], xmm1 + movdqa [rax + 16], xmm5 + + movdqa xmm0, [rdi] + movdqa xmm4, [rdi + 16] + + pmullw xmm0, xmm1 + pmullw xmm4, xmm5 + pxor xmm1, xmm1 + + pcmpgtw xmm2, xmm1 ;calculate eob + pcmpgtw xmm3, xmm1 + packsswb xmm2, xmm3 + pshufb xmm2, [GLOBAL(zz_shuf)] + + pmovmskb edx, xmm2 + + movdqa [rcx], xmm0 ;store dqcoeff + movdqa [rcx + 16], xmm4 ;store dqcoeff + mov rcx, [rsi + vp8_blockd_eob] + + bsr eax, edx ;count 0 + add eax, 1 + + cmp edx, 0 ;if all 0, eob=0 + cmove eax, edx + + mov BYTE PTR [rcx], al ;store eob + + ; begin epilog +%if ABI_IS_32BIT + pop rsi + pop rdi +%else + %ifidn __OUTPUT_FORMAT__,x64 + pop rsi + pop rdi + %endif +%endif + + RESTORE_GOT + pop rbp + ret + +SECTION_RODATA +align 16 +zz_shuf: + db 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 diff --git a/vp8/encoder/x86/ssim_opt.asm b/vp8/encoder/x86/ssim_opt.asm new file mode 100644 index 0000000..c6db3d1 --- /dev/null +++ b/vp8/encoder/x86/ssim_opt.asm @@ -0,0 +1,216 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + +%include "vpx_ports/x86_abi_support.asm" + +; tabulate_ssim - sums sum_s,sum_r,sum_sq_s,sum_sq_r, sum_sxr +%macro TABULATE_SSIM 0 + paddusw xmm15, xmm3 ; sum_s + paddusw xmm14, xmm4 ; sum_r + movdqa xmm1, xmm3 + pmaddwd xmm1, xmm1 + paddd xmm13, xmm1 ; sum_sq_s + movdqa xmm2, xmm4 + pmaddwd xmm2, xmm2 + paddd xmm12, xmm2 ; sum_sq_r + pmaddwd xmm3, xmm4 + paddd xmm11, xmm3 ; sum_sxr +%endmacro + +; Sum across the register %1 starting with q words +%macro SUM_ACROSS_Q 1 + movdqa xmm2,%1 + punpckldq %1,xmm0 + punpckhdq xmm2,xmm0 + paddq %1,xmm2 + movdqa xmm2,%1 + punpcklqdq %1,xmm0 + punpckhqdq xmm2,xmm0 + paddq %1,xmm2 +%endmacro + +; Sum across the register %1 starting with q words +%macro SUM_ACROSS_W 1 + movdqa xmm1, %1 + punpcklwd %1,xmm0 + punpckhwd xmm1,xmm0 + paddd %1, xmm1 + SUM_ACROSS_Q %1 +%endmacro +;void ssim_parms_sse2( +; unsigned char *s, +; int sp, +; unsigned char *r, +; int rp +; unsigned long *sum_s, +; unsigned long *sum_r, +; unsigned long *sum_sq_s, +; unsigned long *sum_sq_r, +; unsigned long *sum_sxr); +; +; TODO: Use parm passing through structure, probably don't need the pxors +; ( calling app will initialize to 0 ) could easily fit everything in sse2 +; without too much hastle, and can probably do better estimates with psadw +; or pavgb At this point this is just meant to be first pass for calculating +; all the parms needed for 16x16 ssim so we can play with dssim as distortion +; in mode selection code. +global sym(vp8_ssim_parms_16x16_sse2) +sym(vp8_ssim_parms_16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + SAVE_XMM 15 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;s + mov rcx, arg(1) ;sp + mov rdi, arg(2) ;r + mov rax, arg(3) ;rp + + pxor xmm0, xmm0 + pxor xmm15,xmm15 ;sum_s + pxor xmm14,xmm14 ;sum_r + pxor xmm13,xmm13 ;sum_sq_s + pxor xmm12,xmm12 ;sum_sq_r + pxor xmm11,xmm11 ;sum_sxr + + mov rdx, 16 ;row counter +.NextRow: + + ;grab source and reference pixels + movdqu xmm5, [rsi] + movdqu xmm6, [rdi] + movdqa xmm3, xmm5 + movdqa xmm4, xmm6 + punpckhbw xmm3, xmm0 ; high_s + punpckhbw xmm4, xmm0 ; high_r + + TABULATE_SSIM + + movdqa xmm3, xmm5 + movdqa xmm4, xmm6 + punpcklbw xmm3, xmm0 ; low_s + punpcklbw xmm4, xmm0 ; low_r + + TABULATE_SSIM + + add rsi, rcx ; next s row + add rdi, rax ; next r row + + dec rdx ; counter + jnz .NextRow + + SUM_ACROSS_W xmm15 + SUM_ACROSS_W xmm14 + SUM_ACROSS_Q xmm13 + SUM_ACROSS_Q xmm12 + SUM_ACROSS_Q xmm11 + + mov rdi,arg(4) + movd [rdi], xmm15; + mov rdi,arg(5) + movd [rdi], xmm14; + mov rdi,arg(6) + movd [rdi], xmm13; + mov rdi,arg(7) + movd [rdi], xmm12; + mov rdi,arg(8) + movd [rdi], xmm11; + + ; begin epilog + pop rdi + pop rsi + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +;void ssim_parms_sse2( +; unsigned char *s, +; int sp, +; unsigned char *r, +; int rp +; unsigned long *sum_s, +; unsigned long *sum_r, +; unsigned long *sum_sq_s, +; unsigned long *sum_sq_r, +; unsigned long *sum_sxr); +; +; TODO: Use parm passing through structure, probably don't need the pxors +; ( calling app will initialize to 0 ) could easily fit everything in sse2 +; without too much hastle, and can probably do better estimates with psadw +; or pavgb At this point this is just meant to be first pass for calculating +; all the parms needed for 16x16 ssim so we can play with dssim as distortion +; in mode selection code. +global sym(vp8_ssim_parms_8x8_sse2) +sym(vp8_ssim_parms_8x8_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + SAVE_XMM 15 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;s + mov rcx, arg(1) ;sp + mov rdi, arg(2) ;r + mov rax, arg(3) ;rp + + pxor xmm0, xmm0 + pxor xmm15,xmm15 ;sum_s + pxor xmm14,xmm14 ;sum_r + pxor xmm13,xmm13 ;sum_sq_s + pxor xmm12,xmm12 ;sum_sq_r + pxor xmm11,xmm11 ;sum_sxr + + mov rdx, 8 ;row counter +.NextRow: + + ;grab source and reference pixels + movq xmm3, [rsi] + movq xmm4, [rdi] + punpcklbw xmm3, xmm0 ; low_s + punpcklbw xmm4, xmm0 ; low_r + + TABULATE_SSIM + + add rsi, rcx ; next s row + add rdi, rax ; next r row + + dec rdx ; counter + jnz .NextRow + + SUM_ACROSS_W xmm15 + SUM_ACROSS_W xmm14 + SUM_ACROSS_Q xmm13 + SUM_ACROSS_Q xmm12 + SUM_ACROSS_Q xmm11 + + mov rdi,arg(4) + movd [rdi], xmm15; + mov rdi,arg(5) + movd [rdi], xmm14; + mov rdi,arg(6) + movd [rdi], xmm13; + mov rdi,arg(7) + movd [rdi], xmm12; + mov rdi,arg(8) + movd [rdi], xmm11; + + ; begin epilog + pop rdi + pop rsi + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/encoder/x86/subtract_mmx.asm b/vp8/encoder/x86/subtract_mmx.asm new file mode 100644 index 0000000..75e8aa3 --- /dev/null +++ b/vp8/encoder/x86/subtract_mmx.asm @@ -0,0 +1,223 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_subtract_b_mmx_impl(unsigned char *z, int src_stride, +; short *diff, unsigned char *Predictor, +; int pitch); +global sym(vp8_subtract_b_mmx_impl) +sym(vp8_subtract_b_mmx_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + + mov rdi, arg(2) ;diff + mov rax, arg(3) ;Predictor + mov rsi, arg(0) ;z + movsxd rdx, dword ptr arg(1);src_stride; + movsxd rcx, dword ptr arg(4);pitch + pxor mm7, mm7 + + movd mm0, [rsi] + movd mm1, [rax] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi], mm0 + + + movd mm0, [rsi+rdx] + movd mm1, [rax+rcx] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi+rcx*2],mm0 + + + movd mm0, [rsi+rdx*2] + movd mm1, [rax+rcx*2] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi+rcx*4], mm0 + + lea rsi, [rsi+rdx*2] + lea rcx, [rcx+rcx*2] + + + + movd mm0, [rsi+rdx] + movd mm1, [rax+rcx] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi+rcx*2], mm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_subtract_mby_mmx(short *diff, unsigned char *src, int src_stride, +;unsigned char *pred, int pred_stride) +global sym(vp8_subtract_mby_mmx) +sym(vp8_subtract_mby_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rdi, arg(0) ;diff + mov rsi, arg(1) ;src + movsxd rdx, dword ptr arg(2);src_stride + mov rax, arg(3) ;pred + push rbx + movsxd rbx, dword ptr arg(4);pred_stride + + pxor mm0, mm0 + mov rcx, 16 + + +.submby_loop: + movq mm1, [rsi] + movq mm3, [rax] + + movq mm2, mm1 + movq mm4, mm3 + + punpcklbw mm1, mm0 + punpcklbw mm3, mm0 + + punpckhbw mm2, mm0 + punpckhbw mm4, mm0 + + psubw mm1, mm3 + psubw mm2, mm4 + + movq [rdi], mm1 + movq [rdi+8], mm2 + + movq mm1, [rsi+8] + movq mm3, [rax+8] + + movq mm2, mm1 + movq mm4, mm3 + + punpcklbw mm1, mm0 + punpcklbw mm3, mm0 + + punpckhbw mm2, mm0 + punpckhbw mm4, mm0 + + psubw mm1, mm3 + psubw mm2, mm4 + + movq [rdi+16], mm1 + movq [rdi+24], mm2 + add rdi, 32 + lea rax, [rax+rbx] + lea rsi, [rsi+rdx] + dec rcx + jnz .submby_loop + + pop rbx + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;vp8_subtract_mbuv_mmx(short *diff, unsigned char *usrc, unsigned char *vsrc, +; int src_stride, unsigned char *upred, +; unsigned char *vpred, int pred_stride) + +global sym(vp8_subtract_mbuv_mmx) +sym(vp8_subtract_mbuv_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + push rsi + push rdi + ; end prolog + + mov rdi, arg(0) ;diff + mov rsi, arg(1) ;usrc + movsxd rdx, dword ptr arg(3);src_stride; + mov rax, arg(4) ;upred + add rdi, 256*2 ;diff = diff + 256 (shorts) + mov rcx, 8 + push rbx + movsxd rbx, dword ptr arg(6);pred_stride + + pxor mm7, mm7 + +.submbu_loop: + movq mm0, [rsi] + movq mm1, [rax] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi], mm0 + movq [rdi+8], mm3 + add rdi, 16 + add rsi, rdx + add rax, rbx + + dec rcx + jnz .submbu_loop + + mov rsi, arg(2) ;vsrc + mov rax, arg(5) ;vpred + mov rcx, 8 + +.submbv_loop: + movq mm0, [rsi] + movq mm1, [rax] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi], mm0 + movq [rdi+8], mm3 + add rdi, 16 + add rsi, rdx + add rax, rbx + + dec rcx + jnz .submbv_loop + + pop rbx + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret diff --git a/vp8/encoder/x86/subtract_sse2.asm b/vp8/encoder/x86/subtract_sse2.asm new file mode 100644 index 0000000..008e9c7 --- /dev/null +++ b/vp8/encoder/x86/subtract_sse2.asm @@ -0,0 +1,245 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_subtract_b_sse2_impl(unsigned char *z, int src_stride, +; short *diff, unsigned char *Predictor, +; int pitch); +global sym(vp8_subtract_b_sse2_impl) +sym(vp8_subtract_b_sse2_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdi, arg(2) ;diff + mov rax, arg(3) ;Predictor + mov rsi, arg(0) ;z + movsxd rdx, dword ptr arg(1);src_stride; + movsxd rcx, dword ptr arg(4);pitch + pxor mm7, mm7 + + movd mm0, [rsi] + movd mm1, [rax] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq MMWORD PTR [rdi], mm0 + + movd mm0, [rsi+rdx] + movd mm1, [rax+rcx] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq MMWORD PTR [rdi+rcx*2], mm0 + + movd mm0, [rsi+rdx*2] + movd mm1, [rax+rcx*2] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq MMWORD PTR [rdi+rcx*4], mm0 + + lea rsi, [rsi+rdx*2] + lea rcx, [rcx+rcx*2] + + movd mm0, [rsi+rdx] + movd mm1, [rax+rcx] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq MMWORD PTR [rdi+rcx*2], mm0 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_subtract_mby_sse2(short *diff, unsigned char *src, int src_stride, +;unsigned char *pred, int pred_stride) +global sym(vp8_subtract_mby_sse2) +sym(vp8_subtract_mby_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdi, arg(0) ;diff + mov rsi, arg(1) ;src + movsxd rdx, dword ptr arg(2);src_stride + mov rax, arg(3) ;pred + movdqa xmm4, [GLOBAL(t80)] + push rbx + mov rcx, 8 ; do two lines at one time + movsxd rbx, dword ptr arg(4);pred_stride + +.submby_loop: + movdqa xmm0, [rsi] ; src + movdqa xmm1, [rax] ; pred + + movdqa xmm2, xmm0 + psubb xmm0, xmm1 + + pxor xmm1, xmm4 ;convert to signed values + pxor xmm2, xmm4 + pcmpgtb xmm1, xmm2 ; obtain sign information + + movdqa xmm2, xmm0 + punpcklbw xmm0, xmm1 ; put sign back to subtraction + punpckhbw xmm2, xmm1 ; put sign back to subtraction + + movdqa xmm3, [rsi + rdx] + movdqa xmm5, [rax + rbx] + + lea rsi, [rsi+rdx*2] + lea rax, [rax+rbx*2] + + movdqa [rdi], xmm0 + movdqa [rdi +16], xmm2 + + movdqa xmm1, xmm3 + psubb xmm3, xmm5 + + pxor xmm5, xmm4 ;convert to signed values + pxor xmm1, xmm4 + pcmpgtb xmm5, xmm1 ; obtain sign information + + movdqa xmm1, xmm3 + punpcklbw xmm3, xmm5 ; put sign back to subtraction + punpckhbw xmm1, xmm5 ; put sign back to subtraction + + movdqa [rdi +32], xmm3 + movdqa [rdi +48], xmm1 + + add rdi, 64 + dec rcx + jnz .submby_loop + + pop rbx + pop rdi + pop rsi + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;vp8_subtract_mbuv_sse2(short *diff, unsigned char *usrc, unsigned char *vsrc, +; int src_stride, unsigned char *upred, +; unsigned char *vpred, int pred_stride) +global sym(vp8_subtract_mbuv_sse2) +sym(vp8_subtract_mbuv_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movdqa xmm4, [GLOBAL(t80)] + mov rdi, arg(0) ;diff + mov rsi, arg(1) ;usrc + movsxd rdx, dword ptr arg(3);src_stride; + mov rax, arg(4) ;upred + add rdi, 256*2 ;diff = diff + 256 (shorts) + mov rcx, 4 + push rbx + movsxd rbx, dword ptr arg(6);pred_stride + + ;u +.submbu_loop: + movq xmm0, [rsi] ; src + movq xmm2, [rsi+rdx] ; src -- next line + movq xmm1, [rax] ; pred + movq xmm3, [rax+rbx] ; pred -- next line + lea rsi, [rsi + rdx*2] + lea rax, [rax + rbx*2] + + punpcklqdq xmm0, xmm2 + punpcklqdq xmm1, xmm3 + + movdqa xmm2, xmm0 + psubb xmm0, xmm1 ; subtraction with sign missed + + pxor xmm1, xmm4 ;convert to signed values + pxor xmm2, xmm4 + pcmpgtb xmm1, xmm2 ; obtain sign information + + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + punpcklbw xmm0, xmm1 ; put sign back to subtraction + punpckhbw xmm2, xmm3 ; put sign back to subtraction + + movdqa [rdi], xmm0 ; store difference + movdqa [rdi +16], xmm2 ; store difference + add rdi, 32 + sub rcx, 1 + jnz .submbu_loop + + mov rsi, arg(2) ;vsrc + mov rax, arg(5) ;vpred + mov rcx, 4 + + ;v +.submbv_loop: + movq xmm0, [rsi] ; src + movq xmm2, [rsi+rdx] ; src -- next line + movq xmm1, [rax] ; pred + movq xmm3, [rax+rbx] ; pred -- next line + lea rsi, [rsi + rdx*2] + lea rax, [rax + rbx*2] + + punpcklqdq xmm0, xmm2 + punpcklqdq xmm1, xmm3 + + movdqa xmm2, xmm0 + psubb xmm0, xmm1 ; subtraction with sign missed + + pxor xmm1, xmm4 ;convert to signed values + pxor xmm2, xmm4 + pcmpgtb xmm1, xmm2 ; obtain sign information + + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + punpcklbw xmm0, xmm1 ; put sign back to subtraction + punpckhbw xmm2, xmm3 ; put sign back to subtraction + + movdqa [rdi], xmm0 ; store difference + movdqa [rdi +16], xmm2 ; store difference + add rdi, 32 + sub rcx, 1 + jnz .submbv_loop + + pop rbx + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +t80: + times 16 db 0x80 diff --git a/vp8/encoder/x86/temporal_filter_apply_sse2.asm b/vp8/encoder/x86/temporal_filter_apply_sse2.asm new file mode 100644 index 0000000..b97c694 --- /dev/null +++ b/vp8/encoder/x86/temporal_filter_apply_sse2.asm @@ -0,0 +1,207 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +; void vp8_temporal_filter_apply_sse2 | arg +; (unsigned char *frame1, | 0 +; unsigned int stride, | 1 +; unsigned char *frame2, | 2 +; unsigned int block_size, | 3 +; int strength, | 4 +; int filter_weight, | 5 +; unsigned int *accumulator, | 6 +; unsigned short *count) | 7 +global sym(vp8_temporal_filter_apply_sse2) +sym(vp8_temporal_filter_apply_sse2): + + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + SAVE_XMM 7 + GET_GOT rbx + push rsi + push rdi + ALIGN_STACK 16, rax + %define block_size 0 + %define strength 16 + %define filter_weight 32 + %define rounding_bit 48 + %define rbp_backup 64 + %define stack_size 80 + sub rsp, stack_size + mov [rsp + rbp_backup], rbp + ; end prolog + + mov rdx, arg(3) + mov [rsp + block_size], rdx + movd xmm6, arg(4) + movdqa [rsp + strength], xmm6 ; where strength is used, all 16 bytes are read + + ; calculate the rounding bit outside the loop + ; 0x8000 >> (16 - strength) + mov rdx, 16 + sub rdx, arg(4) ; 16 - strength + movd xmm4, rdx ; can't use rdx w/ shift + movdqa xmm5, [GLOBAL(_const_top_bit)] + psrlw xmm5, xmm4 + movdqa [rsp + rounding_bit], xmm5 + + mov rsi, arg(0) ; src/frame1 + mov rdx, arg(2) ; predictor frame + mov rdi, arg(6) ; accumulator + mov rax, arg(7) ; count + + ; dup the filter weight and store for later + movd xmm0, arg(5) ; filter_weight + pshuflw xmm0, xmm0, 0 + punpcklwd xmm0, xmm0 + movdqa [rsp + filter_weight], xmm0 + + mov rbp, arg(1) ; stride + pxor xmm7, xmm7 ; zero for extraction + + lea rcx, [rdx + 16*16*1] + cmp dword ptr [rsp + block_size], 8 + jne .temporal_filter_apply_load_16 + lea rcx, [rdx + 8*8*1] + +.temporal_filter_apply_load_8: + movq xmm0, [rsi] ; first row + lea rsi, [rsi + rbp] ; += stride + punpcklbw xmm0, xmm7 ; src[ 0- 7] + movq xmm1, [rsi] ; second row + lea rsi, [rsi + rbp] ; += stride + punpcklbw xmm1, xmm7 ; src[ 8-15] + jmp .temporal_filter_apply_load_finished + +.temporal_filter_apply_load_16: + movdqa xmm0, [rsi] ; src (frame1) + lea rsi, [rsi + rbp] ; += stride + movdqa xmm1, xmm0 + punpcklbw xmm0, xmm7 ; src[ 0- 7] + punpckhbw xmm1, xmm7 ; src[ 8-15] + +.temporal_filter_apply_load_finished: + movdqa xmm2, [rdx] ; predictor (frame2) + movdqa xmm3, xmm2 + punpcklbw xmm2, xmm7 ; pred[ 0- 7] + punpckhbw xmm3, xmm7 ; pred[ 8-15] + + ; modifier = src_byte - pixel_value + psubw xmm0, xmm2 ; src - pred[ 0- 7] + psubw xmm1, xmm3 ; src - pred[ 8-15] + + ; modifier *= modifier + pmullw xmm0, xmm0 ; modifer[ 0- 7]^2 + pmullw xmm1, xmm1 ; modifer[ 8-15]^2 + + ; modifier *= 3 + pmullw xmm0, [GLOBAL(_const_3w)] + pmullw xmm1, [GLOBAL(_const_3w)] + + ; modifer += 0x8000 >> (16 - strength) + paddw xmm0, [rsp + rounding_bit] + paddw xmm1, [rsp + rounding_bit] + + ; modifier >>= strength + psrlw xmm0, [rsp + strength] + psrlw xmm1, [rsp + strength] + + ; modifier = 16 - modifier + ; saturation takes care of modifier > 16 + movdqa xmm3, [GLOBAL(_const_16w)] + movdqa xmm2, [GLOBAL(_const_16w)] + psubusw xmm3, xmm1 + psubusw xmm2, xmm0 + + ; modifier *= filter_weight + pmullw xmm2, [rsp + filter_weight] + pmullw xmm3, [rsp + filter_weight] + + ; count + movdqa xmm4, [rax] + movdqa xmm5, [rax+16] + ; += modifier + paddw xmm4, xmm2 + paddw xmm5, xmm3 + ; write back + movdqa [rax], xmm4 + movdqa [rax+16], xmm5 + lea rax, [rax + 16*2] ; count += 16*(sizeof(short)) + + ; load and extract the predictor up to shorts + pxor xmm7, xmm7 + movdqa xmm0, [rdx] + lea rdx, [rdx + 16*1] ; pred += 16*(sizeof(char)) + movdqa xmm1, xmm0 + punpcklbw xmm0, xmm7 ; pred[ 0- 7] + punpckhbw xmm1, xmm7 ; pred[ 8-15] + + ; modifier *= pixel_value + pmullw xmm0, xmm2 + pmullw xmm1, xmm3 + + ; expand to double words + movdqa xmm2, xmm0 + punpcklwd xmm0, xmm7 ; [ 0- 3] + punpckhwd xmm2, xmm7 ; [ 4- 7] + movdqa xmm3, xmm1 + punpcklwd xmm1, xmm7 ; [ 8-11] + punpckhwd xmm3, xmm7 ; [12-15] + + ; accumulator + movdqa xmm4, [rdi] + movdqa xmm5, [rdi+16] + movdqa xmm6, [rdi+32] + movdqa xmm7, [rdi+48] + ; += modifier + paddd xmm4, xmm0 + paddd xmm5, xmm2 + paddd xmm6, xmm1 + paddd xmm7, xmm3 + ; write back + movdqa [rdi], xmm4 + movdqa [rdi+16], xmm5 + movdqa [rdi+32], xmm6 + movdqa [rdi+48], xmm7 + lea rdi, [rdi + 16*4] ; accumulator += 16*(sizeof(int)) + + cmp rdx, rcx + je .temporal_filter_apply_epilog + pxor xmm7, xmm7 ; zero for extraction + cmp dword ptr [rsp + block_size], 16 + je .temporal_filter_apply_load_16 + jmp .temporal_filter_apply_load_8 + +.temporal_filter_apply_epilog: + ; begin epilog + mov rbp, [rsp + rbp_backup] + add rsp, stack_size + pop rsp + pop rdi + pop rsi + RESTORE_GOT + RESTORE_XMM + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +_const_3w: + times 8 dw 3 +align 16 +_const_top_bit: + times 8 dw 1<<15 +align 16 +_const_16w + times 8 dw 16 diff --git a/vp8/encoder/x86/vp8_enc_stubs_mmx.c b/vp8/encoder/x86/vp8_enc_stubs_mmx.c new file mode 100644 index 0000000..da25f52 --- /dev/null +++ b/vp8/encoder/x86/vp8_enc_stubs_mmx.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx_ports/x86.h" +#include "vp8/encoder/block.h" + +void vp8_short_fdct4x4_mmx(short *input, short *output, int pitch); +void vp8_short_fdct8x4_mmx(short *input, short *output, int pitch) +{ + vp8_short_fdct4x4_mmx(input, output, pitch); + vp8_short_fdct4x4_mmx(input + 4, output + 16, pitch); +} + +int vp8_fast_quantize_b_impl_mmx(short *coeff_ptr, short *zbin_ptr, + short *qcoeff_ptr, short *dequant_ptr, + const short *scan_mask, short *round_ptr, + short *quant_ptr, short *dqcoeff_ptr); +void vp8_fast_quantize_b_mmx(BLOCK *b, BLOCKD *d) +{ + const short *scan_mask = vp8_default_zig_zag_mask; + short *coeff_ptr = b->coeff; + short *zbin_ptr = b->zbin; + short *round_ptr = b->round; + short *quant_ptr = b->quant_fast; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = d->dequant; + + *d->eob = (char)vp8_fast_quantize_b_impl_mmx( + coeff_ptr, + zbin_ptr, + qcoeff_ptr, + dequant_ptr, + scan_mask, + + round_ptr, + quant_ptr, + dqcoeff_ptr + ); +} + +int vp8_mbblock_error_mmx_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +int vp8_mbblock_error_mmx(MACROBLOCK *mb, int dc) +{ + short *coeff_ptr = mb->block[0].coeff; + short *dcoef_ptr = mb->e_mbd.block[0].dqcoeff; + return vp8_mbblock_error_mmx_impl(coeff_ptr, dcoef_ptr, dc); +} + +int vp8_mbuverror_mmx_impl(short *s_ptr, short *d_ptr); +int vp8_mbuverror_mmx(MACROBLOCK *mb) +{ + short *s_ptr = &mb->coeff[256]; + short *d_ptr = &mb->e_mbd.dqcoeff[256]; + return vp8_mbuverror_mmx_impl(s_ptr, d_ptr); +} + +void vp8_subtract_b_mmx_impl(unsigned char *z, int src_stride, + short *diff, unsigned char *predictor, + int pitch); +void vp8_subtract_b_mmx(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *z = *(be->base_src) + be->src; + unsigned int src_stride = be->src_stride; + short *diff = &be->src_diff[0]; + unsigned char *predictor = &bd->predictor[0]; + vp8_subtract_b_mmx_impl(z, src_stride, diff, predictor, pitch); +} diff --git a/vp8/encoder/x86/vp8_enc_stubs_sse2.c b/vp8/encoder/x86/vp8_enc_stubs_sse2.c new file mode 100644 index 0000000..68db815 --- /dev/null +++ b/vp8/encoder/x86/vp8_enc_stubs_sse2.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_config.h" +#include "vpx_rtcd.h" +#include "vpx_ports/x86.h" +#include "vp8/encoder/block.h" + +int vp8_mbblock_error_xmm_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +int vp8_mbblock_error_xmm(MACROBLOCK *mb, int dc) +{ + short *coeff_ptr = mb->block[0].coeff; + short *dcoef_ptr = mb->e_mbd.block[0].dqcoeff; + return vp8_mbblock_error_xmm_impl(coeff_ptr, dcoef_ptr, dc); +} + +int vp8_mbuverror_xmm_impl(short *s_ptr, short *d_ptr); +int vp8_mbuverror_xmm(MACROBLOCK *mb) +{ + short *s_ptr = &mb->coeff[256]; + short *d_ptr = &mb->e_mbd.dqcoeff[256]; + return vp8_mbuverror_xmm_impl(s_ptr, d_ptr); +} + +void vp8_subtract_b_sse2_impl(unsigned char *z, int src_stride, + short *diff, unsigned char *predictor, + int pitch); +void vp8_subtract_b_sse2(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *z = *(be->base_src) + be->src; + unsigned int src_stride = be->src_stride; + short *diff = &be->src_diff[0]; + unsigned char *predictor = &bd->predictor[0]; + vp8_subtract_b_sse2_impl(z, src_stride, diff, predictor, pitch); +} diff --git a/vp8/exports_dec b/vp8/exports_dec new file mode 100644 index 0000000..100ac5c --- /dev/null +++ b/vp8/exports_dec @@ -0,0 +1,2 @@ +data vpx_codec_vp8_dx_algo +text vpx_codec_vp8_dx diff --git a/vp8/exports_enc b/vp8/exports_enc new file mode 100644 index 0000000..29ff35e --- /dev/null +++ b/vp8/exports_enc @@ -0,0 +1,2 @@ +data vpx_codec_vp8_cx_algo +text vpx_codec_vp8_cx diff --git a/vp8/vp8_common.mk b/vp8/vp8_common.mk new file mode 100644 index 0000000..3a7b146 --- /dev/null +++ b/vp8/vp8_common.mk @@ -0,0 +1,187 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + +VP8_COMMON_SRCS-yes += vp8_common.mk +VP8_COMMON_SRCS-yes += common/pragmas.h +VP8_COMMON_SRCS-yes += common/ppflags.h +VP8_COMMON_SRCS-yes += common/onyx.h +VP8_COMMON_SRCS-yes += common/onyxd.h +VP8_COMMON_SRCS-yes += common/alloccommon.c +VP8_COMMON_SRCS-yes += common/asm_com_offsets.c +VP8_COMMON_SRCS-yes += common/blockd.c +VP8_COMMON_SRCS-yes += common/coefupdateprobs.h +VP8_COMMON_SRCS-yes += common/debugmodes.c +VP8_COMMON_SRCS-yes += common/default_coef_probs.h +VP8_COMMON_SRCS-yes += common/dequantize.c +VP8_COMMON_SRCS-yes += common/entropy.c +VP8_COMMON_SRCS-yes += common/entropymode.c +VP8_COMMON_SRCS-yes += common/entropymv.c +VP8_COMMON_SRCS-yes += common/extend.c +VP8_COMMON_SRCS-yes += common/filter.c +VP8_COMMON_SRCS-yes += common/filter.h +VP8_COMMON_SRCS-yes += common/findnearmv.c +VP8_COMMON_SRCS-yes += common/generic/systemdependent.c +VP8_COMMON_SRCS-yes += common/idct_blk.c +VP8_COMMON_SRCS-yes += common/idctllm.c +VP8_COMMON_SRCS-yes += common/idctllm_test.cc +VP8_COMMON_SRCS-yes += common/alloccommon.h +VP8_COMMON_SRCS-yes += common/blockd.h +VP8_COMMON_SRCS-yes += common/common.h +VP8_COMMON_SRCS-yes += common/entropy.h +VP8_COMMON_SRCS-yes += common/entropymode.h +VP8_COMMON_SRCS-yes += common/entropymv.h +VP8_COMMON_SRCS-yes += common/extend.h +VP8_COMMON_SRCS-yes += common/findnearmv.h +VP8_COMMON_SRCS-yes += common/header.h +VP8_COMMON_SRCS-yes += common/invtrans.h +VP8_COMMON_SRCS-yes += common/loopfilter.h +VP8_COMMON_SRCS-yes += common/modecont.h +VP8_COMMON_SRCS-yes += common/mv.h +VP8_COMMON_SRCS-yes += common/onyxc_int.h +VP8_COMMON_SRCS-yes += common/quant_common.h +VP8_COMMON_SRCS-yes += common/reconinter.h +VP8_COMMON_SRCS-yes += common/reconintra4x4.h +VP8_COMMON_SRCS-yes += common/rtcd.c +VP8_COMMON_SRCS-yes += common/rtcd_defs.sh +VP8_COMMON_SRCS-yes += common/setupintrarecon.h +VP8_COMMON_SRCS-yes += common/swapyv12buffer.h +VP8_COMMON_SRCS-yes += common/systemdependent.h +VP8_COMMON_SRCS-yes += common/threading.h +VP8_COMMON_SRCS-yes += common/treecoder.h +VP8_COMMON_SRCS-yes += common/loopfilter.c +VP8_COMMON_SRCS-yes += common/loopfilter_filters.c +VP8_COMMON_SRCS-yes += common/mbpitch.c +VP8_COMMON_SRCS-yes += common/modecont.c +VP8_COMMON_SRCS-yes += common/quant_common.c +VP8_COMMON_SRCS-yes += common/reconinter.c +VP8_COMMON_SRCS-yes += common/reconintra.c +VP8_COMMON_SRCS-yes += common/reconintra4x4.c +VP8_COMMON_SRCS-yes += common/sad_c.c +VP8_COMMON_SRCS-yes += common/setupintrarecon.c +VP8_COMMON_SRCS-yes += common/swapyv12buffer.c +VP8_COMMON_SRCS-yes += common/variance_c.c +VP8_COMMON_SRCS-yes += common/variance.h +VP8_COMMON_SRCS-yes += common/vp8_entropymodedata.h + + + +VP8_COMMON_SRCS-$(CONFIG_POSTPROC_VISUALIZER) += common/textblit.c +VP8_COMMON_SRCS-yes += common/treecoder.c + +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/filter_x86.c +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/filter_x86.h +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/vp8_asm_stubs.c +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/loopfilter_x86.c +VP8_COMMON_SRCS-$(CONFIG_POSTPROC) += common/mfqe.c +VP8_COMMON_SRCS-$(CONFIG_POSTPROC) += common/postproc.h +VP8_COMMON_SRCS-$(CONFIG_POSTPROC) += common/postproc.c +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/dequantize_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idct_blk_mmx.c +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idctllm_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idctllm_mmx_test.cc +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/iwalsh_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/loopfilter_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/recon_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/sad_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/subpixel_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/variance_mmx.c +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/variance_impl_mmx.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/idct_blk_sse2.c +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/idctllm_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/recon_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/recon_wrapper_sse2.c +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/sad_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/subpixel_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/loopfilter_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/iwalsh_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/variance_sse2.c +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/variance_impl_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE3) += common/x86/sad_sse3.asm +VP8_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/sad_ssse3.asm +VP8_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/subpixel_ssse3.asm +VP8_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/variance_ssse3.c +VP8_COMMON_SRCS-$(HAVE_SSSE3) += common/x86/variance_impl_ssse3.asm +VP8_COMMON_SRCS-$(HAVE_SSE4_1) += common/x86/sad_sse4.asm + +ifeq ($(CONFIG_POSTPROC),yes) +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/postproc_x86.c +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/postproc_mmx.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/mfqe_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/postproc_sse2.asm +endif + +ifeq ($(ARCH_X86_64),yes) +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/loopfilter_block_sse2.asm +endif + +# common (c) +VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/filter_arm.c +VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/loopfilter_arm.c +VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/reconintra_arm.c +VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/dequantize_arm.c +VP8_COMMON_SRCS-$(ARCH_ARM) += common/arm/variance_arm.c + +# common (media) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/bilinearfilter_arm.c +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/bilinearfilter_arm.h +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/bilinearfilter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/copymem8x4_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/copymem8x8_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/copymem16x16_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/dc_only_idct_add_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/iwalsh_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/filter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/idct_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/loopfilter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/simpleloopfilter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/sixtappredict8x4_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/intra4x4_predict_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/dequant_idct_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/dequantize_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/idct_blk_v6.c +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/vp8_sad16x16_armv6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/vp8_variance8x8_armv6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/vp8_variance16x16_armv6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/vp8_variance_halfpixvar16x16_h_armv6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/vp8_variance_halfpixvar16x16_v_armv6$(ASM) +VP8_COMMON_SRCS-$(HAVE_MEDIA) += common/arm/armv6/vp8_variance_halfpixvar16x16_hv_armv6$(ASM) + +# common (neon) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/bilinearpredict4x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/bilinearpredict8x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/bilinearpredict8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/bilinearpredict16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/copymem8x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/copymem8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/copymem16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/dc_only_idct_add_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/iwalsh_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/loopfilter_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/loopfiltersimplehorizontaledge_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/loopfiltersimpleverticaledge_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/mbloopfilter_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/shortidct4x4llm_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sad8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sad16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sixtappredict4x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sixtappredict8x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sixtappredict8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/sixtappredict16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/buildintrapredictorsmby_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/save_reg_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/dequant_idct_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/idct_dequant_full_2x_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/idct_dequant_0_2x_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/dequantizeb_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/idct_blk_neon.c +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/variance_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/vp8_subpixelvariance8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/vp8_subpixelvariance16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_NEON) += common/arm/neon/vp8_subpixelvariance16x16s_neon$(ASM) diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c new file mode 100644 index 0000000..5fb74c4 --- /dev/null +++ b/vp8/vp8_cx_iface.c @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx/vpx_codec.h" +#include "vpx/internal/vpx_codec_internal.h" +#include "vpx_version.h" +#include "vp8/encoder/onyx_int.h" +#include "vpx/vp8cx.h" +#include "vp8/encoder/firstpass.h" +#include "vp8/common/onyx.h" +#include +#include + +struct vp8_extracfg +{ + struct vpx_codec_pkt_list *pkt_list; + vp8e_encoding_mode encoding_mode; /** best, good, realtime */ + int cpu_used; /** available cpu percentage in 1/16*/ + unsigned int enable_auto_alt_ref; /** if encoder decides to uses alternate reference frame */ + unsigned int noise_sensitivity; + unsigned int Sharpness; + unsigned int static_thresh; + unsigned int token_partitions; + unsigned int arnr_max_frames; /* alt_ref Noise Reduction Max Frame Count */ + unsigned int arnr_strength; /* alt_ref Noise Reduction Strength */ + unsigned int arnr_type; /* alt_ref filter type */ + vp8e_tuning tuning; + unsigned int cq_level; /* constrained quality level */ + unsigned int rc_max_intra_bitrate_pct; + +}; + +struct extraconfig_map +{ + int usage; + struct vp8_extracfg cfg; +}; + +static const struct extraconfig_map extracfg_map[] = +{ + { + 0, + { + NULL, +#if !(CONFIG_REALTIME_ONLY) + VP8_BEST_QUALITY_ENCODING, /* Encoding Mode */ + 0, /* cpu_used */ +#else + VP8_REAL_TIME_ENCODING, /* Encoding Mode */ + 4, /* cpu_used */ +#endif + 0, /* enable_auto_alt_ref */ + 0, /* noise_sensitivity */ + 0, /* Sharpness */ + 0, /* static_thresh */ +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + VP8_EIGHT_TOKENPARTITION, +#else + VP8_ONE_TOKENPARTITION, /* token_partitions */ +#endif + 0, /* arnr_max_frames */ + 3, /* arnr_strength */ + 3, /* arnr_type*/ + 0, /* tuning*/ + 10, /* cq_level */ + 0, /* rc_max_intra_bitrate_pct */ + } + } +}; + +struct vpx_codec_alg_priv +{ + vpx_codec_priv_t base; + vpx_codec_enc_cfg_t cfg; + struct vp8_extracfg vp8_cfg; + VP8_CONFIG oxcf; + struct VP8_COMP *cpi; + unsigned char *cx_data; + unsigned int cx_data_sz; + vpx_image_t preview_img; + unsigned int next_frame_flag; + vp8_postproc_cfg_t preview_ppcfg; + vpx_codec_pkt_list_decl(64) pkt_list; // changed to accomendate the maximum number of lagged frames allowed + unsigned int fixed_kf_cntr; +}; + + +static vpx_codec_err_t +update_error_state(vpx_codec_alg_priv_t *ctx, + const struct vpx_internal_error_info *error) +{ + vpx_codec_err_t res; + + if ((res = error->error_code)) + ctx->base.err_detail = error->has_detail + ? error->detail + : NULL; + + return res; +} + + +#undef ERROR +#define ERROR(str) do {\ + ctx->base.err_detail = str;\ + return VPX_CODEC_INVALID_PARAM;\ + } while(0) + +#define RANGE_CHECK(p,memb,lo,hi) do {\ + if(!(((p)->memb == lo || (p)->memb > (lo)) && (p)->memb <= hi)) \ + ERROR(#memb " out of range ["#lo".."#hi"]");\ + } while(0) + +#define RANGE_CHECK_HI(p,memb,hi) do {\ + if(!((p)->memb <= (hi))) \ + ERROR(#memb " out of range [.."#hi"]");\ + } while(0) + +#define RANGE_CHECK_LO(p,memb,lo) do {\ + if(!((p)->memb >= (lo))) \ + ERROR(#memb " out of range ["#lo"..]");\ + } while(0) + +#define RANGE_CHECK_BOOL(p,memb) do {\ + if(!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean");\ + } while(0) + +static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, + const vpx_codec_enc_cfg_t *cfg, + const struct vp8_extracfg *vp8_cfg, + int finalize) +{ + RANGE_CHECK(cfg, g_w, 1, 16383); /* 14 bits available */ + RANGE_CHECK(cfg, g_h, 1, 16383); /* 14 bits available */ + RANGE_CHECK(cfg, g_timebase.den, 1, 1000000000); + RANGE_CHECK(cfg, g_timebase.num, 1, cfg->g_timebase.den); + RANGE_CHECK_HI(cfg, g_profile, 3); + RANGE_CHECK_HI(cfg, rc_max_quantizer, 63); + RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer); + RANGE_CHECK_HI(cfg, g_threads, 64); +#if !(CONFIG_REALTIME_ONLY) + RANGE_CHECK_HI(cfg, g_lag_in_frames, 25); +#else + RANGE_CHECK_HI(cfg, g_lag_in_frames, 0); +#endif + RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ); + RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000); + RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000); + RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); + RANGE_CHECK(cfg, kf_mode, VPX_KF_DISABLED, VPX_KF_AUTO); + //RANGE_CHECK_BOOL(cfg, g_delete_firstpassfile); + RANGE_CHECK_BOOL(cfg, rc_resize_allowed); + RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100); + RANGE_CHECK_HI(cfg, rc_resize_up_thresh, 100); + RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100); +#if !(CONFIG_REALTIME_ONLY) + RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_LAST_PASS); +#else + RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_ONE_PASS); +#endif + + /* VP8 does not support a lower bound on the keyframe interval in + * automatic keyframe placement mode. + */ + if (cfg->kf_mode != VPX_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist + && cfg->kf_min_dist > 0) + ERROR("kf_min_dist not supported in auto mode, use 0 " + "or kf_max_dist instead."); + + RANGE_CHECK_BOOL(vp8_cfg, enable_auto_alt_ref); + RANGE_CHECK(vp8_cfg, cpu_used, -16, 16); +#if !(CONFIG_REALTIME_ONLY) + RANGE_CHECK(vp8_cfg, encoding_mode, VP8_BEST_QUALITY_ENCODING, VP8_REAL_TIME_ENCODING); +#else + RANGE_CHECK(vp8_cfg, encoding_mode, VP8_REAL_TIME_ENCODING, VP8_REAL_TIME_ENCODING); +#endif + +#if CONFIG_REALTIME_ONLY && !CONFIG_TEMPORAL_DENOISING + RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 0); +#else + RANGE_CHECK_HI(vp8_cfg, noise_sensitivity, 6); +#endif + + RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION); + RANGE_CHECK_HI(vp8_cfg, Sharpness, 7); + RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15); + RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6); + RANGE_CHECK(vp8_cfg, arnr_type, 1, 3); + RANGE_CHECK(vp8_cfg, cq_level, 0, 63); + if(finalize && cfg->rc_end_usage == VPX_CQ) + RANGE_CHECK(vp8_cfg, cq_level, + cfg->rc_min_quantizer, cfg->rc_max_quantizer); + +#if !(CONFIG_REALTIME_ONLY) + if (cfg->g_pass == VPX_RC_LAST_PASS) + { + size_t packet_sz = sizeof(FIRSTPASS_STATS); + int n_packets = cfg->rc_twopass_stats_in.sz / packet_sz; + FIRSTPASS_STATS *stats; + + if (!cfg->rc_twopass_stats_in.buf) + ERROR("rc_twopass_stats_in.buf not set."); + + if (cfg->rc_twopass_stats_in.sz % packet_sz) + ERROR("rc_twopass_stats_in.sz indicates truncated packet."); + + if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz) + ERROR("rc_twopass_stats_in requires at least two packets."); + + stats = (void*)((char *)cfg->rc_twopass_stats_in.buf + + (n_packets - 1) * packet_sz); + + if ((int)(stats->count + 0.5) != n_packets - 1) + ERROR("rc_twopass_stats_in missing EOS stats packet"); + } +#endif + + RANGE_CHECK(cfg, ts_number_layers, 1, 5); + + if (cfg->ts_number_layers > 1) + { + int i; + RANGE_CHECK_HI(cfg, ts_periodicity, 16); + + for (i=1; its_number_layers; i++) + if (cfg->ts_target_bitrate[i] <= cfg->ts_target_bitrate[i-1]) + ERROR("ts_target_bitrate entries are not strictly increasing"); + + RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers-1], 1, 1); + for (i=cfg->ts_number_layers-2; i>0; i--) + if (cfg->ts_rate_decimator[i-1] != 2*cfg->ts_rate_decimator[i]) + ERROR("ts_rate_decimator factors are not powers of 2"); + + RANGE_CHECK_HI(cfg, ts_layer_id[i], cfg->ts_number_layers-1); + } + +#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING) + if(cfg->g_threads > (1 << vp8_cfg->token_partitions)) + ERROR("g_threads cannot be bigger than number of token partitions"); +#endif + + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx, + const vpx_image_t *img) +{ + switch (img->fmt) + { + case VPX_IMG_FMT_YV12: + case VPX_IMG_FMT_I420: + case VPX_IMG_FMT_VPXI420: + case VPX_IMG_FMT_VPXYV12: + break; + default: + ERROR("Invalid image format. Only YV12 and I420 images are supported"); + } + + if ((img->d_w != ctx->cfg.g_w) || (img->d_h != ctx->cfg.g_h)) + ERROR("Image size must match encoder init configuration size"); + + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, + vpx_codec_enc_cfg_t cfg, + struct vp8_extracfg vp8_cfg, + vpx_codec_priv_enc_mr_cfg_t *mr_cfg) +{ + oxcf->multi_threaded = cfg.g_threads; + oxcf->Version = cfg.g_profile; + + oxcf->Width = cfg.g_w; + oxcf->Height = cfg.g_h; + oxcf->timebase = cfg.g_timebase; + + oxcf->error_resilient_mode = cfg.g_error_resilient; + + switch (cfg.g_pass) + { + case VPX_RC_ONE_PASS: + oxcf->Mode = MODE_BESTQUALITY; + break; + case VPX_RC_FIRST_PASS: + oxcf->Mode = MODE_FIRSTPASS; + break; + case VPX_RC_LAST_PASS: + oxcf->Mode = MODE_SECONDPASS_BEST; + break; + } + + if (cfg.g_pass == VPX_RC_FIRST_PASS) + { + oxcf->allow_lag = 0; + oxcf->lag_in_frames = 0; + } + else + { + oxcf->allow_lag = (cfg.g_lag_in_frames) > 0; + oxcf->lag_in_frames = cfg.g_lag_in_frames; + } + + oxcf->allow_df = (cfg.rc_dropframe_thresh > 0); + oxcf->drop_frames_water_mark = cfg.rc_dropframe_thresh; + + oxcf->allow_spatial_resampling = cfg.rc_resize_allowed; + oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh; + oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh; + + if (cfg.rc_end_usage == VPX_VBR) + { + oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; + } + else if (cfg.rc_end_usage == VPX_CBR) + { + oxcf->end_usage = USAGE_STREAM_FROM_SERVER; + } + else if (cfg.rc_end_usage == VPX_CQ) + { + oxcf->end_usage = USAGE_CONSTRAINED_QUALITY; + } + + oxcf->target_bandwidth = cfg.rc_target_bitrate; + oxcf->rc_max_intra_bitrate_pct = vp8_cfg.rc_max_intra_bitrate_pct; + + oxcf->best_allowed_q = cfg.rc_min_quantizer; + oxcf->worst_allowed_q = cfg.rc_max_quantizer; + oxcf->cq_level = vp8_cfg.cq_level; + oxcf->fixed_q = -1; + + oxcf->under_shoot_pct = cfg.rc_undershoot_pct; + oxcf->over_shoot_pct = cfg.rc_overshoot_pct; + + oxcf->maximum_buffer_size_in_ms = cfg.rc_buf_sz; + oxcf->starting_buffer_level_in_ms = cfg.rc_buf_initial_sz; + oxcf->optimal_buffer_level_in_ms = cfg.rc_buf_optimal_sz; + + oxcf->maximum_buffer_size = cfg.rc_buf_sz; + oxcf->starting_buffer_level = cfg.rc_buf_initial_sz; + oxcf->optimal_buffer_level = cfg.rc_buf_optimal_sz; + + oxcf->two_pass_vbrbias = cfg.rc_2pass_vbr_bias_pct; + oxcf->two_pass_vbrmin_section = cfg.rc_2pass_vbr_minsection_pct; + oxcf->two_pass_vbrmax_section = cfg.rc_2pass_vbr_maxsection_pct; + + oxcf->auto_key = cfg.kf_mode == VPX_KF_AUTO + && cfg.kf_min_dist != cfg.kf_max_dist; + //oxcf->kf_min_dist = cfg.kf_min_dis; + oxcf->key_freq = cfg.kf_max_dist; + + oxcf->number_of_layers = cfg.ts_number_layers; + oxcf->periodicity = cfg.ts_periodicity; + + if (oxcf->number_of_layers > 1) + { + memcpy (oxcf->target_bitrate, cfg.ts_target_bitrate, + sizeof(cfg.ts_target_bitrate)); + memcpy (oxcf->rate_decimator, cfg.ts_rate_decimator, + sizeof(cfg.ts_rate_decimator)); + memcpy (oxcf->layer_id, cfg.ts_layer_id, sizeof(cfg.ts_layer_id)); + } + +#if CONFIG_MULTI_RES_ENCODING + /* When mr_cfg is NULL, oxcf->mr_total_resolutions and oxcf->mr_encoder_id + * are both memset to 0, which ensures the correct logic under this + * situation. + */ + if(mr_cfg) + { + oxcf->mr_total_resolutions = mr_cfg->mr_total_resolutions; + oxcf->mr_encoder_id = mr_cfg->mr_encoder_id; + oxcf->mr_down_sampling_factor.num = mr_cfg->mr_down_sampling_factor.num; + oxcf->mr_down_sampling_factor.den = mr_cfg->mr_down_sampling_factor.den; + oxcf->mr_low_res_mode_info = mr_cfg->mr_low_res_mode_info; + } +#endif + + //oxcf->delete_first_pass_file = cfg.g_delete_firstpassfile; + //strcpy(oxcf->first_pass_file, cfg.g_firstpass_file); + + oxcf->cpu_used = vp8_cfg.cpu_used; + oxcf->encode_breakout = vp8_cfg.static_thresh; + oxcf->play_alternate = vp8_cfg.enable_auto_alt_ref; + oxcf->noise_sensitivity = vp8_cfg.noise_sensitivity; + oxcf->Sharpness = vp8_cfg.Sharpness; + oxcf->token_partitions = vp8_cfg.token_partitions; + + oxcf->two_pass_stats_in = cfg.rc_twopass_stats_in; + oxcf->output_pkt_list = vp8_cfg.pkt_list; + + oxcf->arnr_max_frames = vp8_cfg.arnr_max_frames; + oxcf->arnr_strength = vp8_cfg.arnr_strength; + oxcf->arnr_type = vp8_cfg.arnr_type; + + oxcf->tuning = vp8_cfg.tuning; + + /* + printf("Current VP8 Settings: \n"); + printf("target_bandwidth: %d\n", oxcf->target_bandwidth); + printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity); + printf("Sharpness: %d\n", oxcf->Sharpness); + printf("cpu_used: %d\n", oxcf->cpu_used); + printf("Mode: %d\n", oxcf->Mode); + printf("delete_first_pass_file: %d\n", oxcf->delete_first_pass_file); + printf("auto_key: %d\n", oxcf->auto_key); + printf("key_freq: %d\n", oxcf->key_freq); + printf("end_usage: %d\n", oxcf->end_usage); + printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct); + printf("over_shoot_pct: %d\n", oxcf->over_shoot_pct); + printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level); + printf("optimal_buffer_level: %d\n", oxcf->optimal_buffer_level); + printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size); + printf("fixed_q: %d\n", oxcf->fixed_q); + printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q); + printf("best_allowed_q: %d\n", oxcf->best_allowed_q); + printf("allow_spatial_resampling: %d\n", oxcf->allow_spatial_resampling); + printf("resample_down_water_mark: %d\n", oxcf->resample_down_water_mark); + printf("resample_up_water_mark: %d\n", oxcf->resample_up_water_mark); + printf("allow_df: %d\n", oxcf->allow_df); + printf("drop_frames_water_mark: %d\n", oxcf->drop_frames_water_mark); + printf("two_pass_vbrbias: %d\n", oxcf->two_pass_vbrbias); + printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section); + printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section); + printf("allow_lag: %d\n", oxcf->allow_lag); + printf("lag_in_frames: %d\n", oxcf->lag_in_frames); + printf("play_alternate: %d\n", oxcf->play_alternate); + printf("Version: %d\n", oxcf->Version); + printf("multi_threaded: %d\n", oxcf->multi_threaded); + printf("encode_breakout: %d\n", oxcf->encode_breakout); + */ + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8e_set_config(vpx_codec_alg_priv_t *ctx, + const vpx_codec_enc_cfg_t *cfg) +{ + vpx_codec_err_t res; + + if (((cfg->g_w != ctx->cfg.g_w) || (cfg->g_h != ctx->cfg.g_h)) + && cfg->g_lag_in_frames > 1) + ERROR("Cannot change width or height after initialization"); + + /* Prevent increasing lag_in_frames. This check is stricter than it needs + * to be -- the limit is not increasing past the first lag_in_frames + * value, but we don't track the initial config, only the last successful + * config. + */ + if ((cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames)) + ERROR("Cannot increase lag_in_frames"); + + res = validate_config(ctx, cfg, &ctx->vp8_cfg, 0); + + if (!res) + { + ctx->cfg = *cfg; + set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL); + vp8_change_config(ctx->cpi, &ctx->oxcf); + } + + return res; +} + + +int vp8_reverse_trans(int); + + +static vpx_codec_err_t get_param(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + void *arg = va_arg(args, void *); + +#define MAP(id, var) case id: *(RECAST(id, arg)) = var; break + + if (!arg) + return VPX_CODEC_INVALID_PARAM; + + switch (ctrl_id) + { + MAP(VP8E_GET_LAST_QUANTIZER, vp8_get_quantizer(ctx->cpi)); + MAP(VP8E_GET_LAST_QUANTIZER_64, vp8_reverse_trans(vp8_get_quantizer(ctx->cpi))); + } + + return VPX_CODEC_OK; +#undef MAP +} + + +static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + struct vp8_extracfg xcfg = ctx->vp8_cfg; + +#define MAP(id, var) case id: var = CAST(id, args); break; + + switch (ctrl_id) + { + MAP(VP8E_SET_CPUUSED, xcfg.cpu_used); + MAP(VP8E_SET_ENABLEAUTOALTREF, xcfg.enable_auto_alt_ref); + MAP(VP8E_SET_NOISE_SENSITIVITY, xcfg.noise_sensitivity); + MAP(VP8E_SET_SHARPNESS, xcfg.Sharpness); + MAP(VP8E_SET_STATIC_THRESHOLD, xcfg.static_thresh); + MAP(VP8E_SET_TOKEN_PARTITIONS, xcfg.token_partitions); + + MAP(VP8E_SET_ARNR_MAXFRAMES, xcfg.arnr_max_frames); + MAP(VP8E_SET_ARNR_STRENGTH , xcfg.arnr_strength); + MAP(VP8E_SET_ARNR_TYPE , xcfg.arnr_type); + MAP(VP8E_SET_TUNING, xcfg.tuning); + MAP(VP8E_SET_CQ_LEVEL, xcfg.cq_level); + MAP(VP8E_SET_MAX_INTRA_BITRATE_PCT, xcfg.rc_max_intra_bitrate_pct); + + } + + res = validate_config(ctx, &ctx->cfg, &xcfg, 0); + + if (!res) + { + ctx->vp8_cfg = xcfg; + set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL); + vp8_change_config(ctx->cpi, &ctx->oxcf); + } + + return res; +#undef MAP +} + +static vpx_codec_err_t vp8e_mr_alloc_mem(const vpx_codec_enc_cfg_t *cfg, + void **mem_loc) +{ + vpx_codec_err_t res = 0; + +#if CONFIG_MULTI_RES_ENCODING + int mb_rows = ((cfg->g_w + 15) >>4); + int mb_cols = ((cfg->g_h + 15) >>4); + + *mem_loc = calloc(mb_rows*mb_cols, sizeof(LOWER_RES_INFO)); + if(!(*mem_loc)) + { + free(*mem_loc); + res = VPX_CODEC_MEM_ERROR; + } + else + res = VPX_CODEC_OK; +#endif + + return res; +} + +static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx, + vpx_codec_priv_enc_mr_cfg_t *mr_cfg) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + struct vpx_codec_alg_priv *priv; + vpx_codec_enc_cfg_t *cfg; + unsigned int i; + + struct VP8_COMP *optr; + + if (!ctx->priv) + { + priv = calloc(1, sizeof(struct vpx_codec_alg_priv)); + + if (!priv) + { + return VPX_CODEC_MEM_ERROR; + } + + ctx->priv = &priv->base; + ctx->priv->sz = sizeof(*ctx->priv); + ctx->priv->iface = ctx->iface; + ctx->priv->alg_priv = priv; + ctx->priv->init_flags = ctx->init_flags; + + if (ctx->config.enc) + { + /* Update the reference to the config structure to an + * internal copy. + */ + ctx->priv->alg_priv->cfg = *ctx->config.enc; + ctx->config.enc = &ctx->priv->alg_priv->cfg; + } + + cfg = &ctx->priv->alg_priv->cfg; + + /* Select the extra vp8 configuration table based on the current + * usage value. If the current usage value isn't found, use the + * values for usage case 0. + */ + for (i = 0; + extracfg_map[i].usage && extracfg_map[i].usage != cfg->g_usage; + i++); + + priv->vp8_cfg = extracfg_map[i].cfg; + priv->vp8_cfg.pkt_list = &priv->pkt_list.head; + + priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 2; + + if (priv->cx_data_sz < 32768) priv->cx_data_sz = 32768; + + priv->cx_data = malloc(priv->cx_data_sz); + + if (!priv->cx_data) + { + return VPX_CODEC_MEM_ERROR; + } + + res = validate_config(priv, &priv->cfg, &priv->vp8_cfg, 0); + + if (!res) + { + if(mr_cfg) + ctx->priv->enc.total_encoders = mr_cfg->mr_total_resolutions; + else + ctx->priv->enc.total_encoders = 1; + + set_vp8e_config(&ctx->priv->alg_priv->oxcf, + ctx->priv->alg_priv->cfg, + ctx->priv->alg_priv->vp8_cfg, + mr_cfg); + + optr = vp8_create_compressor(&ctx->priv->alg_priv->oxcf); + + if (!optr) + res = VPX_CODEC_MEM_ERROR; + else + ctx->priv->alg_priv->cpi = optr; + } + } + + return res; +} + +static vpx_codec_err_t vp8e_destroy(vpx_codec_alg_priv_t *ctx) +{ +#if CONFIG_MULTI_RES_ENCODING + /* Free multi-encoder shared memory */ + if (ctx->oxcf.mr_total_resolutions > 0 && (ctx->oxcf.mr_encoder_id == ctx->oxcf.mr_total_resolutions-1)) + free(ctx->oxcf.mr_low_res_mode_info); +#endif + + free(ctx->cx_data); + vp8_remove_compressor(&ctx->cpi); + free(ctx); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, + YV12_BUFFER_CONFIG *yv12) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + yv12->y_buffer = img->planes[VPX_PLANE_Y]; + yv12->u_buffer = img->planes[VPX_PLANE_U]; + yv12->v_buffer = img->planes[VPX_PLANE_V]; + + yv12->y_width = img->d_w; + yv12->y_height = img->d_h; + yv12->uv_width = (1 + yv12->y_width) / 2; + yv12->uv_height = (1 + yv12->y_height) / 2; + + yv12->y_stride = img->stride[VPX_PLANE_Y]; + yv12->uv_stride = img->stride[VPX_PLANE_U]; + + yv12->border = (img->stride[VPX_PLANE_Y] - img->w) / 2; + yv12->clrtype = (img->fmt == VPX_IMG_FMT_VPXI420 || img->fmt == VPX_IMG_FMT_VPXYV12); //REG_YUV = 0 + return res; +} + +static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx, + unsigned long duration, + unsigned long deadline) +{ + unsigned int new_qc; + +#if !(CONFIG_REALTIME_ONLY) + /* Use best quality mode if no deadline is given. */ + new_qc = MODE_BESTQUALITY; + + if (deadline) + { + uint64_t duration_us; + + /* Convert duration parameter from stream timebase to microseconds */ + duration_us = (uint64_t)duration * 1000000 + * (uint64_t)ctx->cfg.g_timebase.num + / (uint64_t)ctx->cfg.g_timebase.den; + + /* If the deadline is more that the duration this frame is to be shown, + * use good quality mode. Otherwise use realtime mode. + */ + new_qc = (deadline > duration_us) ? MODE_GOODQUALITY : MODE_REALTIME; + } + +#else + new_qc = MODE_REALTIME; +#endif + + if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS) + new_qc = MODE_FIRSTPASS; + else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS) + new_qc = (new_qc == MODE_BESTQUALITY) + ? MODE_SECONDPASS_BEST + : MODE_SECONDPASS; + + if (ctx->oxcf.Mode != new_qc) + { + ctx->oxcf.Mode = new_qc; + vp8_change_config(ctx->cpi, &ctx->oxcf); + } +} + + +static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, + const vpx_image_t *img, + vpx_codec_pts_t pts, + unsigned long duration, + vpx_enc_frame_flags_t flags, + unsigned long deadline) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + if (!ctx->cfg.rc_target_bitrate) + return res; + + if (img) + res = validate_img(ctx, img); + + if (!res) + res = validate_config(ctx, &ctx->cfg, &ctx->vp8_cfg, 1); + + pick_quickcompress_mode(ctx, duration, deadline); + vpx_codec_pkt_list_init(&ctx->pkt_list); + + /* Handle Flags */ + if (((flags & VP8_EFLAG_NO_UPD_GF) && (flags & VP8_EFLAG_FORCE_GF)) + || ((flags & VP8_EFLAG_NO_UPD_ARF) && (flags & VP8_EFLAG_FORCE_ARF))) + { + ctx->base.err_detail = "Conflicting flags."; + return VPX_CODEC_INVALID_PARAM; + } + + if (flags & (VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF + | VP8_EFLAG_NO_REF_ARF)) + { + int ref = 7; + + if (flags & VP8_EFLAG_NO_REF_LAST) + ref ^= VP8_LAST_FLAG; + + if (flags & VP8_EFLAG_NO_REF_GF) + ref ^= VP8_GOLD_FLAG; + + if (flags & VP8_EFLAG_NO_REF_ARF) + ref ^= VP8_ALT_FLAG; + + vp8_use_as_reference(ctx->cpi, ref); + } + + if (flags & (VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF + | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_FORCE_GF + | VP8_EFLAG_FORCE_ARF)) + { + int upd = 7; + + if (flags & VP8_EFLAG_NO_UPD_LAST) + upd ^= VP8_LAST_FLAG; + + if (flags & VP8_EFLAG_NO_UPD_GF) + upd ^= VP8_GOLD_FLAG; + + if (flags & VP8_EFLAG_NO_UPD_ARF) + upd ^= VP8_ALT_FLAG; + + vp8_update_reference(ctx->cpi, upd); + } + + if (flags & VP8_EFLAG_NO_UPD_ENTROPY) + { + vp8_update_entropy(ctx->cpi, 0); + } + + /* Handle fixed keyframe intervals */ + if (ctx->cfg.kf_mode == VPX_KF_AUTO + && ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) + { + if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) + { + flags |= VPX_EFLAG_FORCE_KF; + ctx->fixed_kf_cntr = 1; + } + } + + /* Initialize the encoder instance on the first frame*/ + if (!res && ctx->cpi) + { + unsigned int lib_flags; + YV12_BUFFER_CONFIG sd; + int64_t dst_time_stamp, dst_end_time_stamp; + unsigned long size, cx_data_sz; + unsigned char *cx_data; + unsigned char *cx_data_end; + int comp_data_state = 0; + + /* Set up internal flags */ + if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) + ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1; + + if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION) + ((VP8_COMP *)ctx->cpi)->output_partition = 1; + + /* Convert API flags to internal codec lib flags */ + lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0; + + /* vp8 use 10,000,000 ticks/second as time stamp */ + dst_time_stamp = pts * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den; + dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den; + + if (img != NULL) + { + res = image2yuvconfig(img, &sd); + + if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags, + &sd, dst_time_stamp, dst_end_time_stamp)) + { + VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; + res = update_error_state(ctx, &cpi->common.error); + } + + /* reset for next frame */ + ctx->next_frame_flag = 0; + } + + cx_data = ctx->cx_data; + cx_data_sz = ctx->cx_data_sz; + cx_data_end = ctx->cx_data + cx_data_sz; + lib_flags = 0; + + while (cx_data_sz >= ctx->cx_data_sz / 2) + { + comp_data_state = vp8_get_compressed_data(ctx->cpi, + &lib_flags, + &size, + cx_data, + cx_data_end, + &dst_time_stamp, + &dst_end_time_stamp, + !img); + + if(comp_data_state == VPX_CODEC_CORRUPT_FRAME) + return VPX_CODEC_CORRUPT_FRAME; + else if(comp_data_state == -1) + break; + + if (size) + { + vpx_codec_pts_t round, delta; + vpx_codec_cx_pkt_t pkt; + VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; + + /* Add the frame packet to the list of returned packets. */ + round = 1000000 * ctx->cfg.g_timebase.num / 2 - 1; + delta = (dst_end_time_stamp - dst_time_stamp); + pkt.kind = VPX_CODEC_CX_FRAME_PKT; + pkt.data.frame.pts = + (dst_time_stamp * ctx->cfg.g_timebase.den + round) + / ctx->cfg.g_timebase.num / 10000000; + pkt.data.frame.duration = + (delta * ctx->cfg.g_timebase.den + round) + / ctx->cfg.g_timebase.num / 10000000; + pkt.data.frame.flags = lib_flags << 16; + + if (lib_flags & FRAMEFLAGS_KEY) + pkt.data.frame.flags |= VPX_FRAME_IS_KEY; + + if (!cpi->common.show_frame) + { + pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE; + + // This timestamp should be as close as possible to the + // prior PTS so that if a decoder uses pts to schedule when + // to do this, we start right after last frame was decoded. + // Invisible frames have no duration. + pkt.data.frame.pts = ((cpi->last_time_stamp_seen + * ctx->cfg.g_timebase.den + round) + / ctx->cfg.g_timebase.num / 10000000) + 1; + pkt.data.frame.duration = 0; + } + + if (cpi->droppable) + pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE; + + if (cpi->output_partition) + { + int i; + const int num_partitions = + (1 << cpi->common.multi_token_partition) + 1; + + pkt.data.frame.flags |= VPX_FRAME_IS_FRAGMENT; + + for (i = 0; i < num_partitions; ++i) + { +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + pkt.data.frame.buf = cpi->partition_d[i]; +#else + pkt.data.frame.buf = cx_data; + cx_data += cpi->partition_sz[i]; + cx_data_sz -= cpi->partition_sz[i]; +#endif + pkt.data.frame.sz = cpi->partition_sz[i]; + pkt.data.frame.partition_id = i; + /* don't set the fragment bit for the last partition */ + if (i == (num_partitions - 1)) + pkt.data.frame.flags &= ~VPX_FRAME_IS_FRAGMENT; + vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); + } +#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING + /* In lagged mode the encoder can buffer multiple frames. + * We don't want this in partitioned output because + * partitions are spread all over the output buffer. + * So, force an exit! + */ + cx_data_sz -= ctx->cx_data_sz / 2; +#endif + } + else + { + pkt.data.frame.buf = cx_data; + pkt.data.frame.sz = size; + pkt.data.frame.partition_id = -1; + vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); + cx_data += size; + cx_data_sz -= size; + } + + //printf("timestamp: %lld, duration: %d\n", pkt->data.frame.pts, pkt->data.frame.duration); + } + } + } + + return res; +} + + +static const vpx_codec_cx_pkt_t *vp8e_get_cxdata(vpx_codec_alg_priv_t *ctx, + vpx_codec_iter_t *iter) +{ + return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter); +} + +static vpx_codec_err_t vp8e_set_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + vp8_set_reference(ctx->cpi, frame->frame_type, &sd); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +static vpx_codec_err_t vp8e_get_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + vp8_get_reference(ctx->cpi, frame->frame_type, &sd); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +} + +static vpx_codec_err_t vp8e_set_previewpp(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ +#if CONFIG_POSTPROC + vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); + (void)ctr_id; + + if (data) + { + ctx->preview_ppcfg = *((vp8_postproc_cfg_t *)data); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +#else + (void)ctx; + (void)ctr_id; + (void)args; + return VPX_CODEC_INCAPABLE; +#endif +} + + +static vpx_image_t *vp8e_get_preview(vpx_codec_alg_priv_t *ctx) +{ + + YV12_BUFFER_CONFIG sd; + vp8_ppflags_t flags = {0}; + + if (ctx->preview_ppcfg.post_proc_flag) + { + flags.post_proc_flag = ctx->preview_ppcfg.post_proc_flag; + flags.deblocking_level = ctx->preview_ppcfg.deblocking_level; + flags.noise_level = ctx->preview_ppcfg.noise_level; + } + + if (0 == vp8_get_preview_raw_frame(ctx->cpi, &sd, &flags)) + { + + /* + vpx_img_wrap(&ctx->preview_img, VPX_IMG_FMT_YV12, + sd.y_width + 2*VP8BORDERINPIXELS, + sd.y_height + 2*VP8BORDERINPIXELS, + 1, + sd.buffer_alloc); + vpx_img_set_rect(&ctx->preview_img, + VP8BORDERINPIXELS, VP8BORDERINPIXELS, + sd.y_width, sd.y_height); + */ + + ctx->preview_img.bps = 12; + ctx->preview_img.planes[VPX_PLANE_Y] = sd.y_buffer; + ctx->preview_img.planes[VPX_PLANE_U] = sd.u_buffer; + ctx->preview_img.planes[VPX_PLANE_V] = sd.v_buffer; + + if (sd.clrtype == REG_YUV) + ctx->preview_img.fmt = VPX_IMG_FMT_I420; + else + ctx->preview_img.fmt = VPX_IMG_FMT_VPXI420; + + ctx->preview_img.x_chroma_shift = 1; + ctx->preview_img.y_chroma_shift = 1; + + ctx->preview_img.d_w = sd.y_width; + ctx->preview_img.d_h = sd.y_height; + ctx->preview_img.stride[VPX_PLANE_Y] = sd.y_stride; + ctx->preview_img.stride[VPX_PLANE_U] = sd.uv_stride; + ctx->preview_img.stride[VPX_PLANE_V] = sd.uv_stride; + ctx->preview_img.w = sd.y_width; + ctx->preview_img.h = sd.y_height; + + return &ctx->preview_img; + } + else + return NULL; +} + +static vpx_codec_err_t vp8e_update_entropy(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + int update = va_arg(args, int); + vp8_update_entropy(ctx->cpi, update); + return VPX_CODEC_OK; + +} + +static vpx_codec_err_t vp8e_update_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + int update = va_arg(args, int); + vp8_update_reference(ctx->cpi, update); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8e_use_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + int reference_flag = va_arg(args, int); + vp8_use_as_reference(ctx->cpi, reference_flag); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8e_set_roi_map(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_roi_map_t *data = va_arg(args, vpx_roi_map_t *); + + if (data) + { + vpx_roi_map_t *roi = (vpx_roi_map_t *)data; + + if (!vp8_set_roimap(ctx->cpi, roi->roi_map, roi->rows, roi->cols, roi->delta_q, roi->delta_lf, roi->static_threshold)) + return VPX_CODEC_OK; + else + return VPX_CODEC_INVALID_PARAM; + } + else + return VPX_CODEC_INVALID_PARAM; +} + + +static vpx_codec_err_t vp8e_set_activemap(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_active_map_t *data = va_arg(args, vpx_active_map_t *); + + if (data) + { + + vpx_active_map_t *map = (vpx_active_map_t *)data; + + if (!vp8_set_active_map(ctx->cpi, map->active_map, map->rows, map->cols)) + return VPX_CODEC_OK; + else + return VPX_CODEC_INVALID_PARAM; + } + else + return VPX_CODEC_INVALID_PARAM; +} + +static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_scaling_mode_t *data = va_arg(args, vpx_scaling_mode_t *); + + if (data) + { + int res; + vpx_scaling_mode_t scalemode = *(vpx_scaling_mode_t *)data ; + res = vp8_set_internal_size(ctx->cpi, scalemode.h_scaling_mode, scalemode.v_scaling_mode); + + if (!res) + { + /*force next frame a key frame to effect scaling mode */ + ctx->next_frame_flag |= FRAMEFLAGS_KEY; + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + } + else + return VPX_CODEC_INVALID_PARAM; +} + + +static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = +{ + {VP8_SET_REFERENCE, vp8e_set_reference}, + {VP8_COPY_REFERENCE, vp8e_get_reference}, + {VP8_SET_POSTPROC, vp8e_set_previewpp}, + {VP8E_UPD_ENTROPY, vp8e_update_entropy}, + {VP8E_UPD_REFERENCE, vp8e_update_reference}, + {VP8E_USE_REFERENCE, vp8e_use_reference}, + {VP8E_SET_ROI_MAP, vp8e_set_roi_map}, + {VP8E_SET_ACTIVEMAP, vp8e_set_activemap}, + {VP8E_SET_SCALEMODE, vp8e_set_scalemode}, + {VP8E_SET_CPUUSED, set_param}, + {VP8E_SET_NOISE_SENSITIVITY, set_param}, + {VP8E_SET_ENABLEAUTOALTREF, set_param}, + {VP8E_SET_SHARPNESS, set_param}, + {VP8E_SET_STATIC_THRESHOLD, set_param}, + {VP8E_SET_TOKEN_PARTITIONS, set_param}, + {VP8E_GET_LAST_QUANTIZER, get_param}, + {VP8E_GET_LAST_QUANTIZER_64, get_param}, + {VP8E_SET_ARNR_MAXFRAMES, set_param}, + {VP8E_SET_ARNR_STRENGTH , set_param}, + {VP8E_SET_ARNR_TYPE , set_param}, + {VP8E_SET_TUNING, set_param}, + {VP8E_SET_CQ_LEVEL, set_param}, + {VP8E_SET_MAX_INTRA_BITRATE_PCT, set_param}, + { -1, NULL}, +}; + +static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = +{ + { + 0, + { + 0, /* g_usage */ + 0, /* g_threads */ + 0, /* g_profile */ + + 320, /* g_width */ + 240, /* g_height */ + {1, 30}, /* g_timebase */ + + 0, /* g_error_resilient */ + + VPX_RC_ONE_PASS, /* g_pass */ + + 0, /* g_lag_in_frames */ + + 0, /* rc_dropframe_thresh */ + 0, /* rc_resize_allowed */ + 60, /* rc_resize_down_thresold */ + 30, /* rc_resize_up_thresold */ + + VPX_VBR, /* rc_end_usage */ +#if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION) + {0}, /* rc_twopass_stats_in */ +#endif + 256, /* rc_target_bandwidth */ + 4, /* rc_min_quantizer */ + 63, /* rc_max_quantizer */ + 100, /* rc_undershoot_pct */ + 100, /* rc_overshoot_pct */ + + 6000, /* rc_max_buffer_size */ + 4000, /* rc_buffer_initial_size; */ + 5000, /* rc_buffer_optimal_size; */ + + 50, /* rc_two_pass_vbrbias */ + 0, /* rc_two_pass_vbrmin_section */ + 400, /* rc_two_pass_vbrmax_section */ + + /* keyframing settings (kf) */ + VPX_KF_AUTO, /* g_kfmode*/ + 0, /* kf_min_dist */ + 128, /* kf_max_dist */ + +#if VPX_ENCODER_ABI_VERSION == (1 + VPX_CODEC_ABI_VERSION) + 1, /* g_delete_first_pass_file */ + "vp8.fpf" /* first pass filename */ +#endif + + 1, /* ts_number_layers */ + {0}, /* ts_target_bitrate */ + {0}, /* ts_rate_decimator */ + 0, /* ts_periodicity */ + {0}, /* ts_layer_id */ + }}, + { -1, {NOT_IMPLEMENTED}} +}; + + +#ifndef VERSION_STRING +#define VERSION_STRING +#endif +CODEC_INTERFACE(vpx_codec_vp8_cx) = +{ + "WebM Project VP8 Encoder" VERSION_STRING, + VPX_CODEC_INTERNAL_ABI_VERSION, + VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR | + VPX_CODEC_CAP_OUTPUT_PARTITION, + /* vpx_codec_caps_t caps; */ + vp8e_init, /* vpx_codec_init_fn_t init; */ + vp8e_destroy, /* vpx_codec_destroy_fn_t destroy; */ + vp8e_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ + NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */ + NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */ + { + NOT_IMPLEMENTED, /* vpx_codec_peek_si_fn_t peek_si; */ + NOT_IMPLEMENTED, /* vpx_codec_get_si_fn_t get_si; */ + NOT_IMPLEMENTED, /* vpx_codec_decode_fn_t decode; */ + NOT_IMPLEMENTED, /* vpx_codec_frame_get_fn_t frame_get; */ + }, + { + vp8e_usage_cfg_map, /* vpx_codec_enc_cfg_map_t peek_si; */ + vp8e_encode, /* vpx_codec_encode_fn_t encode; */ + vp8e_get_cxdata, /* vpx_codec_get_cx_data_fn_t frame_get; */ + vp8e_set_config, + NOT_IMPLEMENTED, + vp8e_get_preview, + vp8e_mr_alloc_mem, + } /* encoder functions */ +}; diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c new file mode 100644 index 0000000..37773db --- /dev/null +++ b/vp8/vp8_dx_iface.c @@ -0,0 +1,787 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include "vpx/vpx_decoder.h" +#include "vpx/vp8dx.h" +#include "vpx/internal/vpx_codec_internal.h" +#include "vpx_version.h" +#include "common/onyxd.h" +#include "decoder/onyxd_int.h" + +#define VP8_CAP_POSTPROC (CONFIG_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0) +#define VP8_CAP_ERROR_CONCEALMENT (CONFIG_ERROR_CONCEALMENT ? \ + VPX_CODEC_CAP_ERROR_CONCEALMENT : 0) + +typedef vpx_codec_stream_info_t vp8_stream_info_t; + +/* Structures for handling memory allocations */ +typedef enum +{ + VP8_SEG_ALG_PRIV = 256, + VP8_SEG_MAX +} mem_seg_id_t; +#define NELEMENTS(x) ((int)(sizeof(x)/sizeof(x[0]))) + +static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t); + +typedef struct +{ + unsigned int id; + unsigned long sz; + unsigned int align; + unsigned int flags; + unsigned long(*calc_sz)(const vpx_codec_dec_cfg_t *, vpx_codec_flags_t); +} mem_req_t; + +static const mem_req_t vp8_mem_req_segs[] = +{ + {VP8_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, vp8_priv_sz}, + {VP8_SEG_MAX, 0, 0, 0, NULL} +}; + +struct vpx_codec_alg_priv +{ + vpx_codec_priv_t base; + vpx_codec_mmap_t mmaps[NELEMENTS(vp8_mem_req_segs)-1]; + vpx_codec_dec_cfg_t cfg; + vp8_stream_info_t si; + int defer_alloc; + int decoder_init; + struct VP8D_COMP *pbi; + int postproc_cfg_set; + vp8_postproc_cfg_t postproc_cfg; +#if CONFIG_POSTPROC_VISUALIZER + unsigned int dbg_postproc_flag; + int dbg_color_ref_frame_flag; + int dbg_color_mb_modes_flag; + int dbg_color_b_modes_flag; + int dbg_display_mv_flag; +#endif + vpx_image_t img; + int img_setup; + int img_avail; +}; + +static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t flags) +{ + /* Although this declaration is constant, we can't use it in the requested + * segments list because we want to define the requested segments list + * before defining the private type (so that the number of memory maps is + * known) + */ + (void)si; + return sizeof(vpx_codec_alg_priv_t); +} + + +static void vp8_mmap_dtor(vpx_codec_mmap_t *mmap) +{ + free(mmap->priv); +} + +static vpx_codec_err_t vp8_mmap_alloc(vpx_codec_mmap_t *mmap) +{ + vpx_codec_err_t res; + unsigned int align; + + align = mmap->align ? mmap->align - 1 : 0; + + if (mmap->flags & VPX_CODEC_MEM_ZERO) + mmap->priv = calloc(1, mmap->sz + align); + else + mmap->priv = malloc(mmap->sz + align); + + res = (mmap->priv) ? VPX_CODEC_OK : VPX_CODEC_MEM_ERROR; + mmap->base = (void *)((((uintptr_t)mmap->priv) + align) & ~(uintptr_t)align); + mmap->dtor = vp8_mmap_dtor; + return res; +} + +static vpx_codec_err_t vp8_validate_mmaps(const vp8_stream_info_t *si, + const vpx_codec_mmap_t *mmaps, + vpx_codec_flags_t init_flags) +{ + int i; + vpx_codec_err_t res = VPX_CODEC_OK; + + for (i = 0; i < NELEMENTS(vp8_mem_req_segs) - 1; i++) + { + /* Ensure the segment has been allocated */ + if (!mmaps[i].base) + { + res = VPX_CODEC_MEM_ERROR; + break; + } + + /* Verify variable size segment is big enough for the current si. */ + if (vp8_mem_req_segs[i].calc_sz) + { + vpx_codec_dec_cfg_t cfg; + + cfg.w = si->w; + cfg.h = si->h; + + if (mmaps[i].sz < vp8_mem_req_segs[i].calc_sz(&cfg, init_flags)) + { + res = VPX_CODEC_MEM_ERROR; + break; + } + } + } + + return res; +} + +static void vp8_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) +{ + int i; + + ctx->priv = mmap->base; + ctx->priv->sz = sizeof(*ctx->priv); + ctx->priv->iface = ctx->iface; + ctx->priv->alg_priv = mmap->base; + + for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) + ctx->priv->alg_priv->mmaps[i].id = vp8_mem_req_segs[i].id; + + ctx->priv->alg_priv->mmaps[0] = *mmap; + ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si); + ctx->priv->init_flags = ctx->init_flags; + + if (ctx->config.dec) + { + /* Update the reference to the config structure to an internal copy. */ + ctx->priv->alg_priv->cfg = *ctx->config.dec; + ctx->config.dec = &ctx->priv->alg_priv->cfg; + } +} + +static void *mmap_lkup(vpx_codec_alg_priv_t *ctx, unsigned int id) +{ + int i; + + for (i = 0; i < NELEMENTS(ctx->mmaps); i++) + if (ctx->mmaps[i].id == id) + return ctx->mmaps[i].base; + + return NULL; +} +static void vp8_finalize_mmaps(vpx_codec_alg_priv_t *ctx) +{ + /* nothing to clean up */ +} + +static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx, + vpx_codec_priv_enc_mr_cfg_t *data) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + (void) data; + + /* This function only allocates space for the vpx_codec_alg_priv_t + * structure. More memory may be required at the time the stream + * information becomes known. + */ + if (!ctx->priv) + { + vpx_codec_mmap_t mmap; + + mmap.id = vp8_mem_req_segs[0].id; + mmap.sz = sizeof(vpx_codec_alg_priv_t); + mmap.align = vp8_mem_req_segs[0].align; + mmap.flags = vp8_mem_req_segs[0].flags; + + res = vp8_mmap_alloc(&mmap); + + if (!res) + { + vp8_init_ctx(ctx, &mmap); + + ctx->priv->alg_priv->defer_alloc = 1; + /*post processing level initialized to do nothing */ + } + } + + return res; +} + +static vpx_codec_err_t vp8_destroy(vpx_codec_alg_priv_t *ctx) +{ + int i; + + vp8dx_remove_decompressor(ctx->pbi); + + for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) + { + if (ctx->mmaps[i].dtor) + ctx->mmaps[i].dtor(&ctx->mmaps[i]); + } + + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8_peek_si(const uint8_t *data, + unsigned int data_sz, + vpx_codec_stream_info_t *si) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + if(data + data_sz <= data) + res = VPX_CODEC_INVALID_PARAM; + else + { + /* Parse uncompresssed part of key frame header. + * 3 bytes:- including version, frame type and an offset + * 3 bytes:- sync code (0x9d, 0x01, 0x2a) + * 4 bytes:- including image width and height in the lowest 14 bits + * of each 2-byte value. + */ + si->is_kf = 0; + + if (data_sz >= 10 && !(data[0] & 0x01)) /* I-Frame */ + { + const uint8_t *c = data + 3; + si->is_kf = 1; + + /* vet via sync code */ + if (c[0] != 0x9d || c[1] != 0x01 || c[2] != 0x2a) + res = VPX_CODEC_UNSUP_BITSTREAM; + + si->w = (c[3] | (c[4] << 8)) & 0x3fff; + si->h = (c[5] | (c[6] << 8)) & 0x3fff; + + /*printf("w=%d, h=%d\n", si->w, si->h);*/ + if (!(si->h | si->w)) + res = VPX_CODEC_UNSUP_BITSTREAM; + } + else + res = VPX_CODEC_UNSUP_BITSTREAM; + } + + return res; + +} + +static vpx_codec_err_t vp8_get_si(vpx_codec_alg_priv_t *ctx, + vpx_codec_stream_info_t *si) +{ + + unsigned int sz; + + if (si->sz >= sizeof(vp8_stream_info_t)) + sz = sizeof(vp8_stream_info_t); + else + sz = sizeof(vpx_codec_stream_info_t); + + memcpy(si, &ctx->si, sz); + si->sz = sz; + + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t +update_error_state(vpx_codec_alg_priv_t *ctx, + const struct vpx_internal_error_info *error) +{ + vpx_codec_err_t res; + + if ((res = error->error_code)) + ctx->base.err_detail = error->has_detail + ? error->detail + : NULL; + + return res; +} + +static void yuvconfig2image(vpx_image_t *img, + const YV12_BUFFER_CONFIG *yv12, + void *user_priv) +{ + /** vpx_img_wrap() doesn't allow specifying independent strides for + * the Y, U, and V planes, nor other alignment adjustments that + * might be representable by a YV12_BUFFER_CONFIG, so we just + * initialize all the fields.*/ + img->fmt = yv12->clrtype == REG_YUV ? + VPX_IMG_FMT_I420 : VPX_IMG_FMT_VPXI420; + img->w = yv12->y_stride; + img->h = (yv12->y_height + 2 * VP8BORDERINPIXELS + 15) & ~15; + img->d_w = yv12->y_width; + img->d_h = yv12->y_height; + img->x_chroma_shift = 1; + img->y_chroma_shift = 1; + img->planes[VPX_PLANE_Y] = yv12->y_buffer; + img->planes[VPX_PLANE_U] = yv12->u_buffer; + img->planes[VPX_PLANE_V] = yv12->v_buffer; + img->planes[VPX_PLANE_ALPHA] = NULL; + img->stride[VPX_PLANE_Y] = yv12->y_stride; + img->stride[VPX_PLANE_U] = yv12->uv_stride; + img->stride[VPX_PLANE_V] = yv12->uv_stride; + img->stride[VPX_PLANE_ALPHA] = yv12->y_stride; + img->bps = 12; + img->user_priv = user_priv; + img->img_data = yv12->buffer_alloc; + img->img_data_owner = 0; + img->self_allocd = 0; +} + +static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, + const uint8_t *data, + unsigned int data_sz, + void *user_priv, + long deadline) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + ctx->img_avail = 0; + + /* Determine the stream parameters. Note that we rely on peek_si to + * validate that we have a buffer that does not wrap around the top + * of the heap. + */ + if (!ctx->si.h) + res = ctx->base.iface->dec.peek_si(data, data_sz, &ctx->si); + + + /* Perform deferred allocations, if required */ + if (!res && ctx->defer_alloc) + { + int i; + + for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) + { + vpx_codec_dec_cfg_t cfg; + + cfg.w = ctx->si.w; + cfg.h = ctx->si.h; + ctx->mmaps[i].id = vp8_mem_req_segs[i].id; + ctx->mmaps[i].sz = vp8_mem_req_segs[i].sz; + ctx->mmaps[i].align = vp8_mem_req_segs[i].align; + ctx->mmaps[i].flags = vp8_mem_req_segs[i].flags; + + if (!ctx->mmaps[i].sz) + ctx->mmaps[i].sz = vp8_mem_req_segs[i].calc_sz(&cfg, + ctx->base.init_flags); + + res = vp8_mmap_alloc(&ctx->mmaps[i]); + } + + if (!res) + vp8_finalize_mmaps(ctx); + + ctx->defer_alloc = 0; + } + + /* Initialize the decoder instance on the first frame*/ + if (!res && !ctx->decoder_init) + { + res = vp8_validate_mmaps(&ctx->si, ctx->mmaps, ctx->base.init_flags); + + if (!res) + { + VP8D_CONFIG oxcf; + struct VP8D_COMP* optr; + + oxcf.Width = ctx->si.w; + oxcf.Height = ctx->si.h; + oxcf.Version = 9; + oxcf.postprocess = 0; + oxcf.max_threads = ctx->cfg.threads; + oxcf.error_concealment = + (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT); + oxcf.input_fragments = + (ctx->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS); + + optr = vp8dx_create_decompressor(&oxcf); + + /* If postprocessing was enabled by the application and a + * configuration has not been provided, default it. + */ + if (!ctx->postproc_cfg_set + && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) + { + ctx->postproc_cfg.post_proc_flag = + VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE; + ctx->postproc_cfg.deblocking_level = 4; + ctx->postproc_cfg.noise_level = 0; + } + + if (!optr) + res = VPX_CODEC_ERROR; + else + ctx->pbi = optr; + } + + ctx->decoder_init = 1; + } + + if (!res && ctx->pbi) + { + YV12_BUFFER_CONFIG sd; + int64_t time_stamp = 0, time_end_stamp = 0; + vp8_ppflags_t flags = {0}; + + if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) + { + flags.post_proc_flag= ctx->postproc_cfg.post_proc_flag +#if CONFIG_POSTPROC_VISUALIZER + + | ((ctx->dbg_color_ref_frame_flag != 0) ? VP8D_DEBUG_CLR_FRM_REF_BLKS : 0) + | ((ctx->dbg_color_mb_modes_flag != 0) ? VP8D_DEBUG_CLR_BLK_MODES : 0) + | ((ctx->dbg_color_b_modes_flag != 0) ? VP8D_DEBUG_CLR_BLK_MODES : 0) + | ((ctx->dbg_display_mv_flag != 0) ? VP8D_DEBUG_DRAW_MV : 0) +#endif + ; + flags.deblocking_level = ctx->postproc_cfg.deblocking_level; + flags.noise_level = ctx->postproc_cfg.noise_level; +#if CONFIG_POSTPROC_VISUALIZER + flags.display_ref_frame_flag= ctx->dbg_color_ref_frame_flag; + flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag; + flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag; + flags.display_mv_flag = ctx->dbg_display_mv_flag; +#endif + } + + if (vp8dx_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) + { + VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; + res = update_error_state(ctx, &pbi->common.error); + } + + if (!res && 0 == vp8dx_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, &flags)) + { + yuvconfig2image(&ctx->img, &sd, user_priv); + ctx->img_avail = 1; + } + } + + return res; +} + +static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t *ctx, + vpx_codec_iter_t *iter) +{ + vpx_image_t *img = NULL; + + if (ctx->img_avail) + { + /* iter acts as a flip flop, so an image is only returned on the first + * call to get_frame. + */ + if (!(*iter)) + { + img = &ctx->img; + *iter = img; + } + } + + return img; +} + + +static +vpx_codec_err_t vp8_xma_get_mmap(const vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmap, + vpx_codec_iter_t *iter) +{ + vpx_codec_err_t res; + const mem_req_t *seg_iter = *iter; + + /* Get address of next segment request */ + do + { + if (!seg_iter) + seg_iter = vp8_mem_req_segs; + else if (seg_iter->id != VP8_SEG_MAX) + seg_iter++; + + *iter = (vpx_codec_iter_t)seg_iter; + + if (seg_iter->id != VP8_SEG_MAX) + { + mmap->id = seg_iter->id; + mmap->sz = seg_iter->sz; + mmap->align = seg_iter->align; + mmap->flags = seg_iter->flags; + + if (!seg_iter->sz) + mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags); + + res = VPX_CODEC_OK; + } + else + res = VPX_CODEC_LIST_END; + } + while (!mmap->sz && res != VPX_CODEC_LIST_END); + + return res; +} + +static vpx_codec_err_t vp8_xma_set_mmap(vpx_codec_ctx_t *ctx, + const vpx_codec_mmap_t *mmap) +{ + vpx_codec_err_t res = VPX_CODEC_MEM_ERROR; + int i, done; + + if (!ctx->priv) + { + if (mmap->id == VP8_SEG_ALG_PRIV) + { + if (!ctx->priv) + { + vp8_init_ctx(ctx, mmap); + res = VPX_CODEC_OK; + } + } + } + + done = 1; + + if (!res && ctx->priv->alg_priv) + { + for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) + { + if (ctx->priv->alg_priv->mmaps[i].id == mmap->id) + if (!ctx->priv->alg_priv->mmaps[i].base) + { + ctx->priv->alg_priv->mmaps[i] = *mmap; + res = VPX_CODEC_OK; + } + + done &= (ctx->priv->alg_priv->mmaps[i].base != NULL); + } + } + + if (done && !res) + { + vp8_finalize_mmaps(ctx->priv->alg_priv); + res = ctx->iface->init(ctx, NULL); + } + + return res; +} + +static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, + YV12_BUFFER_CONFIG *yv12) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + yv12->y_buffer = img->planes[VPX_PLANE_Y]; + yv12->u_buffer = img->planes[VPX_PLANE_U]; + yv12->v_buffer = img->planes[VPX_PLANE_V]; + + yv12->y_width = img->d_w; + yv12->y_height = img->d_h; + yv12->uv_width = yv12->y_width / 2; + yv12->uv_height = yv12->y_height / 2; + + yv12->y_stride = img->stride[VPX_PLANE_Y]; + yv12->uv_stride = img->stride[VPX_PLANE_U]; + + yv12->border = (img->stride[VPX_PLANE_Y] - img->d_w) / 2; + yv12->clrtype = (img->fmt == VPX_IMG_FMT_VPXI420 || img->fmt == VPX_IMG_FMT_VPXYV12); + + return res; +} + + +static vpx_codec_err_t vp8_set_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + + return vp8dx_set_reference(ctx->pbi, frame->frame_type, &sd); + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +static vpx_codec_err_t vp8_get_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + + return vp8dx_get_reference(ctx->pbi, frame->frame_type, &sd); + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +static vpx_codec_err_t vp8_set_postproc(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ +#if CONFIG_POSTPROC + vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); + + if (data) + { + ctx->postproc_cfg_set = 1; + ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +#else + return VPX_CODEC_INCAPABLE; +#endif +} + +static vpx_codec_err_t vp8_set_dbg_options(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ +#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC + int data = va_arg(args, int); + +#define MAP(id, var) case id: var = data; break; + + switch (ctrl_id) + { + MAP (VP8_SET_DBG_COLOR_REF_FRAME, ctx->dbg_color_ref_frame_flag); + MAP (VP8_SET_DBG_COLOR_MB_MODES, ctx->dbg_color_mb_modes_flag); + MAP (VP8_SET_DBG_COLOR_B_MODES, ctx->dbg_color_b_modes_flag); + MAP (VP8_SET_DBG_DISPLAY_MV, ctx->dbg_display_mv_flag); + } + + return VPX_CODEC_OK; +#else + return VPX_CODEC_INCAPABLE; +#endif +} + +static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + int *update_info = va_arg(args, int *); + VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; + + if (update_info) + { + *update_info = pbi->common.refresh_alt_ref_frame * (int) VP8_ALTR_FRAME + + pbi->common.refresh_golden_frame * (int) VP8_GOLD_FRAME + + pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME; + + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +} + +extern int vp8dx_references_buffer( VP8_COMMON *oci, int ref_frame ); +static vpx_codec_err_t vp8_get_last_ref_frame(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + int *ref_info = va_arg(args, int *); + VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; + VP8_COMMON *oci = &pbi->common; + + if (ref_info) + { + *ref_info = + (vp8dx_references_buffer( oci, ALTREF_FRAME )?VP8_ALTR_FRAME:0) | + (vp8dx_references_buffer( oci, GOLDEN_FRAME )?VP8_GOLD_FRAME:0) | + (vp8dx_references_buffer( oci, LAST_FRAME )?VP8_LAST_FRAME:0); + + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +} + +static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + + int *corrupted = va_arg(args, int *); + + if (corrupted) + { + VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; + *corrupted = pbi->common.frame_to_show->corrupted; + + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] = +{ + {VP8_SET_REFERENCE, vp8_set_reference}, + {VP8_COPY_REFERENCE, vp8_get_reference}, + {VP8_SET_POSTPROC, vp8_set_postproc}, + {VP8_SET_DBG_COLOR_REF_FRAME, vp8_set_dbg_options}, + {VP8_SET_DBG_COLOR_MB_MODES, vp8_set_dbg_options}, + {VP8_SET_DBG_COLOR_B_MODES, vp8_set_dbg_options}, + {VP8_SET_DBG_DISPLAY_MV, vp8_set_dbg_options}, + {VP8D_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates}, + {VP8D_GET_FRAME_CORRUPTED, vp8_get_frame_corrupted}, + {VP8D_GET_LAST_REF_USED, vp8_get_last_ref_frame}, + { -1, NULL}, +}; + + +#ifndef VERSION_STRING +#define VERSION_STRING +#endif +CODEC_INTERFACE(vpx_codec_vp8_dx) = +{ + "WebM Project VP8 Decoder" VERSION_STRING, + VPX_CODEC_INTERNAL_ABI_VERSION, + VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT | + VPX_CODEC_CAP_INPUT_FRAGMENTS, + /* vpx_codec_caps_t caps; */ + vp8_init, /* vpx_codec_init_fn_t init; */ + vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */ + vp8_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ + vp8_xma_get_mmap, /* vpx_codec_get_mmap_fn_t get_mmap; */ + vp8_xma_set_mmap, /* vpx_codec_set_mmap_fn_t set_mmap; */ + { + vp8_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */ + vp8_get_si, /* vpx_codec_get_si_fn_t get_si; */ + vp8_decode, /* vpx_codec_decode_fn_t decode; */ + vp8_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */ + }, + { /* encoder functions */ + NOT_IMPLEMENTED, + NOT_IMPLEMENTED, + NOT_IMPLEMENTED, + NOT_IMPLEMENTED, + NOT_IMPLEMENTED, + NOT_IMPLEMENTED + } +}; diff --git a/vp8/vp8cx.mk b/vp8/vp8cx.mk new file mode 100644 index 0000000..019edbd --- /dev/null +++ b/vp8/vp8cx.mk @@ -0,0 +1,116 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk + +VP8_CX_EXPORTS += exports_enc + +VP8_CX_SRCS-yes += $(VP8_COMMON_SRCS-yes) +VP8_CX_SRCS-no += $(VP8_COMMON_SRCS-no) +VP8_CX_SRCS_REMOVE-yes += $(VP8_COMMON_SRCS_REMOVE-yes) +VP8_CX_SRCS_REMOVE-no += $(VP8_COMMON_SRCS_REMOVE-no) + +ifeq ($(ARCH_ARM),yes) + include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8cx_arm.mk +endif + +VP8_CX_SRCS-yes += vp8_cx_iface.c + +# encoder +#INCLUDES += algo/vpx_common/vpx_mem/include +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += algo/vpx_ref/cpu_id/include +#INCLUDES += common +#INCLUDES += encoder + +VP8_CX_SRCS-yes += encoder/asm_enc_offsets.c +VP8_CX_SRCS-yes += encoder/defaultcoefcounts.h +VP8_CX_SRCS-yes += encoder/bitstream.c +VP8_CX_SRCS-yes += encoder/boolhuff.c +VP8_CX_SRCS-yes += encoder/dct.c +VP8_CX_SRCS-yes += encoder/encodeframe.c +VP8_CX_SRCS-yes += encoder/encodeframe.h +VP8_CX_SRCS-yes += encoder/encodeintra.c +VP8_CX_SRCS-yes += encoder/encodemb.c +VP8_CX_SRCS-yes += encoder/encodemv.c +VP8_CX_SRCS-$(CONFIG_MULTITHREAD) += encoder/ethreading.c +VP8_CX_SRCS-yes += encoder/firstpass.c +VP8_CX_SRCS-yes += encoder/block.h +VP8_CX_SRCS-yes += encoder/boolhuff.h +VP8_CX_SRCS-yes += encoder/bitstream.h +VP8_CX_SRCS-$(CONFIG_TEMPORAL_DENOISING) += encoder/denoising.h +VP8_CX_SRCS-$(CONFIG_TEMPORAL_DENOISING) += encoder/denoising.c +VP8_CX_SRCS-yes += encoder/encodeintra.h +VP8_CX_SRCS-yes += encoder/encodemb.h +VP8_CX_SRCS-yes += encoder/encodemv.h +VP8_CX_SRCS-yes += encoder/firstpass.h +VP8_CX_SRCS-yes += encoder/lookahead.c +VP8_CX_SRCS-yes += encoder/lookahead.h +VP8_CX_SRCS-yes += encoder/mcomp.h +VP8_CX_SRCS-yes += encoder/modecosts.h +VP8_CX_SRCS-yes += encoder/onyx_int.h +VP8_CX_SRCS-yes += encoder/pickinter.h +VP8_CX_SRCS-yes += encoder/psnr.h +VP8_CX_SRCS-yes += encoder/quantize.h +VP8_CX_SRCS-yes += encoder/ratectrl.h +VP8_CX_SRCS-yes += encoder/rdopt.h +VP8_CX_SRCS-yes += encoder/tokenize.h +VP8_CX_SRCS-yes += encoder/treewriter.h +VP8_CX_SRCS-yes += encoder/mcomp.c +VP8_CX_SRCS-yes += encoder/modecosts.c +VP8_CX_SRCS-yes += encoder/onyx_if.c +VP8_CX_SRCS-yes += encoder/pickinter.c +VP8_CX_SRCS-yes += encoder/picklpf.c +VP8_CX_SRCS-yes += encoder/psnr.c +VP8_CX_SRCS-yes += encoder/quantize.c +VP8_CX_SRCS-yes += encoder/ratectrl.c +VP8_CX_SRCS-yes += encoder/rdopt.c +VP8_CX_SRCS-yes += encoder/segmentation.c +VP8_CX_SRCS-yes += encoder/segmentation.h +VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/ssim.c +VP8_CX_SRCS-yes += encoder/tokenize.c +VP8_CX_SRCS-yes += encoder/dct_value_cost.h +VP8_CX_SRCS-yes += encoder/dct_value_tokens.h +VP8_CX_SRCS-yes += encoder/treewriter.c +VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.h +VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.c +VP8_CX_SRCS-yes += encoder/temporal_filter.c +VP8_CX_SRCS-$(CONFIG_MULTI_RES_ENCODING) += encoder/mr_dissim.c +VP8_CX_SRCS-$(CONFIG_MULTI_RES_ENCODING) += encoder/mr_dissim.h + +ifeq ($(CONFIG_REALTIME_ONLY),yes) +VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c +VP8_CX_SRCS_REMOVE-yes += encoder/temporal_filter.c +endif + +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/dct_mmx.asm +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/subtract_mmx.asm +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/vp8_enc_stubs_mmx.c +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/dct_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/fwalsh_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/quantize_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/subtract_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/temporal_filter_apply_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp8_enc_stubs_sse2.c +VP8_CX_SRCS-$(HAVE_SSSE3) += encoder/x86/quantize_ssse3.asm +VP8_CX_SRCS-$(HAVE_SSE4_1) += encoder/x86/quantize_sse4.asm +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/quantize_mmx.asm +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/encodeopt.asm +VP8_CX_SRCS-$(ARCH_X86_64) += encoder/x86/ssim_opt.asm + +ifeq ($(CONFIG_REALTIME_ONLY),yes) +VP8_CX_SRCS_REMOVE-$(HAVE_SSE2) += encoder/x86/temporal_filter_apply_sse2.asm +endif + + +VP8_CX_SRCS-yes := $(filter-out $(VP8_CX_SRCS_REMOVE-yes),$(VP8_CX_SRCS-yes)) diff --git a/vp8/vp8cx_arm.mk b/vp8/vp8cx_arm.mk new file mode 100644 index 0000000..b16615d --- /dev/null +++ b/vp8/vp8cx_arm.mk @@ -0,0 +1,44 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +#VP8_CX_SRCS list is modified according to different platforms. + +#File list for arm +# encoder +VP8_CX_SRCS-$(ARCH_ARM) += encoder/arm/dct_arm.c +VP8_CX_SRCS-$(ARCH_ARM) += encoder/arm/quantize_arm.c + +#File list for edsp +# encoder +VP8_CX_SRCS-$(HAVE_EDSP) += encoder/arm/boolhuff_arm.c +VP8_CX_SRCS_REMOVE-$(HAVE_EDSP) += encoder/boolhuff.c +VP8_CX_SRCS-$(HAVE_EDSP) += encoder/arm/armv5te/boolhuff_armv5te$(ASM) +VP8_CX_SRCS-$(HAVE_EDSP) += encoder/arm/armv5te/vp8_packtokens_armv5$(ASM) +VP8_CX_SRCS-$(HAVE_EDSP) += encoder/arm/armv5te/vp8_packtokens_mbrow_armv5$(ASM) +VP8_CX_SRCS-$(HAVE_EDSP) += encoder/arm/armv5te/vp8_packtokens_partitions_armv5$(ASM) + +#File list for media +# encoder +VP8_CX_SRCS-$(HAVE_MEDIA) += encoder/arm/armv6/vp8_subtract_armv6$(ASM) +VP8_CX_SRCS-$(HAVE_MEDIA) += encoder/arm/armv6/vp8_short_fdct4x4_armv6$(ASM) +VP8_CX_SRCS-$(HAVE_MEDIA) += encoder/arm/armv6/vp8_fast_quantize_b_armv6$(ASM) +VP8_CX_SRCS-$(HAVE_MEDIA) += encoder/arm/armv6/vp8_mse16x16_armv6$(ASM) +VP8_CX_SRCS-$(HAVE_MEDIA) += encoder/arm/armv6/walsh_v6$(ASM) + +#File list for neon +# encoder +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/fastquantizeb_neon$(ASM) +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/picklpf_arm.c +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/shortfdct_neon$(ASM) +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/subtract_neon$(ASM) +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/vp8_mse16x16_neon$(ASM) +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/vp8_memcpy_neon$(ASM) +VP8_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/vp8_shortwalsh4x4_neon$(ASM) diff --git a/vp8/vp8dx.mk b/vp8/vp8dx.mk new file mode 100644 index 0000000..2cfd280 --- /dev/null +++ b/vp8/vp8dx.mk @@ -0,0 +1,64 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk + +VP8_DX_EXPORTS += exports_dec + +VP8_DX_SRCS-yes += $(VP8_COMMON_SRCS-yes) +VP8_DX_SRCS-no += $(VP8_COMMON_SRCS-no) +VP8_DX_SRCS_REMOVE-yes += $(VP8_COMMON_SRCS_REMOVE-yes) +VP8_DX_SRCS_REMOVE-no += $(VP8_COMMON_SRCS_REMOVE-no) + +VP8_DX_SRCS-yes += vp8_dx_iface.c + +# common +#define ARM +#define DISABLE_THREAD + +#INCLUDES += algo/vpx_common/vpx_mem/include +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += decoder + + + +# decoder +#define ARM +#define DISABLE_THREAD + +#INCLUDES += algo/vpx_common/vpx_mem/include +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += decoder + +VP8_DX_SRCS-yes += decoder/asm_dec_offsets.c +VP8_DX_SRCS-yes += decoder/dboolhuff.c +VP8_DX_SRCS-yes += decoder/decodemv.c +VP8_DX_SRCS-yes += decoder/decodframe.c +VP8_DX_SRCS-yes += decoder/detokenize.c +VP8_DX_SRCS-$(CONFIG_ERROR_CONCEALMENT) += decoder/ec_types.h +VP8_DX_SRCS-$(CONFIG_ERROR_CONCEALMENT) += decoder/error_concealment.h +VP8_DX_SRCS-$(CONFIG_ERROR_CONCEALMENT) += decoder/error_concealment.c +VP8_DX_SRCS-yes += decoder/dboolhuff.h +VP8_DX_SRCS-yes += decoder/decodemv.h +VP8_DX_SRCS-yes += decoder/decoderthreading.h +VP8_DX_SRCS-yes += decoder/detokenize.h +VP8_DX_SRCS-yes += decoder/onyxd_int.h +VP8_DX_SRCS-yes += decoder/treereader.h +VP8_DX_SRCS-yes += decoder/onyxd_if.c +VP8_DX_SRCS-$(CONFIG_MULTITHREAD) += decoder/threading.c + +VP8_DX_SRCS-yes := $(filter-out $(VP8_DX_SRCS_REMOVE-yes),$(VP8_DX_SRCS-yes)) diff --git a/vp8_multi_resolution_encoder.c b/vp8_multi_resolution_encoder.c new file mode 100644 index 0000000..78f50c2 --- /dev/null +++ b/vp8_multi_resolution_encoder.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * This is an example demonstrating multi-resolution encoding in VP8. + * High-resolution input video is down-sampled to lower-resolutions. The + * encoder then encodes the video and outputs multiple bitstreams with + * different resolutions. + */ +#include +#include +#include +#include +#include "math.h" +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx/vpx_encoder.h" +#include "vpx/vp8cx.h" +#include "vpx_ports/mem_ops.h" +#define interface (vpx_codec_vp8_cx()) +#define fourcc 0x30385056 + +#define IVF_FILE_HDR_SZ (32) +#define IVF_FRAME_HDR_SZ (12) + +/* + * The input video frame is downsampled several times to generate a multi-level + * hierarchical structure. NUM_ENCODERS is defined as the number of encoding + * levels required. For example, if the size of input video is 1280x720, + * NUM_ENCODERS is 3, and down-sampling factor is 2, the encoder outputs 3 + * bitstreams with resolution of 1280x720(level 0), 640x360(level 1), and + * 320x180(level 2) respectively. + */ +#define NUM_ENCODERS 3 + +/* This example uses the scaler function in libyuv. */ +#include "third_party/libyuv/include/libyuv/basic_types.h" +#include "third_party/libyuv/include/libyuv/scale.h" +#include "third_party/libyuv/include/libyuv/cpu_id.h" + +static double vp8_mse2psnr(double Samples, double Peak, double Mse) +{ + double psnr; + + if ((double)Mse > 0.0) + psnr = 10.0 * log10(Peak * Peak * Samples / Mse); + else + psnr = 60; // Limit to prevent / 0 + + if (psnr > 60) + psnr = 60; + + return psnr; +} + +static void die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + if(fmt[strlen(fmt)-1] != '\n') + printf("\n"); + exit(EXIT_FAILURE); +} + +static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { + const char *detail = vpx_codec_error_detail(ctx); + + printf("%s: %s\n", s, vpx_codec_error(ctx)); + if(detail) + printf(" %s\n",detail); + exit(EXIT_FAILURE); +} + +int (*read_frame_p)(FILE *f, vpx_image_t *img); + +static int read_frame(FILE *f, vpx_image_t *img) { + size_t nbytes, to_read; + int res = 1; + + to_read = img->w*img->h*3/2; + nbytes = fread(img->planes[0], 1, to_read, f); + if(nbytes != to_read) { + res = 0; + if(nbytes > 0) + printf("Warning: Read partial frame. Check your width & height!\n"); + } + return res; +} + +static int read_frame_by_row(FILE *f, vpx_image_t *img) { + size_t nbytes, to_read; + int res = 1; + int plane; + + for (plane = 0; plane < 3; plane++) + { + unsigned char *ptr; + int w = (plane ? (1 + img->d_w) / 2 : img->d_w); + int h = (plane ? (1 + img->d_h) / 2 : img->d_h); + int r; + + /* Determine the correct plane based on the image format. The for-loop + * always counts in Y,U,V order, but this may not match the order of + * the data on disk. + */ + switch (plane) + { + case 1: + ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U]; + break; + case 2: + ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V]; + break; + default: + ptr = img->planes[plane]; + } + + for (r = 0; r < h; r++) + { + to_read = w; + + nbytes = fread(ptr, 1, to_read, f); + if(nbytes != to_read) { + res = 0; + if(nbytes > 0) + printf("Warning: Read partial frame. Check your width & height!\n"); + break; + } + + ptr += img->stride[plane]; + } + if (!res) + break; + } + + return res; +} + +static void write_ivf_file_header(FILE *outfile, + const vpx_codec_enc_cfg_t *cfg, + int frame_cnt) { + char header[32]; + + if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) + return; + header[0] = 'D'; + header[1] = 'K'; + header[2] = 'I'; + header[3] = 'F'; + mem_put_le16(header+4, 0); /* version */ + mem_put_le16(header+6, 32); /* headersize */ + mem_put_le32(header+8, fourcc); /* headersize */ + mem_put_le16(header+12, cfg->g_w); /* width */ + mem_put_le16(header+14, cfg->g_h); /* height */ + mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ + mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ + mem_put_le32(header+24, frame_cnt); /* length */ + mem_put_le32(header+28, 0); /* unused */ + + if(fwrite(header, 1, 32, outfile)); +} + +static void write_ivf_frame_header(FILE *outfile, + const vpx_codec_cx_pkt_t *pkt) +{ + char header[12]; + vpx_codec_pts_t pts; + + if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) + return; + + pts = pkt->data.frame.pts; + mem_put_le32(header, pkt->data.frame.sz); + mem_put_le32(header+4, pts&0xFFFFFFFF); + mem_put_le32(header+8, pts >> 32); + + if(fwrite(header, 1, 12, outfile)); +} + +int main(int argc, char **argv) +{ + FILE *infile, *outfile[NUM_ENCODERS]; + vpx_codec_ctx_t codec[NUM_ENCODERS]; + vpx_codec_enc_cfg_t cfg[NUM_ENCODERS]; + vpx_codec_pts_t frame_cnt = 0; + vpx_image_t raw[NUM_ENCODERS]; + vpx_codec_err_t res[NUM_ENCODERS]; + + int i; + long width; + long height; + int frame_avail; + int got_data; + int flags = 0; + + /*Currently, only realtime mode is supported in multi-resolution encoding.*/ + int arg_deadline = VPX_DL_REALTIME; + + /* Set show_psnr to 1/0 to show/not show PSNR. Choose show_psnr=0 if you + don't need to know PSNR, which will skip PSNR calculation and save + encoding time. */ + int show_psnr = 0; + uint64_t psnr_sse_total[NUM_ENCODERS] = {0}; + uint64_t psnr_samples_total[NUM_ENCODERS] = {0}; + double psnr_totals[NUM_ENCODERS][4] = {{0,0}}; + int psnr_count[NUM_ENCODERS] = {0}; + + /* Set the required target bitrates for each resolution level. + * If target bitrate for highest-resolution level is set to 0, + * (i.e. target_bitrate[0]=0), we skip encoding at that level. + */ + unsigned int target_bitrate[NUM_ENCODERS]={1400, 500, 100}; + /* Enter the frame rate of the input video */ + int framerate = 30; + /* Set down-sampling factor for each resolution level. + dsf[0] controls down sampling from level 0 to level 1; + dsf[1] controls down sampling from level 1 to level 2; + dsf[2] is not used. */ + vpx_rational_t dsf[NUM_ENCODERS] = {{2, 1}, {2, 1}, {1, 1}}; + + if(argc!= (5+NUM_ENCODERS)) + die("Usage: %s \n", + argv[0]); + + printf("Using %s\n",vpx_codec_iface_name(interface)); + + width = strtol(argv[1], NULL, 0); + height = strtol(argv[2], NULL, 0); + + if(width < 16 || width%2 || height <16 || height%2) + die("Invalid resolution: %ldx%ld", width, height); + + /* Open input video file for encoding */ + if(!(infile = fopen(argv[3], "rb"))) + die("Failed to open %s for reading", argv[3]); + + /* Open output file for each encoder to output bitstreams */ + for (i=0; i< NUM_ENCODERS; i++) + { + if(!target_bitrate[i]) + { + outfile[i] = NULL; + continue; + } + + if(!(outfile[i] = fopen(argv[i+4], "wb"))) + die("Failed to open %s for writing", argv[i+4]); + } + + show_psnr = strtol(argv[NUM_ENCODERS + 4], NULL, 0); + + /* Populate default encoder configuration */ + for (i=0; i< NUM_ENCODERS; i++) + { + res[i] = vpx_codec_enc_config_default(interface, &cfg[i], 0); + if(res[i]) { + printf("Failed to get config: %s\n", vpx_codec_err_to_string(res[i])); + return EXIT_FAILURE; + } + } + + /* + * Update the default configuration according to needs of the application. + */ + /* Highest-resolution encoder settings */ + cfg[0].g_w = width; + cfg[0].g_h = height; + cfg[0].g_threads = 1; /* number of threads used */ + cfg[0].rc_dropframe_thresh = 0; + cfg[0].rc_end_usage = VPX_CBR; + cfg[0].rc_resize_allowed = 0; + cfg[0].rc_min_quantizer = 4; + cfg[0].rc_max_quantizer = 56; + cfg[0].rc_undershoot_pct = 98; + cfg[0].rc_overshoot_pct = 100; + cfg[0].rc_buf_initial_sz = 500; + cfg[0].rc_buf_optimal_sz = 600; + cfg[0].rc_buf_sz = 1000; + //cfg[0].rc_dropframe_thresh = 10; + cfg[0].g_error_resilient = 1; /* Enable error resilient mode */ + cfg[0].g_lag_in_frames = 0; + + /* Disable automatic keyframe placement */ + //cfg[0].kf_mode = VPX_KF_DISABLED; + cfg[0].kf_min_dist = cfg[0].kf_max_dist = 1000; + + cfg[0].rc_target_bitrate = target_bitrate[0]; /* Set target bitrate */ + cfg[0].g_timebase.num = 1; /* Set fps */ + cfg[0].g_timebase.den = framerate; + + /* Other-resolution encoder settings */ + for (i=1; i< NUM_ENCODERS; i++) + { + memcpy(&cfg[i], &cfg[0], sizeof(vpx_codec_enc_cfg_t)); + + cfg[i].g_threads = 1; /* number of threads used */ + cfg[i].rc_target_bitrate = target_bitrate[i]; + + /* Note: Width & height of other-resolution encoders are calculated + * from the highest-resolution encoder's size and the corresponding + * down_sampling_factor. + */ + { + unsigned int iw = cfg[i-1].g_w*dsf[i-1].den + dsf[i-1].num - 1; + unsigned int ih = cfg[i-1].g_h*dsf[i-1].den + dsf[i-1].num - 1; + cfg[i].g_w = iw/dsf[i-1].num; + cfg[i].g_h = ih/dsf[i-1].num; + } + + /* Make width & height to be multiplier of 2. */ + // Should support odd size ??? + if((cfg[i].g_w)%2)cfg[i].g_w++; + if((cfg[i].g_h)%2)cfg[i].g_h++; + } + + /* Allocate image for each encoder */ + for (i=0; i< NUM_ENCODERS; i++) + if(!vpx_img_alloc(&raw[i], VPX_IMG_FMT_I420, cfg[i].g_w, cfg[i].g_h, 32)) + die("Failed to allocate image", cfg[i].g_w, cfg[i].g_h); + + if (raw[0].stride[VPX_PLANE_Y] == raw[0].d_w) + read_frame_p = read_frame; + else + read_frame_p = read_frame_by_row; + + for (i=0; i< NUM_ENCODERS; i++) + if(outfile[i]) + write_ivf_file_header(outfile[i], &cfg[i], 0); + + /* Initialize multi-encoder */ + if(vpx_codec_enc_init_multi(&codec[0], interface, &cfg[0], NUM_ENCODERS, + (show_psnr ? VPX_CODEC_USE_PSNR : 0), &dsf[0])) + die_codec(&codec[0], "Failed to initialize encoder"); + + /* The extra encoding configuration parameters can be set as follows. */ + /* Set encoding speed */ + for ( i=0; i=0 ; i--) + { + got_data = 0; + + while( (pkt[i] = vpx_codec_get_cx_data(&codec[i], &iter[i])) ) + { + got_data = 1; + switch(pkt[i]->kind) { + case VPX_CODEC_CX_FRAME_PKT: + write_ivf_frame_header(outfile[i], pkt[i]); + if(fwrite(pkt[i]->data.frame.buf, 1, pkt[i]->data.frame.sz, + outfile[i])); + break; + case VPX_CODEC_PSNR_PKT: + if (show_psnr) + { + int j; + + psnr_sse_total[i] += pkt[i]->data.psnr.sse[0]; + psnr_samples_total[i] += pkt[i]->data.psnr.samples[0]; + for (j = 0; j < 4; j++) + { + //fprintf(stderr, "%.3lf ", pkt[i]->data.psnr.psnr[j]); + psnr_totals[i][j] += pkt[i]->data.psnr.psnr[j]; + } + psnr_count[i]++; + } + + break; + default: + break; + } + printf(pkt[i]->kind == VPX_CODEC_CX_FRAME_PKT + && (pkt[i]->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); + fflush(stdout); + } + } + frame_cnt++; + } + printf("\n"); + + fclose(infile); + + printf("Processed %ld frames.\n",(long int)frame_cnt-1); + for (i=0; i< NUM_ENCODERS; i++) + { + /* Calculate PSNR and print it out */ + if ( (show_psnr) && (psnr_count[i]>0) ) + { + int j; + double ovpsnr = vp8_mse2psnr(psnr_samples_total[i], 255.0, + psnr_sse_total[i]); + + fprintf(stderr, "\n ENC%d PSNR (Overall/Avg/Y/U/V)", i); + + fprintf(stderr, " %.3lf", ovpsnr); + for (j = 0; j < 4; j++) + { + fprintf(stderr, " %.3lf", psnr_totals[i][j]/psnr_count[i]); + } + } + + if(vpx_codec_destroy(&codec[i])) + die_codec(&codec[i], "Failed to destroy codec"); + + vpx_img_free(&raw[i]); + + if(!outfile[i]) + continue; + + /* Try to rewrite the file header with the actual frame count */ + if(!fseek(outfile[i], 0, SEEK_SET)) + write_ivf_file_header(outfile[i], &cfg[i], frame_cnt-1); + fclose(outfile[i]); + } + printf("\n"); + + return EXIT_SUCCESS; +} diff --git a/vp8_scalable_patterns.c b/vp8_scalable_patterns.c new file mode 100644 index 0000000..4311b1a --- /dev/null +++ b/vp8_scalable_patterns.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This is an example demonstrating how to implement a multi-layer VP8 + * encoding scheme based on temporal scalability for video applications + * that benefit from a scalable bitstream. + */ +#include +#include +#include +#include +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx/vpx_encoder.h" +#include "vpx/vp8cx.h" +#define interface (vpx_codec_vp8_cx()) +#define fourcc 0x30385056 + +#define IVF_FILE_HDR_SZ (32) +#define IVF_FRAME_HDR_SZ (12) + +static void mem_put_le16(char *mem, unsigned int val) { + mem[0] = val; + mem[1] = val>>8; +} + +static void mem_put_le32(char *mem, unsigned int val) { + mem[0] = val; + mem[1] = val>>8; + mem[2] = val>>16; + mem[3] = val>>24; +} + +static void die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + if(fmt[strlen(fmt)-1] != '\n') + printf("\n"); + exit(EXIT_FAILURE); +} + +static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { + const char *detail = vpx_codec_error_detail(ctx); + + printf("%s: %s\n", s, vpx_codec_error(ctx)); + if(detail) + printf(" %s\n",detail); + exit(EXIT_FAILURE); +} + +static int read_frame(FILE *f, vpx_image_t *img) { + size_t nbytes, to_read; + int res = 1; + + to_read = img->w*img->h*3/2; + nbytes = fread(img->planes[0], 1, to_read, f); + if(nbytes != to_read) { + res = 0; + if(nbytes > 0) + printf("Warning: Read partial frame. Check your width & height!\n"); + } + return res; +} + +static void write_ivf_file_header(FILE *outfile, + const vpx_codec_enc_cfg_t *cfg, + int frame_cnt) { + char header[32]; + + if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) + return; + header[0] = 'D'; + header[1] = 'K'; + header[2] = 'I'; + header[3] = 'F'; + mem_put_le16(header+4, 0); /* version */ + mem_put_le16(header+6, 32); /* headersize */ + mem_put_le32(header+8, fourcc); /* headersize */ + mem_put_le16(header+12, cfg->g_w); /* width */ + mem_put_le16(header+14, cfg->g_h); /* height */ + mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ + mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ + mem_put_le32(header+24, frame_cnt); /* length */ + mem_put_le32(header+28, 0); /* unused */ + + if(fwrite(header, 1, 32, outfile)); +} + + +static void write_ivf_frame_header(FILE *outfile, + const vpx_codec_cx_pkt_t *pkt) +{ + char header[12]; + vpx_codec_pts_t pts; + + if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) + return; + + pts = pkt->data.frame.pts; + mem_put_le32(header, pkt->data.frame.sz); + mem_put_le32(header+4, pts&0xFFFFFFFF); + mem_put_le32(header+8, pts >> 32); + + if(fwrite(header, 1, 12, outfile)); +} + +static int mode_to_num_layers[9] = {2, 2, 3, 3, 3, 3, 5, 2, 3}; + +int main(int argc, char **argv) { + FILE *infile, *outfile[VPX_TS_MAX_LAYERS]; + vpx_codec_ctx_t codec; + vpx_codec_enc_cfg_t cfg; + int frame_cnt = 0; + vpx_image_t raw; + vpx_codec_err_t res; + unsigned int width; + unsigned int height; + int frame_avail; + int got_data; + int flags = 0; + int i; + int pts = 0; // PTS starts at 0 + int frame_duration = 1; // 1 timebase tick per frame + + int layering_mode = 0; + int frames_in_layer[VPX_TS_MAX_LAYERS] = {0}; + int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; + int flag_periodicity; + int max_intra_size_pct; + + // Check usage and arguments + if (argc < 9) + die("Usage: %s " + " ... \n", argv[0]); + + width = strtol (argv[3], NULL, 0); + height = strtol (argv[4], NULL, 0); + if (width < 16 || width%2 || height <16 || height%2) + die ("Invalid resolution: %d x %d", width, height); + + if (!sscanf(argv[7], "%d", &layering_mode)) + die ("Invalid mode %s", argv[7]); + if (layering_mode<0 || layering_mode>8) + die ("Invalid mode (0..8) %s", argv[7]); + + if (argc != 8+mode_to_num_layers[layering_mode]) + die ("Invalid number of arguments"); + + if (!vpx_img_alloc (&raw, VPX_IMG_FMT_I420, width, height, 1)) + die ("Failed to allocate image", width, height); + + printf("Using %s\n",vpx_codec_iface_name(interface)); + + // Populate encoder configuration + res = vpx_codec_enc_config_default(interface, &cfg, 0); + if(res) { + printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); + return EXIT_FAILURE; + } + + // Update the default configuration with our settings + cfg.g_w = width; + cfg.g_h = height; + + // Timebase format e.g. 30fps: numerator=1, demoninator=30 + if (!sscanf (argv[5], "%d", &cfg.g_timebase.num )) + die ("Invalid timebase numerator %s", argv[5]); + if (!sscanf (argv[6], "%d", &cfg.g_timebase.den )) + die ("Invalid timebase denominator %s", argv[6]); + + for (i=8; i<8+mode_to_num_layers[layering_mode]; i++) + if (!sscanf(argv[i], "%d", &cfg.ts_target_bitrate[i-8])) + die ("Invalid data rate %s", argv[i]); + + // Real time parameters + cfg.rc_dropframe_thresh = 0; // 30 + cfg.rc_end_usage = VPX_CBR; + cfg.rc_resize_allowed = 0; + cfg.rc_min_quantizer = 8; + cfg.rc_max_quantizer = 56; + cfg.rc_undershoot_pct = 100; + cfg.rc_overshoot_pct = 15; + cfg.rc_buf_initial_sz = 500; + cfg.rc_buf_optimal_sz = 600; + cfg.rc_buf_sz = 1000; + + // Enable error resilient mode + cfg.g_error_resilient = 1; + cfg.g_lag_in_frames = 0; + cfg.kf_mode = VPX_KF_DISABLED; + + // Disable automatic keyframe placement + cfg.kf_min_dist = cfg.kf_max_dist = 1000; + + // Temporal scaling parameters: + // NOTE: The 3 prediction frames cannot be used interchangeably due to + // differences in the way they are handled throughout the code. The + // frames should be allocated to layers in the order LAST, GF, ARF. + // Other combinations work, but may produce slightly inferior results. + switch (layering_mode) + { + + case 0: + { + // 2-layers, 2-frame period + int ids[2] = {0,1}; + cfg.ts_number_layers = 2; + cfg.ts_periodicity = 2; + cfg.ts_rate_decimator[0] = 2; + cfg.ts_rate_decimator[1] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; +#if 1 + // 0=L, 1=GF, Intra-layer prediction enabled + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; + layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_REF_ARF; +#else + // 0=L, 1=GF, Intra-layer prediction disabled + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; + layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST; +#endif + break; + } + + case 1: + { + // 2-layers, 3-frame period + int ids[3] = {0,1,1}; + cfg.ts_number_layers = 2; + cfg.ts_periodicity = 3; + cfg.ts_rate_decimator[0] = 3; + cfg.ts_rate_decimator[1] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; + + // 0=L, 1=GF, Intra-layer prediction enabled + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[1] = + layer_flags[2] = VP8_EFLAG_NO_REF_GF | + VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_UPD_LAST; + break; + } + + case 2: + { + // 3-layers, 6-frame period + int ids[6] = {0,2,2,1,2,2}; + cfg.ts_number_layers = 3; + cfg.ts_periodicity = 6; + cfg.ts_rate_decimator[0] = 6; + cfg.ts_rate_decimator[1] = 3; + cfg.ts_rate_decimator[2] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; + + // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_UPD_LAST; + layer_flags[1] = + layer_flags[2] = + layer_flags[4] = + layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; + break; + } + + case 3: + { + // 3-layers, 4-frame period + int ids[4] = {0,2,1,2}; + cfg.ts_number_layers = 3; + cfg.ts_periodicity = 4; + cfg.ts_rate_decimator[0] = 4; + cfg.ts_rate_decimator[1] = 2; + cfg.ts_rate_decimator[2] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; + + // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_UPD_LAST; + layer_flags[1] = + layer_flags[3] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF; + break; + } + + case 4: + { + // 3-layers, 4-frame period + int ids[4] = {0,2,1,2}; + cfg.ts_number_layers = 3; + cfg.ts_periodicity = 4; + cfg.ts_rate_decimator[0] = 4; + cfg.ts_rate_decimator[1] = 2; + cfg.ts_rate_decimator[2] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; + + // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, + // disabled in layer 2 + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[2] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; + layer_flags[1] = + layer_flags[3] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF; + break; + } + + case 5: + { + // 3-layers, 4-frame period + int ids[4] = {0,2,1,2}; + cfg.ts_number_layers = 3; + cfg.ts_periodicity = 4; + cfg.ts_rate_decimator[0] = 4; + cfg.ts_rate_decimator[1] = 2; + cfg.ts_rate_decimator[2] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; + + // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[2] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; + layer_flags[1] = + layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; + break; + } + + case 6: + { + // NOTE: Probably of academic interest only + + // 5-layers, 16-frame period + int ids[16] = {0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4}; + cfg.ts_number_layers = 5; + cfg.ts_periodicity = 16; + cfg.ts_rate_decimator[0] = 16; + cfg.ts_rate_decimator[1] = 8; + cfg.ts_rate_decimator[2] = 4; + cfg.ts_rate_decimator[3] = 2; + cfg.ts_rate_decimator[4] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = cfg.ts_periodicity; + + layer_flags[0] = VPX_EFLAG_FORCE_KF; + layer_flags[1] = + layer_flags[3] = + layer_flags[5] = + layer_flags[7] = + layer_flags[9] = + layer_flags[11] = + layer_flags[13] = + layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF; + layer_flags[2] = + layer_flags[6] = + layer_flags[10] = + layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF; + layer_flags[4] = + layer_flags[12] = VP8_EFLAG_NO_REF_LAST | + VP8_EFLAG_NO_UPD_ARF; + layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF; + break; + } + + case 7: + { + // 2-layers + int ids[2] = {0,1}; + cfg.ts_number_layers = 2; + cfg.ts_periodicity = 2; + cfg.ts_rate_decimator[0] = 2; + cfg.ts_rate_decimator[1] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = 8; + + // 0=L, 1=GF + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; + layer_flags[2] = + layer_flags[4] = + layer_flags[6] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[3] = + layer_flags[5] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; + layer_flags[7] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_UPD_ENTROPY; + break; + } + + case 8: + default: + { + // 3-layers + int ids[4] = {0,2,1,2}; + cfg.ts_number_layers = 3; + cfg.ts_periodicity = 4; + cfg.ts_rate_decimator[0] = 4; + cfg.ts_rate_decimator[1] = 2; + cfg.ts_rate_decimator[2] = 1; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + flag_periodicity = 8; + + // 0=L, 1=GF, 2=ARF + layer_flags[0] = VPX_EFLAG_FORCE_KF | + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; + layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; + layer_flags[3] = + layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; + layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; + layer_flags[6] = VP8_EFLAG_NO_REF_ARF | + VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; + layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_UPD_ENTROPY; + break; + } + } + + // Open input file + if(!(infile = fopen(argv[1], "rb"))) + die("Failed to open %s for reading", argv[1]); + + // Open an output file for each stream + for (i=0; i(_tokenPartitions)); + + frame_avail = 1; + while (frame_avail || got_data) { + vpx_codec_iter_t iter = NULL; + const vpx_codec_cx_pkt_t *pkt; + + flags = layer_flags[frame_cnt % flag_periodicity]; + + frame_avail = read_frame(infile, &raw); + if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, + 1, flags, VPX_DL_REALTIME)) + die_codec(&codec, "Failed to encode frame"); + + // Reset KF flag + if (layering_mode != 6) + layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; + + got_data = 0; + while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { + got_data = 1; + switch (pkt->kind) { + case VPX_CODEC_CX_FRAME_PKT: + for (i=cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; + idata.frame.buf, 1, pkt->data.frame.sz, + outfile[i])); + frames_in_layer[i]++; + } + break; + default: + break; + } + printf (pkt->kind == VPX_CODEC_CX_FRAME_PKT + && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); + fflush (stdout); + } + frame_cnt++; + pts += frame_duration; + } + printf ("\n"); + fclose (infile); + + printf ("Processed %d frames.\n",frame_cnt-1); + if (vpx_codec_destroy(&codec)) + die_codec (&codec, "Failed to destroy codec"); + + // Try to rewrite the output file headers with the actual frame count + for (i=0; i + * my_codec.c: + * vpx_codec_iface_t my_codec = { + * "My Codec v1.0", + * VPX_CODEC_ALG_ABI_VERSION, + * ... + * }; + * + * + * An application instantiates a specific decoder instance by using + * vpx_codec_init() and a pointer to the algorithm's interface structure: + *
        + *     my_app.c:
        + *       extern vpx_codec_iface_t my_codec;
        + *       {
        + *           vpx_codec_ctx_t algo;
        + *           res = vpx_codec_init(&algo, &my_codec);
        + *       }
        + *     
        + * + * Once initialized, the instance is manged using other functions from + * the vpx_codec_* family. + */ +#ifndef VPX_CODEC_INTERNAL_H +#define VPX_CODEC_INTERNAL_H +#include "../vpx_decoder.h" +#include "../vpx_encoder.h" +#include + + +/*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_CODEC_INTERNAL_ABI_VERSION (4) /**<\hideinitializer*/ + +typedef struct vpx_codec_alg_priv vpx_codec_alg_priv_t; +typedef struct vpx_codec_priv_enc_mr_cfg vpx_codec_priv_enc_mr_cfg_t; + +/*!\brief init function pointer prototype + * + * Performs algorithm-specific initialization of the decoder context. This + * function is called by the generic vpx_codec_init() wrapper function, so + * plugins implementing this interface may trust the input parameters to be + * properly initialized. + * + * \param[in] ctx Pointer to this instance's context + * \retval #VPX_CODEC_OK + * The input stream was recognized and decoder initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory operation failed. + */ +typedef vpx_codec_err_t (*vpx_codec_init_fn_t)(vpx_codec_ctx_t *ctx, + vpx_codec_priv_enc_mr_cfg_t *data); + +/*!\brief destroy function pointer prototype + * + * Performs algorithm-specific destruction of the decoder context. This + * function is called by the generic vpx_codec_destroy() wrapper function, + * so plugins implementing this interface may trust the input parameters + * to be properly initialized. + * + * \param[in] ctx Pointer to this instance's context + * \retval #VPX_CODEC_OK + * The input stream was recognized and decoder initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory operation failed. + */ +typedef vpx_codec_err_t (*vpx_codec_destroy_fn_t)(vpx_codec_alg_priv_t *ctx); + +/*!\brief parse stream info function pointer prototype + * + * Performs high level parsing of the bitstream. This function is called by + * the generic vpx_codec_parse_stream() wrapper function, so plugins implementing + * this interface may trust the input parameters to be properly initialized. + * + * \param[in] data Pointer to a block of data to parse + * \param[in] data_sz Size of the data buffer + * \param[in,out] si Pointer to stream info to update. The size member + * \ref MUST be properly initialized, but \ref MAY be + * clobbered by the algorithm. This parameter \ref MAY + * be NULL. + * + * \retval #VPX_CODEC_OK + * Bitstream is parsable and stream information updated + */ +typedef vpx_codec_err_t (*vpx_codec_peek_si_fn_t)(const uint8_t *data, + unsigned int data_sz, + vpx_codec_stream_info_t *si); + +/*!\brief Return information about the current stream. + * + * Returns information about the stream that has been parsed during decoding. + * + * \param[in] ctx Pointer to this instance's context + * \param[in,out] si Pointer to stream info to update. The size member + * \ref MUST be properly initialized, but \ref MAY be + * clobbered by the algorithm. This parameter \ref MAY + * be NULL. + * + * \retval #VPX_CODEC_OK + * Bitstream is parsable and stream information updated + */ +typedef vpx_codec_err_t (*vpx_codec_get_si_fn_t)(vpx_codec_alg_priv_t *ctx, + vpx_codec_stream_info_t *si); + +/*!\brief control function pointer prototype + * + * This function is used to exchange algorithm specific data with the decoder + * instance. This can be used to implement features specific to a particular + * algorithm. + * + * This function is called by the generic vpx_codec_control() wrapper + * function, so plugins implementing this interface may trust the input + * parameters to be properly initialized. However, this interface does not + * provide type safety for the exchanged data or assign meanings to the + * control codes. Those details should be specified in the algorithm's + * header file. In particular, the ctrl_id parameter is guaranteed to exist + * in the algorithm's control mapping table, and the data parameter may be NULL. + * + * + * \param[in] ctx Pointer to this instance's context + * \param[in] ctrl_id Algorithm specific control identifier + * \param[in,out] data Data to exchange with algorithm instance. + * + * \retval #VPX_CODEC_OK + * The internal state data was deserialized. + */ +typedef vpx_codec_err_t (*vpx_codec_control_fn_t)(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list ap); + +/*!\brief control function pointer mapping + * + * This structure stores the mapping between control identifiers and + * implementing functions. Each algorithm provides a list of these + * mappings. This list is searched by the vpx_codec_control() wrapper + * function to determine which function to invoke. The special + * value {0, NULL} is used to indicate end-of-list, and must be + * present. The special value {0, } can be used as a catch-all + * mapping. This implies that ctrl_id values chosen by the algorithm + * \ref MUST be non-zero. + */ +typedef const struct +{ + int ctrl_id; + vpx_codec_control_fn_t fn; +} vpx_codec_ctrl_fn_map_t; + +/*!\brief decode data function pointer prototype + * + * Processes a buffer of coded data. If the processing results in a new + * decoded frame becoming available, #VPX_CODEC_CB_PUT_SLICE and + * #VPX_CODEC_CB_PUT_FRAME events are generated as appropriate. This + * function is called by the generic vpx_codec_decode() wrapper function, + * so plugins implementing this interface may trust the input parameters + * to be properly initialized. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] data Pointer to this block of new coded data. If + * NULL, a #VPX_CODEC_CB_PUT_FRAME event is posted + * for the previously decoded frame. + * \param[in] data_sz Size of the coded data, in bytes. + * + * \return Returns #VPX_CODEC_OK if the coded data was processed completely + * and future pictures can be decoded without error. Otherwise, + * see the descriptions of the other error codes in ::vpx_codec_err_t + * for recoverability capabilities. + */ +typedef vpx_codec_err_t (*vpx_codec_decode_fn_t)(vpx_codec_alg_priv_t *ctx, + const uint8_t *data, + unsigned int data_sz, + void *user_priv, + long deadline); + +/*!\brief Decoded frames iterator + * + * Iterates over a list of the frames available for display. The iterator + * storage should be initialized to NULL to start the iteration. Iteration is + * complete when this function returns NULL. + * + * The list of available frames becomes valid upon completion of the + * vpx_codec_decode call, and remains valid until the next call to vpx_codec_decode. + * + * \param[in] ctx Pointer to this instance's context + * \param[in out] iter Iterator storage, initialized to NULL + * + * \return Returns a pointer to an image, if one is ready for display. Frames + * produced will always be in PTS (presentation time stamp) order. + */ +typedef vpx_image_t*(*vpx_codec_get_frame_fn_t)(vpx_codec_alg_priv_t *ctx, + vpx_codec_iter_t *iter); + + +/*\brief eXternal Memory Allocation memory map get iterator + * + * Iterates over a list of the memory maps requested by the decoder. The + * iterator storage should be initialized to NULL to start the iteration. + * Iteration is complete when this function returns NULL. + * + * \param[in out] iter Iterator storage, initialized to NULL + * + * \return Returns a pointer to an memory segment descriptor, or NULL to + * indicate end-of-list. + */ +typedef vpx_codec_err_t (*vpx_codec_get_mmap_fn_t)(const vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmap, + vpx_codec_iter_t *iter); + + +/*\brief eXternal Memory Allocation memory map set iterator + * + * Sets a memory descriptor inside the decoder instance. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] mmap Memory map to store. + * + * \retval #VPX_CODEC_OK + * The memory map was accepted and stored. + * \retval #VPX_CODEC_MEM_ERROR + * The memory map was rejected. + */ +typedef vpx_codec_err_t (*vpx_codec_set_mmap_fn_t)(vpx_codec_ctx_t *ctx, + const vpx_codec_mmap_t *mmap); + + +typedef vpx_codec_err_t (*vpx_codec_encode_fn_t)(vpx_codec_alg_priv_t *ctx, + const vpx_image_t *img, + vpx_codec_pts_t pts, + unsigned long duration, + vpx_enc_frame_flags_t flags, + unsigned long deadline); +typedef const vpx_codec_cx_pkt_t*(*vpx_codec_get_cx_data_fn_t)(vpx_codec_alg_priv_t *ctx, + vpx_codec_iter_t *iter); + +typedef vpx_codec_err_t +(*vpx_codec_enc_config_set_fn_t)(vpx_codec_alg_priv_t *ctx, + const vpx_codec_enc_cfg_t *cfg); +typedef vpx_fixed_buf_t * +(*vpx_codec_get_global_headers_fn_t)(vpx_codec_alg_priv_t *ctx); + +typedef vpx_image_t * +(*vpx_codec_get_preview_frame_fn_t)(vpx_codec_alg_priv_t *ctx); + +typedef vpx_codec_err_t +(*vpx_codec_enc_mr_get_mem_loc_fn_t)(const vpx_codec_enc_cfg_t *cfg, + void **mem_loc); + +/*!\brief usage configuration mapping + * + * This structure stores the mapping between usage identifiers and + * configuration structures. Each algorithm provides a list of these + * mappings. This list is searched by the vpx_codec_enc_config_default() + * wrapper function to determine which config to return. The special value + * {-1, {0}} is used to indicate end-of-list, and must be present. At least + * one mapping must be present, in addition to the end-of-list. + * + */ +typedef const struct +{ + int usage; + vpx_codec_enc_cfg_t cfg; +} vpx_codec_enc_cfg_map_t; + +#define NOT_IMPLEMENTED 0 + +/*!\brief Decoder algorithm interface interface + * + * All decoders \ref MUST expose a variable of this type. + */ +struct vpx_codec_iface +{ + const char *name; /**< Identification String */ + int abi_version; /**< Implemented ABI version */ + vpx_codec_caps_t caps; /**< Decoder capabilities */ + vpx_codec_init_fn_t init; /**< \copydoc ::vpx_codec_init_fn_t */ + vpx_codec_destroy_fn_t destroy; /**< \copydoc ::vpx_codec_destroy_fn_t */ + vpx_codec_ctrl_fn_map_t *ctrl_maps; /**< \copydoc ::vpx_codec_ctrl_fn_map_t */ + vpx_codec_get_mmap_fn_t get_mmap; /**< \copydoc ::vpx_codec_get_mmap_fn_t */ + vpx_codec_set_mmap_fn_t set_mmap; /**< \copydoc ::vpx_codec_set_mmap_fn_t */ + struct + { + vpx_codec_peek_si_fn_t peek_si; /**< \copydoc ::vpx_codec_peek_si_fn_t */ + vpx_codec_get_si_fn_t get_si; /**< \copydoc ::vpx_codec_peek_si_fn_t */ + vpx_codec_decode_fn_t decode; /**< \copydoc ::vpx_codec_decode_fn_t */ + vpx_codec_get_frame_fn_t get_frame; /**< \copydoc ::vpx_codec_get_frame_fn_t */ + } dec; + struct + { + vpx_codec_enc_cfg_map_t *cfg_maps; /**< \copydoc ::vpx_codec_enc_cfg_map_t */ + vpx_codec_encode_fn_t encode; /**< \copydoc ::vpx_codec_encode_fn_t */ + vpx_codec_get_cx_data_fn_t get_cx_data; /**< \copydoc ::vpx_codec_get_cx_data_fn_t */ + vpx_codec_enc_config_set_fn_t cfg_set; /**< \copydoc ::vpx_codec_enc_config_set_fn_t */ + vpx_codec_get_global_headers_fn_t get_glob_hdrs; /**< \copydoc ::vpx_codec_get_global_headers_fn_t */ + vpx_codec_get_preview_frame_fn_t get_preview; /**< \copydoc ::vpx_codec_get_preview_frame_fn_t */ + vpx_codec_enc_mr_get_mem_loc_fn_t mr_get_mem_loc; /**< \copydoc ::vpx_codec_enc_mr_get_mem_loc_fn_t */ + } enc; +}; + +/*!\brief Callback function pointer / user data pair storage */ +typedef struct vpx_codec_priv_cb_pair +{ + union + { + vpx_codec_put_frame_cb_fn_t put_frame; + vpx_codec_put_slice_cb_fn_t put_slice; + } u; + void *user_priv; +} vpx_codec_priv_cb_pair_t; + + +/*!\brief Instance private storage + * + * This structure is allocated by the algorithm's init function. It can be + * extended in one of two ways. First, a second, algorithm specific structure + * can be allocated and the priv member pointed to it. Alternatively, this + * structure can be made the first member of the algorithm specific structure, + * and the pointer cast to the proper type. + */ +struct vpx_codec_priv +{ + unsigned int sz; + vpx_codec_iface_t *iface; + struct vpx_codec_alg_priv *alg_priv; + const char *err_detail; + vpx_codec_flags_t init_flags; + struct + { + vpx_codec_priv_cb_pair_t put_frame_cb; + vpx_codec_priv_cb_pair_t put_slice_cb; + } dec; + struct + { + int tbd; + struct vpx_fixed_buf cx_data_dst_buf; + unsigned int cx_data_pad_before; + unsigned int cx_data_pad_after; + vpx_codec_cx_pkt_t cx_data_pkt; + unsigned int total_encoders; + } enc; +}; + +/* + * Multi-resolution encoding internal configuration + */ +struct vpx_codec_priv_enc_mr_cfg +{ + unsigned int mr_total_resolutions; + unsigned int mr_encoder_id; + struct vpx_rational mr_down_sampling_factor; + void* mr_low_res_mode_info; +}; + +#undef VPX_CTRL_USE_TYPE +#define VPX_CTRL_USE_TYPE(id, typ) \ + static typ id##__value(va_list args) {return va_arg(args, typ);} \ + static typ id##__convert(void *x)\ + {\ + union\ + {\ + void *x;\ + typ d;\ + } u;\ + u.x = x;\ + return u.d;\ + } + + +#undef VPX_CTRL_USE_TYPE_DEPRECATED +#define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) \ + static typ id##__value(va_list args) {return va_arg(args, typ);} \ + static typ id##__convert(void *x)\ + {\ + union\ + {\ + void *x;\ + typ d;\ + } u;\ + u.x = x;\ + return u.d;\ + } + +#define CAST(id, arg) id##__value(arg) +#define RECAST(id, x) id##__convert(x) + + +/* CODEC_INTERFACE convenience macro + * + * By convention, each codec interface is a struct with extern linkage, where + * the symbol is suffixed with _algo. A getter function is also defined to + * return a pointer to the struct, since in some cases it's easier to work + * with text symbols than data symbols (see issue #169). This function has + * the same name as the struct, less the _algo suffix. The CODEC_INTERFACE + * macro is provided to define this getter function automatically. + */ +#define CODEC_INTERFACE(id)\ +vpx_codec_iface_t* id(void) { return &id##_algo; }\ +vpx_codec_iface_t id##_algo + + +/* Internal Utility Functions + * + * The following functions are intended to be used inside algorithms as + * utilities for manipulating vpx_codec_* data structures. + */ +struct vpx_codec_pkt_list +{ + unsigned int cnt; + unsigned int max; + struct vpx_codec_cx_pkt pkts[1]; +}; + +#define vpx_codec_pkt_list_decl(n)\ + union {struct vpx_codec_pkt_list head;\ + struct {struct vpx_codec_pkt_list head;\ + struct vpx_codec_cx_pkt pkts[n];} alloc;} + +#define vpx_codec_pkt_list_init(m)\ + (m)->alloc.head.cnt = 0,\ + (m)->alloc.head.max = sizeof((m)->alloc.pkts) / sizeof((m)->alloc.pkts[0]) + +int +vpx_codec_pkt_list_add(struct vpx_codec_pkt_list *, + const struct vpx_codec_cx_pkt *); + +const vpx_codec_cx_pkt_t* +vpx_codec_pkt_list_get(struct vpx_codec_pkt_list *list, + vpx_codec_iter_t *iter); + + +#include +#include +struct vpx_internal_error_info +{ + vpx_codec_err_t error_code; + int has_detail; + char detail[80]; + int setjmp; + jmp_buf jmp; +}; + +static void vpx_internal_error(struct vpx_internal_error_info *info, + vpx_codec_err_t error, + const char *fmt, + ...) +{ + va_list ap; + + info->error_code = error; + info->has_detail = 0; + + if (fmt) + { + size_t sz = sizeof(info->detail); + + info->has_detail = 1; + va_start(ap, fmt); + vsnprintf(info->detail, sz - 1, fmt, ap); + va_end(ap); + info->detail[sz-1] = '\0'; + } + + if (info->setjmp) + longjmp(info->jmp, info->error_code); +} +#endif diff --git a/vpx/src/vpx_codec.c b/vpx/src/vpx_codec.c new file mode 100644 index 0000000..f1a8b67 --- /dev/null +++ b/vpx/src/vpx_codec.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\file + * \brief Provides the high level interface to wrap decoder algorithms. + * + */ +#include +#include "vpx/vpx_integer.h" +#include "vpx/internal/vpx_codec_internal.h" +#include "vpx_version.h" + +#define SAVE_STATUS(ctx,var) (ctx?(ctx->err = var):var) + +int vpx_codec_version(void) +{ + return VERSION_PACKED; +} + + +const char *vpx_codec_version_str(void) +{ + return VERSION_STRING_NOSP; +} + + +const char *vpx_codec_version_extra_str(void) +{ + return VERSION_EXTRA; +} + + +const char *vpx_codec_iface_name(vpx_codec_iface_t *iface) +{ + return iface ? iface->name : ""; +} + +const char *vpx_codec_err_to_string(vpx_codec_err_t err) +{ + switch (err) + { + case VPX_CODEC_OK: + return "Success"; + case VPX_CODEC_ERROR: + return "Unspecified internal error"; + case VPX_CODEC_MEM_ERROR: + return "Memory allocation error"; + case VPX_CODEC_ABI_MISMATCH: + return "ABI version mismatch"; + case VPX_CODEC_INCAPABLE: + return "Codec does not implement requested capability"; + case VPX_CODEC_UNSUP_BITSTREAM: + return "Bitstream not supported by this decoder"; + case VPX_CODEC_UNSUP_FEATURE: + return "Bitstream required feature not supported by this decoder"; + case VPX_CODEC_CORRUPT_FRAME: + return "Corrupt frame detected"; + case VPX_CODEC_INVALID_PARAM: + return "Invalid parameter"; + case VPX_CODEC_LIST_END: + return "End of iterated list"; + } + + return "Unrecognized error code"; +} + +const char *vpx_codec_error(vpx_codec_ctx_t *ctx) +{ + return (ctx) ? vpx_codec_err_to_string(ctx->err) + : vpx_codec_err_to_string(VPX_CODEC_INVALID_PARAM); +} + +const char *vpx_codec_error_detail(vpx_codec_ctx_t *ctx) +{ + if (ctx && ctx->err) + return ctx->priv ? ctx->priv->err_detail : ctx->err_detail; + + return NULL; +} + + +vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx) +{ + vpx_codec_err_t res; + + if (!ctx) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv) + res = VPX_CODEC_ERROR; + else + { + if (ctx->priv->alg_priv) + ctx->iface->destroy(ctx->priv->alg_priv); + + ctx->iface = NULL; + ctx->name = NULL; + ctx->priv = NULL; + res = VPX_CODEC_OK; + } + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface) +{ + return (iface) ? iface->caps : 0; +} + + +vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx, + int ctrl_id, + ...) +{ + vpx_codec_err_t res; + + if (!ctx || !ctrl_id) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv || !ctx->iface->ctrl_maps) + res = VPX_CODEC_ERROR; + else + { + vpx_codec_ctrl_fn_map_t *entry; + + res = VPX_CODEC_ERROR; + + for (entry = ctx->iface->ctrl_maps; entry && entry->fn; entry++) + { + if (!entry->ctrl_id || entry->ctrl_id == ctrl_id) + { + va_list ap; + + va_start(ap, ctrl_id); + res = entry->fn(ctx->priv->alg_priv, ctrl_id, ap); + va_end(ap); + break; + } + } + } + + return SAVE_STATUS(ctx, res); +} diff --git a/vpx/src/vpx_decoder.c b/vpx/src/vpx_decoder.c new file mode 100644 index 0000000..59a783d --- /dev/null +++ b/vpx/src/vpx_decoder.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\file + * \brief Provides the high level interface to wrap decoder algorithms. + * + */ +#include +#include "vpx/internal/vpx_codec_internal.h" + +#define SAVE_STATUS(ctx,var) (ctx?(ctx->err = var):var) + +vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + vpx_codec_dec_cfg_t *cfg, + vpx_codec_flags_t flags, + int ver) +{ + vpx_codec_err_t res; + + if (ver != VPX_DECODER_ABI_VERSION) + res = VPX_CODEC_ABI_MISMATCH; + else if (!ctx || !iface) + res = VPX_CODEC_INVALID_PARAM; + else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) + res = VPX_CODEC_ABI_MISMATCH; + else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_POSTPROC) && !(iface->caps & VPX_CODEC_CAP_POSTPROC)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_ERROR_CONCEALMENT) && + !(iface->caps & VPX_CODEC_CAP_ERROR_CONCEALMENT)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_INPUT_FRAGMENTS) && + !(iface->caps & VPX_CODEC_CAP_INPUT_FRAGMENTS)) + res = VPX_CODEC_INCAPABLE; + else if (!(iface->caps & VPX_CODEC_CAP_DECODER)) + res = VPX_CODEC_INCAPABLE; + else + { + memset(ctx, 0, sizeof(*ctx)); + ctx->iface = iface; + ctx->name = iface->name; + ctx->priv = NULL; + ctx->init_flags = flags; + ctx->config.dec = cfg; + res = VPX_CODEC_OK; + + if (!(flags & VPX_CODEC_USE_XMA)) + { + res = ctx->iface->init(ctx, NULL); + + if (res) + { + ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; + vpx_codec_destroy(ctx); + } + + if (ctx->priv) + ctx->priv->iface = ctx->iface; + } + } + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_err_t vpx_codec_peek_stream_info(vpx_codec_iface_t *iface, + const uint8_t *data, + unsigned int data_sz, + vpx_codec_stream_info_t *si) +{ + vpx_codec_err_t res; + + if (!iface || !data || !data_sz || !si + || si->sz < sizeof(vpx_codec_stream_info_t)) + res = VPX_CODEC_INVALID_PARAM; + else + { + /* Set default/unknown values */ + si->w = 0; + si->h = 0; + + res = iface->dec.peek_si(data, data_sz, si); + } + + return res; +} + + +vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx, + vpx_codec_stream_info_t *si) +{ + vpx_codec_err_t res; + + if (!ctx || !si || si->sz < sizeof(vpx_codec_stream_info_t)) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv) + res = VPX_CODEC_ERROR; + else + { + /* Set default/unknown values */ + si->w = 0; + si->h = 0; + + res = ctx->iface->dec.get_si(ctx->priv->alg_priv, si); + } + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx, + const uint8_t *data, + unsigned int data_sz, + void *user_priv, + long deadline) +{ + vpx_codec_err_t res; + + /* Sanity checks */ + /* NULL data ptr allowed if data_sz is 0 too */ + if (!ctx || (!data && data_sz)) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv) + res = VPX_CODEC_ERROR; + else + { + res = ctx->iface->dec.decode(ctx->priv->alg_priv, data, data_sz, + user_priv, deadline); + } + + return SAVE_STATUS(ctx, res); +} + +vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx, + vpx_codec_iter_t *iter) +{ + vpx_image_t *img; + + if (!ctx || !iter || !ctx->iface || !ctx->priv) + img = NULL; + else + img = ctx->iface->dec.get_frame(ctx->priv->alg_priv, iter); + + return img; +} + + +vpx_codec_err_t vpx_codec_register_put_frame_cb(vpx_codec_ctx_t *ctx, + vpx_codec_put_frame_cb_fn_t cb, + void *user_priv) +{ + vpx_codec_err_t res; + + if (!ctx || !cb) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv + || !(ctx->iface->caps & VPX_CODEC_CAP_PUT_FRAME)) + res = VPX_CODEC_ERROR; + else + { + ctx->priv->dec.put_frame_cb.u.put_frame = cb; + ctx->priv->dec.put_frame_cb.user_priv = user_priv; + res = VPX_CODEC_OK; + } + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx, + vpx_codec_put_slice_cb_fn_t cb, + void *user_priv) +{ + vpx_codec_err_t res; + + if (!ctx || !cb) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv + || !(ctx->iface->caps & VPX_CODEC_CAP_PUT_FRAME)) + res = VPX_CODEC_ERROR; + else + { + ctx->priv->dec.put_slice_cb.u.put_slice = cb; + ctx->priv->dec.put_slice_cb.user_priv = user_priv; + res = VPX_CODEC_OK; + } + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_err_t vpx_codec_get_mem_map(vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmap, + vpx_codec_iter_t *iter) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + if (!ctx || !mmap || !iter || !ctx->iface) + res = VPX_CODEC_INVALID_PARAM; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_XMA)) + res = VPX_CODEC_ERROR; + else + res = ctx->iface->get_mmap(ctx, mmap, iter); + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_err_t vpx_codec_set_mem_map(vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmap, + unsigned int num_maps) +{ + vpx_codec_err_t res = VPX_CODEC_MEM_ERROR; + + if (!ctx || !mmap || !ctx->iface) + res = VPX_CODEC_INVALID_PARAM; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_XMA)) + res = VPX_CODEC_ERROR; + else + { + unsigned int i; + + for (i = 0; i < num_maps; i++, mmap++) + { + if (!mmap->base) + break; + + /* Everything look ok, set the mmap in the decoder */ + res = ctx->iface->set_mmap(ctx, mmap); + + if (res) + break; + } + } + + return SAVE_STATUS(ctx, res); +} diff --git a/vpx/src/vpx_encoder.c b/vpx/src/vpx_encoder.c new file mode 100644 index 0000000..03ddc62 --- /dev/null +++ b/vpx/src/vpx_encoder.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\file + * \brief Provides the high level interface to wrap encoder algorithms. + * + */ +#include +#include +#include "vpx/internal/vpx_codec_internal.h" +#include "vpx_config.h" + +#define SAVE_STATUS(ctx,var) (ctx?(ctx->err = var):var) + +vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + vpx_codec_enc_cfg_t *cfg, + vpx_codec_flags_t flags, + int ver) +{ + vpx_codec_err_t res; + + if (ver != VPX_ENCODER_ABI_VERSION) + res = VPX_CODEC_ABI_MISMATCH; + else if (!ctx || !iface || !cfg) + res = VPX_CODEC_INVALID_PARAM; + else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) + res = VPX_CODEC_ABI_MISMATCH; + else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_PSNR) + && !(iface->caps & VPX_CODEC_CAP_PSNR)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION) + && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION)) + res = VPX_CODEC_INCAPABLE; + else + { + ctx->iface = iface; + ctx->name = iface->name; + ctx->priv = NULL; + ctx->init_flags = flags; + ctx->config.enc = cfg; + res = ctx->iface->init(ctx, NULL); + + if (res) + { + ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; + vpx_codec_destroy(ctx); + } + + if (ctx->priv) + ctx->priv->iface = ctx->iface; + } + + return SAVE_STATUS(ctx, res); +} + +vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + vpx_codec_enc_cfg_t *cfg, + int num_enc, + vpx_codec_flags_t flags, + vpx_rational_t *dsf, + int ver) +{ + vpx_codec_err_t res = 0; + + if (ver != VPX_ENCODER_ABI_VERSION) + res = VPX_CODEC_ABI_MISMATCH; + else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1)) + res = VPX_CODEC_INVALID_PARAM; + else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) + res = VPX_CODEC_ABI_MISMATCH; + else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_PSNR) + && !(iface->caps & VPX_CODEC_CAP_PSNR)) + res = VPX_CODEC_INCAPABLE; + else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION) + && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION)) + res = VPX_CODEC_INCAPABLE; + else + { + int i; + void *mem_loc = NULL; + + if(!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc))) + { + for (i = 0; i < num_enc; i++) + { + vpx_codec_priv_enc_mr_cfg_t mr_cfg; + + /* Validate down-sampling factor. */ + if(dsf->num < 1 || dsf->num > 4096 || dsf->den < 1 || + dsf->den > dsf->num) + { + res = VPX_CODEC_INVALID_PARAM; + break; + } + + mr_cfg.mr_low_res_mode_info = mem_loc; + mr_cfg.mr_total_resolutions = num_enc; + mr_cfg.mr_encoder_id = num_enc-1-i; + mr_cfg.mr_down_sampling_factor.num = dsf->num; + mr_cfg.mr_down_sampling_factor.den = dsf->den; + + ctx->iface = iface; + ctx->name = iface->name; + ctx->priv = NULL; + ctx->init_flags = flags; + ctx->config.enc = cfg; + res = ctx->iface->init(ctx, &mr_cfg); + + if (res) + { + ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; + vpx_codec_destroy(ctx); + } + + if (ctx->priv) + ctx->priv->iface = ctx->iface; + + if (res) + break; + + ctx++; + cfg++; + dsf++; + } + } + } + + return SAVE_STATUS(ctx, res); +} + + +vpx_codec_err_t vpx_codec_enc_config_default(vpx_codec_iface_t *iface, + vpx_codec_enc_cfg_t *cfg, + unsigned int usage) +{ + vpx_codec_err_t res; + vpx_codec_enc_cfg_map_t *map; + + if (!iface || !cfg || usage > INT_MAX) + res = VPX_CODEC_INVALID_PARAM; + else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) + res = VPX_CODEC_INCAPABLE; + else + { + res = VPX_CODEC_INVALID_PARAM; + + for (map = iface->enc.cfg_maps; map->usage >= 0; map++) + { + if (map->usage == (int)usage) + { + *cfg = map->cfg; + cfg->g_usage = usage; + res = VPX_CODEC_OK; + break; + } + } + } + + return res; +} + + +#if ARCH_X86 || ARCH_X86_64 +/* On X86, disable the x87 unit's internal 80 bit precision for better + * consistency with the SSE unit's 64 bit precision. + */ +#include "vpx_ports/x86.h" +#define FLOATING_POINT_INIT() do {\ + unsigned short x87_orig_mode = x87_set_double_precision(); +#define FLOATING_POINT_RESTORE() \ + x87_set_control_word(x87_orig_mode); }while(0) + + +#else +static void FLOATING_POINT_INIT() {} +static void FLOATING_POINT_RESTORE() {} +#endif + + +vpx_codec_err_t vpx_codec_encode(vpx_codec_ctx_t *ctx, + const vpx_image_t *img, + vpx_codec_pts_t pts, + unsigned long duration, + vpx_enc_frame_flags_t flags, + unsigned long deadline) +{ + vpx_codec_err_t res = 0; + + if (!ctx || (img && !duration)) + res = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv) + res = VPX_CODEC_ERROR; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) + res = VPX_CODEC_INCAPABLE; + else + { + /* Execute in a normalized floating point environment, if the platform + * requires it. + */ + unsigned int num_enc =ctx->priv->enc.total_encoders; + + FLOATING_POINT_INIT(); + + if (num_enc == 1) + res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, + duration, flags, deadline); + else + { + /* Multi-resolution encoding: + * Encode multi-levels in reverse order. For example, + * if mr_total_resolutions = 3, first encode level 2, + * then encode level 1, and finally encode level 0. + */ + int i; + + ctx += num_enc - 1; + if (img) img += num_enc - 1; + + for (i = num_enc-1; i >= 0; i--) + { + if ((res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, + duration, flags, deadline))) + break; + + ctx--; + if (img) img--; + } + ctx++; + } + + FLOATING_POINT_RESTORE(); + } + + return SAVE_STATUS(ctx, res); +} + + +const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t *ctx, + vpx_codec_iter_t *iter) +{ + const vpx_codec_cx_pkt_t *pkt = NULL; + + if (ctx) + { + if (!iter) + ctx->err = VPX_CODEC_INVALID_PARAM; + else if (!ctx->iface || !ctx->priv) + ctx->err = VPX_CODEC_ERROR; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) + ctx->err = VPX_CODEC_INCAPABLE; + else + pkt = ctx->iface->enc.get_cx_data(ctx->priv->alg_priv, iter); + } + + if (pkt && pkt->kind == VPX_CODEC_CX_FRAME_PKT) + { + /* If the application has specified a destination area for the + * compressed data, and the codec has not placed the data there, + * and it fits, copy it. + */ + char *dst_buf = ctx->priv->enc.cx_data_dst_buf.buf; + + if (dst_buf + && pkt->data.raw.buf != dst_buf + && pkt->data.raw.sz + + ctx->priv->enc.cx_data_pad_before + + ctx->priv->enc.cx_data_pad_after + <= ctx->priv->enc.cx_data_dst_buf.sz) + { + vpx_codec_cx_pkt_t *modified_pkt = &ctx->priv->enc.cx_data_pkt; + + memcpy(dst_buf + ctx->priv->enc.cx_data_pad_before, + pkt->data.raw.buf, pkt->data.raw.sz); + *modified_pkt = *pkt; + modified_pkt->data.raw.buf = dst_buf; + modified_pkt->data.raw.sz += ctx->priv->enc.cx_data_pad_before + + ctx->priv->enc.cx_data_pad_after; + pkt = modified_pkt; + } + + if (dst_buf == pkt->data.raw.buf) + { + ctx->priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz; + ctx->priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz; + } + } + + return pkt; +} + + +vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t *ctx, + const vpx_fixed_buf_t *buf, + unsigned int pad_before, + unsigned int pad_after) +{ + if (!ctx || !ctx->priv) + return VPX_CODEC_INVALID_PARAM; + + if (buf) + { + ctx->priv->enc.cx_data_dst_buf = *buf; + ctx->priv->enc.cx_data_pad_before = pad_before; + ctx->priv->enc.cx_data_pad_after = pad_after; + } + else + { + ctx->priv->enc.cx_data_dst_buf.buf = NULL; + ctx->priv->enc.cx_data_dst_buf.sz = 0; + ctx->priv->enc.cx_data_pad_before = 0; + ctx->priv->enc.cx_data_pad_after = 0; + } + + return VPX_CODEC_OK; +} + + +const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t *ctx) +{ + vpx_image_t *img = NULL; + + if (ctx) + { + if (!ctx->iface || !ctx->priv) + ctx->err = VPX_CODEC_ERROR; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) + ctx->err = VPX_CODEC_INCAPABLE; + else if (!ctx->iface->enc.get_preview) + ctx->err = VPX_CODEC_INCAPABLE; + else + img = ctx->iface->enc.get_preview(ctx->priv->alg_priv); + } + + return img; +} + + +vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t *ctx) +{ + vpx_fixed_buf_t *buf = NULL; + + if (ctx) + { + if (!ctx->iface || !ctx->priv) + ctx->err = VPX_CODEC_ERROR; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) + ctx->err = VPX_CODEC_INCAPABLE; + else if (!ctx->iface->enc.get_glob_hdrs) + ctx->err = VPX_CODEC_INCAPABLE; + else + buf = ctx->iface->enc.get_glob_hdrs(ctx->priv->alg_priv); + } + + return buf; +} + + +vpx_codec_err_t vpx_codec_enc_config_set(vpx_codec_ctx_t *ctx, + const vpx_codec_enc_cfg_t *cfg) +{ + vpx_codec_err_t res; + + if (!ctx || !ctx->iface || !ctx->priv || !cfg) + res = VPX_CODEC_INVALID_PARAM; + else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) + res = VPX_CODEC_INCAPABLE; + else + res = ctx->iface->enc.cfg_set(ctx->priv->alg_priv, cfg); + + return SAVE_STATUS(ctx, res); +} + + +int vpx_codec_pkt_list_add(struct vpx_codec_pkt_list *list, + const struct vpx_codec_cx_pkt *pkt) +{ + if (list->cnt < list->max) + { + list->pkts[list->cnt++] = *pkt; + return 0; + } + + return 1; +} + + +const vpx_codec_cx_pkt_t *vpx_codec_pkt_list_get(struct vpx_codec_pkt_list *list, + vpx_codec_iter_t *iter) +{ + const vpx_codec_cx_pkt_t *pkt; + + if (!(*iter)) + { + *iter = list->pkts; + } + + pkt = (const void *) * iter; + + if ((size_t)(pkt - list->pkts) < list->cnt) + *iter = pkt + 1; + else + pkt = NULL; + + return pkt; +} diff --git a/vpx/src/vpx_image.c b/vpx/src/vpx_image.c new file mode 100644 index 0000000..336b6e2 --- /dev/null +++ b/vpx/src/vpx_image.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include "vpx/vpx_image.h" + +#define ADDRESS_STORAGE_SIZE sizeof(size_t) +/*returns an addr aligned to the byte boundary specified by align*/ +#define align_addr(addr,align) (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align)) + +/* Memalign code is copied from vpx_mem.c */ +static void *img_buf_memalign(size_t align, size_t size) +{ + void *addr, + * x = NULL; + + addr = malloc(size + align - 1 + ADDRESS_STORAGE_SIZE); + + if (addr) + { + x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align); + /* save the actual malloc address */ + ((size_t *)x)[-1] = (size_t)addr; + } + + return x; +} + +static void img_buf_free(void *memblk) +{ + if (memblk) + { + void *addr = (void *)(((size_t *)memblk)[-1]); + free(addr); + } +} + +static vpx_image_t *img_alloc_helper(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int buf_align, + unsigned int stride_align, + unsigned char *img_data) +{ + + unsigned int h, w, s, xcs, ycs, bps; + int align; + + /* Treat align==0 like align==1 */ + if (!buf_align) + buf_align = 1; + + /* Validate alignment (must be power of 2) */ + if (buf_align & (buf_align - 1)) + goto fail; + + /* Treat align==0 like align==1 */ + if (!stride_align) + stride_align = 1; + + /* Validate alignment (must be power of 2) */ + if (stride_align & (stride_align - 1)) + goto fail; + + /* Get sample size for this format */ + switch (fmt) + { + case VPX_IMG_FMT_RGB32: + case VPX_IMG_FMT_RGB32_LE: + case VPX_IMG_FMT_ARGB: + case VPX_IMG_FMT_ARGB_LE: + bps = 32; + break; + case VPX_IMG_FMT_RGB24: + case VPX_IMG_FMT_BGR24: + bps = 24; + break; + case VPX_IMG_FMT_RGB565: + case VPX_IMG_FMT_RGB565_LE: + case VPX_IMG_FMT_RGB555: + case VPX_IMG_FMT_RGB555_LE: + case VPX_IMG_FMT_UYVY: + case VPX_IMG_FMT_YUY2: + case VPX_IMG_FMT_YVYU: + bps = 16; + break; + case VPX_IMG_FMT_I420: + case VPX_IMG_FMT_YV12: + case VPX_IMG_FMT_VPXI420: + case VPX_IMG_FMT_VPXYV12: + bps = 12; + break; + default: + bps = 16; + break; + } + + /* Get chroma shift values for this format */ + switch (fmt) + { + case VPX_IMG_FMT_I420: + case VPX_IMG_FMT_YV12: + case VPX_IMG_FMT_VPXI420: + case VPX_IMG_FMT_VPXYV12: + xcs = 1; + break; + default: + xcs = 0; + break; + } + + switch (fmt) + { + case VPX_IMG_FMT_I420: + case VPX_IMG_FMT_YV12: + case VPX_IMG_FMT_VPXI420: + case VPX_IMG_FMT_VPXYV12: + ycs = 1; + break; + default: + ycs = 0; + break; + } + + /* Calculate storage sizes given the chroma subsampling */ + align = (1 << xcs) - 1; + w = (d_w + align) & ~align; + align = (1 << ycs) - 1; + h = (d_h + align) & ~align; + s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8; + s = (s + stride_align - 1) & ~(stride_align - 1); + + /* Allocate the new image */ + if (!img) + { + img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t)); + + if (!img) + goto fail; + + img->self_allocd = 1; + } + else + { + memset(img, 0, sizeof(vpx_image_t)); + } + + img->img_data = img_data; + + if (!img_data) + { + img->img_data = img_buf_memalign(buf_align, ((fmt & VPX_IMG_FMT_PLANAR)? + h * s * bps / 8 : h * s)); + img->img_data_owner = 1; + } + + if (!img->img_data) + goto fail; + + img->fmt = fmt; + img->w = w; + img->h = h; + img->x_chroma_shift = xcs; + img->y_chroma_shift = ycs; + img->bps = bps; + + /* Calculate strides */ + img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = s; + img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = s >> xcs; + + /* Default viewport to entire image */ + if (!vpx_img_set_rect(img, 0, 0, d_w, d_h)) + return img; + +fail: + vpx_img_free(img); + return NULL; +} + +vpx_image_t *vpx_img_alloc(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int align) +{ + return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL); +} + +vpx_image_t *vpx_img_wrap(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int stride_align, + unsigned char *img_data) +{ + /* By setting buf_align = 1, we don't change buffer alignment in this + * function. */ + return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, img_data); +} + +int vpx_img_set_rect(vpx_image_t *img, + unsigned int x, + unsigned int y, + unsigned int w, + unsigned int h) +{ + unsigned char *data; + + if (x + w <= img->w && y + h <= img->h) + { + img->d_w = w; + img->d_h = h; + + /* Calculate plane pointers */ + if (!(img->fmt & VPX_IMG_FMT_PLANAR)) + { + img->planes[VPX_PLANE_PACKED] = + img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED]; + } + else + { + data = img->img_data; + + if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) + { + img->planes[VPX_PLANE_ALPHA] = + data + x + y * img->stride[VPX_PLANE_ALPHA]; + data += img->h * img->stride[VPX_PLANE_ALPHA]; + } + + img->planes[VPX_PLANE_Y] = data + x + y * img->stride[VPX_PLANE_Y]; + data += img->h * img->stride[VPX_PLANE_Y]; + + if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) + { + img->planes[VPX_PLANE_U] = data + + (x >> img->x_chroma_shift) + + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U]; + data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U]; + img->planes[VPX_PLANE_V] = data + + (x >> img->x_chroma_shift) + + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V]; + } + else + { + img->planes[VPX_PLANE_V] = data + + (x >> img->x_chroma_shift) + + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V]; + data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V]; + img->planes[VPX_PLANE_U] = data + + (x >> img->x_chroma_shift) + + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U]; + } + } + + return 0; + } + + return -1; +} + +void vpx_img_flip(vpx_image_t *img) +{ + /* Note: In the calculation pointer adjustment calculation, we want the + * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99 + * standard indicates that if the adjustment parameter is unsigned, the + * stride parameter will be promoted to unsigned, causing errors when + * the lhs is a larger type than the rhs. + */ + img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y]; + img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y]; + + img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) + * img->stride[VPX_PLANE_U]; + img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U]; + + img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) + * img->stride[VPX_PLANE_V]; + img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V]; + + img->planes[VPX_PLANE_ALPHA] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA]; + img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA]; +} + +void vpx_img_free(vpx_image_t *img) +{ + if (img) + { + if (img->img_data && img->img_data_owner) + img_buf_free(img->img_data); + + if (img->self_allocd) + free(img); + } +} diff --git a/vpx/vp8.h b/vpx/vp8.h new file mode 100644 index 0000000..2952203 --- /dev/null +++ b/vpx/vp8.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup vp8 VP8 + * \ingroup codecs + * VP8 is vpx's newest video compression algorithm that uses motion + * compensated prediction, Discrete Cosine Transform (DCT) coding of the + * prediction error signal and context dependent entropy coding techniques + * based on arithmetic principles. It features: + * - YUV 4:2:0 image format + * - Macro-block based coding (16x16 luma plus two 8x8 chroma) + * - 1/4 (1/8) pixel accuracy motion compensated prediction + * - 4x4 DCT transform + * - 128 level linear quantizer + * - In loop deblocking filter + * - Context-based entropy coding + * + * @{ + */ +/*!\file + * \brief Provides controls common to both the VP8 encoder and decoder. + */ +#ifndef VP8_H +#define VP8_H +#include "vpx_codec_impl_top.h" + +/*!\brief Control functions + * + * The set of macros define the control functions of VP8 interface + */ +enum vp8_com_control_id +{ + VP8_SET_REFERENCE = 1, /**< pass in an external frame into decoder to be used as reference frame */ + VP8_COPY_REFERENCE = 2, /**< get a copy of reference frame from the decoder */ + VP8_SET_POSTPROC = 3, /**< set the decoder's post processing settings */ + VP8_SET_DBG_COLOR_REF_FRAME = 4, /**< set the reference frames to color for each macroblock */ + VP8_SET_DBG_COLOR_MB_MODES = 5, /**< set which macro block modes to color */ + VP8_SET_DBG_COLOR_B_MODES = 6, /**< set which blocks modes to color */ + VP8_SET_DBG_DISPLAY_MV = 7, /**< set which motion vector modes to draw */ + VP8_COMMON_CTRL_ID_MAX, + VP8_DECODER_CTRL_ID_START = 256 +}; + +/*!\brief post process flags + * + * The set of macros define VP8 decoder post processing flags + */ +enum vp8_postproc_level +{ + VP8_NOFILTERING = 0, + VP8_DEBLOCK = 1<<0, + VP8_DEMACROBLOCK = 1<<1, + VP8_ADDNOISE = 1<<2, + VP8_DEBUG_TXT_FRAME_INFO = 1<<3, /**< print frame information */ + VP8_DEBUG_TXT_MBLK_MODES = 1<<4, /**< print macro block modes over each macro block */ + VP8_DEBUG_TXT_DC_DIFF = 1<<5, /**< print dc diff for each macro block */ + VP8_DEBUG_TXT_RATE_INFO = 1<<6, /**< print video rate info (encoder only) */ + VP8_MFQE = 1<<10 +}; + +/*!\brief post process flags + * + * This define a structure that describe the post processing settings. For + * the best objective measure (using the PSNR metric) set post_proc_flag + * to VP8_DEBLOCK and deblocking_level to 1. + */ + +typedef struct vp8_postproc_cfg +{ + int post_proc_flag; /**< the types of post processing to be done, should be combination of "vp8_postproc_level" */ + int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */ + int noise_level; /**< the strength of additive noise, valid range [0, 16] */ +} vp8_postproc_cfg_t; + +/*!\brief reference frame type + * + * The set of macros define the type of VP8 reference frames + */ +typedef enum vpx_ref_frame_type +{ + VP8_LAST_FRAME = 1, + VP8_GOLD_FRAME = 2, + VP8_ALTR_FRAME = 4 +} vpx_ref_frame_type_t; + +/*!\brief reference frame data struct + * + * define the data struct to access vp8 reference frames + */ + +typedef struct vpx_ref_frame +{ + vpx_ref_frame_type_t frame_type; /**< which reference frame */ + vpx_image_t img; /**< reference frame data in image format */ +} vpx_ref_frame_t; + + +/*!\brief vp8 decoder control function parameter type + * + * defines the data type for each of VP8 decoder control function requires + */ + +VPX_CTRL_USE_TYPE(VP8_SET_REFERENCE, vpx_ref_frame_t *) +VPX_CTRL_USE_TYPE(VP8_COPY_REFERENCE, vpx_ref_frame_t *) +VPX_CTRL_USE_TYPE(VP8_SET_POSTPROC, vp8_postproc_cfg_t *) +VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_REF_FRAME, int) +VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_MB_MODES, int) +VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_B_MODES, int) +VPX_CTRL_USE_TYPE(VP8_SET_DBG_DISPLAY_MV, int) + + +/*! @} - end defgroup vp8 */ + +#include "vpx_codec_impl_bottom.h" +#endif diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h new file mode 100644 index 0000000..0af631c --- /dev/null +++ b/vpx/vp8cx.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup vp8_encoder WebM VP8 Encoder + * \ingroup vp8 + * + * @{ + */ +#include "vp8.h" + +/*!\file + * \brief Provides definitions for using the VP8 encoder algorithm within the + * vpx Codec Interface. + */ +#ifndef VP8CX_H +#define VP8CX_H +#include "vpx_codec_impl_top.h" + +/*!\name Algorithm interface for VP8 + * + * This interface provides the capability to encode raw VP8 streams, as would + * be found in AVI files. + * @{ + */ +extern vpx_codec_iface_t vpx_codec_vp8_cx_algo; +extern vpx_codec_iface_t* vpx_codec_vp8_cx(void); +/*!@} - end algorithm interface member group*/ + + +/* + * Algorithm Flags + */ + +/*!\brief Don't reference the last frame + * + * When this flag is set, the encoder will not use the last frame as a + * predictor. When not set, the encoder will choose whether to use the + * last frame or not automatically. + */ +#define VP8_EFLAG_NO_REF_LAST (1<<16) + + +/*!\brief Don't reference the golden frame + * + * When this flag is set, the encoder will not use the golden frame as a + * predictor. When not set, the encoder will choose whether to use the + * golden frame or not automatically. + */ +#define VP8_EFLAG_NO_REF_GF (1<<17) + + +/*!\brief Don't reference the alternate reference frame + * + * When this flag is set, the encoder will not use the alt ref frame as a + * predictor. When not set, the encoder will choose whether to use the + * alt ref frame or not automatically. + */ +#define VP8_EFLAG_NO_REF_ARF (1<<21) + + +/*!\brief Don't update the last frame + * + * When this flag is set, the encoder will not update the last frame with + * the contents of the current frame. + */ +#define VP8_EFLAG_NO_UPD_LAST (1<<18) + + +/*!\brief Don't update the golden frame + * + * When this flag is set, the encoder will not update the golden frame with + * the contents of the current frame. + */ +#define VP8_EFLAG_NO_UPD_GF (1<<22) + + +/*!\brief Don't update the alternate reference frame + * + * When this flag is set, the encoder will not update the alt ref frame with + * the contents of the current frame. + */ +#define VP8_EFLAG_NO_UPD_ARF (1<<23) + + +/*!\brief Force golden frame update + * + * When this flag is set, the encoder copy the contents of the current frame + * to the golden frame buffer. + */ +#define VP8_EFLAG_FORCE_GF (1<<19) + + +/*!\brief Force alternate reference frame update + * + * When this flag is set, the encoder copy the contents of the current frame + * to the alternate reference frame buffer. + */ +#define VP8_EFLAG_FORCE_ARF (1<<24) + + +/*!\brief Disable entropy update + * + * When this flag is set, the encoder will not update its internal entropy + * model based on the entropy of this frame. + */ +#define VP8_EFLAG_NO_UPD_ENTROPY (1<<20) + + +/*!\brief VP8 encoder control functions + * + * This set of macros define the control functions available for the VP8 + * encoder interface. + * + * \sa #vpx_codec_control + */ +enum vp8e_enc_control_id +{ + VP8E_UPD_ENTROPY = 5, /**< control function to set mode of entropy update in encoder */ + VP8E_UPD_REFERENCE, /**< control function to set reference update mode in encoder */ + VP8E_USE_REFERENCE, /**< control function to set which reference frame encoder can use */ + VP8E_SET_ROI_MAP, /**< control function to pass an ROI map to encoder */ + VP8E_SET_ACTIVEMAP, /**< control function to pass an Active map to encoder */ + VP8E_SET_SCALEMODE = 11, /**< control function to set encoder scaling mode */ + /*!\brief control function to set vp8 encoder cpuused + * + * Changes in this value influences, among others, the encoder's selection + * of motion estimation methods. Values greater than 0 will increase encoder + * speed at the expense of quality. + * The full set of adjustments can be found in + * onyx_if.c:vp8_set_speed_features(). + * \todo List highlights of the changes at various levels. + * + * \note Valid range: -16..16 + */ + VP8E_SET_CPUUSED = 13, + VP8E_SET_ENABLEAUTOALTREF, /**< control function to enable vp8 to automatic set and use altref frame */ + VP8E_SET_NOISE_SENSITIVITY, /**< control function to set noise sensitivity */ + VP8E_SET_SHARPNESS, /**< control function to set sharpness */ + VP8E_SET_STATIC_THRESHOLD, /**< control function to set the threshold for macroblocks treated static */ + VP8E_SET_TOKEN_PARTITIONS, /**< control function to set the number of token partitions */ + VP8E_GET_LAST_QUANTIZER, /**< return the quantizer chosen by the + encoder for the last frame using the internal + scale */ + VP8E_GET_LAST_QUANTIZER_64, /**< return the quantizer chosen by the + encoder for the last frame, using the 0..63 + scale as used by the rc_*_quantizer config + parameters */ + VP8E_SET_ARNR_MAXFRAMES, /**< control function to set the max number of frames blurred creating arf*/ + VP8E_SET_ARNR_STRENGTH , /**< control function to set the filter strength for the arf */ + VP8E_SET_ARNR_TYPE , /**< control function to set the type of filter to use for the arf*/ + VP8E_SET_TUNING, /**< control function to set visual tuning */ + /*!\brief control function to set constrained quality level + * + * \attention For this value to be used vpx_codec_enc_cfg_t::g_usage must be + * set to #VPX_CQ. + * \note Valid range: 0..63 + */ + VP8E_SET_CQ_LEVEL, + + /*!\brief Max data rate for Intra frames + * + * This value controls additional clamping on the maximum size of a + * keyframe. It is expressed as a percentage of the average + * per-frame bitrate, with the special (and default) value 0 meaning + * unlimited, or no additional clamping beyond the codec's built-in + * algorithm. + * + * For example, to allocate no more than 4.5 frames worth of bitrate + * to a keyframe, set this to 450. + * + */ + VP8E_SET_MAX_INTRA_BITRATE_PCT +}; + +/*!\brief vpx 1-D scaling mode + * + * This set of constants define 1-D vpx scaling modes + */ +typedef enum vpx_scaling_mode_1d +{ + VP8E_NORMAL = 0, + VP8E_FOURFIVE = 1, + VP8E_THREEFIVE = 2, + VP8E_ONETWO = 3 +} VPX_SCALING_MODE; + + +/*!\brief vpx region of interest map + * + * These defines the data structures for the region of interest map + * + */ + +typedef struct vpx_roi_map +{ + unsigned char *roi_map; /**< specify an id between 0 and 3 for each 16x16 region within a frame */ + unsigned int rows; /**< number of rows */ + unsigned int cols; /**< number of cols */ + int delta_q[4]; /**< quantizer delta [-64, 64] off baseline for regions with id between 0 and 3*/ + int delta_lf[4]; /**< loop filter strength delta [-32, 32] for regions with id between 0 and 3 */ + unsigned int static_threshold[4];/**< threshold for region to be treated as static */ +} vpx_roi_map_t; + +/*!\brief vpx active region map + * + * These defines the data structures for active region map + * + */ + + +typedef struct vpx_active_map +{ + unsigned char *active_map; /**< specify an on (1) or off (0) each 16x16 region within a frame */ + unsigned int rows; /**< number of rows */ + unsigned int cols; /**< number of cols */ +} vpx_active_map_t; + +/*!\brief vpx image scaling mode + * + * This defines the data structure for image scaling mode + * + */ +typedef struct vpx_scaling_mode +{ + VPX_SCALING_MODE h_scaling_mode; /**< horizontal scaling mode */ + VPX_SCALING_MODE v_scaling_mode; /**< vertical scaling mode */ +} vpx_scaling_mode_t; + +/*!\brief VP8 encoding mode + * + * This defines VP8 encoding mode + * + */ +typedef enum +{ + VP8_BEST_QUALITY_ENCODING, + VP8_GOOD_QUALITY_ENCODING, + VP8_REAL_TIME_ENCODING +} vp8e_encoding_mode; + +/*!\brief VP8 token partition mode + * + * This defines VP8 partitioning mode for compressed data, i.e., the number of + * sub-streams in the bitstream. Used for parallelized decoding. + * + */ + +typedef enum +{ + VP8_ONE_TOKENPARTITION = 0, + VP8_TWO_TOKENPARTITION = 1, + VP8_FOUR_TOKENPARTITION = 2, + VP8_EIGHT_TOKENPARTITION = 3 +} vp8e_token_partitions; + + +/*!\brief VP8 model tuning parameters + * + * Changes the encoder to tune for certain types of input material. + * + */ +typedef enum +{ + VP8_TUNE_PSNR, + VP8_TUNE_SSIM +} vp8e_tuning; + + +/*!\brief VP8 encoder control function parameter type + * + * Defines the data types that VP8E control functions take. Note that + * additional common controls are defined in vp8.h + * + */ + + +/* These controls have been deprecated in favor of the flags parameter to + * vpx_codec_encode(). See the definition of VP8_EFLAG_* above. + */ +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_ENTROPY, int) +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_REFERENCE, int) +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_USE_REFERENCE, int) + +VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *) +VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *) +VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *) + +VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int) +VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_SHARPNESS, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_STATIC_THRESHOLD, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_TOKEN_PARTITIONS, vp8e_token_partitions) + +VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_MAXFRAMES, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_STRENGTH , unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_TYPE , unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_TUNING, vp8e_tuning) +VPX_CTRL_USE_TYPE(VP8E_SET_CQ_LEVEL , unsigned int) + +VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *) +VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *) + +VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int) + + +/*! @} - end defgroup vp8_encoder */ +#include "vpx_codec_impl_bottom.h" +#endif diff --git a/vpx/vp8dx.h b/vpx/vp8dx.h new file mode 100644 index 0000000..8661035 --- /dev/null +++ b/vpx/vp8dx.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vp8.h" + +/*!\defgroup vp8_decoder WebM VP8 Decoder + * \ingroup vp8 + * + * @{ + */ +/*!\file + * \brief Provides definitions for using the VP8 algorithm within the vpx Decoder + * interface. + */ +#ifndef VP8DX_H +#define VP8DX_H +#include "vpx_codec_impl_top.h" + +/*!\name Algorithm interface for VP8 + * + * This interface provides the capability to decode raw VP8 streams, as would + * be found in AVI files and other non-Flash uses. + * @{ + */ +extern vpx_codec_iface_t vpx_codec_vp8_dx_algo; +extern vpx_codec_iface_t* vpx_codec_vp8_dx(void); +/*!@} - end algorithm interface member group*/ + +/* Include controls common to both the encoder and decoder */ +#include "vp8.h" + + +/*!\brief VP8 decoder control functions + * + * This set of macros define the control functions available for the VP8 + * decoder interface. + * + * \sa #vpx_codec_control + */ +enum vp8_dec_control_id +{ + /** control function to get info on which reference frames were updated + * by the last decode + */ + VP8D_GET_LAST_REF_UPDATES = VP8_DECODER_CTRL_ID_START, + + /** check if the indicated frame is corrupted */ + VP8D_GET_FRAME_CORRUPTED, + + /** control function to get info on which reference frames were used + * by the last decode + */ + VP8D_GET_LAST_REF_USED, + + VP8_DECODER_CTRL_ID_MAX +} ; + + +/*!\brief VP8 decoder control function parameter type + * + * Defines the data types that VP8D control functions take. Note that + * additional common controls are defined in vp8.h + * + */ + + +VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *) +VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *) +VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *) + +/*! @} - end defgroup vp8_decoder */ + + +#include "vpx_codec_impl_bottom.h" +#endif diff --git a/vpx/vpx_codec.h b/vpx/vpx_codec.h new file mode 100644 index 0000000..d92e165 --- /dev/null +++ b/vpx/vpx_codec.h @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup codec Common Algorithm Interface + * This abstraction allows applications to easily support multiple video + * formats with minimal code duplication. This section describes the interface + * common to all codecs (both encoders and decoders). + * @{ + */ + +/*!\file + * \brief Describes the codec algorithm interface to applications. + * + * This file describes the interface between an application and a + * video codec algorithm. + * + * An application instantiates a specific codec instance by using + * vpx_codec_init() and a pointer to the algorithm's interface structure: + *
        + *     my_app.c:
        + *       extern vpx_codec_iface_t my_codec;
        + *       {
        + *           vpx_codec_ctx_t algo;
        + *           res = vpx_codec_init(&algo, &my_codec);
        + *       }
        + *     
        + * + * Once initialized, the instance is manged using other functions from + * the vpx_codec_* family. + */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef VPX_CODEC_H +#define VPX_CODEC_H +#include "vpx_integer.h" +#include "vpx_image.h" + + /*!\brief Decorator indicating a function is deprecated */ +#ifndef DEPRECATED +#if defined(__GNUC__) && __GNUC__ +#define DEPRECATED __attribute__ ((deprecated)) +#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */ +#elif defined(_MSC_VER) +#define DEPRECATED +#define DECLSPEC_DEPRECATED __declspec(deprecated) /**< \copydoc #DEPRECATED */ +#else +#define DEPRECATED +#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */ +#endif +#endif + + /*!\brief Decorator indicating a function is potentially unused */ +#ifdef UNUSED +#elif __GNUC__ +#define UNUSED __attribute__ ((unused)) +#else +#define UNUSED +#endif + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_CODEC_ABI_VERSION (2 + VPX_IMAGE_ABI_VERSION) /**<\hideinitializer*/ + + /*!\brief Algorithm return codes */ + typedef enum { + /*!\brief Operation completed without error */ + VPX_CODEC_OK, + + /*!\brief Unspecified error */ + VPX_CODEC_ERROR, + + /*!\brief Memory operation failed */ + VPX_CODEC_MEM_ERROR, + + /*!\brief ABI version mismatch */ + VPX_CODEC_ABI_MISMATCH, + + /*!\brief Algorithm does not have required capability */ + VPX_CODEC_INCAPABLE, + + /*!\brief The given bitstream is not supported. + * + * The bitstream was unable to be parsed at the highest level. The decoder + * is unable to proceed. This error \ref SHOULD be treated as fatal to the + * stream. */ + VPX_CODEC_UNSUP_BITSTREAM, + + /*!\brief Encoded bitstream uses an unsupported feature + * + * The decoder does not implement a feature required by the encoder. This + * return code should only be used for features that prevent future + * pictures from being properly decoded. This error \ref MAY be treated as + * fatal to the stream or \ref MAY be treated as fatal to the current GOP. + */ + VPX_CODEC_UNSUP_FEATURE, + + /*!\brief The coded data for this stream is corrupt or incomplete + * + * There was a problem decoding the current frame. This return code + * should only be used for failures that prevent future pictures from + * being properly decoded. This error \ref MAY be treated as fatal to the + * stream or \ref MAY be treated as fatal to the current GOP. If decoding + * is continued for the current GOP, artifacts may be present. + */ + VPX_CODEC_CORRUPT_FRAME, + + /*!\brief An application-supplied parameter is not valid. + * + */ + VPX_CODEC_INVALID_PARAM, + + /*!\brief An iterator reached the end of list. + * + */ + VPX_CODEC_LIST_END + + } + vpx_codec_err_t; + + + /*! \brief Codec capabilities bitfield + * + * Each codec advertises the capabilities it supports as part of its + * ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces + * or functionality, and are not required to be supported. + * + * The available flags are specified by VPX_CODEC_CAP_* defines. + */ + typedef long vpx_codec_caps_t; +#define VPX_CODEC_CAP_DECODER 0x1 /**< Is a decoder */ +#define VPX_CODEC_CAP_ENCODER 0x2 /**< Is an encoder */ +#define VPX_CODEC_CAP_XMA 0x4 /**< Supports eXternal Memory Allocation */ + + + /*! \brief Initialization-time Feature Enabling + * + * Certain codec features must be known at initialization time, to allow for + * proper memory allocation. + * + * The available flags are specified by VPX_CODEC_USE_* defines. + */ + typedef long vpx_codec_flags_t; +#define VPX_CODEC_USE_XMA 0x00000001 /**< Use eXternal Memory Allocation mode */ + + + /*!\brief Codec interface structure. + * + * Contains function pointers and other data private to the codec + * implementation. This structure is opaque to the application. + */ + typedef const struct vpx_codec_iface vpx_codec_iface_t; + + + /*!\brief Codec private data structure. + * + * Contains data private to the codec implementation. This structure is opaque + * to the application. + */ + typedef struct vpx_codec_priv vpx_codec_priv_t; + + + /*!\brief Iterator + * + * Opaque storage used for iterating over lists. + */ + typedef const void *vpx_codec_iter_t; + + + /*!\brief Codec context structure + * + * All codecs \ref MUST support this context structure fully. In general, + * this data should be considered private to the codec algorithm, and + * not be manipulated or examined by the calling application. Applications + * may reference the 'name' member to get a printable description of the + * algorithm. + */ + typedef struct vpx_codec_ctx + { + const char *name; /**< Printable interface name */ + vpx_codec_iface_t *iface; /**< Interface pointers */ + vpx_codec_err_t err; /**< Last returned error */ + const char *err_detail; /**< Detailed info, if available */ + vpx_codec_flags_t init_flags; /**< Flags passed at init time */ + union + { + struct vpx_codec_dec_cfg *dec; /**< Decoder Configuration Pointer */ + struct vpx_codec_enc_cfg *enc; /**< Encoder Configuration Pointer */ + void *raw; + } config; /**< Configuration pointer aliasing union */ + vpx_codec_priv_t *priv; /**< Algorithm private storage */ + } vpx_codec_ctx_t; + + + /* + * Library Version Number Interface + * + * For example, see the following sample return values: + * vpx_codec_version() (1<<16 | 2<<8 | 3) + * vpx_codec_version_str() "v1.2.3-rc1-16-gec6a1ba" + * vpx_codec_version_extra_str() "rc1-16-gec6a1ba" + */ + + /*!\brief Return the version information (as an integer) + * + * Returns a packed encoding of the library version number. This will only include + * the major.minor.patch component of the version number. Note that this encoded + * value should be accessed through the macros provided, as the encoding may change + * in the future. + * + */ + int vpx_codec_version(void); +#define VPX_VERSION_MAJOR(v) ((v>>16)&0xff) /**< extract major from packed version */ +#define VPX_VERSION_MINOR(v) ((v>>8)&0xff) /**< extract minor from packed version */ +#define VPX_VERSION_PATCH(v) ((v>>0)&0xff) /**< extract patch from packed version */ + + /*!\brief Return the version major number */ +#define vpx_codec_version_major() ((vpx_codec_version()>>16)&0xff) + + /*!\brief Return the version minor number */ +#define vpx_codec_version_minor() ((vpx_codec_version()>>8)&0xff) + + /*!\brief Return the version patch number */ +#define vpx_codec_version_patch() ((vpx_codec_version()>>0)&0xff) + + + /*!\brief Return the version information (as a string) + * + * Returns a printable string containing the full library version number. This may + * contain additional text following the three digit version number, as to indicate + * release candidates, prerelease versions, etc. + * + */ + const char *vpx_codec_version_str(void); + + + /*!\brief Return the version information (as a string) + * + * Returns a printable "extra string". This is the component of the string returned + * by vpx_codec_version_str() following the three digit version number. + * + */ + const char *vpx_codec_version_extra_str(void); + + + /*!\brief Return the build configuration + * + * Returns a printable string containing an encoded version of the build + * configuration. This may be useful to vpx support. + * + */ + const char *vpx_codec_build_config(void); + + + /*!\brief Return the name for a given interface + * + * Returns a human readable string for name of the given codec interface. + * + * \param[in] iface Interface pointer + * + */ + const char *vpx_codec_iface_name(vpx_codec_iface_t *iface); + + + /*!\brief Convert error number to printable string + * + * Returns a human readable string for the last error returned by the + * algorithm. The returned error will be one line and will not contain + * any newline characters. + * + * + * \param[in] err Error number. + * + */ + const char *vpx_codec_err_to_string(vpx_codec_err_t err); + + + /*!\brief Retrieve error synopsis for codec context + * + * Returns a human readable string for the last error returned by the + * algorithm. The returned error will be one line and will not contain + * any newline characters. + * + * + * \param[in] ctx Pointer to this instance's context. + * + */ + const char *vpx_codec_error(vpx_codec_ctx_t *ctx); + + + /*!\brief Retrieve detailed error information for codec context + * + * Returns a human readable string providing detailed information about + * the last error. + * + * \param[in] ctx Pointer to this instance's context. + * + * \retval NULL + * No detailed information is available. + */ + const char *vpx_codec_error_detail(vpx_codec_ctx_t *ctx); + + + /* REQUIRED FUNCTIONS + * + * The following functions are required to be implemented for all codecs. + * They represent the base case functionality expected of all codecs. + */ + + /*!\brief Destroy a codec instance + * + * Destroys a codec context, freeing any associated memory buffers. + * + * \param[in] ctx Pointer to this instance's context + * + * \retval #VPX_CODEC_OK + * The codec algorithm initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory allocation failed. + */ + vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx); + + + /*!\brief Get the capabilities of an algorithm. + * + * Retrieves the capabilities bitfield from the algorithm's interface. + * + * \param[in] iface Pointer to the algorithm interface + * + */ + vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface); + + + /*!\brief Control algorithm + * + * This function is used to exchange algorithm specific data with the codec + * instance. This can be used to implement features specific to a particular + * algorithm. + * + * This wrapper function dispatches the request to the helper function + * associated with the given ctrl_id. It tries to call this function + * transparently, but will return #VPX_CODEC_ERROR if the request could not + * be dispatched. + * + * Note that this function should not be used directly. Call the + * #vpx_codec_control wrapper macro instead. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] ctrl_id Algorithm specific control identifier + * + * \retval #VPX_CODEC_OK + * The control request was processed. + * \retval #VPX_CODEC_ERROR + * The control request was not processed. + * \retval #VPX_CODEC_INVALID_PARAM + * The data was not valid. + */ + vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx, + int ctrl_id, + ...); +#if defined(VPX_DISABLE_CTRL_TYPECHECKS) && VPX_DISABLE_CTRL_TYPECHECKS +# define vpx_codec_control(ctx,id,data) vpx_codec_control_(ctx,id,data) +# define VPX_CTRL_USE_TYPE(id, typ) +# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) +# define VPX_CTRL_VOID(id, typ) + +#else + /*!\brief vpx_codec_control wrapper macro + * + * This macro allows for type safe conversions across the variadic parameter + * to vpx_codec_control_(). + * + * \internal + * It works by dispatching the call to the control function through a wrapper + * function named with the id parameter. + */ +# define vpx_codec_control(ctx,id,data) vpx_codec_control_##id(ctx,id,data)\ + /**<\hideinitializer*/ + + + /*!\brief vpx_codec_control type definition macro + * + * This macro allows for type safe conversions across the variadic parameter + * to vpx_codec_control_(). It defines the type of the argument for a given + * control identifier. + * + * \internal + * It defines a static function with + * the correctly typed arguments as a wrapper to the type-unsafe internal + * function. + */ +# define VPX_CTRL_USE_TYPE(id, typ) \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) UNUSED;\ + \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\ + return vpx_codec_control_(ctx, ctrl_id, data);\ + } /**<\hideinitializer*/ + + + /*!\brief vpx_codec_control deprecated type definition macro + * + * Like #VPX_CTRL_USE_TYPE, but indicates that the specified control is + * deprecated and should not be used. Consult the documentation for your + * codec for more information. + * + * \internal + * It defines a static function with the correctly typed arguments as a + * wrapper to the type-unsafe internal function. + */ +# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) \ + DECLSPEC_DEPRECATED static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) DEPRECATED UNUSED;\ + \ + DECLSPEC_DEPRECATED static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\ + return vpx_codec_control_(ctx, ctrl_id, data);\ + } /**<\hideinitializer*/ + + + /*!\brief vpx_codec_control void type definition macro + * + * This macro allows for type safe conversions across the variadic parameter + * to vpx_codec_control_(). It indicates that a given control identifier takes + * no argument. + * + * \internal + * It defines a static function without a data argument as a wrapper to the + * type-unsafe internal function. + */ +# define VPX_CTRL_VOID(id) \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t*, int) UNUSED;\ + \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id) {\ + return vpx_codec_control_(ctx, ctrl_id);\ + } /**<\hideinitializer*/ + + +#endif + + + /*!\defgroup cap_xma External Memory Allocation Functions + * + * The following functions are required to be implemented for all codecs + * that advertise the VPX_CODEC_CAP_XMA capability. Calling these functions + * for codecs that don't advertise this capability will result in an error + * code being returned, usually VPX_CODEC_INCAPABLE + * @{ + */ + + + /*!\brief Memory Map Entry + * + * This structure is used to contain the properties of a memory segment. It + * is populated by the codec in the request phase, and by the calling + * application once the requested allocation has been performed. + */ + typedef struct vpx_codec_mmap + { + /* + * The following members are set by the codec when requesting a segment + */ + unsigned int id; /**< identifier for the segment's contents */ + unsigned long sz; /**< size of the segment, in bytes */ + unsigned int align; /**< required alignment of the segment, in bytes */ + unsigned int flags; /**< bitfield containing segment properties */ +#define VPX_CODEC_MEM_ZERO 0x1 /**< Segment must be zeroed by allocation */ +#define VPX_CODEC_MEM_WRONLY 0x2 /**< Segment need not be readable */ +#define VPX_CODEC_MEM_FAST 0x4 /**< Place in fast memory, if available */ + + /* The following members are to be filled in by the allocation function */ + void *base; /**< pointer to the allocated segment */ + void (*dtor)(struct vpx_codec_mmap *map); /**< destructor to call */ + void *priv; /**< allocator private storage */ + } vpx_codec_mmap_t; /**< alias for struct vpx_codec_mmap */ + + + /*!\brief Iterate over the list of segments to allocate. + * + * Iterates over a list of the segments to allocate. The iterator storage + * should be initialized to NULL to start the iteration. Iteration is complete + * when this function returns VPX_CODEC_LIST_END. The amount of memory needed to + * allocate is dependent upon the size of the encoded stream. In cases where the + * stream is not available at allocation time, a fixed size must be requested. + * The codec will not be able to operate on streams larger than the size used at + * allocation time. + * + * \param[in] ctx Pointer to this instance's context. + * \param[out] mmap Pointer to the memory map entry to populate. + * \param[in,out] iter Iterator storage, initialized to NULL + * + * \retval #VPX_CODEC_OK + * The memory map entry was populated. + * \retval #VPX_CODEC_ERROR + * Codec does not support XMA mode. + * \retval #VPX_CODEC_MEM_ERROR + * Unable to determine segment size from stream info. + */ + vpx_codec_err_t vpx_codec_get_mem_map(vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmap, + vpx_codec_iter_t *iter); + + + /*!\brief Identify allocated segments to codec instance + * + * Stores a list of allocated segments in the codec. Segments \ref MUST be + * passed in the order they are read from vpx_codec_get_mem_map(), but may be + * passed in groups of any size. Segments \ref MUST be set only once. The + * allocation function \ref MUST ensure that the vpx_codec_mmap_t::base member + * is non-NULL. If the segment requires cleanup handling (e.g., calling free() + * or close()) then the vpx_codec_mmap_t::dtor member \ref MUST be populated. + * + * \param[in] ctx Pointer to this instance's context. + * \param[in] mmaps Pointer to the first memory map entry in the list. + * \param[in] num_maps Number of entries being set at this time + * + * \retval #VPX_CODEC_OK + * The segment was stored in the codec context. + * \retval #VPX_CODEC_INCAPABLE + * Codec does not support XMA mode. + * \retval #VPX_CODEC_MEM_ERROR + * Segment base address was not set, or segment was already stored. + + */ + vpx_codec_err_t vpx_codec_set_mem_map(vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmaps, + unsigned int num_maps); + + /*!@} - end defgroup cap_xma*/ + /*!@} - end defgroup codec*/ + + +#endif +#ifdef __cplusplus +} +#endif diff --git a/vpx/vpx_codec.mk b/vpx/vpx_codec.mk new file mode 100644 index 0000000..427fd0f --- /dev/null +++ b/vpx/vpx_codec.mk @@ -0,0 +1,25 @@ +## +## Copyright (c) 2010 The WebM project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license +## that can be found in the LICENSE file in the root of the source +## tree. An additional intellectual property rights grant can be found +## in the file PATENTS. All contributing project authors may +## be found in the AUTHORS file in the root of the source tree. +## + + +API_EXPORTS += exports + +API_SRCS-yes += src/vpx_decoder.c +API_SRCS-yes += vpx_decoder.h +API_SRCS-yes += src/vpx_encoder.c +API_SRCS-yes += vpx_encoder.h +API_SRCS-yes += internal/vpx_codec_internal.h +API_SRCS-yes += src/vpx_codec.c +API_SRCS-yes += src/vpx_image.c +API_SRCS-yes += vpx_codec.h +API_SRCS-yes += vpx_codec.mk +API_SRCS-yes += vpx_codec_impl_bottom.h +API_SRCS-yes += vpx_codec_impl_top.h +API_SRCS-yes += vpx_image.h diff --git a/vpx/vpx_codec_impl_bottom.h b/vpx/vpx_codec_impl_bottom.h new file mode 100644 index 0000000..6eb79a8 --- /dev/null +++ b/vpx/vpx_codec_impl_bottom.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file is to be included at the bottom of the header files defining the + * interface to individual codecs and contains matching blocks to those defined + * in vpx_codec_impl_top.h + */ +#ifdef __cplusplus +} +#endif diff --git a/vpx/vpx_codec_impl_top.h b/vpx/vpx_codec_impl_top.h new file mode 100644 index 0000000..c9b8cfa --- /dev/null +++ b/vpx/vpx_codec_impl_top.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file is to be included at the top of the header files defining the + * interface to individual codecs and contains various workarounds common + * to all codec implementations. + */ +#ifdef __cplusplus +extern "C" { +#endif diff --git a/vpx/vpx_decoder.h b/vpx/vpx_decoder.h new file mode 100644 index 0000000..7992cc4 --- /dev/null +++ b/vpx/vpx_decoder.h @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup decoder Decoder Algorithm Interface + * \ingroup codec + * This abstraction allows applications using this decoder to easily support + * multiple video formats with minimal code duplication. This section describes + * the interface common to all decoders. + * @{ + */ + +/*!\file + * \brief Describes the decoder algorithm interface to applications. + * + * This file describes the interface between an application and a + * video decoder algorithm. + * + */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef VPX_DECODER_H +#define VPX_DECODER_H +#include "vpx_codec.h" + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_DECODER_ABI_VERSION (2 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ + + /*! \brief Decoder capabilities bitfield + * + * Each decoder advertises the capabilities it supports as part of its + * ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces + * or functionality, and are not required to be supported by a decoder. + * + * The available flags are specified by VPX_CODEC_CAP_* defines. + */ +#define VPX_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */ +#define VPX_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */ +#define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */ +#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /**< Can conceal errors due to + packet loss */ +#define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 /**< Can receive encoded frames + one fragment at a time */ + + /*! \brief Initialization-time Feature Enabling + * + * Certain codec features must be known at initialization time, to allow for + * proper memory allocation. + * + * The available flags are specified by VPX_CODEC_USE_* defines. + */ +#define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */ +#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 /**< Conceal errors in decoded + frames */ +#define VPX_CODEC_USE_INPUT_FRAGMENTS 0x40000 /**< The input frame should be + passed to the decoder one + fragment at a time */ + + /*!\brief Stream properties + * + * This structure is used to query or set properties of the decoded + * stream. Algorithms may extend this structure with data specific + * to their bitstream by setting the sz member appropriately. + */ + typedef struct vpx_codec_stream_info + { + unsigned int sz; /**< Size of this structure */ + unsigned int w; /**< Width (or 0 for unknown/default) */ + unsigned int h; /**< Height (or 0 for unknown/default) */ + unsigned int is_kf; /**< Current frame is a keyframe */ + } vpx_codec_stream_info_t; + + /* REQUIRED FUNCTIONS + * + * The following functions are required to be implemented for all decoders. + * They represent the base case functionality expected of all decoders. + */ + + + /*!\brief Initialization Configurations + * + * This structure is used to pass init time configuration options to the + * decoder. + */ + typedef struct vpx_codec_dec_cfg + { + unsigned int threads; /**< Maximum number of threads to use, default 1 */ + unsigned int w; /**< Width */ + unsigned int h; /**< Height */ + } vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */ + + + /*!\brief Initialize a decoder instance + * + * Initializes a decoder context using the given interface. Applications + * should call the vpx_codec_dec_init convenience macro instead of this + * function directly, to ensure that the ABI version number parameter + * is properly initialized. + * + * In XMA mode (activated by setting VPX_CODEC_USE_XMA in the flags + * parameter), the storage pointed to by the cfg parameter must be + * kept readable and stable until all memory maps have been set. + * + * \param[in] ctx Pointer to this instance's context. + * \param[in] iface Pointer to the algorithm interface to use. + * \param[in] cfg Configuration to use, if known. May be NULL. + * \param[in] flags Bitfield of VPX_CODEC_USE_* flags + * \param[in] ver ABI version number. Must be set to + * VPX_DECODER_ABI_VERSION + * \retval #VPX_CODEC_OK + * The decoder algorithm initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory allocation failed. + */ + vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + vpx_codec_dec_cfg_t *cfg, + vpx_codec_flags_t flags, + int ver); + + /*!\brief Convenience macro for vpx_codec_dec_init_ver() + * + * Ensures the ABI version parameter is properly set. + */ +#define vpx_codec_dec_init(ctx, iface, cfg, flags) \ + vpx_codec_dec_init_ver(ctx, iface, cfg, flags, VPX_DECODER_ABI_VERSION) + + + /*!\brief Parse stream info from a buffer + * + * Performs high level parsing of the bitstream. Construction of a decoder + * context is not necessary. Can be used to determine if the bitstream is + * of the proper format, and to extract information from the stream. + * + * \param[in] iface Pointer to the algorithm interface + * \param[in] data Pointer to a block of data to parse + * \param[in] data_sz Size of the data buffer + * \param[in,out] si Pointer to stream info to update. The size member + * \ref MUST be properly initialized, but \ref MAY be + * clobbered by the algorithm. This parameter \ref MAY + * be NULL. + * + * \retval #VPX_CODEC_OK + * Bitstream is parsable and stream information updated + */ + vpx_codec_err_t vpx_codec_peek_stream_info(vpx_codec_iface_t *iface, + const uint8_t *data, + unsigned int data_sz, + vpx_codec_stream_info_t *si); + + + /*!\brief Return information about the current stream. + * + * Returns information about the stream that has been parsed during decoding. + * + * \param[in] ctx Pointer to this instance's context + * \param[in,out] si Pointer to stream info to update. The size member + * \ref MUST be properly initialized, but \ref MAY be + * clobbered by the algorithm. This parameter \ref MAY + * be NULL. + * + * \retval #VPX_CODEC_OK + * Bitstream is parsable and stream information updated + */ + vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx, + vpx_codec_stream_info_t *si); + + + /*!\brief Decode data + * + * Processes a buffer of coded data. If the processing results in a new + * decoded frame becoming available, PUT_SLICE and PUT_FRAME events may be + * generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode + * time stamp) order. Frames produced will always be in PTS (presentation + * time stamp) order. + * If the decoder is configured with VPX_CODEC_USE_INPUT_FRAGMENTS enabled, + * data and data_sz can contain a fragment of the encoded frame. Fragment + * \#n must contain at least partition \#n, but can also contain subsequent + * partitions (\#n+1 - \#n+i), and if so, fragments \#n+1, .., \#n+i must + * be empty. When no more data is available, this function should be called + * with NULL as data and 0 as data_sz. The memory passed to this function + * must be available until the frame has been decoded. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] data Pointer to this block of new coded data. If + * NULL, a VPX_CODEC_CB_PUT_FRAME event is posted + * for the previously decoded frame. + * \param[in] data_sz Size of the coded data, in bytes. + * \param[in] user_priv Application specific data to associate with + * this frame. + * \param[in] deadline Soft deadline the decoder should attempt to meet, + * in us. Set to zero for unlimited. + * + * \return Returns #VPX_CODEC_OK if the coded data was processed completely + * and future pictures can be decoded without error. Otherwise, + * see the descriptions of the other error codes in ::vpx_codec_err_t + * for recoverability capabilities. + */ + vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx, + const uint8_t *data, + unsigned int data_sz, + void *user_priv, + long deadline); + + + /*!\brief Decoded frames iterator + * + * Iterates over a list of the frames available for display. The iterator + * storage should be initialized to NULL to start the iteration. Iteration is + * complete when this function returns NULL. + * + * The list of available frames becomes valid upon completion of the + * vpx_codec_decode call, and remains valid until the next call to vpx_codec_decode. + * + * \param[in] ctx Pointer to this instance's context + * \param[in,out] iter Iterator storage, initialized to NULL + * + * \return Returns a pointer to an image, if one is ready for display. Frames + * produced will always be in PTS (presentation time stamp) order. + */ + vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx, + vpx_codec_iter_t *iter); + + + /*!\defgroup cap_put_frame Frame-Based Decoding Functions + * + * The following functions are required to be implemented for all decoders + * that advertise the VPX_CODEC_CAP_PUT_FRAME capability. Calling these functions + * for codecs that don't advertise this capability will result in an error + * code being returned, usually VPX_CODEC_ERROR + * @{ + */ + + /*!\brief put frame callback prototype + * + * This callback is invoked by the decoder to notify the application of + * the availability of decoded image data. + */ + typedef void (*vpx_codec_put_frame_cb_fn_t)(void *user_priv, + const vpx_image_t *img); + + + /*!\brief Register for notification of frame completion. + * + * Registers a given function to be called when a decoded frame is + * available. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] cb Pointer to the callback function + * \param[in] user_priv User's private data + * + * \retval #VPX_CODEC_OK + * Callback successfully registered. + * \retval #VPX_CODEC_ERROR + * Decoder context not initialized, or algorithm not capable of + * posting slice completion. + */ + vpx_codec_err_t vpx_codec_register_put_frame_cb(vpx_codec_ctx_t *ctx, + vpx_codec_put_frame_cb_fn_t cb, + void *user_priv); + + + /*!@} - end defgroup cap_put_frame */ + + /*!\defgroup cap_put_slice Slice-Based Decoding Functions + * + * The following functions are required to be implemented for all decoders + * that advertise the VPX_CODEC_CAP_PUT_SLICE capability. Calling these functions + * for codecs that don't advertise this capability will result in an error + * code being returned, usually VPX_CODEC_ERROR + * @{ + */ + + /*!\brief put slice callback prototype + * + * This callback is invoked by the decoder to notify the application of + * the availability of partially decoded image data. The + */ + typedef void (*vpx_codec_put_slice_cb_fn_t)(void *user_priv, + const vpx_image_t *img, + const vpx_image_rect_t *valid, + const vpx_image_rect_t *update); + + + /*!\brief Register for notification of slice completion. + * + * Registers a given function to be called when a decoded slice is + * available. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] cb Pointer to the callback function + * \param[in] user_priv User's private data + * + * \retval #VPX_CODEC_OK + * Callback successfully registered. + * \retval #VPX_CODEC_ERROR + * Decoder context not initialized, or algorithm not capable of + * posting slice completion. + */ + vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx, + vpx_codec_put_slice_cb_fn_t cb, + void *user_priv); + + + /*!@} - end defgroup cap_put_slice*/ + + /*!@} - end defgroup decoder*/ + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h new file mode 100644 index 0000000..239036e --- /dev/null +++ b/vpx/vpx_encoder.h @@ -0,0 +1,931 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup encoder Encoder Algorithm Interface + * \ingroup codec + * This abstraction allows applications using this encoder to easily support + * multiple video formats with minimal code duplication. This section describes + * the interface common to all encoders. + * @{ + */ + +/*!\file + * \brief Describes the encoder algorithm interface to applications. + * + * This file describes the interface between an application and a + * video encoder algorithm. + * + */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef VPX_ENCODER_H +#define VPX_ENCODER_H +#include "vpx_codec.h" + +/*! Temporal Scalability: Maximum length of the sequence defining frame + * layer membership + */ +#define VPX_TS_MAX_PERIODICITY 16 + +/*! Temporal Scalability: Maximum number of coding layers */ +#define VPX_TS_MAX_LAYERS 5 + +/*!\deprecated Use #VPX_TS_MAX_PERIODICITY instead. */ +#define MAX_PERIODICITY VPX_TS_MAX_PERIODICITY + +/*!\deprecated Use #VPX_TS_MAX_LAYERS instead. */ +#define MAX_LAYERS VPX_TS_MAX_LAYERS + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_ENCODER_ABI_VERSION (3 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ + + + /*! \brief Encoder capabilities bitfield + * + * Each encoder advertises the capabilities it supports as part of its + * ::vpx_codec_iface_t interface structure. Capabilities are extra + * interfaces or functionality, and are not required to be supported + * by an encoder. + * + * The available flags are specified by VPX_CODEC_CAP_* defines. + */ +#define VPX_CODEC_CAP_PSNR 0x10000 /**< Can issue PSNR packets */ + + /*! Can output one partition at a time. Each partition is returned in its + * own VPX_CODEC_CX_FRAME_PKT, with the FRAME_IS_FRAGMENT flag set for + * every partition but the last. In this mode all frames are always + * returned partition by partition. + */ +#define VPX_CODEC_CAP_OUTPUT_PARTITION 0x20000 + + + /*! \brief Initialization-time Feature Enabling + * + * Certain codec features must be known at initialization time, to allow + * for proper memory allocation. + * + * The available flags are specified by VPX_CODEC_USE_* defines. + */ +#define VPX_CODEC_USE_PSNR 0x10000 /**< Calculate PSNR on each frame */ +#define VPX_CODEC_USE_OUTPUT_PARTITION 0x20000 /**< Make the encoder output one + partition at a time. */ + + + /*!\brief Generic fixed size buffer structure + * + * This structure is able to hold a reference to any fixed size buffer. + */ + typedef struct vpx_fixed_buf + { + void *buf; /**< Pointer to the data */ + size_t sz; /**< Length of the buffer, in chars */ + } vpx_fixed_buf_t; /**< alias for struct vpx_fixed_buf */ + + + /*!\brief Time Stamp Type + * + * An integer, which when multiplied by the stream's time base, provides + * the absolute time of a sample. + */ + typedef int64_t vpx_codec_pts_t; + + + /*!\brief Compressed Frame Flags + * + * This type represents a bitfield containing information about a compressed + * frame that may be useful to an application. The most significant 16 bits + * can be used by an algorithm to provide additional detail, for example to + * support frame types that are codec specific (MPEG-1 D-frames for example) + */ + typedef uint32_t vpx_codec_frame_flags_t; +#define VPX_FRAME_IS_KEY 0x1 /**< frame is the start of a GOP */ +#define VPX_FRAME_IS_DROPPABLE 0x2 /**< frame can be dropped without affecting + the stream (no future frame depends on + this one) */ +#define VPX_FRAME_IS_INVISIBLE 0x4 /**< frame should be decoded but will not + be shown */ +#define VPX_FRAME_IS_FRAGMENT 0x8 /**< this is a fragment of the encoded + frame */ + + /*!\brief Error Resilient flags + * + * These flags define which error resilient features to enable in the + * encoder. The flags are specified through the + * vpx_codec_enc_cfg::g_error_resilient variable. + */ + typedef uint32_t vpx_codec_er_flags_t; +#define VPX_ERROR_RESILIENT_DEFAULT 0x1 /**< Improve resiliency against + losses of whole frames */ +#define VPX_ERROR_RESILIENT_PARTITIONS 0x2 /**< The frame partitions are + independently decodable by the + bool decoder, meaning that + partitions can be decoded even + though earlier partitions have + been lost. Note that intra + predicition is still done over + the partition boundary. */ + + /*!\brief Encoder output packet variants + * + * This enumeration lists the different kinds of data packets that can be + * returned by calls to vpx_codec_get_cx_data(). Algorithms \ref MAY + * extend this list to provide additional functionality. + */ + enum vpx_codec_cx_pkt_kind + { + VPX_CODEC_CX_FRAME_PKT, /**< Compressed video frame */ + VPX_CODEC_STATS_PKT, /**< Two-pass statistics for this frame */ + VPX_CODEC_PSNR_PKT, /**< PSNR statistics for this frame */ + VPX_CODEC_CUSTOM_PKT = 256 /**< Algorithm extensions */ + }; + + + /*!\brief Encoder output packet + * + * This structure contains the different kinds of output data the encoder + * may produce while compressing a frame. + */ + typedef struct vpx_codec_cx_pkt + { + enum vpx_codec_cx_pkt_kind kind; /**< packet variant */ + union + { + struct + { + void *buf; /**< compressed data buffer */ + size_t sz; /**< length of compressed data */ + vpx_codec_pts_t pts; /**< time stamp to show frame + (in timebase units) */ + unsigned long duration; /**< duration to show frame + (in timebase units) */ + vpx_codec_frame_flags_t flags; /**< flags for this frame */ + int partition_id; /**< the partition id + defines the decoding order + of the partitions. Only + applicable when "output partition" + mode is enabled. First partition + has id 0.*/ + + } frame; /**< data for compressed frame packet */ + struct vpx_fixed_buf twopass_stats; /**< data for two-pass packet */ + struct vpx_psnr_pkt + { + unsigned int samples[4]; /**< Number of samples, total/y/u/v */ + uint64_t sse[4]; /**< sum squared error, total/y/u/v */ + double psnr[4]; /**< PSNR, total/y/u/v */ + } psnr; /**< data for PSNR packet */ + struct vpx_fixed_buf raw; /**< data for arbitrary packets */ + + /* This packet size is fixed to allow codecs to extend this + * interface without having to manage storage for raw packets, + * i.e., if it's smaller than 128 bytes, you can store in the + * packet list directly. + */ + char pad[128 - sizeof(enum vpx_codec_cx_pkt_kind)]; /**< fixed sz */ + } data; /**< packet data */ + } vpx_codec_cx_pkt_t; /**< alias for struct vpx_codec_cx_pkt */ + + + /*!\brief Rational Number + * + * This structure holds a fractional value. + */ + typedef struct vpx_rational + { + int num; /**< fraction numerator */ + int den; /**< fraction denominator */ + } vpx_rational_t; /**< alias for struct vpx_rational */ + + + /*!\brief Multi-pass Encoding Pass */ + enum vpx_enc_pass + { + VPX_RC_ONE_PASS, /**< Single pass mode */ + VPX_RC_FIRST_PASS, /**< First pass of multi-pass mode */ + VPX_RC_LAST_PASS /**< Final pass of multi-pass mode */ + }; + + + /*!\brief Rate control mode */ + enum vpx_rc_mode + { + VPX_VBR, /**< Variable Bit Rate (VBR) mode */ + VPX_CBR, /**< Constant Bit Rate (CBR) mode */ + VPX_CQ /**< Constant Quality (CQ) mode */ + }; + + + /*!\brief Keyframe placement mode. + * + * This enumeration determines whether keyframes are placed automatically by + * the encoder or whether this behavior is disabled. Older releases of this + * SDK were implemented such that VPX_KF_FIXED meant keyframes were disabled. + * This name is confusing for this behavior, so the new symbols to be used + * are VPX_KF_AUTO and VPX_KF_DISABLED. + */ + enum vpx_kf_mode + { + VPX_KF_FIXED, /**< deprecated, implies VPX_KF_DISABLED */ + VPX_KF_AUTO, /**< Encoder determines optimal placement automatically */ + VPX_KF_DISABLED = 0 /**< Encoder does not place keyframes. */ + }; + + + /*!\brief Encoded Frame Flags + * + * This type indicates a bitfield to be passed to vpx_codec_encode(), defining + * per-frame boolean values. By convention, bits common to all codecs will be + * named VPX_EFLAG_*, and bits specific to an algorithm will be named + * /algo/_eflag_*. The lower order 16 bits are reserved for common use. + */ + typedef long vpx_enc_frame_flags_t; +#define VPX_EFLAG_FORCE_KF (1<<0) /**< Force this frame to be a keyframe */ + + + /*!\brief Encoder configuration structure + * + * This structure contains the encoder settings that have common representations + * across all codecs. This doesn't imply that all codecs support all features, + * however. + */ + typedef struct vpx_codec_enc_cfg + { + /* + * generic settings (g) + */ + + /*!\brief Algorithm specific "usage" value + * + * Algorithms may define multiple values for usage, which may convey the + * intent of how the application intends to use the stream. If this value + * is non-zero, consult the documentation for the codec to determine its + * meaning. + */ + unsigned int g_usage; + + + /*!\brief Maximum number of threads to use + * + * For multi-threaded implementations, use no more than this number of + * threads. The codec may use fewer threads than allowed. The value + * 0 is equivalent to the value 1. + */ + unsigned int g_threads; + + + /*!\brief Bitstream profile to use + * + * Some codecs support a notion of multiple bitstream profiles. Typically + * this maps to a set of features that are turned on or off. Often the + * profile to use is determined by the features of the intended decoder. + * Consult the documentation for the codec to determine the valid values + * for this parameter, or set to zero for a sane default. + */ + unsigned int g_profile; /**< profile of bitstream to use */ + + + + /*!\brief Width of the frame + * + * This value identifies the presentation resolution of the frame, + * in pixels. Note that the frames passed as input to the encoder must + * have this resolution. Frames will be presented by the decoder in this + * resolution, independent of any spatial resampling the encoder may do. + */ + unsigned int g_w; + + + /*!\brief Height of the frame + * + * This value identifies the presentation resolution of the frame, + * in pixels. Note that the frames passed as input to the encoder must + * have this resolution. Frames will be presented by the decoder in this + * resolution, independent of any spatial resampling the encoder may do. + */ + unsigned int g_h; + + + /*!\brief Stream timebase units + * + * Indicates the smallest interval of time, in seconds, used by the stream. + * For fixed frame rate material, or variable frame rate material where + * frames are timed at a multiple of a given clock (ex: video capture), + * the \ref RECOMMENDED method is to set the timebase to the reciprocal + * of the frame rate (ex: 1001/30000 for 29.970 Hz NTSC). This allows the + * pts to correspond to the frame number, which can be handy. For + * re-encoding video from containers with absolute time timestamps, the + * \ref RECOMMENDED method is to set the timebase to that of the parent + * container or multimedia framework (ex: 1/1000 for ms, as in FLV). + */ + struct vpx_rational g_timebase; + + + /*!\brief Enable error resilient modes. + * + * The error resilient bitfield indicates to the encoder which features + * it should enable to take measures for streaming over lossy or noisy + * links. + */ + vpx_codec_er_flags_t g_error_resilient; + + + /*!\brief Multi-pass Encoding Mode + * + * This value should be set to the current phase for multi-pass encoding. + * For single pass, set to #VPX_RC_ONE_PASS. + */ + enum vpx_enc_pass g_pass; + + + /*!\brief Allow lagged encoding + * + * If set, this value allows the encoder to consume a number of input + * frames before producing output frames. This allows the encoder to + * base decisions for the current frame on future frames. This does + * increase the latency of the encoding pipeline, so it is not appropriate + * in all situations (ex: realtime encoding). + * + * Note that this is a maximum value -- the encoder may produce frames + * sooner than the given limit. Set this value to 0 to disable this + * feature. + */ + unsigned int g_lag_in_frames; + + + /* + * rate control settings (rc) + */ + + /*!\brief Temporal resampling configuration, if supported by the codec. + * + * Temporal resampling allows the codec to "drop" frames as a strategy to + * meet its target data rate. This can cause temporal discontinuities in + * the encoded video, which may appear as stuttering during playback. This + * trade-off is often acceptable, but for many applications is not. It can + * be disabled in these cases. + * + * Note that not all codecs support this feature. All vpx VPx codecs do. + * For other codecs, consult the documentation for that algorithm. + * + * This threshold is described as a percentage of the target data buffer. + * When the data buffer falls below this percentage of fullness, a + * dropped frame is indicated. Set the threshold to zero (0) to disable + * this feature. + */ + unsigned int rc_dropframe_thresh; + + + /*!\brief Enable/disable spatial resampling, if supported by the codec. + * + * Spatial resampling allows the codec to compress a lower resolution + * version of the frame, which is then upscaled by the encoder to the + * correct presentation resolution. This increases visual quality at + * low data rates, at the expense of CPU time on the encoder/decoder. + */ + unsigned int rc_resize_allowed; + + + /*!\brief Spatial resampling up watermark. + * + * This threshold is described as a percentage of the target data buffer. + * When the data buffer rises above this percentage of fullness, the + * encoder will step up to a higher resolution version of the frame. + */ + unsigned int rc_resize_up_thresh; + + + /*!\brief Spatial resampling down watermark. + * + * This threshold is described as a percentage of the target data buffer. + * When the data buffer falls below this percentage of fullness, the + * encoder will step down to a lower resolution version of the frame. + */ + unsigned int rc_resize_down_thresh; + + + /*!\brief Rate control algorithm to use. + * + * Indicates whether the end usage of this stream is to be streamed over + * a bandwidth constrained link, indicating that Constant Bit Rate (CBR) + * mode should be used, or whether it will be played back on a high + * bandwidth link, as from a local disk, where higher variations in + * bitrate are acceptable. + */ + enum vpx_rc_mode rc_end_usage; + + + /*!\brief Two-pass stats buffer. + * + * A buffer containing all of the stats packets produced in the first + * pass, concatenated. + */ + struct vpx_fixed_buf rc_twopass_stats_in; + + + /*!\brief Target data rate + * + * Target bandwidth to use for this stream, in kilobits per second. + */ + unsigned int rc_target_bitrate; + + + /* + * quantizer settings + */ + + + /*!\brief Minimum (Best Quality) Quantizer + * + * The quantizer is the most direct control over the quality of the + * encoded image. The range of valid values for the quantizer is codec + * specific. Consult the documentation for the codec to determine the + * values to use. To determine the range programmatically, call + * vpx_codec_enc_config_default() with a usage value of 0. + */ + unsigned int rc_min_quantizer; + + + /*!\brief Maximum (Worst Quality) Quantizer + * + * The quantizer is the most direct control over the quality of the + * encoded image. The range of valid values for the quantizer is codec + * specific. Consult the documentation for the codec to determine the + * values to use. To determine the range programmatically, call + * vpx_codec_enc_config_default() with a usage value of 0. + */ + unsigned int rc_max_quantizer; + + + /* + * bitrate tolerance + */ + + + /*!\brief Rate control adaptation undershoot control + * + * This value, expressed as a percentage of the target bitrate, + * controls the maximum allowed adaptation speed of the codec. + * This factor controls the maximum amount of bits that can + * be subtracted from the target bitrate in order to compensate + * for prior overshoot. + * + * Valid values in the range 0-1000. + */ + unsigned int rc_undershoot_pct; + + + /*!\brief Rate control adaptation overshoot control + * + * This value, expressed as a percentage of the target bitrate, + * controls the maximum allowed adaptation speed of the codec. + * This factor controls the maximum amount of bits that can + * be added to the target bitrate in order to compensate for + * prior undershoot. + * + * Valid values in the range 0-1000. + */ + unsigned int rc_overshoot_pct; + + + /* + * decoder buffer model parameters + */ + + + /*!\brief Decoder Buffer Size + * + * This value indicates the amount of data that may be buffered by the + * decoding application. Note that this value is expressed in units of + * time (milliseconds). For example, a value of 5000 indicates that the + * client will buffer (at least) 5000ms worth of encoded data. Use the + * target bitrate (#rc_target_bitrate) to convert to bits/bytes, if + * necessary. + */ + unsigned int rc_buf_sz; + + + /*!\brief Decoder Buffer Initial Size + * + * This value indicates the amount of data that will be buffered by the + * decoding application prior to beginning playback. This value is + * expressed in units of time (milliseconds). Use the target bitrate + * (#rc_target_bitrate) to convert to bits/bytes, if necessary. + */ + unsigned int rc_buf_initial_sz; + + + /*!\brief Decoder Buffer Optimal Size + * + * This value indicates the amount of data that the encoder should try + * to maintain in the decoder's buffer. This value is expressed in units + * of time (milliseconds). Use the target bitrate (#rc_target_bitrate) + * to convert to bits/bytes, if necessary. + */ + unsigned int rc_buf_optimal_sz; + + + /* + * 2 pass rate control parameters + */ + + + /*!\brief Two-pass mode CBR/VBR bias + * + * Bias, expressed on a scale of 0 to 100, for determining target size + * for the current frame. The value 0 indicates the optimal CBR mode + * value should be used. The value 100 indicates the optimal VBR mode + * value should be used. Values in between indicate which way the + * encoder should "lean." + */ + unsigned int rc_2pass_vbr_bias_pct; /**< RC mode bias between CBR and VBR(0-100: 0->CBR, 100->VBR) */ + + + /*!\brief Two-pass mode per-GOP minimum bitrate + * + * This value, expressed as a percentage of the target bitrate, indicates + * the minimum bitrate to be used for a single GOP (aka "section") + */ + unsigned int rc_2pass_vbr_minsection_pct; + + + /*!\brief Two-pass mode per-GOP maximum bitrate + * + * This value, expressed as a percentage of the target bitrate, indicates + * the maximum bitrate to be used for a single GOP (aka "section") + */ + unsigned int rc_2pass_vbr_maxsection_pct; + + + /* + * keyframing settings (kf) + */ + + /*!\brief Keyframe placement mode + * + * This value indicates whether the encoder should place keyframes at a + * fixed interval, or determine the optimal placement automatically + * (as governed by the #kf_min_dist and #kf_max_dist parameters) + */ + enum vpx_kf_mode kf_mode; + + + /*!\brief Keyframe minimum interval + * + * This value, expressed as a number of frames, prevents the encoder from + * placing a keyframe nearer than kf_min_dist to the previous keyframe. At + * least kf_min_dist frames non-keyframes will be coded before the next + * keyframe. Set kf_min_dist equal to kf_max_dist for a fixed interval. + */ + unsigned int kf_min_dist; + + + /*!\brief Keyframe maximum interval + * + * This value, expressed as a number of frames, forces the encoder to code + * a keyframe if one has not been coded in the last kf_max_dist frames. + * A value of 0 implies all frames will be keyframes. Set kf_min_dist + * equal to kf_max_dist for a fixed interval. + */ + unsigned int kf_max_dist; + + /* + * Temporal scalability settings (ts) + */ + + /*!\brief Number of coding layers + * + * This value specifies the number of coding layers to be used. + */ + unsigned int ts_number_layers; + + /*!\brief Target bitrate for each layer + * + * These values specify the target coding bitrate for each coding layer. + */ + unsigned int ts_target_bitrate[VPX_TS_MAX_LAYERS]; + + /*!\brief Frame rate decimation factor for each layer + * + * These values specify the frame rate decimation factors to apply + * to each layer. + */ + unsigned int ts_rate_decimator[VPX_TS_MAX_LAYERS]; + + /*!\brief Length of the sequence defining frame layer membership + * + * This value specifies the length of the sequence that defines the + * membership of frames to layers. For example, if ts_periodicity=8 then + * frames are assigned to coding layers with a repeated sequence of + * length 8. + */ + unsigned int ts_periodicity; + + /*!\brief Template defining the membership of frames to coding layers + * + * This array defines the membership of frames to coding layers. For a + * 2-layer encoding that assigns even numbered frames to one layer (0) + * and odd numbered frames to a second layer (1) with ts_periodicity=8, + * then ts_layer_id = (0,1,0,1,0,1,0,1). + */ + unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY]; + } vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ + + + /*!\brief Initialize an encoder instance + * + * Initializes a encoder context using the given interface. Applications + * should call the vpx_codec_enc_init convenience macro instead of this + * function directly, to ensure that the ABI version number parameter + * is properly initialized. + * + * In XMA mode (activated by setting VPX_CODEC_USE_XMA in the flags + * parameter), the storage pointed to by the cfg parameter must be + * kept readable and stable until all memory maps have been set. + * + * \param[in] ctx Pointer to this instance's context. + * \param[in] iface Pointer to the algorithm interface to use. + * \param[in] cfg Configuration to use, if known. May be NULL. + * \param[in] flags Bitfield of VPX_CODEC_USE_* flags + * \param[in] ver ABI version number. Must be set to + * VPX_ENCODER_ABI_VERSION + * \retval #VPX_CODEC_OK + * The decoder algorithm initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory allocation failed. + */ + vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + vpx_codec_enc_cfg_t *cfg, + vpx_codec_flags_t flags, + int ver); + + + /*!\brief Convenience macro for vpx_codec_enc_init_ver() + * + * Ensures the ABI version parameter is properly set. + */ +#define vpx_codec_enc_init(ctx, iface, cfg, flags) \ + vpx_codec_enc_init_ver(ctx, iface, cfg, flags, VPX_ENCODER_ABI_VERSION) + + + /*!\brief Initialize multi-encoder instance + * + * Initializes multi-encoder context using the given interface. + * Applications should call the vpx_codec_enc_init_multi convenience macro + * instead of this function directly, to ensure that the ABI version number + * parameter is properly initialized. + * + * In XMA mode (activated by setting VPX_CODEC_USE_XMA in the flags + * parameter), the storage pointed to by the cfg parameter must be + * kept readable and stable until all memory maps have been set. + * + * \param[in] ctx Pointer to this instance's context. + * \param[in] iface Pointer to the algorithm interface to use. + * \param[in] cfg Configuration to use, if known. May be NULL. + * \param[in] num_enc Total number of encoders. + * \param[in] flags Bitfield of VPX_CODEC_USE_* flags + * \param[in] dsf Pointer to down-sampling factors. + * \param[in] ver ABI version number. Must be set to + * VPX_ENCODER_ABI_VERSION + * \retval #VPX_CODEC_OK + * The decoder algorithm initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory allocation failed. + */ + vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + vpx_codec_enc_cfg_t *cfg, + int num_enc, + vpx_codec_flags_t flags, + vpx_rational_t *dsf, + int ver); + + + /*!\brief Convenience macro for vpx_codec_enc_init_multi_ver() + * + * Ensures the ABI version parameter is properly set. + */ +#define vpx_codec_enc_init_multi(ctx, iface, cfg, num_enc, flags, dsf) \ + vpx_codec_enc_init_multi_ver(ctx, iface, cfg, num_enc, flags, dsf, \ + VPX_ENCODER_ABI_VERSION) + + + /*!\brief Get a default configuration + * + * Initializes a encoder configuration structure with default values. Supports + * the notion of "usages" so that an algorithm may offer different default + * settings depending on the user's intended goal. This function \ref SHOULD + * be called by all applications to initialize the configuration structure + * before specializing the configuration with application specific values. + * + * \param[in] iface Pointer to the algorithm interface to use. + * \param[out] cfg Configuration buffer to populate + * \param[in] usage End usage. Set to 0 or use codec specific values. + * + * \retval #VPX_CODEC_OK + * The configuration was populated. + * \retval #VPX_CODEC_INCAPABLE + * Interface is not an encoder interface. + * \retval #VPX_CODEC_INVALID_PARAM + * A parameter was NULL, or the usage value was not recognized. + */ + vpx_codec_err_t vpx_codec_enc_config_default(vpx_codec_iface_t *iface, + vpx_codec_enc_cfg_t *cfg, + unsigned int usage); + + + /*!\brief Set or change configuration + * + * Reconfigures an encoder instance according to the given configuration. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] cfg Configuration buffer to use + * + * \retval #VPX_CODEC_OK + * The configuration was populated. + * \retval #VPX_CODEC_INCAPABLE + * Interface is not an encoder interface. + * \retval #VPX_CODEC_INVALID_PARAM + * A parameter was NULL, or the usage value was not recognized. + */ + vpx_codec_err_t vpx_codec_enc_config_set(vpx_codec_ctx_t *ctx, + const vpx_codec_enc_cfg_t *cfg); + + + /*!\brief Get global stream headers + * + * Retrieves a stream level global header packet, if supported by the codec. + * + * \param[in] ctx Pointer to this instance's context + * + * \retval NULL + * Encoder does not support global header + * \retval Non-NULL + * Pointer to buffer containing global header packet + */ + vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t *ctx); + + +#define VPX_DL_REALTIME (1) /**< deadline parameter analogous to + * VPx REALTIME mode. */ +#define VPX_DL_GOOD_QUALITY (1000000) /**< deadline parameter analogous to + * VPx GOOD QUALITY mode. */ +#define VPX_DL_BEST_QUALITY (0) /**< deadline parameter analogous to + * VPx BEST QUALITY mode. */ + /*!\brief Encode a frame + * + * Encodes a video frame at the given "presentation time." The presentation + * time stamp (PTS) \ref MUST be strictly increasing. + * + * The encoder supports the notion of a soft real-time deadline. Given a + * non-zero value to the deadline parameter, the encoder will make a "best + * effort" guarantee to return before the given time slice expires. It is + * implicit that limiting the available time to encode will degrade the + * output quality. The encoder can be given an unlimited time to produce the + * best possible frame by specifying a deadline of '0'. This deadline + * supercedes the VPx notion of "best quality, good quality, realtime". + * Applications that wish to map these former settings to the new deadline + * based system can use the symbols #VPX_DL_REALTIME, #VPX_DL_GOOD_QUALITY, + * and #VPX_DL_BEST_QUALITY. + * + * When the last frame has been passed to the encoder, this function should + * continue to be called, with the img parameter set to NULL. This will + * signal the end-of-stream condition to the encoder and allow it to encode + * any held buffers. Encoding is complete when vpx_codec_encode() is called + * and vpx_codec_get_cx_data() returns no data. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] img Image data to encode, NULL to flush. + * \param[in] pts Presentation time stamp, in timebase units. + * \param[in] duration Duration to show frame, in timebase units. + * \param[in] flags Flags to use for encoding this frame. + * \param[in] deadline Time to spend encoding, in microseconds. (0=infinite) + * + * \retval #VPX_CODEC_OK + * The configuration was populated. + * \retval #VPX_CODEC_INCAPABLE + * Interface is not an encoder interface. + * \retval #VPX_CODEC_INVALID_PARAM + * A parameter was NULL, the image format is unsupported, etc. + */ + vpx_codec_err_t vpx_codec_encode(vpx_codec_ctx_t *ctx, + const vpx_image_t *img, + vpx_codec_pts_t pts, + unsigned long duration, + vpx_enc_frame_flags_t flags, + unsigned long deadline); + + /*!\brief Set compressed data output buffer + * + * Sets the buffer that the codec should output the compressed data + * into. This call effectively sets the buffer pointer returned in the + * next VPX_CODEC_CX_FRAME_PKT packet. Subsequent packets will be + * appended into this buffer. The buffer is preserved across frames, + * so applications must periodically call this function after flushing + * the accumulated compressed data to disk or to the network to reset + * the pointer to the buffer's head. + * + * `pad_before` bytes will be skipped before writing the compressed + * data, and `pad_after` bytes will be appended to the packet. The size + * of the packet will be the sum of the size of the actual compressed + * data, pad_before, and pad_after. The padding bytes will be preserved + * (not overwritten). + * + * Note that calling this function does not guarantee that the returned + * compressed data will be placed into the specified buffer. In the + * event that the encoded data will not fit into the buffer provided, + * the returned packet \ref MAY point to an internal buffer, as it would + * if this call were never used. In this event, the output packet will + * NOT have any padding, and the application must free space and copy it + * to the proper place. This is of particular note in configurations + * that may output multiple packets for a single encoded frame (e.g., lagged + * encoding) or if the application does not reset the buffer periodically. + * + * Applications may restore the default behavior of the codec providing + * the compressed data buffer by calling this function with a NULL + * buffer. + * + * Applications \ref MUSTNOT call this function during iteration of + * vpx_codec_get_cx_data(). + * + * \param[in] ctx Pointer to this instance's context + * \param[in] buf Buffer to store compressed data into + * \param[in] pad_before Bytes to skip before writing compressed data + * \param[in] pad_after Bytes to skip after writing compressed data + * + * \retval #VPX_CODEC_OK + * The buffer was set successfully. + * \retval #VPX_CODEC_INVALID_PARAM + * A parameter was NULL, the image format is unsupported, etc. + */ + vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t *ctx, + const vpx_fixed_buf_t *buf, + unsigned int pad_before, + unsigned int pad_after); + + + /*!\brief Encoded data iterator + * + * Iterates over a list of data packets to be passed from the encoder to the + * application. The different kinds of packets available are enumerated in + * #vpx_codec_cx_pkt_kind. + * + * #VPX_CODEC_CX_FRAME_PKT packets should be passed to the application's + * muxer. Multiple compressed frames may be in the list. + * #VPX_CODEC_STATS_PKT packets should be appended to a global buffer. + * + * The application \ref MUST silently ignore any packet kinds that it does + * not recognize or support. + * + * The data buffers returned from this function are only guaranteed to be + * valid until the application makes another call to any vpx_codec_* function. + * + * \param[in] ctx Pointer to this instance's context + * \param[in,out] iter Iterator storage, initialized to NULL + * + * \return Returns a pointer to an output data packet (compressed frame data, + * two-pass statistics, etc.) or NULL to signal end-of-list. + * + */ + const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t *ctx, + vpx_codec_iter_t *iter); + + + /*!\brief Get Preview Frame + * + * Returns an image that can be used as a preview. Shows the image as it would + * exist at the decompressor. The application \ref MUST NOT write into this + * image buffer. + * + * \param[in] ctx Pointer to this instance's context + * + * \return Returns a pointer to a preview image, or NULL if no image is + * available. + * + */ + const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t *ctx); + + + /*!@} - end defgroup encoder*/ + +#endif +#ifdef __cplusplus +} +#endif diff --git a/vpx/vpx_image.h b/vpx/vpx_image.h new file mode 100644 index 0000000..3e42447 --- /dev/null +++ b/vpx/vpx_image.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\file + * \brief Describes the vpx image descriptor and associated operations + * + */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef VPX_IMAGE_H +#define VPX_IMAGE_H + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_IMAGE_ABI_VERSION (1) /**<\hideinitializer*/ + + +#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format */ +#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U plane in memory */ +#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel component */ + + + /*!\brief List of supported image formats */ + typedef enum vpx_img_fmt { + VPX_IMG_FMT_NONE, + VPX_IMG_FMT_RGB24, /**< 24 bit per pixel packed RGB */ + VPX_IMG_FMT_RGB32, /**< 32 bit per pixel packed 0RGB */ + VPX_IMG_FMT_RGB565, /**< 16 bit per pixel, 565 */ + VPX_IMG_FMT_RGB555, /**< 16 bit per pixel, 555 */ + VPX_IMG_FMT_UYVY, /**< UYVY packed YUV */ + VPX_IMG_FMT_YUY2, /**< YUYV packed YUV */ + VPX_IMG_FMT_YVYU, /**< YVYU packed YUV */ + VPX_IMG_FMT_BGR24, /**< 24 bit per pixel packed BGR */ + VPX_IMG_FMT_RGB32_LE, /**< 32 bit packed BGR0 */ + VPX_IMG_FMT_ARGB, /**< 32 bit packed ARGB, alpha=255 */ + VPX_IMG_FMT_ARGB_LE, /**< 32 bit packed BGRA, alpha=255 */ + VPX_IMG_FMT_RGB565_LE, /**< 16 bit per pixel, gggbbbbb rrrrrggg */ + VPX_IMG_FMT_RGB555_LE, /**< 16 bit per pixel, gggbbbbb 0rrrrrgg */ + VPX_IMG_FMT_YV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1, /**< planar YVU */ + VPX_IMG_FMT_I420 = VPX_IMG_FMT_PLANAR | 2, + VPX_IMG_FMT_VPXYV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 3, /** < planar 4:2:0 format with vpx color space */ + VPX_IMG_FMT_VPXI420 = VPX_IMG_FMT_PLANAR | 4 /** < planar 4:2:0 format with vpx color space */ + } + vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */ + +#if !defined(VPX_CODEC_DISABLE_COMPAT) || !VPX_CODEC_DISABLE_COMPAT +#define IMG_FMT_PLANAR VPX_IMG_FMT_PLANAR /**< \deprecated Use #VPX_IMG_FMT_PLANAR */ +#define IMG_FMT_UV_FLIP VPX_IMG_FMT_UV_FLIP /**< \deprecated Use #VPX_IMG_FMT_UV_FLIP */ +#define IMG_FMT_HAS_ALPHA VPX_IMG_FMT_HAS_ALPHA /**< \deprecated Use #VPX_IMG_FMT_HAS_ALPHA */ + + /*!\brief Deprecated list of supported image formats + * \deprecated New code should use #vpx_img_fmt + */ +#define img_fmt vpx_img_fmt + /*!\brief alias for enum img_fmt. + * \deprecated New code should use #vpx_img_fmt_t + */ +#define img_fmt_t vpx_img_fmt_t + +#define IMG_FMT_NONE VPX_IMG_FMT_NONE /**< \deprecated Use #VPX_IMG_FMT_NONE */ +#define IMG_FMT_RGB24 VPX_IMG_FMT_RGB24 /**< \deprecated Use #VPX_IMG_FMT_RGB24 */ +#define IMG_FMT_RGB32 VPX_IMG_FMT_RGB32 /**< \deprecated Use #VPX_IMG_FMT_RGB32 */ +#define IMG_FMT_RGB565 VPX_IMG_FMT_RGB565 /**< \deprecated Use #VPX_IMG_FMT_RGB565 */ +#define IMG_FMT_RGB555 VPX_IMG_FMT_RGB555 /**< \deprecated Use #VPX_IMG_FMT_RGB555 */ +#define IMG_FMT_UYVY VPX_IMG_FMT_UYVY /**< \deprecated Use #VPX_IMG_FMT_UYVY */ +#define IMG_FMT_YUY2 VPX_IMG_FMT_YUY2 /**< \deprecated Use #VPX_IMG_FMT_YUY2 */ +#define IMG_FMT_YVYU VPX_IMG_FMT_YVYU /**< \deprecated Use #VPX_IMG_FMT_YVYU */ +#define IMG_FMT_BGR24 VPX_IMG_FMT_BGR24 /**< \deprecated Use #VPX_IMG_FMT_BGR24 */ +#define IMG_FMT_RGB32_LE VPX_IMG_FMT_RGB32_LE /**< \deprecated Use #VPX_IMG_FMT_RGB32_LE */ +#define IMG_FMT_ARGB VPX_IMG_FMT_ARGB /**< \deprecated Use #VPX_IMG_FMT_ARGB */ +#define IMG_FMT_ARGB_LE VPX_IMG_FMT_ARGB_LE /**< \deprecated Use #VPX_IMG_FMT_ARGB_LE */ +#define IMG_FMT_RGB565_LE VPX_IMG_FMT_RGB565_LE /**< \deprecated Use #VPX_IMG_FMT_RGB565_LE */ +#define IMG_FMT_RGB555_LE VPX_IMG_FMT_RGB555_LE /**< \deprecated Use #VPX_IMG_FMT_RGB555_LE */ +#define IMG_FMT_YV12 VPX_IMG_FMT_YV12 /**< \deprecated Use #VPX_IMG_FMT_YV12 */ +#define IMG_FMT_I420 VPX_IMG_FMT_I420 /**< \deprecated Use #VPX_IMG_FMT_I420 */ +#define IMG_FMT_VPXYV12 VPX_IMG_FMT_VPXYV12 /**< \deprecated Use #VPX_IMG_FMT_VPXYV12 */ +#define IMG_FMT_VPXI420 VPX_IMG_FMT_VPXI420 /**< \deprecated Use #VPX_IMG_FMT_VPXI420 */ +#endif /* VPX_CODEC_DISABLE_COMPAT */ + + /**\brief Image Descriptor */ + typedef struct vpx_image + { + vpx_img_fmt_t fmt; /**< Image Format */ + + /* Image storage dimensions */ + unsigned int w; /**< Stored image width */ + unsigned int h; /**< Stored image height */ + + /* Image display dimensions */ + unsigned int d_w; /**< Displayed image width */ + unsigned int d_h; /**< Displayed image height */ + + /* Chroma subsampling info */ + unsigned int x_chroma_shift; /**< subsampling order, X */ + unsigned int y_chroma_shift; /**< subsampling order, Y */ + + /* Image data pointers. */ +#define VPX_PLANE_PACKED 0 /**< To be used for all packed formats */ +#define VPX_PLANE_Y 0 /**< Y (Luminance) plane */ +#define VPX_PLANE_U 1 /**< U (Chroma) plane */ +#define VPX_PLANE_V 2 /**< V (Chroma) plane */ +#define VPX_PLANE_ALPHA 3 /**< A (Transparency) plane */ +#if !defined(VPX_CODEC_DISABLE_COMPAT) || !VPX_CODEC_DISABLE_COMPAT +#define PLANE_PACKED VPX_PLANE_PACKED +#define PLANE_Y VPX_PLANE_Y +#define PLANE_U VPX_PLANE_U +#define PLANE_V VPX_PLANE_V +#define PLANE_ALPHA VPX_PLANE_ALPHA +#endif + unsigned char *planes[4]; /**< pointer to the top left pixel for each plane */ + int stride[4]; /**< stride between rows for each plane */ + + int bps; /**< bits per sample (for packed formats) */ + + /* The following member may be set by the application to associate data + * with this image. + */ + void *user_priv; /**< may be set by the application to associate data + * with this image. */ + + /* The following members should be treated as private. */ + unsigned char *img_data; /**< private */ + int img_data_owner; /**< private */ + int self_allocd; /**< private */ + } vpx_image_t; /**< alias for struct vpx_image */ + + /**\brief Representation of a rectangle on a surface */ + typedef struct vpx_image_rect + { + unsigned int x; /**< leftmost column */ + unsigned int y; /**< topmost row */ + unsigned int w; /**< width */ + unsigned int h; /**< height */ + } vpx_image_rect_t; /**< alias for struct vpx_image_rect */ + + /*!\brief Open a descriptor, allocating storage for the underlying image + * + * Returns a descriptor for storing an image of the given format. The + * storage for the descriptor is allocated on the heap. + * + * \param[in] img Pointer to storage for descriptor. If this parameter + * is NULL, the storage for the descriptor will be + * allocated on the heap. + * \param[in] fmt Format for the image + * \param[in] d_w Width of the image + * \param[in] d_h Height of the image + * \param[in] align Alignment, in bytes, of the image buffer and + * each row in the image(stride). + * + * \return Returns a pointer to the initialized image descriptor. If the img + * parameter is non-null, the value of the img parameter will be + * returned. + */ + vpx_image_t *vpx_img_alloc(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int align); + + /*!\brief Open a descriptor, using existing storage for the underlying image + * + * Returns a descriptor for storing an image of the given format. The + * storage for descriptor has been allocated elsewhere, and a descriptor is + * desired to "wrap" that storage. + * + * \param[in] img Pointer to storage for descriptor. If this parameter + * is NULL, the storage for the descriptor will be + * allocated on the heap. + * \param[in] fmt Format for the image + * \param[in] d_w Width of the image + * \param[in] d_h Height of the image + * \param[in] align Alignment, in bytes, of each row in the image. + * \param[in] img_data Storage to use for the image + * + * \return Returns a pointer to the initialized image descriptor. If the img + * parameter is non-null, the value of the img parameter will be + * returned. + */ + vpx_image_t *vpx_img_wrap(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int align, + unsigned char *img_data); + + + /*!\brief Set the rectangle identifying the displayed portion of the image + * + * Updates the displayed rectangle (aka viewport) on the image surface to + * match the specified coordinates and size. + * + * \param[in] img Image descriptor + * \param[in] x leftmost column + * \param[in] y topmost row + * \param[in] w width + * \param[in] h height + * + * \return 0 if the requested rectangle is valid, nonzero otherwise. + */ + int vpx_img_set_rect(vpx_image_t *img, + unsigned int x, + unsigned int y, + unsigned int w, + unsigned int h); + + + /*!\brief Flip the image vertically (top for bottom) + * + * Adjusts the image descriptor's pointers and strides to make the image + * be referenced upside-down. + * + * \param[in] img Image descriptor + */ + void vpx_img_flip(vpx_image_t *img); + + /*!\brief Close an image descriptor + * + * Frees all allocated storage associated with an image descriptor. + * + * \param[in] img Image descriptor + */ + void vpx_img_free(vpx_image_t *img); + +#endif +#ifdef __cplusplus +} +#endif diff --git a/vpx/vpx_integer.h b/vpx/vpx_integer.h new file mode 100644 index 0000000..218bca7 --- /dev/null +++ b/vpx/vpx_integer.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_INTEGER_H +#define VPX_INTEGER_H + +/* get ptrdiff_t, size_t, wchar_t, NULL */ +#include + +#if (defined(_MSC_VER) && (_MSC_VER < 1600)) || defined(VPX_EMULATE_INTTYPES) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#if (defined(_MSC_VER) && (_MSC_VER < 1600)) +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#endif + +#ifndef _UINTPTR_T_DEFINED +typedef size_t uintptr_t; +#endif + +#else + +/* Most platforms have the C99 standard integer types. */ + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS +#endif +#include + +#endif + +/* VS2010 defines stdint.h, but not inttypes.h */ +#if defined(_MSC_VER) +#define PRId64 "I64d" +#else +#include +#endif + +#endif diff --git a/vpx_mem/include/vpx_mem_intrnl.h b/vpx_mem/include/vpx_mem_intrnl.h new file mode 100644 index 0000000..63c6b77 --- /dev/null +++ b/vpx_mem/include/vpx_mem_intrnl.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __VPX_MEM_INTRNL_H__ +#define __VPX_MEM_INTRNL_H__ +#include "vpx_config.h" + +#ifndef CONFIG_MEM_MANAGER +# if defined(VXWORKS) +# define CONFIG_MEM_MANAGER 1 /*include heap manager functionality,*/ +/*default: enabled on vxworks*/ +# else +# define CONFIG_MEM_MANAGER 0 /*include heap manager functionality*/ +# endif +#endif /*CONFIG_MEM_MANAGER*/ + +#ifndef CONFIG_MEM_TRACKER +# define CONFIG_MEM_TRACKER 1 /*include xvpx_* calls in the lib*/ +#endif + +#ifndef CONFIG_MEM_CHECKS +# define CONFIG_MEM_CHECKS 0 /*include some basic safety checks in +vpx_memcpy, _memset, and _memmove*/ +#endif + +#ifndef USE_GLOBAL_FUNCTION_POINTERS +# define USE_GLOBAL_FUNCTION_POINTERS 0 /*use function pointers instead of compiled functions.*/ +#endif + +#if CONFIG_MEM_TRACKER +# include "vpx_mem_tracker.h" +# if VPX_MEM_TRACKER_VERSION_CHIEF != 2 || VPX_MEM_TRACKER_VERSION_MAJOR != 5 +# error "vpx_mem requires memory tracker version 2.5 to track memory usage" +# endif +#endif + +#define ADDRESS_STORAGE_SIZE sizeof(size_t) + +#ifndef DEFAULT_ALIGNMENT +# if defined(VXWORKS) +# define DEFAULT_ALIGNMENT 32 /*default addr alignment to use in + calls to vpx_* functions other + than vpx_memalign*/ +# else +# define DEFAULT_ALIGNMENT 1 +# endif +#endif + +#if DEFAULT_ALIGNMENT < 1 +# error "DEFAULT_ALIGNMENT must be >= 1!" +#endif + +#if CONFIG_MEM_TRACKER +# define TRY_BOUNDS_CHECK 1 /*when set to 1 pads each allocation, + integrity can be checked using + vpx_memory_tracker_check_integrity + or on free by defining*/ +/*TRY_BOUNDS_CHECK_ON_FREE*/ +#else +# define TRY_BOUNDS_CHECK 0 +#endif /*CONFIG_MEM_TRACKER*/ + +#if TRY_BOUNDS_CHECK +# define TRY_BOUNDS_CHECK_ON_FREE 0 /*checks mem integrity on every + free, very expensive*/ +# define BOUNDS_CHECK_VALUE 0xdeadbeef /*value stored before/after ea. + mem addr for bounds checking*/ +# define BOUNDS_CHECK_PAD_SIZE 32 /*size of the padding before and + after ea allocation to be filled + with BOUNDS_CHECK_VALUE. + this should be a multiple of 4*/ +#else +# define BOUNDS_CHECK_VALUE 0 +# define BOUNDS_CHECK_PAD_SIZE 0 +#endif /*TRY_BOUNDS_CHECK*/ + +#ifndef REMOVE_PRINTFS +# define REMOVE_PRINTFS 0 +#endif + +/* Should probably use a vpx_mem logger function. */ +#if REMOVE_PRINTFS +# define _P(x) +#else +# define _P(x) x +#endif + +/*returns an addr aligned to the byte boundary specified by align*/ +#define align_addr(addr,align) (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align)) + +#endif /*__VPX_MEM_INTRNL_H__*/ diff --git a/vpx_mem/include/vpx_mem_tracker.h b/vpx_mem/include/vpx_mem_tracker.h new file mode 100644 index 0000000..ef2b29b --- /dev/null +++ b/vpx_mem/include/vpx_mem_tracker.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __VPX_MEM_TRACKER_H__ +#define __VPX_MEM_TRACKER_H__ + +/* vpx_mem_tracker version info */ +#define vpx_mem_tracker_version "2.5.1.1" + +#define VPX_MEM_TRACKER_VERSION_CHIEF 2 +#define VPX_MEM_TRACKER_VERSION_MAJOR 5 +#define VPX_MEM_TRACKER_VERSION_MINOR 1 +#define VPX_MEM_TRACKER_VERSION_PATCH 1 +/* END - vpx_mem_tracker version info */ + +#include + +struct mem_block +{ + size_t addr; + unsigned int size, + line; + char *file; + struct mem_block *prev, + * next; + + int padded; // This mem_block has padding for integrity checks. + // As of right now, this should only be 0 if + // using vpx_mem_alloc to allocate cache memory. + // 2005-01-11 tjf +}; + +#if defined(__cplusplus) +extern "C" { +#endif + + /* + vpx_memory_tracker_init(int padding_size, int pad_value) + padding_size - the size of the padding before and after each mem addr. + Values > 0 indicate that integrity checks can be performed + by inspecting these areas. + pad_value - the initial value within the padding area before and after + each mem addr. + + Initializes the memory tracker interface. Should be called before any + other calls to the memory tracker. + */ + int vpx_memory_tracker_init(int padding_size, int pad_value); + + /* + vpx_memory_tracker_destroy() + Deinitializes the memory tracker interface + */ + void vpx_memory_tracker_destroy(); + + /* + vpx_memory_tracker_add(size_t addr, unsigned int size, + char * file, unsigned int line) + addr - memory address to be added to list + size - size of addr + file - the file addr was referenced from + line - the line in file addr was referenced from + Adds memory address addr, it's size, file and line it came from + to the memory tracker allocation table + */ + void vpx_memory_tracker_add(size_t addr, unsigned int size, + char *file, unsigned int line, + int padded); + + /* + vpx_memory_tracker_add(size_t addr, unsigned int size, char * file, unsigned int line) + addr - memory address to be added to be removed + padded - if 0, disables bounds checking on this memory block even if bounds + checking is enabled. (for example, when allocating cache memory, we still want + to check for memory leaks, but we do not waste cache space for bounds check padding) + Removes the specified address from the memory tracker's allocation + table + Return: + 0: on success + -1: if memory allocation table's mutex could not be locked + -2: if the addr was not found in the list + */ + int vpx_memory_tracker_remove(size_t addr); + + /* + vpx_memory_tracker_find(unsigned int addr) + addr - address to be found in the memory tracker's + allocation table + Return: + If found, pointer to the memory block that matches addr + NULL otherwise + */ + struct mem_block *vpx_memory_tracker_find(size_t addr); + + /* + vpx_memory_tracker_dump() + Dumps the current contents of the memory + tracker allocation table + */ + void vpx_memory_tracker_dump(); + + /* + vpx_memory_tracker_check_integrity() + If a padding_size was provided to vpx_memory_tracker_init() + This function will verify that the region before and after each + memory address contains the specified pad_value. Should the check + fail, the filename and line of the check will be printed out. + */ + void vpx_memory_tracker_check_integrity(char *file, unsigned int line); + + /* + vpx_memory_tracker_set_log_type + type - value representing the logging type to use + option - type specific option. This will be interpreted differently + based on the type. + Sets the logging type for the memory tracker. + Values currently supported: + 0: if option is NULL, log to stderr, otherwise interpret option as a + filename and attempt to open it. + 1: Use output_debug_string (WIN32 only), option ignored + Return: + 0: on success + -1: if the logging type could not be set, because the value was invalid + or because a file could not be opened + */ + int vpx_memory_tracker_set_log_type(int type, char *option); + + /* + vpx_memory_tracker_set_log_func + userdata - ptr to be passed to the supplied logfunc, can be NULL + logfunc - the logging function to be used to output data from + vpx_memory_track_dump/check_integrity + Sets a logging function to be used by the memory tracker. + Return: + 0: on success + -1: if the logging type could not be set because logfunc was NULL + */ + int vpx_memory_tracker_set_log_func(void *userdata, + void(*logfunc)(void *userdata, + const char *fmt, va_list args)); + + /* Wrappers to standard library functions. */ + typedef void*(* mem_track_malloc_func)(size_t); + typedef void*(* mem_track_calloc_func)(size_t, size_t); + typedef void*(* mem_track_realloc_func)(void *, size_t); + typedef void (* mem_track_free_func)(void *); + typedef void*(* mem_track_memcpy_func)(void *, const void *, size_t); + typedef void*(* mem_track_memset_func)(void *, int, size_t); + typedef void*(* mem_track_memmove_func)(void *, const void *, size_t); + + /* + vpx_memory_tracker_set_functions + + Sets the function pointers for the standard library functions. + + Return: + 0: on success + -1: if the use global function pointers is not set. + */ + int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l + , mem_track_calloc_func g_calloc_l + , mem_track_realloc_func g_realloc_l + , mem_track_free_func g_free_l + , mem_track_memcpy_func g_memcpy_l + , mem_track_memset_func g_memset_l + , mem_track_memmove_func g_memmove_l); + +#if defined(__cplusplus) +} +#endif + +#endif //__VPX_MEM_TRACKER_H__ diff --git a/vpx_mem/memory_manager/hmm_alloc.c b/vpx_mem/memory_manager/hmm_alloc.c new file mode 100644 index 0000000..22c4a54 --- /dev/null +++ b/vpx_mem/memory_manager/hmm_alloc.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +void *U(alloc)(U(descriptor) *desc, U(size_aau) n) +{ +#ifdef HMM_AUDIT_FAIL + + if (desc->avl_tree_root) + AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root)) +#endif + + if (desc->last_freed) + { +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(desc->last_freed) +#endif + + U(into_free_collection)(desc, (head_record *)(desc->last_freed)); + + desc->last_freed = 0; + } + + /* Add space for block header. */ + n += HEAD_AAUS; + + /* Convert n from number of address alignment units to block alignment + ** units. */ + n = DIV_ROUND_UP(n, HMM_BLOCK_ALIGN_UNIT); + + if (n < MIN_BLOCK_BAUS) + n = MIN_BLOCK_BAUS; + + { + /* Search for the first node of the bin containing the smallest + ** block big enough to satisfy request. */ + ptr_record *ptr_rec_ptr = + U(avl_search)( + (U(avl_avl) *) & (desc->avl_tree_root), (U(size_bau)) n, + AVL_GREATER_EQUAL); + + /* If an approprate bin is found, satisfy the allocation request, + ** otherwise return null pointer. */ + return(ptr_rec_ptr ? + U(alloc_from_bin)(desc, ptr_rec_ptr, (U(size_bau)) n) : 0); + } +} diff --git a/vpx_mem/memory_manager/hmm_base.c b/vpx_mem/memory_manager/hmm_base.c new file mode 100644 index 0000000..ad1da03 --- /dev/null +++ b/vpx_mem/memory_manager/hmm_base.c @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +void U(init)(U(descriptor) *desc) +{ + desc->avl_tree_root = 0; + desc->last_freed = 0; +} + +/* Remove a free block from a bin's doubly-linked list when it is not, +** the first block in the bin. +*/ +void U(dll_remove)( + /* Pointer to pointer record in the block to be removed. */ + ptr_record *to_remove) +{ + to_remove->prev->next = to_remove->next; + + if (to_remove->next) + to_remove->next->prev = to_remove->prev; +} + +/* Put a block into the free collection of a heap. +*/ +void U(into_free_collection)( + /* Pointer to heap descriptor. */ + U(descriptor) *desc, + /* Pointer to head record of block. */ + head_record *head_ptr) +{ + ptr_record *ptr_rec_ptr = HEAD_TO_PTR_REC(head_ptr); + + ptr_record *bin_front_ptr = + U(avl_insert)((U(avl_avl) *) & (desc->avl_tree_root), ptr_rec_ptr); + + if (bin_front_ptr != ptr_rec_ptr) + { + /* The block was not inserted into the AVL tree because there is + ** already a bin for the size of the block. */ + + MARK_SUCCESSIVE_BLOCK_IN_FREE_BIN(head_ptr) + ptr_rec_ptr->self = ptr_rec_ptr; + + /* Make the block the new second block in the bin's doubly-linked + ** list. */ + ptr_rec_ptr->prev = bin_front_ptr; + ptr_rec_ptr->next = bin_front_ptr->next; + bin_front_ptr->next = ptr_rec_ptr; + + if (ptr_rec_ptr->next) + ptr_rec_ptr->next->prev = ptr_rec_ptr; + } + else + /* Block is first block in new bin. */ + ptr_rec_ptr->next = 0; +} + +/* Allocate a block from a given bin. Returns a pointer to the payload +** of the removed block. The "last freed" pointer must be null prior +** to calling this function. +*/ +void *U(alloc_from_bin)( + /* Pointer to heap descriptor. */ + U(descriptor) *desc, + /* Pointer to pointer record of first block in bin. */ + ptr_record *bin_front_ptr, + /* Number of BAUs needed in the allocated block. If the block taken + ** from the bin is significantly larger than the number of BAUs needed, + ** the "extra" BAUs are split off to form a new free block. */ + U(size_bau) n_baus) +{ + head_record *head_ptr; + U(size_bau) rem_baus; + + if (bin_front_ptr->next) + { + /* There are multiple blocks in this bin. Use the 2nd block in + ** the bin to avoid needless change to the AVL tree. + */ + + ptr_record *ptr_rec_ptr = bin_front_ptr->next; + head_ptr = PTR_REC_TO_HEAD(ptr_rec_ptr); + +#ifdef AUDIT_FAIL + AUDIT_BLOCK(head_ptr) +#endif + + U(dll_remove)(ptr_rec_ptr); + } + else + { + /* There is only one block in the bin, so it has to be removed + ** from the AVL tree. + */ + + head_ptr = PTR_REC_TO_HEAD(bin_front_ptr); + + U(avl_remove)( + (U(avl_avl) *) &(desc->avl_tree_root), BLOCK_BAUS(head_ptr)); + } + + MARK_BLOCK_ALLOCATED(head_ptr) + + rem_baus = BLOCK_BAUS(head_ptr) - n_baus; + + if (rem_baus >= MIN_BLOCK_BAUS) + { + /* Since there are enough "extra" BAUs, split them off to form + ** a new free block. + */ + + head_record *rem_head_ptr = + (head_record *) BAUS_FORWARD(head_ptr, n_baus); + + /* Change the next block's header to reflect the fact that the + ** block preceeding it is now smaller. + */ + SET_PREV_BLOCK_BAUS( + BAUS_FORWARD(head_ptr, head_ptr->block_size), rem_baus) + + head_ptr->block_size = n_baus; + + rem_head_ptr->previous_block_size = n_baus; + rem_head_ptr->block_size = rem_baus; + + desc->last_freed = rem_head_ptr; + } + + return(HEAD_TO_PTR_REC(head_ptr)); +} + +/* Take a block out of the free collection. +*/ +void U(out_of_free_collection)( + /* Descriptor of heap that block is in. */ + U(descriptor) *desc, + /* Pointer to head of block to take out of free collection. */ + head_record *head_ptr) +{ + ptr_record *ptr_rec_ptr = HEAD_TO_PTR_REC(head_ptr); + + if (ptr_rec_ptr->self == ptr_rec_ptr) + /* Block is not the front block in its bin, so all we have to + ** do is take it out of the bin's doubly-linked list. */ + U(dll_remove)(ptr_rec_ptr); + else + { + ptr_record *next = ptr_rec_ptr->next; + + if (next) + /* Block is the front block in its bin, and there is at least + ** one other block in the bin. Substitute the next block for + ** the front block. */ + U(avl_subst)((U(avl_avl) *) &(desc->avl_tree_root), next); + else + /* Block is the front block in its bin, but there is no other + ** block in the bin. Eliminate the bin. */ + U(avl_remove)( + (U(avl_avl) *) &(desc->avl_tree_root), BLOCK_BAUS(head_ptr)); + } +} + +void U(free)(U(descriptor) *desc, void *payload_ptr) +{ + /* Flags if coalesce with adjacent block. */ + int coalesce; + + head_record *fwd_head_ptr; + head_record *free_head_ptr = PTR_REC_TO_HEAD(payload_ptr); + + desc->num_baus_can_shrink = 0; + +#ifdef HMM_AUDIT_FAIL + + AUDIT_BLOCK(free_head_ptr) + + /* Make sure not freeing an already free block. */ + if (!IS_BLOCK_ALLOCATED(free_head_ptr)) + HMM_AUDIT_FAIL + + if (desc->avl_tree_root) + /* Audit root block in AVL tree. */ + AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root)) + +#endif + + fwd_head_ptr = + (head_record *) BAUS_FORWARD(free_head_ptr, free_head_ptr->block_size); + + if (free_head_ptr->previous_block_size) + { + /* Coalesce with backward block if possible. */ + + head_record *bkwd_head_ptr = + (head_record *) BAUS_BACKWARD( + free_head_ptr, free_head_ptr->previous_block_size); + +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(bkwd_head_ptr) +#endif + + if (bkwd_head_ptr == (head_record *)(desc->last_freed)) + { + desc->last_freed = 0; + coalesce = 1; + } + else if (IS_BLOCK_ALLOCATED(bkwd_head_ptr)) + coalesce = 0; + else + { + U(out_of_free_collection)(desc, bkwd_head_ptr); + coalesce = 1; + } + + if (coalesce) + { + bkwd_head_ptr->block_size += free_head_ptr->block_size; + SET_PREV_BLOCK_BAUS(fwd_head_ptr, BLOCK_BAUS(bkwd_head_ptr)) + free_head_ptr = bkwd_head_ptr; + } + } + + if (fwd_head_ptr->block_size == 0) + { + /* Block to be freed is last block before dummy end-of-chunk block. */ + desc->end_of_shrinkable_chunk = + BAUS_FORWARD(fwd_head_ptr, DUMMY_END_BLOCK_BAUS); + desc->num_baus_can_shrink = BLOCK_BAUS(free_head_ptr); + + if (PREV_BLOCK_BAUS(free_head_ptr) == 0) + /* Free block is the entire chunk, so shrinking can eliminate + ** entire chunk including dummy end block. */ + desc->num_baus_can_shrink += DUMMY_END_BLOCK_BAUS; + } + else + { + /* Coalesce with forward block if possible. */ + +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(fwd_head_ptr) +#endif + + if (fwd_head_ptr == (head_record *)(desc->last_freed)) + { + desc->last_freed = 0; + coalesce = 1; + } + else if (IS_BLOCK_ALLOCATED(fwd_head_ptr)) + coalesce = 0; + else + { + U(out_of_free_collection)(desc, fwd_head_ptr); + coalesce = 1; + } + + if (coalesce) + { + free_head_ptr->block_size += fwd_head_ptr->block_size; + + fwd_head_ptr = + (head_record *) BAUS_FORWARD( + fwd_head_ptr, BLOCK_BAUS(fwd_head_ptr)); + + SET_PREV_BLOCK_BAUS(fwd_head_ptr, BLOCK_BAUS(free_head_ptr)) + + if (fwd_head_ptr->block_size == 0) + { + /* Coalesced block to be freed is last block before dummy + ** end-of-chunk block. */ + desc->end_of_shrinkable_chunk = + BAUS_FORWARD(fwd_head_ptr, DUMMY_END_BLOCK_BAUS); + desc->num_baus_can_shrink = BLOCK_BAUS(free_head_ptr); + + if (PREV_BLOCK_BAUS(free_head_ptr) == 0) + /* Free block is the entire chunk, so shrinking can + ** eliminate entire chunk including dummy end block. */ + desc->num_baus_can_shrink += DUMMY_END_BLOCK_BAUS; + } + } + } + + if (desc->last_freed) + { + /* There is a last freed block, but it is not adjacent to the + ** block being freed by this call to free, so put the last + ** freed block into the free collection. + */ + +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(desc->last_freed) +#endif + + U(into_free_collection)(desc, (head_record *)(desc->last_freed)); + } + + desc->last_freed = free_head_ptr; +} + +void U(new_chunk)(U(descriptor) *desc, void *start, U(size_bau) n_baus) +{ +#ifdef HMM_AUDIT_FAIL + + if (desc->avl_tree_root) + /* Audit root block in AVL tree. */ + AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root)) +#endif + +#undef HEAD_PTR +#define HEAD_PTR ((head_record *) start) + + /* Make the chunk one big free block followed by a dummy end block. + */ + + n_baus -= DUMMY_END_BLOCK_BAUS; + + HEAD_PTR->previous_block_size = 0; + HEAD_PTR->block_size = n_baus; + + U(into_free_collection)(desc, HEAD_PTR); + + /* Set up the dummy end block. */ + start = BAUS_FORWARD(start, n_baus); + HEAD_PTR->previous_block_size = n_baus; + HEAD_PTR->block_size = 0; + +#undef HEAD_PTR +} + +#ifdef HMM_AUDIT_FAIL + +/* Function that does audit fail actions defined my preprocessor symbol, +** and returns a dummy integer value. +*/ +int U(audit_block_fail_dummy_return)(void) +{ + HMM_AUDIT_FAIL + + /* Dummy return. */ + return(0); +} + +#endif + +/* AVL Tree instantiation. */ + +#ifdef HMM_AUDIT_FAIL + +/* The AVL tree generic package passes an ACCESS of 1 when it "touches" +** a child node for the first time during a particular operation. I use +** this feature to audit only one time (per operation) the free blocks +** that are tree nodes. Since the root node is not a child node, it has +** to be audited directly. +*/ + +/* The pain you feel while reading these macros will not be in vain. It +** will remove all doubt from you mind that C++ inline functions are +** a very good thing. +*/ + +#define AVL_GET_LESS(H, ACCESS) \ + (((ACCESS) ? AUDIT_BLOCK_AS_EXPR(PTR_REC_TO_HEAD(H)) : 0), (H)->self) +#define AVL_GET_GREATER(H, ACCESS) \ + (((ACCESS) ? AUDIT_BLOCK_AS_EXPR(PTR_REC_TO_HEAD(H)) : 0), (H)->prev) + +#else + +#define AVL_GET_LESS(H, ACCESS) ((H)->self) +#define AVL_GET_GREATER(H, ACCESS) ((H)->prev) + +#endif + +#define AVL_SET_LESS(H, LH) (H)->self = (LH); +#define AVL_SET_GREATER(H, GH) (H)->prev = (GH); + +/* high bit of high bit of +** block_size previous_block_size balance factor +** ----------- ------------------- -------------- +** 0 0 n/a (block allocated) +** 0 1 1 +** 1 0 -1 +** 1 1 0 +*/ + +#define AVL_GET_BALANCE_FACTOR(H) \ + ((((head_record *) (PTR_REC_TO_HEAD(H)))->block_size & \ + HIGH_BIT_BAU_SIZE) ? \ + (((head_record *) (PTR_REC_TO_HEAD(H)))->previous_block_size & \ + HIGH_BIT_BAU_SIZE ? 0 : -1) : 1) + +#define AVL_SET_BALANCE_FACTOR(H, BF) \ + { \ + register head_record *p = \ + (head_record *) PTR_REC_TO_HEAD(H); \ + register int bal_f = (BF); \ + \ + if (bal_f <= 0) \ + p->block_size |= HIGH_BIT_BAU_SIZE; \ + else \ + p->block_size &= ~HIGH_BIT_BAU_SIZE; \ + if (bal_f >= 0) \ + p->previous_block_size |= HIGH_BIT_BAU_SIZE; \ + else \ + p->previous_block_size &= ~HIGH_BIT_BAU_SIZE; \ + } + +#define COMPARE_KEY_KEY(K1, K2) ((K1) == (K2) ? 0 : ((K1) > (K2) ? 1 : -1)) + +#define AVL_COMPARE_KEY_NODE(K, H) \ + COMPARE_KEY_KEY(K, BLOCK_BAUS(PTR_REC_TO_HEAD(H))) + +#define AVL_COMPARE_NODE_NODE(H1, H2) \ + COMPARE_KEY_KEY(BLOCK_BAUS(PTR_REC_TO_HEAD(H1)), \ + BLOCK_BAUS(PTR_REC_TO_HEAD(H2))) + +#define AVL_NULL ((ptr_record *) 0) + +#define AVL_IMPL_MASK \ + ( AVL_IMPL_INSERT | AVL_IMPL_SEARCH | AVL_IMPL_REMOVE | AVL_IMPL_SUBST ) + +#include "cavl_impl.h" diff --git a/vpx_mem/memory_manager/hmm_dflt_abort.c b/vpx_mem/memory_manager/hmm_dflt_abort.c new file mode 100644 index 0000000..d92435c --- /dev/null +++ b/vpx_mem/memory_manager/hmm_dflt_abort.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +/* The function in this file performs default actions if self-auditing +** finds heap corruption. Don't rely on this code to handle the +** case where HMM is being used to implement the malloc and free standard +** library functions. Rewrite the function if necessary to avoid using +** I/O and execution termination functions that call malloc or free. +** In Unix, for example, you would replace the fputs calls with calls +** to the write system call using file handle number 2. +*/ +#include "hmm_intrnl.h" +#include +#include + +static int entered = 0; + +/* Print abort message, file and line. Terminate execution. +*/ +void hmm_dflt_abort(const char *file, const char *line) +{ + /* Avoid use of printf(), which is more likely to use heap. */ + + if (entered) + + /* The standard I/O functions called a heap function and caused + ** an indirect recursive call to this function. So we'll have + ** to just exit without printing a message. */ + while (1); + + entered = 1; + + fputs("\n_abort - Heap corruption\n" "File: ", stderr); + fputs(file, stderr); + fputs(" Line: ", stderr); + fputs(line, stderr); + fputs("\n\n", stderr); + fputs("hmm_dflt_abort: while(1)!!!\n", stderr); + fflush(stderr); + + while (1); +} diff --git a/vpx_mem/memory_manager/hmm_grow.c b/vpx_mem/memory_manager/hmm_grow.c new file mode 100644 index 0000000..9a4b6e4 --- /dev/null +++ b/vpx_mem/memory_manager/hmm_grow.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +void U(grow_chunk)(U(descriptor) *desc, void *end, U(size_bau) n_baus) +{ +#undef HEAD_PTR +#define HEAD_PTR ((head_record *) end) + + end = BAUS_BACKWARD(end, DUMMY_END_BLOCK_BAUS); + +#ifdef HMM_AUDIT_FAIL + + if (HEAD_PTR->block_size != 0) + /* Chunk does not have valid dummy end block. */ + HMM_AUDIT_FAIL + +#endif + + /* Create a new block that absorbs the old dummy end block. */ + HEAD_PTR->block_size = n_baus; + + /* Set up the new dummy end block. */ + { + head_record *dummy = (head_record *) BAUS_FORWARD(end, n_baus); + dummy->previous_block_size = n_baus; + dummy->block_size = 0; + } + + /* Simply free the new block, allowing it to coalesce with any + ** free block at that was the last block in the chunk prior to + ** growth. + */ + U(free)(desc, HEAD_TO_PTR_REC(end)); + +#undef HEAD_PTR +} diff --git a/vpx_mem/memory_manager/hmm_largest.c b/vpx_mem/memory_manager/hmm_largest.c new file mode 100644 index 0000000..c3c6f2c --- /dev/null +++ b/vpx_mem/memory_manager/hmm_largest.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +U(size_aau) U(largest_available)(U(descriptor) *desc) +{ + U(size_bau) largest; + + if (!(desc->avl_tree_root)) + largest = 0; + else + { +#ifdef HMM_AUDIT_FAIL + /* Audit root block in AVL tree. */ + AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root)) +#endif + + largest = + BLOCK_BAUS( + PTR_REC_TO_HEAD( + U(avl_search)( + (U(avl_avl) *) & (desc->avl_tree_root), + (U(size_bau)) ~(U(size_bau)) 0, AVL_LESS))); + } + + if (desc->last_freed) + { + /* Size of last freed block. */ + register U(size_bau) lf_size; + +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(desc->last_freed) +#endif + + lf_size = BLOCK_BAUS(desc->last_freed); + + if (lf_size > largest) + largest = lf_size; + } + + /* Convert largest size to AAUs and subract head size leaving payload + ** size. + */ + return(largest ? + ((largest * ((U(size_aau)) HMM_BLOCK_ALIGN_UNIT)) - HEAD_AAUS) : + 0); +} diff --git a/vpx_mem/memory_manager/hmm_resize.c b/vpx_mem/memory_manager/hmm_resize.c new file mode 100644 index 0000000..f90da96 --- /dev/null +++ b/vpx_mem/memory_manager/hmm_resize.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +int U(resize)(U(descriptor) *desc, void *mem, U(size_aau) n) +{ + U(size_aau) i; + head_record *next_head_ptr; + head_record *head_ptr = PTR_REC_TO_HEAD(mem); + + /* Flag. */ + int next_block_free; + + /* Convert n from desired block size in AAUs to BAUs. */ + n += HEAD_AAUS; + n = DIV_ROUND_UP(n, HMM_BLOCK_ALIGN_UNIT); + + if (n < MIN_BLOCK_BAUS) + n = MIN_BLOCK_BAUS; + +#ifdef HMM_AUDIT_FAIL + + AUDIT_BLOCK(head_ptr) + + if (!IS_BLOCK_ALLOCATED(head_ptr)) + HMM_AUDIT_FAIL + + if (desc->avl_tree_root) + AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root)) + +#endif + + i = head_ptr->block_size; + + next_head_ptr = + (head_record *) BAUS_FORWARD(head_ptr, head_ptr->block_size); + + next_block_free = + (next_head_ptr == desc->last_freed) || + !IS_BLOCK_ALLOCATED(next_head_ptr); + + if (next_block_free) + /* Block can expand into next free block. */ + i += BLOCK_BAUS(next_head_ptr); + + if (n > i) + /* Not enough room for block to expand. */ + return(-1); + + if (next_block_free) + { +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(next_head_ptr) +#endif + + if (next_head_ptr == desc->last_freed) + desc->last_freed = 0; + else + U(out_of_free_collection)(desc, next_head_ptr); + + next_head_ptr = + (head_record *) BAUS_FORWARD(head_ptr, (U(size_bau)) i); + } + + /* Set i to number of "extra" BAUs. */ + i -= n; + + if (i < MIN_BLOCK_BAUS) + /* Not enough extra BAUs to be a block on their own, so just keep them + ** in the block being resized. + */ + { + n += i; + i = n; + } + else + { + /* There are enough "leftover" BAUs in the next block to + ** form a remainder block. */ + + head_record *rem_head_ptr; + + rem_head_ptr = (head_record *) BAUS_FORWARD(head_ptr, n); + + rem_head_ptr->previous_block_size = (U(size_bau)) n; + rem_head_ptr->block_size = (U(size_bau)) i; + + if (desc->last_freed) + { +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(desc->last_freed) +#endif + + U(into_free_collection)(desc, (head_record *)(desc->last_freed)); + + desc->last_freed = 0; + } + + desc->last_freed = rem_head_ptr; + } + + head_ptr->block_size = (U(size_bau)) n; + next_head_ptr->previous_block_size = (U(size_bau)) i; + + return(0); +} diff --git a/vpx_mem/memory_manager/hmm_shrink.c b/vpx_mem/memory_manager/hmm_shrink.c new file mode 100644 index 0000000..78fe268 --- /dev/null +++ b/vpx_mem/memory_manager/hmm_shrink.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +void U(shrink_chunk)(U(descriptor) *desc, U(size_bau) n_baus_to_shrink) +{ + head_record *dummy_end_block = (head_record *) + BAUS_BACKWARD(desc->end_of_shrinkable_chunk, DUMMY_END_BLOCK_BAUS); + +#ifdef HMM_AUDIT_FAIL + + if (dummy_end_block->block_size != 0) + /* Chunk does not have valid dummy end block. */ + HMM_AUDIT_FAIL + +#endif + + if (n_baus_to_shrink) + { + head_record *last_block = (head_record *) + BAUS_BACKWARD( + dummy_end_block, dummy_end_block->previous_block_size); + +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(last_block) +#endif + + if (last_block == desc->last_freed) + { + U(size_bau) bs = BLOCK_BAUS(last_block); + + /* Chunk will not be shrunk out of existence if + ** 1. There is at least one allocated block in the chunk + ** and the amount to shrink is exactly the size of the + ** last block, OR + ** 2. After the last block is shrunk, there will be enough + ** BAUs left in it to form a minimal size block. */ + int chunk_will_survive = + (PREV_BLOCK_BAUS(last_block) && (n_baus_to_shrink == bs)) || + (n_baus_to_shrink <= (U(size_bau))(bs - MIN_BLOCK_BAUS)); + + if (chunk_will_survive || + (!PREV_BLOCK_BAUS(last_block) && + (n_baus_to_shrink == + (U(size_bau))(bs + DUMMY_END_BLOCK_BAUS)))) + { + desc->last_freed = 0; + + if (chunk_will_survive) + { + bs -= n_baus_to_shrink; + + if (bs) + { + /* The last (non-dummy) block was not completely + ** eliminated by the shrink. */ + + last_block->block_size = bs; + + /* Create new dummy end record. + */ + dummy_end_block = + (head_record *) BAUS_FORWARD(last_block, bs); + dummy_end_block->previous_block_size = bs; + dummy_end_block->block_size = 0; + +#ifdef HMM_AUDIT_FAIL + + if (desc->avl_tree_root) + AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root)) +#endif + + U(into_free_collection)(desc, last_block); + } + else + { + /* The last (non-dummy) block was completely + ** eliminated by the shrink. Make its head + ** the new dummy end block. + */ + last_block->block_size = 0; + last_block->previous_block_size &= ~HIGH_BIT_BAU_SIZE; + } + } + } + +#ifdef HMM_AUDIT_FAIL + else + HMM_AUDIT_FAIL +#endif + } + +#ifdef HMM_AUDIT_FAIL + else + HMM_AUDIT_FAIL +#endif + } +} diff --git a/vpx_mem/memory_manager/hmm_true.c b/vpx_mem/memory_manager/hmm_true.c new file mode 100644 index 0000000..3f7be8f --- /dev/null +++ b/vpx_mem/memory_manager/hmm_true.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#include "hmm_intrnl.h" + +U(size_aau) U(true_size)(void *payload_ptr) +{ + register head_record *head_ptr = PTR_REC_TO_HEAD(payload_ptr); + +#ifdef HMM_AUDIT_FAIL + AUDIT_BLOCK(head_ptr) +#endif + + /* Convert block size from BAUs to AAUs. Subtract head size, leaving + ** payload size. + */ + return( + (BLOCK_BAUS(head_ptr) * ((U(size_aau)) HMM_BLOCK_ALIGN_UNIT)) - + HEAD_AAUS); +} diff --git a/vpx_mem/memory_manager/include/cavl_if.h b/vpx_mem/memory_manager/include/cavl_if.h new file mode 100644 index 0000000..1b2c9b7 --- /dev/null +++ b/vpx_mem/memory_manager/include/cavl_if.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* Abstract AVL Tree Generic C Package. +** Interface generation header file. +** +** This code is in the public domain. See cavl_tree.html for interface +** documentation. +** +** Version: 1.5 Author: Walt Karas +*/ + +/* This header contains the definition of CHAR_BIT (number of bits in a +** char). */ +#include + +#undef L_ +#undef L_EST_LONG_BIT +#undef L_SIZE +#undef L_SC +#undef L_LONG_BIT +#undef L_BIT_ARR_DEFN + +#ifndef AVL_SEARCH_TYPE_DEFINED_ +#define AVL_SEARCH_TYPE_DEFINED_ + +typedef enum +{ + AVL_EQUAL = 1, + AVL_LESS = 2, + AVL_GREATER = 4, + AVL_LESS_EQUAL = AVL_EQUAL | AVL_LESS, + AVL_GREATER_EQUAL = AVL_EQUAL | AVL_GREATER +} +avl_search_type; + +#endif + +#ifdef AVL_UNIQUE + +#define L_ AVL_UNIQUE + +#else + +#define L_(X) X + +#endif + +/* Determine storage class for function prototypes. */ +#ifdef AVL_PRIVATE + +#define L_SC static + +#else + +#define L_SC extern + +#endif + +#ifdef AVL_SIZE + +#define L_SIZE AVL_SIZE + +#else + +#define L_SIZE unsigned long + +#endif + +typedef struct +{ +#ifdef AVL_INSIDE_STRUCT + + AVL_INSIDE_STRUCT + +#endif + + AVL_HANDLE root; +} +L_(avl); + +/* Function prototypes. */ + +L_SC void L_(init)(L_(avl) *tree); + +L_SC int L_(is_empty)(L_(avl) *tree); + +L_SC AVL_HANDLE L_(insert)(L_(avl) *tree, AVL_HANDLE h); + +L_SC AVL_HANDLE L_(search)(L_(avl) *tree, AVL_KEY k, avl_search_type st); + +L_SC AVL_HANDLE L_(search_least)(L_(avl) *tree); + +L_SC AVL_HANDLE L_(search_greatest)(L_(avl) *tree); + +L_SC AVL_HANDLE L_(remove)(L_(avl) *tree, AVL_KEY k); + +L_SC AVL_HANDLE L_(subst)(L_(avl) *tree, AVL_HANDLE new_node); + +#ifdef AVL_BUILD_ITER_TYPE + +L_SC int L_(build)( + L_(avl) *tree, AVL_BUILD_ITER_TYPE p, L_SIZE num_nodes); + +#endif + +/* ANSI C/ISO C++ require that a long have at least 32 bits. Set +** L_EST_LONG_BIT to be the greatest multiple of 8 in the range +** 32 - 64 (inclusive) that is less than or equal to the number of +** bits in a long. +*/ + +#if (((LONG_MAX >> 31) >> 7) == 0) + +#define L_EST_LONG_BIT 32 + +#elif (((LONG_MAX >> 31) >> 15) == 0) + +#define L_EST_LONG_BIT 40 + +#elif (((LONG_MAX >> 31) >> 23) == 0) + +#define L_EST_LONG_BIT 48 + +#elif (((LONG_MAX >> 31) >> 31) == 0) + +#define L_EST_LONG_BIT 56 + +#else + +#define L_EST_LONG_BIT 64 + +#endif + +/* Number of bits in a long. */ +#define L_LONG_BIT (sizeof(long) * CHAR_BIT) + +/* The macro L_BIT_ARR_DEFN defines a bit array whose index is a (0-based) +** node depth. The definition depends on whether the maximum depth is more +** or less than the number of bits in a single long. +*/ + +#if ((AVL_MAX_DEPTH) > L_EST_LONG_BIT) + +/* Maximum depth may be more than number of bits in a long. */ + +#define L_BIT_ARR_DEFN(NAME) \ + unsigned long NAME[((AVL_MAX_DEPTH) + L_LONG_BIT - 1) / L_LONG_BIT]; + +#else + +/* Maximum depth is definitely less than number of bits in a long. */ + +#define L_BIT_ARR_DEFN(NAME) unsigned long NAME; + +#endif + +/* Iterator structure. */ +typedef struct +{ + /* Tree being iterated over. */ + L_(avl) *tree_; + + /* Records a path into the tree. If bit n is true, indicates + ** take greater branch from the nth node in the path, otherwise + ** take the less branch. bit 0 gives branch from root, and + ** so on. */ + L_BIT_ARR_DEFN(branch) + + /* Zero-based depth of path into tree. */ + unsigned depth; + + /* Handles of nodes in path from root to current node (returned by *). */ + AVL_HANDLE path_h[(AVL_MAX_DEPTH) - 1]; +} +L_(iter); + +/* Iterator function prototypes. */ + +L_SC void L_(start_iter)( + L_(avl) *tree, L_(iter) *iter, AVL_KEY k, avl_search_type st); + +L_SC void L_(start_iter_least)(L_(avl) *tree, L_(iter) *iter); + +L_SC void L_(start_iter_greatest)(L_(avl) *tree, L_(iter) *iter); + +L_SC AVL_HANDLE L_(get_iter)(L_(iter) *iter); + +L_SC void L_(incr_iter)(L_(iter) *iter); + +L_SC void L_(decr_iter)(L_(iter) *iter); + +L_SC void L_(init_iter)(L_(iter) *iter); + +#define AVL_IMPL_INIT 1 +#define AVL_IMPL_IS_EMPTY (1 << 1) +#define AVL_IMPL_INSERT (1 << 2) +#define AVL_IMPL_SEARCH (1 << 3) +#define AVL_IMPL_SEARCH_LEAST (1 << 4) +#define AVL_IMPL_SEARCH_GREATEST (1 << 5) +#define AVL_IMPL_REMOVE (1 << 6) +#define AVL_IMPL_BUILD (1 << 7) +#define AVL_IMPL_START_ITER (1 << 8) +#define AVL_IMPL_START_ITER_LEAST (1 << 9) +#define AVL_IMPL_START_ITER_GREATEST (1 << 10) +#define AVL_IMPL_GET_ITER (1 << 11) +#define AVL_IMPL_INCR_ITER (1 << 12) +#define AVL_IMPL_DECR_ITER (1 << 13) +#define AVL_IMPL_INIT_ITER (1 << 14) +#define AVL_IMPL_SUBST (1 << 15) + +#define AVL_IMPL_ALL (~0) + +#undef L_ +#undef L_EST_LONG_BIT +#undef L_SIZE +#undef L_SC +#undef L_LONG_BIT +#undef L_BIT_ARR_DEFN diff --git a/vpx_mem/memory_manager/include/cavl_impl.h b/vpx_mem/memory_manager/include/cavl_impl.h new file mode 100644 index 0000000..5e165dd --- /dev/null +++ b/vpx_mem/memory_manager/include/cavl_impl.h @@ -0,0 +1,1267 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* Abstract AVL Tree Generic C Package. +** Implementation generation header file. +** +** This code is in the public domain. See cavl_tree.html for interface +** documentation. +** +** Version: 1.5 Author: Walt Karas +*/ + +#undef L_ +#undef L_EST_LONG_BIT +#undef L_SIZE +#undef l_tree +#undef L_MASK_HIGH_BIT +#undef L_LONG_BIT +#undef L_BIT_ARR_DEFN +#undef L_BIT_ARR_VAL +#undef L_BIT_ARR_0 +#undef L_BIT_ARR_1 +#undef L_BIT_ARR_ALL +#undef L_BIT_ARR_LONGS +#undef L_IMPL_MASK +#undef L_CHECK_READ_ERROR +#undef L_CHECK_READ_ERROR_INV_DEPTH +#undef L_SC +#undef L_BALANCE_PARAM_PREFIX + +#ifdef AVL_UNIQUE + +#define L_ AVL_UNIQUE + +#else + +#define L_(X) X + +#endif + +/* Determine correct storage class for functions */ +#ifdef AVL_PRIVATE + +#define L_SC static + +#else + +#define L_SC + +#endif + +#ifdef AVL_SIZE + +#define L_SIZE AVL_SIZE + +#else + +#define L_SIZE unsigned long + +#endif + +#define L_MASK_HIGH_BIT ((int) ~ ((~ (unsigned) 0) >> 1)) + +/* ANSI C/ISO C++ require that a long have at least 32 bits. Set +** L_EST_LONG_BIT to be the greatest multiple of 8 in the range +** 32 - 64 (inclusive) that is less than or equal to the number of +** bits in a long. +*/ + +#if (((LONG_MAX >> 31) >> 7) == 0) + +#define L_EST_LONG_BIT 32 + +#elif (((LONG_MAX >> 31) >> 15) == 0) + +#define L_EST_LONG_BIT 40 + +#elif (((LONG_MAX >> 31) >> 23) == 0) + +#define L_EST_LONG_BIT 48 + +#elif (((LONG_MAX >> 31) >> 31) == 0) + +#define L_EST_LONG_BIT 56 + +#else + +#define L_EST_LONG_BIT 64 + +#endif + +#define L_LONG_BIT (sizeof(long) * CHAR_BIT) + +#if ((AVL_MAX_DEPTH) > L_EST_LONG_BIT) + +/* The maximum depth may be greater than the number of bits in a long, +** so multiple longs are needed to hold a bit array indexed by node +** depth. */ + +#define L_BIT_ARR_LONGS (((AVL_MAX_DEPTH) + L_LONG_BIT - 1) / L_LONG_BIT) + +#define L_BIT_ARR_DEFN(NAME) unsigned long NAME[L_BIT_ARR_LONGS]; + +#define L_BIT_ARR_VAL(BIT_ARR, BIT_NUM) \ + ((BIT_ARR)[(BIT_NUM) / L_LONG_BIT] & (1L << ((BIT_NUM) % L_LONG_BIT))) + +#define L_BIT_ARR_0(BIT_ARR, BIT_NUM) \ + (BIT_ARR)[(BIT_NUM) / L_LONG_BIT] &= ~(1L << ((BIT_NUM) % L_LONG_BIT)); + +#define L_BIT_ARR_1(BIT_ARR, BIT_NUM) \ + (BIT_ARR)[(BIT_NUM) / L_LONG_BIT] |= 1L << ((BIT_NUM) % L_LONG_BIT); + +#define L_BIT_ARR_ALL(BIT_ARR, BIT_VAL) \ + { int i = L_BIT_ARR_LONGS; do (BIT_ARR)[--i] = 0L - (BIT_VAL); while(i); } + +#else /* The bit array can definitely fit in one long */ + +#define L_BIT_ARR_DEFN(NAME) unsigned long NAME; + +#define L_BIT_ARR_VAL(BIT_ARR, BIT_NUM) ((BIT_ARR) & (1L << (BIT_NUM))) + +#define L_BIT_ARR_0(BIT_ARR, BIT_NUM) (BIT_ARR) &= ~(1L << (BIT_NUM)); + +#define L_BIT_ARR_1(BIT_ARR, BIT_NUM) (BIT_ARR) |= 1L << (BIT_NUM); + +#define L_BIT_ARR_ALL(BIT_ARR, BIT_VAL) (BIT_ARR) = 0L - (BIT_VAL); + +#endif + +#ifdef AVL_READ_ERRORS_HAPPEN + +#define L_CHECK_READ_ERROR(ERROR_RETURN) \ + { if (AVL_READ_ERROR) return(ERROR_RETURN); } + +#else + +#define L_CHECK_READ_ERROR(ERROR_RETURN) + +#endif + +/* The presumed reason that an instantiation places additional fields +** inside the AVL tree structure is that the SET_ and GET_ macros +** need these fields. The "balance" function does not explicitly use +** any fields in the AVL tree structure, so only pass an AVL tree +** structure pointer to "balance" if it has instantiation-specific +** fields that are (presumably) needed by the SET_/GET_ calls within +** "balance". +*/ +#ifdef AVL_INSIDE_STRUCT + +#define L_BALANCE_PARAM_CALL_PREFIX l_tree, +#define L_BALANCE_PARAM_DECL_PREFIX L_(avl) *l_tree, + +#else + +#define L_BALANCE_PARAM_CALL_PREFIX +#define L_BALANCE_PARAM_DECL_PREFIX + +#endif + +#ifdef AVL_IMPL_MASK + +#define L_IMPL_MASK (AVL_IMPL_MASK) + +#else + +/* Define all functions. */ +#define L_IMPL_MASK AVL_IMPL_ALL + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_INIT) + +L_SC void L_(init)(L_(avl) *l_tree) +{ + l_tree->root = AVL_NULL; +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_IS_EMPTY) + +L_SC int L_(is_empty)(L_(avl) *l_tree) +{ + return(l_tree->root == AVL_NULL); +} + +#endif + +/* Put the private balance function in the same compilation module as +** the insert function. */ +#if (L_IMPL_MASK & AVL_IMPL_INSERT) + +/* Balances subtree, returns handle of root node of subtree after balancing. +*/ +L_SC AVL_HANDLE L_(balance)(L_BALANCE_PARAM_DECL_PREFIX AVL_HANDLE bal_h) +{ + AVL_HANDLE deep_h; + + /* Either the "greater than" or the "less than" subtree of + ** this node has to be 2 levels deeper (or else it wouldn't + ** need balancing). + */ + if (AVL_GET_BALANCE_FACTOR(bal_h) > 0) + { + /* "Greater than" subtree is deeper. */ + + deep_h = AVL_GET_GREATER(bal_h, 1); + + L_CHECK_READ_ERROR(AVL_NULL) + + if (AVL_GET_BALANCE_FACTOR(deep_h) < 0) + { + int bf; + + AVL_HANDLE old_h = bal_h; + bal_h = AVL_GET_LESS(deep_h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + AVL_SET_GREATER(old_h, AVL_GET_LESS(bal_h, 1)) + AVL_SET_LESS(deep_h, AVL_GET_GREATER(bal_h, 1)) + AVL_SET_LESS(bal_h, old_h) + AVL_SET_GREATER(bal_h, deep_h) + + bf = AVL_GET_BALANCE_FACTOR(bal_h); + + if (bf != 0) + { + if (bf > 0) + { + AVL_SET_BALANCE_FACTOR(old_h, -1) + AVL_SET_BALANCE_FACTOR(deep_h, 0) + } + else + { + AVL_SET_BALANCE_FACTOR(deep_h, 1) + AVL_SET_BALANCE_FACTOR(old_h, 0) + } + + AVL_SET_BALANCE_FACTOR(bal_h, 0) + } + else + { + AVL_SET_BALANCE_FACTOR(old_h, 0) + AVL_SET_BALANCE_FACTOR(deep_h, 0) + } + } + else + { + AVL_SET_GREATER(bal_h, AVL_GET_LESS(deep_h, 0)) + AVL_SET_LESS(deep_h, bal_h) + + if (AVL_GET_BALANCE_FACTOR(deep_h) == 0) + { + AVL_SET_BALANCE_FACTOR(deep_h, -1) + AVL_SET_BALANCE_FACTOR(bal_h, 1) + } + else + { + AVL_SET_BALANCE_FACTOR(deep_h, 0) + AVL_SET_BALANCE_FACTOR(bal_h, 0) + } + + bal_h = deep_h; + } + } + else + { + /* "Less than" subtree is deeper. */ + + deep_h = AVL_GET_LESS(bal_h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + + if (AVL_GET_BALANCE_FACTOR(deep_h) > 0) + { + int bf; + AVL_HANDLE old_h = bal_h; + bal_h = AVL_GET_GREATER(deep_h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + AVL_SET_LESS(old_h, AVL_GET_GREATER(bal_h, 0)) + AVL_SET_GREATER(deep_h, AVL_GET_LESS(bal_h, 0)) + AVL_SET_GREATER(bal_h, old_h) + AVL_SET_LESS(bal_h, deep_h) + + bf = AVL_GET_BALANCE_FACTOR(bal_h); + + if (bf != 0) + { + if (bf < 0) + { + AVL_SET_BALANCE_FACTOR(old_h, 1) + AVL_SET_BALANCE_FACTOR(deep_h, 0) + } + else + { + AVL_SET_BALANCE_FACTOR(deep_h, -1) + AVL_SET_BALANCE_FACTOR(old_h, 0) + } + + AVL_SET_BALANCE_FACTOR(bal_h, 0) + } + else + { + AVL_SET_BALANCE_FACTOR(old_h, 0) + AVL_SET_BALANCE_FACTOR(deep_h, 0) + } + } + else + { + AVL_SET_LESS(bal_h, AVL_GET_GREATER(deep_h, 0)) + AVL_SET_GREATER(deep_h, bal_h) + + if (AVL_GET_BALANCE_FACTOR(deep_h) == 0) + { + AVL_SET_BALANCE_FACTOR(deep_h, 1) + AVL_SET_BALANCE_FACTOR(bal_h, -1) + } + else + { + AVL_SET_BALANCE_FACTOR(deep_h, 0) + AVL_SET_BALANCE_FACTOR(bal_h, 0) + } + + bal_h = deep_h; + } + } + + return(bal_h); +} + +L_SC AVL_HANDLE L_(insert)(L_(avl) *l_tree, AVL_HANDLE h) +{ + AVL_SET_LESS(h, AVL_NULL) + AVL_SET_GREATER(h, AVL_NULL) + AVL_SET_BALANCE_FACTOR(h, 0) + + if (l_tree->root == AVL_NULL) + l_tree->root = h; + else + { + /* Last unbalanced node encountered in search for insertion point. */ + AVL_HANDLE unbal = AVL_NULL; + /* Parent of last unbalanced node. */ + AVL_HANDLE parent_unbal = AVL_NULL; + /* Balance factor of last unbalanced node. */ + int unbal_bf; + + /* Zero-based depth in tree. */ + unsigned depth = 0, unbal_depth = 0; + + /* Records a path into the tree. If bit n is true, indicates + ** take greater branch from the nth node in the path, otherwise + ** take the less branch. bit 0 gives branch from root, and + ** so on. */ + L_BIT_ARR_DEFN(branch) + + AVL_HANDLE hh = l_tree->root; + AVL_HANDLE parent = AVL_NULL; + int cmp; + + do + { + if (AVL_GET_BALANCE_FACTOR(hh) != 0) + { + unbal = hh; + parent_unbal = parent; + unbal_depth = depth; + } + + cmp = AVL_COMPARE_NODE_NODE(h, hh); + + if (cmp == 0) + /* Duplicate key. */ + return(hh); + + parent = hh; + + if (cmp > 0) + { + hh = AVL_GET_GREATER(hh, 1); + L_BIT_ARR_1(branch, depth) + } + else + { + hh = AVL_GET_LESS(hh, 1); + L_BIT_ARR_0(branch, depth) + } + + L_CHECK_READ_ERROR(AVL_NULL) + depth++; + } + while (hh != AVL_NULL); + + /* Add node to insert as leaf of tree. */ + if (cmp < 0) + AVL_SET_LESS(parent, h) + else + AVL_SET_GREATER(parent, h) + + depth = unbal_depth; + + if (unbal == AVL_NULL) + hh = l_tree->root; + else + { + cmp = L_BIT_ARR_VAL(branch, depth) ? 1 : -1; + depth++; + unbal_bf = AVL_GET_BALANCE_FACTOR(unbal); + + if (cmp < 0) + unbal_bf--; + else /* cmp > 0 */ + unbal_bf++; + + hh = cmp < 0 ? AVL_GET_LESS(unbal, 1) : AVL_GET_GREATER(unbal, 1); + L_CHECK_READ_ERROR(AVL_NULL) + + if ((unbal_bf != -2) && (unbal_bf != 2)) + { + /* No rebalancing of tree is necessary. */ + AVL_SET_BALANCE_FACTOR(unbal, unbal_bf) + unbal = AVL_NULL; + } + } + + if (hh != AVL_NULL) + while (h != hh) + { + cmp = L_BIT_ARR_VAL(branch, depth) ? 1 : -1; + depth++; + + if (cmp < 0) + { + AVL_SET_BALANCE_FACTOR(hh, -1) + hh = AVL_GET_LESS(hh, 1); + } + else /* cmp > 0 */ + { + AVL_SET_BALANCE_FACTOR(hh, 1) + hh = AVL_GET_GREATER(hh, 1); + } + + L_CHECK_READ_ERROR(AVL_NULL) + } + + if (unbal != AVL_NULL) + { + unbal = L_(balance)(L_BALANCE_PARAM_CALL_PREFIX unbal); + L_CHECK_READ_ERROR(AVL_NULL) + + if (parent_unbal == AVL_NULL) + l_tree->root = unbal; + else + { + depth = unbal_depth - 1; + cmp = L_BIT_ARR_VAL(branch, depth) ? 1 : -1; + + if (cmp < 0) + AVL_SET_LESS(parent_unbal, unbal) + else /* cmp > 0 */ + AVL_SET_GREATER(parent_unbal, unbal) + } + } + + } + + return(h); +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_SEARCH) + +L_SC AVL_HANDLE L_(search)(L_(avl) *l_tree, AVL_KEY k, avl_search_type st) +{ + int cmp, target_cmp; + AVL_HANDLE match_h = AVL_NULL; + AVL_HANDLE h = l_tree->root; + + if (st & AVL_LESS) + target_cmp = 1; + else if (st & AVL_GREATER) + target_cmp = -1; + else + target_cmp = 0; + + while (h != AVL_NULL) + { + cmp = AVL_COMPARE_KEY_NODE(k, h); + + if (cmp == 0) + { + if (st & AVL_EQUAL) + { + match_h = h; + break; + } + + cmp = -target_cmp; + } + else if (target_cmp != 0) + if (!((cmp ^ target_cmp) & L_MASK_HIGH_BIT)) + /* cmp and target_cmp are both positive or both negative. */ + match_h = h; + + h = cmp < 0 ? AVL_GET_LESS(h, 1) : AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + } + + return(match_h); +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_SEARCH_LEAST) + +L_SC AVL_HANDLE L_(search_least)(L_(avl) *l_tree) +{ + AVL_HANDLE h = l_tree->root; + AVL_HANDLE parent = AVL_NULL; + + while (h != AVL_NULL) + { + parent = h; + h = AVL_GET_LESS(h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + } + + return(parent); +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_SEARCH_GREATEST) + +L_SC AVL_HANDLE L_(search_greatest)(L_(avl) *l_tree) +{ + AVL_HANDLE h = l_tree->root; + AVL_HANDLE parent = AVL_NULL; + + while (h != AVL_NULL) + { + parent = h; + h = AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + } + + return(parent); +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_REMOVE) + +/* Prototype of balance function (called by remove) in case not in +** same compilation unit. +*/ +L_SC AVL_HANDLE L_(balance)(L_BALANCE_PARAM_DECL_PREFIX AVL_HANDLE bal_h); + +L_SC AVL_HANDLE L_(remove)(L_(avl) *l_tree, AVL_KEY k) +{ + /* Zero-based depth in tree. */ + unsigned depth = 0, rm_depth; + + /* Records a path into the tree. If bit n is true, indicates + ** take greater branch from the nth node in the path, otherwise + ** take the less branch. bit 0 gives branch from root, and + ** so on. */ + L_BIT_ARR_DEFN(branch) + + AVL_HANDLE h = l_tree->root; + AVL_HANDLE parent = AVL_NULL; + AVL_HANDLE child; + AVL_HANDLE path; + int cmp, cmp_shortened_sub_with_path; + int reduced_depth; + int bf; + AVL_HANDLE rm; + AVL_HANDLE parent_rm; + + for (; ;) + { + if (h == AVL_NULL) + /* No node in tree with given key. */ + return(AVL_NULL); + + cmp = AVL_COMPARE_KEY_NODE(k, h); + + if (cmp == 0) + /* Found node to remove. */ + break; + + parent = h; + + if (cmp > 0) + { + h = AVL_GET_GREATER(h, 1); + L_BIT_ARR_1(branch, depth) + } + else + { + h = AVL_GET_LESS(h, 1); + L_BIT_ARR_0(branch, depth) + } + + L_CHECK_READ_ERROR(AVL_NULL) + depth++; + cmp_shortened_sub_with_path = cmp; + } + + rm = h; + parent_rm = parent; + rm_depth = depth; + + /* If the node to remove is not a leaf node, we need to get a + ** leaf node, or a node with a single leaf as its child, to put + ** in the place of the node to remove. We will get the greatest + ** node in the less subtree (of the node to remove), or the least + ** node in the greater subtree. We take the leaf node from the + ** deeper subtree, if there is one. */ + + if (AVL_GET_BALANCE_FACTOR(h) < 0) + { + child = AVL_GET_LESS(h, 1); + L_BIT_ARR_0(branch, depth) + cmp = -1; + } + else + { + child = AVL_GET_GREATER(h, 1); + L_BIT_ARR_1(branch, depth) + cmp = 1; + } + + L_CHECK_READ_ERROR(AVL_NULL) + depth++; + + if (child != AVL_NULL) + { + cmp = -cmp; + + do + { + parent = h; + h = child; + + if (cmp < 0) + { + child = AVL_GET_LESS(h, 1); + L_BIT_ARR_0(branch, depth) + } + else + { + child = AVL_GET_GREATER(h, 1); + L_BIT_ARR_1(branch, depth) + } + + L_CHECK_READ_ERROR(AVL_NULL) + depth++; + } + while (child != AVL_NULL); + + if (parent == rm) + /* Only went through do loop once. Deleted node will be replaced + ** in the tree structure by one of its immediate children. */ + cmp_shortened_sub_with_path = -cmp; + else + cmp_shortened_sub_with_path = cmp; + + /* Get the handle of the opposite child, which may not be null. */ + child = cmp > 0 ? AVL_GET_LESS(h, 0) : AVL_GET_GREATER(h, 0); + } + + if (parent == AVL_NULL) + /* There were only 1 or 2 nodes in this tree. */ + l_tree->root = child; + else if (cmp_shortened_sub_with_path < 0) + AVL_SET_LESS(parent, child) + else + AVL_SET_GREATER(parent, child) + + /* "path" is the parent of the subtree being eliminated or reduced + ** from a depth of 2 to 1. If "path" is the node to be removed, we + ** set path to the node we're about to poke into the position of the + ** node to be removed. */ + path = parent == rm ? h : parent; + + if (h != rm) + { + /* Poke in the replacement for the node to be removed. */ + AVL_SET_LESS(h, AVL_GET_LESS(rm, 0)) + AVL_SET_GREATER(h, AVL_GET_GREATER(rm, 0)) + AVL_SET_BALANCE_FACTOR(h, AVL_GET_BALANCE_FACTOR(rm)) + + if (parent_rm == AVL_NULL) + l_tree->root = h; + else + { + depth = rm_depth - 1; + + if (L_BIT_ARR_VAL(branch, depth)) + AVL_SET_GREATER(parent_rm, h) + else + AVL_SET_LESS(parent_rm, h) + } + } + + if (path != AVL_NULL) + { + /* Create a temporary linked list from the parent of the path node + ** to the root node. */ + h = l_tree->root; + parent = AVL_NULL; + depth = 0; + + while (h != path) + { + if (L_BIT_ARR_VAL(branch, depth)) + { + child = AVL_GET_GREATER(h, 1); + AVL_SET_GREATER(h, parent) + } + else + { + child = AVL_GET_LESS(h, 1); + AVL_SET_LESS(h, parent) + } + + L_CHECK_READ_ERROR(AVL_NULL) + depth++; + parent = h; + h = child; + } + + /* Climb from the path node to the root node using the linked + ** list, restoring the tree structure and rebalancing as necessary. + */ + reduced_depth = 1; + cmp = cmp_shortened_sub_with_path; + + for (; ;) + { + if (reduced_depth) + { + bf = AVL_GET_BALANCE_FACTOR(h); + + if (cmp < 0) + bf++; + else /* cmp > 0 */ + bf--; + + if ((bf == -2) || (bf == 2)) + { + h = L_(balance)(L_BALANCE_PARAM_CALL_PREFIX h); + L_CHECK_READ_ERROR(AVL_NULL) + bf = AVL_GET_BALANCE_FACTOR(h); + } + else + AVL_SET_BALANCE_FACTOR(h, bf) + reduced_depth = (bf == 0); + } + + if (parent == AVL_NULL) + break; + + child = h; + h = parent; + depth--; + cmp = L_BIT_ARR_VAL(branch, depth) ? 1 : -1; + + if (cmp < 0) + { + parent = AVL_GET_LESS(h, 1); + AVL_SET_LESS(h, child) + } + else + { + parent = AVL_GET_GREATER(h, 1); + AVL_SET_GREATER(h, child) + } + + L_CHECK_READ_ERROR(AVL_NULL) + } + + l_tree->root = h; + } + + return(rm); +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_SUBST) + +L_SC AVL_HANDLE L_(subst)(L_(avl) *l_tree, AVL_HANDLE new_node) +{ + AVL_HANDLE h = l_tree->root; + AVL_HANDLE parent = AVL_NULL; + int cmp, last_cmp; + + /* Search for node already in tree with same key. */ + for (; ;) + { + if (h == AVL_NULL) + /* No node in tree with same key as new node. */ + return(AVL_NULL); + + cmp = AVL_COMPARE_NODE_NODE(new_node, h); + + if (cmp == 0) + /* Found the node to substitute new one for. */ + break; + + last_cmp = cmp; + parent = h; + h = cmp < 0 ? AVL_GET_LESS(h, 1) : AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR(AVL_NULL) + } + + /* Copy tree housekeeping fields from node in tree to new node. */ + AVL_SET_LESS(new_node, AVL_GET_LESS(h, 0)) + AVL_SET_GREATER(new_node, AVL_GET_GREATER(h, 0)) + AVL_SET_BALANCE_FACTOR(new_node, AVL_GET_BALANCE_FACTOR(h)) + + if (parent == AVL_NULL) + /* New node is also new root. */ + l_tree->root = new_node; + else + { + /* Make parent point to new node. */ + if (last_cmp < 0) + AVL_SET_LESS(parent, new_node) + else + AVL_SET_GREATER(parent, new_node) + } + + return(h); +} + +#endif + +#ifdef AVL_BUILD_ITER_TYPE + +#if (L_IMPL_MASK & AVL_IMPL_BUILD) + +L_SC int L_(build)( + L_(avl) *l_tree, AVL_BUILD_ITER_TYPE p, L_SIZE num_nodes) +{ + /* Gives path to subtree being built. If bit n is false, branch + ** less from the node at depth n, if true branch greater. */ + L_BIT_ARR_DEFN(branch) + + /* If bit n is true, then for the current subtree at depth n, its + ** greater subtree has one more node than its less subtree. */ + L_BIT_ARR_DEFN(rem) + + /* Depth of root node of current subtree. */ + unsigned depth = 0; + + /* Number of nodes in current subtree. */ + L_SIZE num_sub = num_nodes; + + /* The algorithm relies on a stack of nodes whose less subtree has + ** been built, but whose greater subtree has not yet been built. + ** The stack is implemented as linked list. The nodes are linked + ** together by having the "greater" handle of a node set to the + ** next node in the list. "less_parent" is the handle of the first + ** node in the list. */ + AVL_HANDLE less_parent = AVL_NULL; + + /* h is root of current subtree, child is one of its children. */ + AVL_HANDLE h; + AVL_HANDLE child; + + if (num_nodes == 0) + { + l_tree->root = AVL_NULL; + return(1); + } + + for (; ;) + { + while (num_sub > 2) + { + /* Subtract one for root of subtree. */ + num_sub--; + + if (num_sub & 1) + L_BIT_ARR_1(rem, depth) + else + L_BIT_ARR_0(rem, depth) + L_BIT_ARR_0(branch, depth) + depth++; + + num_sub >>= 1; + } + + if (num_sub == 2) + { + /* Build a subtree with two nodes, slanting to greater. + ** I arbitrarily chose to always have the extra node in the + ** greater subtree when there is an odd number of nodes to + ** split between the two subtrees. */ + + h = AVL_BUILD_ITER_VAL(p); + L_CHECK_READ_ERROR(0) + AVL_BUILD_ITER_INCR(p) + child = AVL_BUILD_ITER_VAL(p); + L_CHECK_READ_ERROR(0) + AVL_BUILD_ITER_INCR(p) + AVL_SET_LESS(child, AVL_NULL) + AVL_SET_GREATER(child, AVL_NULL) + AVL_SET_BALANCE_FACTOR(child, 0) + AVL_SET_GREATER(h, child) + AVL_SET_LESS(h, AVL_NULL) + AVL_SET_BALANCE_FACTOR(h, 1) + } + else /* num_sub == 1 */ + { + /* Build a subtree with one node. */ + + h = AVL_BUILD_ITER_VAL(p); + L_CHECK_READ_ERROR(0) + AVL_BUILD_ITER_INCR(p) + AVL_SET_LESS(h, AVL_NULL) + AVL_SET_GREATER(h, AVL_NULL) + AVL_SET_BALANCE_FACTOR(h, 0) + } + + while (depth) + { + depth--; + + if (!L_BIT_ARR_VAL(branch, depth)) + /* We've completed a less subtree. */ + break; + + /* We've completed a greater subtree, so attach it to + ** its parent (that is less than it). We pop the parent + ** off the stack of less parents. */ + child = h; + h = less_parent; + less_parent = AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR(0) + AVL_SET_GREATER(h, child) + /* num_sub = 2 * (num_sub - rem[depth]) + rem[depth] + 1 */ + num_sub <<= 1; + num_sub += L_BIT_ARR_VAL(rem, depth) ? 0 : 1; + + if (num_sub & (num_sub - 1)) + /* num_sub is not a power of 2. */ + AVL_SET_BALANCE_FACTOR(h, 0) + else + /* num_sub is a power of 2. */ + AVL_SET_BALANCE_FACTOR(h, 1) + } + + if (num_sub == num_nodes) + /* We've completed the full tree. */ + break; + + /* The subtree we've completed is the less subtree of the + ** next node in the sequence. */ + + child = h; + h = AVL_BUILD_ITER_VAL(p); + L_CHECK_READ_ERROR(0) + AVL_BUILD_ITER_INCR(p) + AVL_SET_LESS(h, child) + + /* Put h into stack of less parents. */ + AVL_SET_GREATER(h, less_parent) + less_parent = h; + + /* Proceed to creating greater than subtree of h. */ + L_BIT_ARR_1(branch, depth) + num_sub += L_BIT_ARR_VAL(rem, depth) ? 1 : 0; + depth++; + + } /* end for ( ; ; ) */ + + l_tree->root = h; + + return(1); +} + +#endif + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_INIT_ITER) + +/* Initialize depth to invalid value, to indicate iterator is +** invalid. (Depth is zero-base.) It's not necessary to initialize +** iterators prior to passing them to the "start" function. +*/ +L_SC void L_(init_iter)(L_(iter) *iter) +{ + iter->depth = ~0; +} + +#endif + +#ifdef AVL_READ_ERRORS_HAPPEN + +#define L_CHECK_READ_ERROR_INV_DEPTH \ + { if (AVL_READ_ERROR) { iter->depth = ~0; return; } } + +#else + +#define L_CHECK_READ_ERROR_INV_DEPTH + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_START_ITER) + +L_SC void L_(start_iter)( + L_(avl) *l_tree, L_(iter) *iter, AVL_KEY k, avl_search_type st) +{ + AVL_HANDLE h = l_tree->root; + unsigned d = 0; + int cmp, target_cmp; + + /* Save the tree that we're going to iterate through in a + ** member variable. */ + iter->tree_ = l_tree; + + iter->depth = ~0; + + if (h == AVL_NULL) + /* Tree is empty. */ + return; + + if (st & AVL_LESS) + /* Key can be greater than key of starting node. */ + target_cmp = 1; + else if (st & AVL_GREATER) + /* Key can be less than key of starting node. */ + target_cmp = -1; + else + /* Key must be same as key of starting node. */ + target_cmp = 0; + + for (; ;) + { + cmp = AVL_COMPARE_KEY_NODE(k, h); + + if (cmp == 0) + { + if (st & AVL_EQUAL) + { + /* Equal node was sought and found as starting node. */ + iter->depth = d; + break; + } + + cmp = -target_cmp; + } + else if (target_cmp != 0) + if (!((cmp ^ target_cmp) & L_MASK_HIGH_BIT)) + /* cmp and target_cmp are both negative or both positive. */ + iter->depth = d; + + h = cmp < 0 ? AVL_GET_LESS(h, 1) : AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR_INV_DEPTH + + if (h == AVL_NULL) + break; + + if (cmp > 0) + L_BIT_ARR_1(iter->branch, d) + else + L_BIT_ARR_0(iter->branch, d) + iter->path_h[d++] = h; + } +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_START_ITER_LEAST) + +L_SC void L_(start_iter_least)(L_(avl) *l_tree, L_(iter) *iter) +{ + AVL_HANDLE h = l_tree->root; + + iter->tree_ = l_tree; + + iter->depth = ~0; + + L_BIT_ARR_ALL(iter->branch, 0) + + while (h != AVL_NULL) + { + if (iter->depth != ~0) + iter->path_h[iter->depth] = h; + + iter->depth++; + h = AVL_GET_LESS(h, 1); + L_CHECK_READ_ERROR_INV_DEPTH + } +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_START_ITER_GREATEST) + +L_SC void L_(start_iter_greatest)(L_(avl) *l_tree, L_(iter) *iter) +{ + AVL_HANDLE h = l_tree->root; + + iter->tree_ = l_tree; + + iter->depth = ~0; + + L_BIT_ARR_ALL(iter->branch, 1) + + while (h != AVL_NULL) + { + if (iter->depth != ~0) + iter->path_h[iter->depth] = h; + + iter->depth++; + h = AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR_INV_DEPTH + } +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_GET_ITER) + +L_SC AVL_HANDLE L_(get_iter)(L_(iter) *iter) +{ + if (iter->depth == ~0) + return(AVL_NULL); + + return(iter->depth == 0 ? + iter->tree_->root : iter->path_h[iter->depth - 1]); +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_INCR_ITER) + +L_SC void L_(incr_iter)(L_(iter) *iter) +{ +#define l_tree (iter->tree_) + + if (iter->depth != ~0) + { + AVL_HANDLE h = + AVL_GET_GREATER((iter->depth == 0 ? + iter->tree_->root : iter->path_h[iter->depth - 1]), 1); + L_CHECK_READ_ERROR_INV_DEPTH + + if (h == AVL_NULL) + do + { + if (iter->depth == 0) + { + iter->depth = ~0; + break; + } + + iter->depth--; + } + while (L_BIT_ARR_VAL(iter->branch, iter->depth)); + else + { + L_BIT_ARR_1(iter->branch, iter->depth) + iter->path_h[iter->depth++] = h; + + for (; ;) + { + h = AVL_GET_LESS(h, 1); + L_CHECK_READ_ERROR_INV_DEPTH + + if (h == AVL_NULL) + break; + + L_BIT_ARR_0(iter->branch, iter->depth) + iter->path_h[iter->depth++] = h; + } + } + } + +#undef l_tree +} + +#endif + +#if (L_IMPL_MASK & AVL_IMPL_DECR_ITER) + +L_SC void L_(decr_iter)(L_(iter) *iter) +{ +#define l_tree (iter->tree_) + + if (iter->depth != ~0) + { + AVL_HANDLE h = + AVL_GET_LESS((iter->depth == 0 ? + iter->tree_->root : iter->path_h[iter->depth - 1]), 1); + L_CHECK_READ_ERROR_INV_DEPTH + + if (h == AVL_NULL) + do + { + if (iter->depth == 0) + { + iter->depth = ~0; + break; + } + + iter->depth--; + } + while (!L_BIT_ARR_VAL(iter->branch, iter->depth)); + else + { + L_BIT_ARR_0(iter->branch, iter->depth) + iter->path_h[iter->depth++] = h; + + for (; ;) + { + h = AVL_GET_GREATER(h, 1); + L_CHECK_READ_ERROR_INV_DEPTH + + if (h == AVL_NULL) + break; + + L_BIT_ARR_1(iter->branch, iter->depth) + iter->path_h[iter->depth++] = h; + } + } + } + +#undef l_tree +} + +#endif + +/* Tidy up the preprocessor symbol name space. */ +#undef L_ +#undef L_EST_LONG_BIT +#undef L_SIZE +#undef L_MASK_HIGH_BIT +#undef L_LONG_BIT +#undef L_BIT_ARR_DEFN +#undef L_BIT_ARR_VAL +#undef L_BIT_ARR_0 +#undef L_BIT_ARR_1 +#undef L_BIT_ARR_ALL +#undef L_CHECK_READ_ERROR +#undef L_CHECK_READ_ERROR_INV_DEPTH +#undef L_BIT_ARR_LONGS +#undef L_IMPL_MASK +#undef L_CHECK_READ_ERROR +#undef L_CHECK_READ_ERROR_INV_DEPTH +#undef L_SC +#undef L_BALANCE_PARAM_CALL_PREFIX +#undef L_BALANCE_PARAM_DECL_PREFIX diff --git a/vpx_mem/memory_manager/include/heapmm.h b/vpx_mem/memory_manager/include/heapmm.h new file mode 100644 index 0000000..33004ca --- /dev/null +++ b/vpx_mem/memory_manager/include/heapmm.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +/* External header file for Heap Memory Manager. See documentation in +** heapmm.html. +*/ + +#undef HMM_PROCESS + +/* Include once per configuration in a particular translation unit. */ + +#ifndef HMM_CNFG_NUM + +/* Default configuration. */ + +#ifndef HMM_INC_CNFG_DFLT +#define HMM_INC_CNFG_DFLT +#define HMM_PROCESS +#endif + +#elif HMM_CNFG_NUM == 0 + +/* Test configuration. */ + +#ifndef HMM_INC_CNFG_0 +#define HMM_INC_CNFG_0 +#define HMM_PROCESS +#endif + +#elif HMM_CNFG_NUM == 1 + +#ifndef HMM_INC_CNFG_1 +#define HMM_INC_CNFG_1 +#define HMM_PROCESS +#endif + +#elif HMM_CNFG_NUM == 2 + +#ifndef HMM_INC_CNFG_2 +#define HMM_INC_CNFG_2 +#define HMM_PROCESS +#endif + +#elif HMM_CNFG_NUM == 3 + +#ifndef HMM_INC_CNFG_3 +#define HMM_INC_CNFG_3 +#define HMM_PROCESS +#endif + +#elif HMM_CNFG_NUM == 4 + +#ifndef HMM_INC_CNFG_4 +#define HMM_INC_CNFG_4 +#define HMM_PROCESS +#endif + +#elif HMM_CNFG_NUM == 5 + +#ifndef HMM_INC_CNFG_5 +#define HMM_INC_CNFG_5 +#define HMM_PROCESS +#endif + +#endif + +#ifdef HMM_PROCESS + +#include "hmm_cnfg.h" + +/* Heap descriptor. */ +typedef struct HMM_UNIQUE(structure) +{ + /* private: */ + + /* Pointer to (payload of) root node in AVL tree. This field should + ** really be the AVL tree descriptor (type avl_avl). But (in the + ** instantiation of the AVL tree generic package used in package) the + ** AVL tree descriptor simply contains a pointer to the root. So, + ** whenever a pointer to the AVL tree descriptor is needed, I use the + ** cast: + ** + ** (avl_avl *) &(heap_desc->avl_tree_root) + ** + ** (where heap_desc is a pointer to a heap descriptor). This trick + ** allows me to avoid including cavl_if.h in this external header. */ + void *avl_tree_root; + + /* Pointer to first byte of last block freed, after any coalescing. */ + void *last_freed; + + /* public: */ + + HMM_UNIQUE(size_bau) num_baus_can_shrink; + void *end_of_shrinkable_chunk; +} +HMM_UNIQUE(descriptor); + +/* Prototypes for externally-callable functions. */ + +void HMM_UNIQUE(init)(HMM_UNIQUE(descriptor) *desc); + +void *HMM_UNIQUE(alloc)( + HMM_UNIQUE(descriptor) *desc, HMM_UNIQUE(size_aau) num_addr_align_units); + +/* NOT YET IMPLEMENTED */ +void *HMM_UNIQUE(greedy_alloc)( + HMM_UNIQUE(descriptor) *desc, HMM_UNIQUE(size_aau) needed_addr_align_units, + HMM_UNIQUE(size_aau) coveted_addr_align_units); + +int HMM_UNIQUE(resize)( + HMM_UNIQUE(descriptor) *desc, void *mem, + HMM_UNIQUE(size_aau) num_addr_align_units); + +/* NOT YET IMPLEMENTED */ +int HMM_UNIQUE(greedy_resize)( + HMM_UNIQUE(descriptor) *desc, void *mem, + HMM_UNIQUE(size_aau) needed_addr_align_units, + HMM_UNIQUE(size_aau) coveted_addr_align_units); + +void HMM_UNIQUE(free)(HMM_UNIQUE(descriptor) *desc, void *mem); + +HMM_UNIQUE(size_aau) HMM_UNIQUE(true_size)(void *mem); + +HMM_UNIQUE(size_aau) HMM_UNIQUE(largest_available)( + HMM_UNIQUE(descriptor) *desc); + +void HMM_UNIQUE(new_chunk)( + HMM_UNIQUE(descriptor) *desc, void *start_of_chunk, + HMM_UNIQUE(size_bau) num_block_align_units); + +void HMM_UNIQUE(grow_chunk)( + HMM_UNIQUE(descriptor) *desc, void *end_of_chunk, + HMM_UNIQUE(size_bau) num_block_align_units); + +/* NOT YET IMPLEMENTED */ +void HMM_UNIQUE(shrink_chunk)( + HMM_UNIQUE(descriptor) *desc, + HMM_UNIQUE(size_bau) num_block_align_units); + +#endif /* defined HMM_PROCESS */ diff --git a/vpx_mem/memory_manager/include/hmm_cnfg.h b/vpx_mem/memory_manager/include/hmm_cnfg.h new file mode 100644 index 0000000..30b9f50 --- /dev/null +++ b/vpx_mem/memory_manager/include/hmm_cnfg.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +/* Configure Heap Memory Manager for processor architecture, compiler, +** and desired performance characteristics. This file is included +** by heapmm.h, so these definitions can be used by code external to +** HMM. You can change the default configuration, and/or create alternate +** configuration(s). +*/ + +/* To allow for multiple configurations of HMM to be used in the same +** compilation unit, undefine all preprocessor symbols that will be +** defined below. +*/ +#undef HMM_ADDR_ALIGN_UNIT +#undef HMM_BLOCK_ALIGN_UNIT +#undef HMM_UNIQUE +#undef HMM_DESC_PARAM +#undef HMM_SYM_TO_STRING +#undef HMM_SYM_TO_STRING +#undef HMM_AUDIT_FAIL + +/* Turn X into a string after one macro expansion pass of X. This trick +** works with both GCC and Visual C++. */ +#define HMM_SYM_TO_STRING(X) HMM_SYM_TO_STRING(X) +#define HMM_SYM_TO_STRING(X) #X + +#ifndef HMM_CNFG_NUM + +/* Default configuration. */ + +/* Use hmm_ prefix to avoid identifier conflicts. */ +#define HMM_UNIQUE(BASE) hmm_ ## BASE + +/* Number of bytes in an Address Alignment Unit (AAU). */ +//fwg +//#define HMM_ADDR_ALIGN_UNIT sizeof(int) +#define HMM_ADDR_ALIGN_UNIT 32 + +/* Number of AAUs in a Block Alignment Unit (BAU). */ +#define HMM_BLOCK_ALIGN_UNIT 1 + +/* Type of unsigned integer big enough to hold the size of a Block in AAUs. */ +typedef unsigned long HMM_UNIQUE(size_aau); + +/* Type of unsigned integer big enough to hold the size of a Block/Chunk +** in BAUs. The high bit will be robbed. */ +typedef unsigned long HMM_UNIQUE(size_bau); + +void hmm_dflt_abort(const char *, const char *); + +/* Actions upon a self-audit failure. Must expand to a single complete +** statement. If you remove the definition of this macro, no self-auditing +** will be performed. */ +#define HMM_AUDIT_FAIL \ + hmm_dflt_abort(__FILE__, HMM_SYM_TO_STRING(__LINE__)); + +#elif HMM_CNFG_NUM == 0 + +/* Definitions for testing. */ + +#define HMM_UNIQUE(BASE) thmm_ ## BASE + +#define HMM_ADDR_ALIGN_UNIT sizeof(int) + +#define HMM_BLOCK_ALIGN_UNIT 3 + +typedef unsigned HMM_UNIQUE(size_aau); + +typedef unsigned short HMM_UNIQUE(size_bau); + +/* Under this test setup, a long jump is done if there is a self-audit +** failure. +*/ + +extern jmp_buf HMM_UNIQUE(jmp_buf); +extern const char *HMM_UNIQUE(fail_file); +extern unsigned HMM_UNIQUE(fail_line); + +#define HMM_AUDIT_FAIL \ + { HMM_UNIQUE(fail_file) = __FILE__; HMM_UNIQUE(fail_line) = __LINE__; \ + longjmp(HMM_UNIQUE(jmp_buf), 1); } + +#elif HMM_CNFG_NUM == 1 + +/* Put configuration 1 definitions here (if there is a configuration 1). */ + +#elif HMM_CNFG_NUM == 2 + +/* Put configuration 2 definitions here. */ + +#elif HMM_CNFG_NUM == 3 + +/* Put configuration 3 definitions here. */ + +#elif HMM_CNFG_NUM == 4 + +/* Put configuration 4 definitions here. */ + +#elif HMM_CNFG_NUM == 5 + +/* Put configuration 5 definitions here. */ + +#endif diff --git a/vpx_mem/memory_manager/include/hmm_intrnl.h b/vpx_mem/memory_manager/include/hmm_intrnl.h new file mode 100644 index 0000000..5d62abc --- /dev/null +++ b/vpx_mem/memory_manager/include/hmm_intrnl.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This code is in the public domain. +** Version: 1.1 Author: Walt Karas +*/ + +#ifndef HMM_INTRNL_H_ +#define HMM_INTRNL_H_ + +#ifdef __uClinux__ +# include +#endif + +#include "heapmm.h" + +#define U(BASE) HMM_UNIQUE(BASE) + +/* Mask of high bit of variable of size_bau type. */ +#define HIGH_BIT_BAU_SIZE \ + ((U(size_bau)) ~ (((U(size_bau)) ~ (U(size_bau)) 0) >> 1)) + +/* Add a given number of AAUs to pointer. */ +#define AAUS_FORWARD(PTR, AAU_OFFSET) \ + (((char *) (PTR)) + ((AAU_OFFSET) * ((U(size_aau)) HMM_ADDR_ALIGN_UNIT))) + +/* Subtract a given number of AAUs from pointer. */ +#define AAUS_BACKWARD(PTR, AAU_OFFSET) \ + (((char *) (PTR)) - ((AAU_OFFSET) * ((U(size_aau)) HMM_ADDR_ALIGN_UNIT))) + +/* Add a given number of BAUs to a pointer. */ +#define BAUS_FORWARD(PTR, BAU_OFFSET) \ + AAUS_FORWARD((PTR), (BAU_OFFSET) * ((U(size_aau)) HMM_BLOCK_ALIGN_UNIT)) + +/* Subtract a given number of BAUs to a pointer. */ +#define BAUS_BACKWARD(PTR, BAU_OFFSET) \ + AAUS_BACKWARD((PTR), (BAU_OFFSET) * ((U(size_aau)) HMM_BLOCK_ALIGN_UNIT)) + +typedef struct head_struct +{ + /* Sizes in Block Alignment Units. */ + HMM_UNIQUE(size_bau) previous_block_size, block_size; +} +head_record; + +typedef struct ptr_struct +{ + struct ptr_struct *self, *prev, *next; +} +ptr_record; + +/* Divide and round up any fraction to the next whole number. */ +#define DIV_ROUND_UP(NUMER, DENOM) (((NUMER) + (DENOM) - 1) / (DENOM)) + +/* Number of AAUs in a block head. */ +#define HEAD_AAUS DIV_ROUND_UP(sizeof(head_record), HMM_ADDR_ALIGN_UNIT) + +/* Number of AAUs in a block pointer record. */ +#define PTR_RECORD_AAUS DIV_ROUND_UP(sizeof(ptr_record), HMM_ADDR_ALIGN_UNIT) + +/* Number of BAUs in a dummy end record (at end of chunk). */ +#define DUMMY_END_BLOCK_BAUS DIV_ROUND_UP(HEAD_AAUS, HMM_BLOCK_ALIGN_UNIT) + +/* Minimum number of BAUs in a block (allowing room for the pointer record. */ +#define MIN_BLOCK_BAUS \ + DIV_ROUND_UP(HEAD_AAUS + PTR_RECORD_AAUS, HMM_BLOCK_ALIGN_UNIT) + +/* Return number of BAUs in block (masking off high bit containing block +** status). */ +#define BLOCK_BAUS(HEAD_PTR) \ + (((head_record *) (HEAD_PTR))->block_size & ~HIGH_BIT_BAU_SIZE) + +/* Return number of BAUs in previous block (masking off high bit containing +** block status). */ +#define PREV_BLOCK_BAUS(HEAD_PTR) \ + (((head_record *) (HEAD_PTR))->previous_block_size & ~HIGH_BIT_BAU_SIZE) + +/* Set number of BAUs in previous block, preserving high bit containing +** block status. */ +#define SET_PREV_BLOCK_BAUS(HEAD_PTR, N_BAUS) \ + { register head_record *h_ptr = (head_record *) (HEAD_PTR); \ + h_ptr->previous_block_size &= HIGH_BIT_BAU_SIZE; \ + h_ptr->previous_block_size |= (N_BAUS); } + +/* Convert pointer to pointer record of block to pointer to block's head +** record. */ +#define PTR_REC_TO_HEAD(PTR_REC_PTR) \ + ((head_record *) AAUS_BACKWARD(PTR_REC_PTR, HEAD_AAUS)) + +/* Convert pointer to block head to pointer to block's pointer record. */ +#define HEAD_TO_PTR_REC(HEAD_PTR) \ + ((ptr_record *) AAUS_FORWARD(HEAD_PTR, HEAD_AAUS)) + +/* Returns non-zero if block is allocated. */ +#define IS_BLOCK_ALLOCATED(HEAD_PTR) \ + (((((head_record *) (HEAD_PTR))->block_size | \ + ((head_record *) (HEAD_PTR))->previous_block_size) & \ + HIGH_BIT_BAU_SIZE) == 0) + +#define MARK_BLOCK_ALLOCATED(HEAD_PTR) \ + { register head_record *h_ptr = (head_record *) (HEAD_PTR); \ + h_ptr->block_size &= ~HIGH_BIT_BAU_SIZE; \ + h_ptr->previous_block_size &= ~HIGH_BIT_BAU_SIZE; } + +/* Mark a block as free when it is not the first block in a bin (and +** therefore not a node in the AVL tree). */ +#define MARK_SUCCESSIVE_BLOCK_IN_FREE_BIN(HEAD_PTR) \ + { register head_record *h_ptr = (head_record *) (HEAD_PTR); \ + h_ptr->block_size |= HIGH_BIT_BAU_SIZE; } + +/* Prototypes for internal functions implemented in one file and called in +** another. +*/ + +void U(into_free_collection)(U(descriptor) *desc, head_record *head_ptr); + +void U(out_of_free_collection)(U(descriptor) *desc, head_record *head_ptr); + +void *U(alloc_from_bin)( + U(descriptor) *desc, ptr_record *bin_front_ptr, U(size_bau) n_baus); + +#ifdef HMM_AUDIT_FAIL + +/* Simply contains a reference to the HMM_AUDIT_FAIL macro and a +** dummy return. */ +int U(audit_block_fail_dummy_return)(void); + + +/* Auditing a block consists of checking that the size in its head +** matches the previous block size in the head of the next block. */ +#define AUDIT_BLOCK_AS_EXPR(HEAD_PTR) \ + ((BLOCK_BAUS(HEAD_PTR) == \ + PREV_BLOCK_BAUS(BAUS_FORWARD(HEAD_PTR, BLOCK_BAUS(HEAD_PTR)))) ? \ + 0 : U(audit_block_fail_dummy_return)()) + +#define AUDIT_BLOCK(HEAD_PTR) \ + { void *h_ptr = (HEAD_PTR); AUDIT_BLOCK_AS_EXPR(h_ptr); } + +#endif + +/* Interface to AVL tree generic package instantiation. */ + +#define AVL_UNIQUE(BASE) U(avl_ ## BASE) + +#define AVL_HANDLE ptr_record * + +#define AVL_KEY U(size_bau) + +#define AVL_MAX_DEPTH 64 + +#include "cavl_if.h" + +#endif /* Include once. */ diff --git a/vpx_mem/vpx_mem.c b/vpx_mem/vpx_mem.c new file mode 100644 index 0000000..eade432 --- /dev/null +++ b/vpx_mem/vpx_mem.c @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#define __VPX_MEM_C__ + +#include "vpx_mem.h" +#include +#include +#include +#include "include/vpx_mem_intrnl.h" + +#if CONFIG_MEM_TRACKER +#ifndef VPX_NO_GLOBALS +static unsigned long g_alloc_count = 0; +#else +#include "vpx_global_handling.h" +#define g_alloc_count vpxglobalm(vpxmem,g_alloc_count) +#endif +#endif + +#if CONFIG_MEM_MANAGER +# include "heapmm.h" +# include "hmm_intrnl.h" + +# define SHIFT_HMM_ADDR_ALIGN_UNIT 5 +# define TOTAL_MEMORY_TO_ALLOCATE 20971520 /* 20 * 1024 * 1024 */ + +# define MM_DYNAMIC_MEMORY 1 +# if MM_DYNAMIC_MEMORY +static unsigned char *g_p_mng_memory_raw = NULL; +static unsigned char *g_p_mng_memory = NULL; +# else +static unsigned char g_p_mng_memory[TOTAL_MEMORY_TO_ALLOCATE]; +# endif + +static size_t g_mm_memory_size = TOTAL_MEMORY_TO_ALLOCATE; + +static hmm_descriptor hmm_d; +static int g_mng_memory_allocated = 0; + +static int vpx_mm_create_heap_memory(); +static void *vpx_mm_realloc(void *memblk, size_t size); +#endif /*CONFIG_MEM_MANAGER*/ + +#if USE_GLOBAL_FUNCTION_POINTERS +struct GLOBAL_FUNC_POINTERS +{ + g_malloc_func g_malloc; + g_calloc_func g_calloc; + g_realloc_func g_realloc; + g_free_func g_free; + g_memcpy_func g_memcpy; + g_memset_func g_memset; + g_memmove_func g_memmove; +} *g_func = NULL; + +# define VPX_MALLOC_L g_func->g_malloc +# define VPX_REALLOC_L g_func->g_realloc +# define VPX_FREE_L g_func->g_free +# define VPX_MEMCPY_L g_func->g_memcpy +# define VPX_MEMSET_L g_func->g_memset +# define VPX_MEMMOVE_L g_func->g_memmove +#else +# define VPX_MALLOC_L malloc +# define VPX_REALLOC_L realloc +# define VPX_FREE_L free +# define VPX_MEMCPY_L memcpy +# define VPX_MEMSET_L memset +# define VPX_MEMMOVE_L memmove +#endif /* USE_GLOBAL_FUNCTION_POINTERS */ + +unsigned int vpx_mem_get_version() +{ + unsigned int ver = ((unsigned int)(unsigned char)VPX_MEM_VERSION_CHIEF << 24 | + (unsigned int)(unsigned char)VPX_MEM_VERSION_MAJOR << 16 | + (unsigned int)(unsigned char)VPX_MEM_VERSION_MINOR << 8 | + (unsigned int)(unsigned char)VPX_MEM_VERSION_PATCH); + return ver; +} + +int vpx_mem_set_heap_size(size_t size) +{ + int ret = -1; + +#if CONFIG_MEM_MANAGER +#if MM_DYNAMIC_MEMORY + + if (!g_mng_memory_allocated && size) + { + g_mm_memory_size = size; + ret = 0; + } + else + ret = -3; + +#else + ret = -2; +#endif +#else + (void)size; +#endif + + return ret; +} + +void *vpx_memalign(size_t align, size_t size) +{ + void *addr, + * x = NULL; + +#if CONFIG_MEM_MANAGER + int number_aau; + + if (vpx_mm_create_heap_memory() < 0) + { + _P(printf("[vpx][mm] ERROR vpx_memalign() Couldn't create memory for Heap.\n");) + } + + number_aau = ((size + align - 1 + ADDRESS_STORAGE_SIZE) >> + SHIFT_HMM_ADDR_ALIGN_UNIT) + 1; + + addr = hmm_alloc(&hmm_d, number_aau); +#else + addr = VPX_MALLOC_L(size + align - 1 + ADDRESS_STORAGE_SIZE); +#endif /*CONFIG_MEM_MANAGER*/ + + if (addr) + { + x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align); + /* save the actual malloc address */ + ((size_t *)x)[-1] = (size_t)addr; + } + + return x; +} + +void *vpx_malloc(size_t size) +{ + return vpx_memalign(DEFAULT_ALIGNMENT, size); +} + +void *vpx_calloc(size_t num, size_t size) +{ + void *x; + + x = vpx_memalign(DEFAULT_ALIGNMENT, num * size); + + if (x) + VPX_MEMSET_L(x, 0, num * size); + + return x; +} + +void *vpx_realloc(void *memblk, size_t size) +{ + void *addr, + * new_addr = NULL; + int align = DEFAULT_ALIGNMENT; + + /* + The realloc() function changes the size of the object pointed to by + ptr to the size specified by size, and returns a pointer to the + possibly moved block. The contents are unchanged up to the lesser + of the new and old sizes. If ptr is null, realloc() behaves like + malloc() for the specified size. If size is zero (0) and ptr is + not a null pointer, the object pointed to is freed. + */ + if (!memblk) + new_addr = vpx_malloc(size); + else if (!size) + vpx_free(memblk); + else + { + addr = (void *)(((size_t *)memblk)[-1]); + memblk = NULL; + +#if CONFIG_MEM_MANAGER + new_addr = vpx_mm_realloc(addr, size + align + ADDRESS_STORAGE_SIZE); +#else + new_addr = VPX_REALLOC_L(addr, size + align + ADDRESS_STORAGE_SIZE); +#endif + + if (new_addr) + { + addr = new_addr; + new_addr = (void *)(((size_t) + ((unsigned char *)new_addr + ADDRESS_STORAGE_SIZE) + (align - 1)) & + (size_t) - align); + /* save the actual malloc address */ + ((size_t *)new_addr)[-1] = (size_t)addr; + } + } + + return new_addr; +} + +void vpx_free(void *memblk) +{ + if (memblk) + { + void *addr = (void *)(((size_t *)memblk)[-1]); +#if CONFIG_MEM_MANAGER + hmm_free(&hmm_d, addr); +#else + VPX_FREE_L(addr); +#endif + } +} + +#if CONFIG_MEM_TRACKER +void *xvpx_memalign(size_t align, size_t size, char *file, int line) +{ +#if TRY_BOUNDS_CHECK + unsigned char *x_bounds; +#endif + + void *x; + + if (g_alloc_count == 0) + { +#if TRY_BOUNDS_CHECK + int i_rv = vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE); +#else + int i_rv = vpx_memory_tracker_init(0, 0); +#endif + + if (i_rv < 0) + { + _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");) + } + } + +#if TRY_BOUNDS_CHECK + { + int i; + unsigned int tempme = BOUNDS_CHECK_VALUE; + + x_bounds = vpx_memalign(align, size + (BOUNDS_CHECK_PAD_SIZE * 2)); + + if (x_bounds) + { + /*we're aligning the address twice here but to keep things + consistent we want to have the padding come before the stored + address so no matter what free function gets called we will + attempt to free the correct address*/ + x_bounds = (unsigned char *)(((size_t *)x_bounds)[-1]); + x = align_addr(x_bounds + BOUNDS_CHECK_PAD_SIZE + ADDRESS_STORAGE_SIZE, + (int)align); + /* save the actual malloc address */ + ((size_t *)x)[-1] = (size_t)x_bounds; + + for (i = 0; i < BOUNDS_CHECK_PAD_SIZE; i += sizeof(unsigned int)) + { + VPX_MEMCPY_L(x_bounds + i, &tempme, sizeof(unsigned int)); + VPX_MEMCPY_L((unsigned char *)x + size + i, + &tempme, sizeof(unsigned int)); + } + } + else + x = NULL; + } +#else + x = vpx_memalign(align, size); +#endif /*TRY_BOUNDS_CHECK*/ + + g_alloc_count++; + + vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1); + + return x; +} + +void *xvpx_malloc(size_t size, char *file, int line) +{ + return xvpx_memalign(DEFAULT_ALIGNMENT, size, file, line); +} + +void *xvpx_calloc(size_t num, size_t size, char *file, int line) +{ + void *x = xvpx_memalign(DEFAULT_ALIGNMENT, num * size, file, line); + + if (x) + VPX_MEMSET_L(x, 0, num * size); + + return x; +} + +void *xvpx_realloc(void *memblk, size_t size, char *file, int line) +{ + struct mem_block *p = NULL; + int orig_size = 0, + orig_line = 0; + char *orig_file = NULL; + +#if TRY_BOUNDS_CHECK + unsigned char *x_bounds = memblk ? + (unsigned char *)(((size_t *)memblk)[-1]) : + NULL; +#endif + + void *x; + + if (g_alloc_count == 0) + { +#if TRY_BOUNDS_CHECK + + if (!vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE)) +#else + if (!vpx_memory_tracker_init(0, 0)) +#endif + { + _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");) + } + } + + if ((p = vpx_memory_tracker_find((size_t)memblk))) + { + orig_size = p->size; + orig_file = p->file; + orig_line = p->line; + } + +#if TRY_BOUNDS_CHECK_ON_FREE + vpx_memory_tracker_check_integrity(file, line); +#endif + + /* have to do this regardless of success, because + * the memory that does get realloc'd may change + * the bounds values of this block + */ + vpx_memory_tracker_remove((size_t)memblk); + +#if TRY_BOUNDS_CHECK + { + int i; + unsigned int tempme = BOUNDS_CHECK_VALUE; + + x_bounds = vpx_realloc(memblk, size + (BOUNDS_CHECK_PAD_SIZE * 2)); + + if (x_bounds) + { + x_bounds = (unsigned char *)(((size_t *)x_bounds)[-1]); + x = align_addr(x_bounds + BOUNDS_CHECK_PAD_SIZE + ADDRESS_STORAGE_SIZE, + (int)DEFAULT_ALIGNMENT); + /* save the actual malloc address */ + ((size_t *)x)[-1] = (size_t)x_bounds; + + for (i = 0; i < BOUNDS_CHECK_PAD_SIZE; i += sizeof(unsigned int)) + { + VPX_MEMCPY_L(x_bounds + i, &tempme, sizeof(unsigned int)); + VPX_MEMCPY_L((unsigned char *)x + size + i, + &tempme, sizeof(unsigned int)); + } + } + else + x = NULL; + } +#else + x = vpx_realloc(memblk, size); +#endif /*TRY_BOUNDS_CHECK*/ + + if (!memblk) ++g_alloc_count; + + if (x) + vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1); + else + vpx_memory_tracker_add((size_t)memblk, orig_size, orig_file, orig_line, 1); + + return x; +} + +void xvpx_free(void *p_address, char *file, int line) +{ +#if TRY_BOUNDS_CHECK + unsigned char *p_bounds_address = (unsigned char *)p_address; + /*p_bounds_address -= BOUNDS_CHECK_PAD_SIZE;*/ +#endif + +#if !TRY_BOUNDS_CHECK_ON_FREE + (void)file; + (void)line; +#endif + + if (p_address) + { +#if TRY_BOUNDS_CHECK_ON_FREE + vpx_memory_tracker_check_integrity(file, line); +#endif + + /* if the addr isn't found in the list, assume it was allocated via + * vpx_ calls not xvpx_, therefore it does not contain any padding + */ + if (vpx_memory_tracker_remove((size_t)p_address) == -2) + { + p_bounds_address = p_address; + _P(fprintf(stderr, "[vpx_mem][xvpx_free] addr: %p not found in" + " list; freed from file:%s" + " line:%d\n", p_address, file, line)); + } + else + --g_alloc_count; + +#if TRY_BOUNDS_CHECK + vpx_free(p_bounds_address); +#else + vpx_free(p_address); +#endif + + if (!g_alloc_count) + vpx_memory_tracker_destroy(); + } +} + +#endif /*CONFIG_MEM_TRACKER*/ + +#if CONFIG_MEM_CHECKS +#if defined(VXWORKS) +#include /*for task_delay()*/ +/* This function is only used to get a stack trace of the player +object so we can se where we are having a problem. */ +static int get_my_tt(int task) +{ + tt(task); + + return 0; +} + +static void vx_sleep(int msec) +{ + int ticks_to_sleep = 0; + + if (msec) + { + int msec_per_tick = 1000 / sys_clk_rate_get(); + + if (msec < msec_per_tick) + ticks_to_sleep++; + else + ticks_to_sleep = msec / msec_per_tick; + } + + task_delay(ticks_to_sleep); +} +#endif +#endif + +void *vpx_memcpy(void *dest, const void *source, size_t length) +{ +#if CONFIG_MEM_CHECKS + + if (((int)dest < 0x4000) || ((int)source < 0x4000)) + { + _P(printf("WARNING: vpx_memcpy dest:0x%x source:0x%x len:%d\n", (int)dest, (int)source, length);) + +#if defined(VXWORKS) + sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0); + + vx_sleep(10000); +#endif + } + +#endif + + return VPX_MEMCPY_L(dest, source, length); +} + +void *vpx_memset(void *dest, int val, size_t length) +{ +#if CONFIG_MEM_CHECKS + + if ((int)dest < 0x4000) + { + _P(printf("WARNING: vpx_memset dest:0x%x val:%d len:%d\n", (int)dest, val, length);) + +#if defined(VXWORKS) + sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0); + + vx_sleep(10000); +#endif + } + +#endif + + return VPX_MEMSET_L(dest, val, length); +} + +void *vpx_memmove(void *dest, const void *src, size_t count) +{ +#if CONFIG_MEM_CHECKS + + if (((int)dest < 0x4000) || ((int)src < 0x4000)) + { + _P(printf("WARNING: vpx_memmove dest:0x%x src:0x%x count:%d\n", (int)dest, (int)src, count);) + +#if defined(VXWORKS) + sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0); + + vx_sleep(10000); +#endif + } + +#endif + + return VPX_MEMMOVE_L(dest, src, count); +} + +#if CONFIG_MEM_MANAGER + +static int vpx_mm_create_heap_memory() +{ + int i_rv = 0; + + if (!g_mng_memory_allocated) + { +#if MM_DYNAMIC_MEMORY + g_p_mng_memory_raw = + (unsigned char *)malloc(g_mm_memory_size + HMM_ADDR_ALIGN_UNIT); + + if (g_p_mng_memory_raw) + { + g_p_mng_memory = (unsigned char *)((((unsigned int)g_p_mng_memory_raw) + + HMM_ADDR_ALIGN_UNIT - 1) & + -(int)HMM_ADDR_ALIGN_UNIT); + + _P(printf("[vpx][mm] total memory size:%d g_p_mng_memory_raw:0x%x g_p_mng_memory:0x%x\n" + , g_mm_memory_size + HMM_ADDR_ALIGN_UNIT + , (unsigned int)g_p_mng_memory_raw + , (unsigned int)g_p_mng_memory);) + } + else + { + _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n" + , g_mm_memory_size);) + + i_rv = -1; + } + + if (g_p_mng_memory) +#endif + { + int chunk_size = 0; + + g_mng_memory_allocated = 1; + + hmm_init(&hmm_d); + + chunk_size = g_mm_memory_size >> SHIFT_HMM_ADDR_ALIGN_UNIT; + + chunk_size -= DUMMY_END_BLOCK_BAUS; + + _P(printf("[vpx][mm] memory size:%d for vpx memory manager. g_p_mng_memory:0x%x chunk_size:%d\n" + , g_mm_memory_size + , (unsigned int)g_p_mng_memory + , chunk_size);) + + hmm_new_chunk(&hmm_d, (void *)g_p_mng_memory, chunk_size); + } + +#if MM_DYNAMIC_MEMORY + else + { + _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n" + , g_mm_memory_size);) + + i_rv = -1; + } + +#endif + } + + return i_rv; +} + +static void *vpx_mm_realloc(void *memblk, size_t size) +{ + void *p_ret = NULL; + + if (vpx_mm_create_heap_memory() < 0) + { + _P(printf("[vpx][mm] ERROR vpx_mm_realloc() Couldn't create memory for Heap.\n");) + } + else + { + int i_rv = 0; + int old_num_aaus; + int new_num_aaus; + + old_num_aaus = hmm_true_size(memblk); + new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1; + + if (old_num_aaus == new_num_aaus) + { + p_ret = memblk; + } + else + { + i_rv = hmm_resize(&hmm_d, memblk, new_num_aaus); + + if (i_rv == 0) + { + p_ret = memblk; + } + else + { + /* Error. Try to malloc and then copy data. */ + void *p_from_malloc; + + new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1; + p_from_malloc = hmm_alloc(&hmm_d, new_num_aaus); + + if (p_from_malloc) + { + vpx_memcpy(p_from_malloc, memblk, size); + hmm_free(&hmm_d, memblk); + + p_ret = p_from_malloc; + } + } + } + } + + return p_ret; +} +#endif /*CONFIG_MEM_MANAGER*/ + +#if USE_GLOBAL_FUNCTION_POINTERS +# if CONFIG_MEM_TRACKER +extern int vpx_memory_tracker_set_functions(g_malloc_func g_malloc_l + , g_calloc_func g_calloc_l + , g_realloc_func g_realloc_l + , g_free_func g_free_l + , g_memcpy_func g_memcpy_l + , g_memset_func g_memset_l + , g_memmove_func g_memmove_l); +# endif +#endif /*USE_GLOBAL_FUNCTION_POINTERS*/ +int vpx_mem_set_functions(g_malloc_func g_malloc_l + , g_calloc_func g_calloc_l + , g_realloc_func g_realloc_l + , g_free_func g_free_l + , g_memcpy_func g_memcpy_l + , g_memset_func g_memset_l + , g_memmove_func g_memmove_l) +{ +#if USE_GLOBAL_FUNCTION_POINTERS + + /* If use global functions is turned on then the + application must set the global functions before + it does anything else or vpx_mem will have + unpredictable results. */ + if (!g_func) + { + g_func = (struct GLOBAL_FUNC_POINTERS *) + g_malloc_l(sizeof(struct GLOBAL_FUNC_POINTERS)); + + if (!g_func) + { + return -1; + } + } + +#if CONFIG_MEM_TRACKER + { + int rv = 0; + rv = vpx_memory_tracker_set_functions(g_malloc_l + , g_calloc_l + , g_realloc_l + , g_free_l + , g_memcpy_l + , g_memset_l + , g_memmove_l); + + if (rv < 0) + { + return rv; + } + } +#endif + + g_func->g_malloc = g_malloc_l; + g_func->g_calloc = g_calloc_l; + g_func->g_realloc = g_realloc_l; + g_func->g_free = g_free_l; + g_func->g_memcpy = g_memcpy_l; + g_func->g_memset = g_memset_l; + g_func->g_memmove = g_memmove_l; + + return 0; +#else + (void)g_malloc_l; + (void)g_calloc_l; + (void)g_realloc_l; + (void)g_free_l; + (void)g_memcpy_l; + (void)g_memset_l; + (void)g_memmove_l; + return -1; +#endif +} + +int vpx_mem_unset_functions() +{ +#if USE_GLOBAL_FUNCTION_POINTERS + + if (g_func) + { + g_free_func temp_free = g_func->g_free; + temp_free(g_func); + g_func = NULL; + } + +#endif + return 0; +} diff --git a/vpx_mem/vpx_mem.h b/vpx_mem/vpx_mem.h new file mode 100644 index 0000000..749eaa4 --- /dev/null +++ b/vpx_mem/vpx_mem.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __VPX_MEM_H__ +#define __VPX_MEM_H__ + +#if defined(__uClinux__) +# include +#endif + +/* vpx_mem version info */ +#define vpx_mem_version "2.2.1.5" + +#define VPX_MEM_VERSION_CHIEF 2 +#define VPX_MEM_VERSION_MAJOR 2 +#define VPX_MEM_VERSION_MINOR 1 +#define VPX_MEM_VERSION_PATCH 5 +/* end - vpx_mem version info */ + +#ifndef VPX_TRACK_MEM_USAGE +# define VPX_TRACK_MEM_USAGE 0 /* enable memory tracking/integrity checks */ +#endif +#ifndef VPX_CHECK_MEM_FUNCTIONS +# define VPX_CHECK_MEM_FUNCTIONS 0 /* enable basic safety checks in _memcpy, + _memset, and _memmove */ +#endif +#ifndef REPLACE_BUILTIN_FUNCTIONS +# define REPLACE_BUILTIN_FUNCTIONS 0 /* replace builtin functions with their + vpx_ equivalents */ +#endif + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + /* + vpx_mem_get_version() + provided for runtime version checking. Returns an unsigned int of the form + CHIEF | MAJOR | MINOR | PATCH, where the chief version number is the high + order byte. + */ + unsigned int vpx_mem_get_version(void); + + /* + vpx_mem_set_heap_size(size_t size) + size - size in bytes for the memory manager to allocate for its heap + Sets the memory manager's initial heap size + Return: + 0: on success + -1: if memory manager calls have not been included in the vpx_mem lib + -2: if the memory manager has been compiled to use static memory + -3: if the memory manager has already allocated its heap + */ + int vpx_mem_set_heap_size(size_t size); + + void *vpx_memalign(size_t align, size_t size); + void *vpx_malloc(size_t size); + void *vpx_calloc(size_t num, size_t size); + void *vpx_realloc(void *memblk, size_t size); + void vpx_free(void *memblk); + + void *vpx_memcpy(void *dest, const void *src, size_t length); + void *vpx_memset(void *dest, int val, size_t length); + void *vpx_memmove(void *dest, const void *src, size_t count); + + /* special memory functions */ + void *vpx_mem_alloc(int id, size_t size, size_t align); + void vpx_mem_free(int id, void *mem, size_t size); + + /* Wrappers to standard library functions. */ + typedef void*(* g_malloc_func)(size_t); + typedef void*(* g_calloc_func)(size_t, size_t); + typedef void*(* g_realloc_func)(void *, size_t); + typedef void (* g_free_func)(void *); + typedef void*(* g_memcpy_func)(void *, const void *, size_t); + typedef void*(* g_memset_func)(void *, int, size_t); + typedef void*(* g_memmove_func)(void *, const void *, size_t); + + int vpx_mem_set_functions(g_malloc_func g_malloc_l + , g_calloc_func g_calloc_l + , g_realloc_func g_realloc_l + , g_free_func g_free_l + , g_memcpy_func g_memcpy_l + , g_memset_func g_memset_l + , g_memmove_func g_memmove_l); + int vpx_mem_unset_functions(void); + + + /* some defines for backward compatibility */ +#define DMEM_GENERAL 0 + +#define duck_memalign(X,Y,Z) vpx_memalign(X,Y) +#define duck_malloc(X,Y) vpx_malloc(X) +#define duck_calloc(X,Y,Z) vpx_calloc(X,Y) +#define duck_realloc vpx_realloc +#define duck_free vpx_free +#define duck_memcpy vpx_memcpy +#define duck_memmove vpx_memmove +#define duck_memset vpx_memset + +#if REPLACE_BUILTIN_FUNCTIONS +# ifndef __VPX_MEM_C__ +# define memalign vpx_memalign +# define malloc vpx_malloc +# define calloc vpx_calloc +# define realloc vpx_realloc +# define free vpx_free +# define memcpy vpx_memcpy +# define memmove vpx_memmove +# define memset vpx_memset +# endif +#endif + +#if CONFIG_MEM_TRACKER +#include + /*from vpx_mem/vpx_mem_tracker.c*/ + extern void vpx_memory_tracker_dump(); + extern void vpx_memory_tracker_check_integrity(char *file, unsigned int line); + extern int vpx_memory_tracker_set_log_type(int type, char *option); + extern int vpx_memory_tracker_set_log_func(void *userdata, + void(*logfunc)(void *userdata, + const char *fmt, va_list args)); +# ifndef __VPX_MEM_C__ +# define vpx_memalign(align, size) xvpx_memalign((align), (size), __FILE__, __LINE__) +# define vpx_malloc(size) xvpx_malloc((size), __FILE__, __LINE__) +# define vpx_calloc(num, size) xvpx_calloc(num, size, __FILE__, __LINE__) +# define vpx_realloc(addr, size) xvpx_realloc(addr, size, __FILE__, __LINE__) +# define vpx_free(addr) xvpx_free(addr, __FILE__, __LINE__) +# define vpx_memory_tracker_check_integrity() vpx_memory_tracker_check_integrity(__FILE__, __LINE__) +# define vpx_mem_alloc(id,size,align) xvpx_mem_alloc(id, size, align, __FILE__, __LINE__) +# define vpx_mem_free(id,mem,size) xvpx_mem_free(id, mem, size, __FILE__, __LINE__) +# endif + + void *xvpx_memalign(size_t align, size_t size, char *file, int line); + void *xvpx_malloc(size_t size, char *file, int line); + void *xvpx_calloc(size_t num, size_t size, char *file, int line); + void *xvpx_realloc(void *memblk, size_t size, char *file, int line); + void xvpx_free(void *memblk, char *file, int line); + void *xvpx_mem_alloc(int id, size_t size, size_t align, char *file, int line); + void xvpx_mem_free(int id, void *mem, size_t size, char *file, int line); + +#else +# ifndef __VPX_MEM_C__ +# define vpx_memory_tracker_dump() +# define vpx_memory_tracker_check_integrity() +# define vpx_memory_tracker_set_log_type(t,o) 0 +# define vpx_memory_tracker_set_log_func(u,f) 0 +# endif +#endif + +#if !VPX_CHECK_MEM_FUNCTIONS +# ifndef __VPX_MEM_C__ +# include +# define vpx_memcpy memcpy +# define vpx_memset memset +# define vpx_memmove memmove +# endif +#endif + +#ifdef VPX_MEM_PLTFRM +# include VPX_MEM_PLTFRM +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* __VPX_MEM_H__ */ diff --git a/vpx_mem/vpx_mem.mk b/vpx_mem/vpx_mem.mk new file mode 100644 index 0000000..4663c5a --- /dev/null +++ b/vpx_mem/vpx_mem.mk @@ -0,0 +1,22 @@ +MEM_SRCS-yes += vpx_mem.mk +MEM_SRCS-yes += vpx_mem.c +MEM_SRCS-yes += vpx_mem.h +MEM_SRCS-yes += include/vpx_mem_intrnl.h + +MEM_SRCS-$(CONFIG_MEM_TRACKER) += vpx_mem_tracker.c +MEM_SRCS-$(CONFIG_MEM_TRACKER) += include/vpx_mem_tracker.h + +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_true.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_resize.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_shrink.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_largest.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_dflt_abort.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_base.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/include +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/include/hmm_intrnl.h +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/include/cavl_if.h +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/include/hmm_cnfg.h +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/include/heapmm.h +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/include/cavl_impl.h +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_grow.c +MEM_SRCS-$(CONFIG_MEM_MANAGER) += memory_manager/hmm_alloc.c diff --git a/vpx_mem/vpx_mem_tracker.c b/vpx_mem/vpx_mem_tracker.c new file mode 100644 index 0000000..b37076e --- /dev/null +++ b/vpx_mem/vpx_mem_tracker.c @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + vpx_mem_tracker.c + + jwz 2003-09-30: + Stores a list of addreses, their size, and file and line they came from. + All exposed lib functions are prefaced by vpx_ and allow the global list + to be thread safe. + Current supported platforms are: + Linux, Win32, win_ce and vx_works + Further support can be added by defining the platform specific mutex + in the memory_tracker struct as well as calls to create/destroy/lock/unlock + the mutex in vpx_memory_tracker_init/Destroy and memory_tracker_lock_mutex/unlock_mutex +*/ +#include "vpx_config.h" + +#if defined(__uClinux__) +# include +#endif + +#if HAVE_PTHREAD_H +# include +#elif defined(WIN32) || defined(_WIN32_WCE) +# define WIN32_LEAN_AND_MEAN +# include +# include +#elif defined(VXWORKS) +# include +#endif + +#include +#include +#include //VXWORKS doesn't have a malloc/memory.h file, +//this should pull in malloc,free,etc. +#include + +#include "include/vpx_mem_tracker.h" + +#undef vpx_malloc //undefine any vpx_mem macros that may affect calls to +#undef vpx_free //memory functions in this file +#undef vpx_memcpy +#undef vpx_memset + + +#ifndef USE_GLOBAL_FUNCTION_POINTERS +# define USE_GLOBAL_FUNCTION_POINTERS 0 //use function pointers instead of compiled functions. +#endif + +#if USE_GLOBAL_FUNCTION_POINTERS +static mem_track_malloc_func g_malloc = malloc; +static mem_track_calloc_func g_calloc = calloc; +static mem_track_realloc_func g_realloc = realloc; +static mem_track_free_func g_free = free; +static mem_track_memcpy_func g_memcpy = memcpy; +static mem_track_memset_func g_memset = memset; +static mem_track_memmove_func g_memmove = memmove; +# define MEM_TRACK_MALLOC g_malloc +# define MEM_TRACK_FREE g_free +# define MEM_TRACK_MEMCPY g_memcpy +# define MEM_TRACK_MEMSET g_memset +#else +# define MEM_TRACK_MALLOC vpx_malloc +# define MEM_TRACK_FREE vpx_free +# define MEM_TRACK_MEMCPY vpx_memcpy +# define MEM_TRACK_MEMSET vpx_memset +#endif // USE_GLOBAL_FUNCTION_POINTERS + +/* prototypes for internal library functions */ +static void memtrack_log(const char *fmt, ...); +static void memory_tracker_dump(); +static void memory_tracker_check_integrity(char *file, unsigned int line); +static void memory_tracker_add(size_t addr, unsigned int size, + char *file, unsigned int line, + int padded); +static int memory_tracker_remove(size_t addr); +static struct mem_block *memory_tracker_find(size_t addr); + +#if defined(NO_MUTEX) +# define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited) +# define memory_tracker_unlock_mutex() +#else +static int memory_tracker_lock_mutex(); +static int memory_tracker_unlock_mutex(); +#endif + +#ifndef VPX_NO_GLOBALS +struct memory_tracker +{ + struct mem_block *head, + * tail; + int len, + totalsize; + unsigned int current_allocated, + max_allocated; + +#if HAVE_PTHREAD_H + pthread_mutex_t mutex; +#elif defined(WIN32) || defined(_WIN32_WCE) + HANDLE mutex; +#elif defined(VXWORKS) + SEM_ID mutex; +#elif defined(NO_MUTEX) +#else +#error "No mutex type defined for this platform!" +#endif + + int padding_size, + pad_value; +}; + +static struct memory_tracker memtrack; //our global memory allocation list +static int g_b_mem_tracker_inited = 0; //indicates whether the global list has +//been initialized (1:yes/0:no) +static struct +{ + FILE *file; + int type; + void (*func)(void *userdata, const char *fmt, va_list args); + void *userdata; +} g_logging = {NULL, 0, NULL, NULL}; +#else +# include "vpx_global_handling.h" +#define g_b_mem_tracker_inited vpxglobalm(vpxmem,g_b_mem_tracker_inited) +#define g_logging vpxglobalm(vpxmem,g_logging) +#define memtrack vpxglobalm(vpxmem,memtrack) +#endif // #ifndef VPX_NO_GLOBALS + +extern void *vpx_malloc(size_t size); +extern void vpx_free(void *memblk); +extern void *vpx_memcpy(void *dest, const void *src, size_t length); +extern void *vpx_memset(void *dest, int val, size_t length); + +/* + * + * Exposed library functions + * +*/ + +/* + vpx_memory_tracker_init(int padding_size, int pad_value) + padding_size - the size of the padding before and after each mem addr. + Values > 0 indicate that integrity checks can be performed + by inspecting these areas. + pad_value - the initial value within the padding area before and after + each mem addr. + + Initializes global memory tracker structure + Allocates the head of the list +*/ +int vpx_memory_tracker_init(int padding_size, int pad_value) +{ + if (!g_b_mem_tracker_inited) + { + if ((memtrack.head = (struct mem_block *) + MEM_TRACK_MALLOC(sizeof(struct mem_block)))) + { + int ret; + + MEM_TRACK_MEMSET(memtrack.head, 0, sizeof(struct mem_block)); + + memtrack.tail = memtrack.head; + + memtrack.current_allocated = 0; + memtrack.max_allocated = 0; + + memtrack.padding_size = padding_size; + memtrack.pad_value = pad_value; + +#if HAVE_PTHREAD_H + ret = pthread_mutex_init(&memtrack.mutex, + NULL); /*mutex attributes (NULL=default)*/ +#elif defined(WIN32) || defined(_WIN32_WCE) + memtrack.mutex = CreateMutex(NULL, /*security attributes*/ + FALSE, /*we don't want initial ownership*/ + NULL); /*mutex name*/ + ret = !memtrack.mutex; +#elif defined(VXWORKS) + memtrack.mutex = sem_bcreate(SEM_Q_FIFO, /*SEM_Q_FIFO non-priority based mutex*/ + SEM_FULL); /*SEM_FULL initial state is unlocked*/ + ret = !memtrack.mutex; +#elif defined(NO_MUTEX) + ret = 0; +#endif + + if (ret) + { + memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n"); + + MEM_TRACK_FREE(memtrack.head); + memtrack.head = NULL; + } + else + { + memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version" pad_size:%d pad_val:0x%x %d\n" + , padding_size + , pad_value + , pad_value); + g_b_mem_tracker_inited = 1; + } + } + } + + return g_b_mem_tracker_inited; +} + +/* + vpx_memory_tracker_destroy() + If our global struct was initialized zeros out all its members, + frees memory and destroys it's mutex +*/ +void vpx_memory_tracker_destroy() +{ + if (!memory_tracker_lock_mutex()) + { + struct mem_block *p = memtrack.head, + * p2 = memtrack.head; + + memory_tracker_dump(); + + while (p) + { + p2 = p; + p = p->next; + + MEM_TRACK_FREE(p2); + } + + memtrack.head = NULL; + memtrack.tail = NULL; + memtrack.len = 0; + memtrack.current_allocated = 0; + memtrack.max_allocated = 0; + + if (!g_logging.type && g_logging.file && g_logging.file != stderr) + { + fclose(g_logging.file); + g_logging.file = NULL; + } + + memory_tracker_unlock_mutex(); + + g_b_mem_tracker_inited = 0; + } +} + +/* + vpx_memory_tracker_add(size_t addr, unsigned int size, + char * file, unsigned int line) + addr - memory address to be added to list + size - size of addr + file - the file addr was referenced from + line - the line in file addr was referenced from + Adds memory address addr, it's size, file and line it came from + to the global list via the thread safe internal library function +*/ +void vpx_memory_tracker_add(size_t addr, unsigned int size, + char *file, unsigned int line, + int padded) +{ + memory_tracker_add(addr, size, file, line, padded); +} + +/* + vpx_memory_tracker_remove(size_t addr) + addr - memory address to be removed from list + Removes addr from the global list via the thread safe + internal remove function + Return: + Same as described for memory_tracker_remove +*/ +int vpx_memory_tracker_remove(size_t addr) +{ + return memory_tracker_remove(addr); +} + +/* + vpx_memory_tracker_find(size_t addr) + addr - address to be found in list + Return: + If found, pointer to the memory block that matches addr + NULL otherwise +*/ +struct mem_block *vpx_memory_tracker_find(size_t addr) +{ + struct mem_block *p = NULL; + + if (!memory_tracker_lock_mutex()) + { + p = memory_tracker_find(addr); + memory_tracker_unlock_mutex(); + } + + return p; +} + +/* + vpx_memory_tracker_dump() + Locks the memory tracker's mutex and calls the internal + library function to dump the current contents of the + global memory allocation list +*/ +void vpx_memory_tracker_dump() +{ + if (!memory_tracker_lock_mutex()) + { + memory_tracker_dump(); + memory_tracker_unlock_mutex(); + } +} + +/* + vpx_memory_tracker_check_integrity(char* file, unsigned int line) + file - The file name where the check was placed + line - The line in file where the check was placed + Locks the memory tracker's mutex and calls the internal + integrity check function to inspect every address in the global + memory allocation list +*/ +void vpx_memory_tracker_check_integrity(char *file, unsigned int line) +{ + if (!memory_tracker_lock_mutex()) + { + memory_tracker_check_integrity(file, line); + memory_tracker_unlock_mutex(); + } +} + +/* + vpx_memory_tracker_set_log_type + Sets the logging type for the memory tracker. Based on the value it will + direct its output to the appropriate place. + Return: + 0: on success + -1: if the logging type could not be set, because the value was invalid + or because a file could not be opened +*/ +int vpx_memory_tracker_set_log_type(int type, char *option) +{ + int ret = -1; + + switch (type) + { + case 0: + g_logging.type = 0; + + if (!option) + { + g_logging.file = stderr; + ret = 0; + } + else + { + if ((g_logging.file = fopen((char *)option, "w"))) + ret = 0; + } + + break; +#if defined(WIN32) && !defined(_WIN32_WCE) + case 1: + g_logging.type = type; + ret = 0; + break; +#endif + default: + break; + } + + //output the version to the new logging destination + if (!ret) + memtrack_log("Memory Tracker logging initialized, " + "Memory Tracker v."vpx_mem_tracker_version"\n"); + + return ret; +} + +/* + vpx_memory_tracker_set_log_func + Sets a logging function to be used by the memory tracker. + Return: + 0: on success + -1: if the logging type could not be set because logfunc was NULL +*/ +int vpx_memory_tracker_set_log_func(void *userdata, + void(*logfunc)(void *userdata, + const char *fmt, va_list args)) +{ + int ret = -1; + + if (logfunc) + { + g_logging.type = -1; + g_logging.userdata = userdata; + g_logging.func = logfunc; + ret = 0; + } + + //output the version to the new logging destination + if (!ret) + memtrack_log("Memory Tracker logging initialized, " + "Memory Tracker v."vpx_mem_tracker_version"\n"); + + return ret; +} + +/* + * + * END - Exposed library functions + * +*/ + + +/* + * + * Internal library functions + * +*/ + +static void memtrack_log(const char *fmt, ...) +{ + va_list list; + + va_start(list, fmt); + + switch (g_logging.type) + { + case -1: + + if (g_logging.func) + g_logging.func(g_logging.userdata, fmt, list); + + break; + case 0: + + if (g_logging.file) + { + vfprintf(g_logging.file, fmt, list); + fflush(g_logging.file); + } + + break; +#if defined(WIN32) && !defined(_WIN32_WCE) + case 1: + { + char temp[1024]; + _vsnprintf(temp, sizeof(temp) / sizeof(char) - 1, fmt, list); + OutputDebugString(temp); + } + break; +#endif + default: + break; + } + + va_end(list); +} + +/* + memory_tracker_dump() + Dumps the current contents of the global memory allocation list +*/ +static void memory_tracker_dump() +{ + int i = 0; + struct mem_block *p = (memtrack.head ? memtrack.head->next : NULL); + + memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n", + memtrack.current_allocated, memtrack.max_allocated); + + while (p) + { +#if defined(WIN32) && !defined(_WIN32_WCE) + + /*when using outputdebugstring, output filenames so they + can be clicked to be opened in visual studio*/ + if (g_logging.type == 1) + memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n" + " %s(%d):\n", i, + p->addr, i, p->size, + p->file, p->line); + else +#endif + memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i, + p->addr, i, p->size, + p->file, p->line); + + p = p->next; + ++i; + } + + memtrack_log("\n"); +} + +/* + memory_tracker_check_integrity(char* file, unsigned int file) + file - the file name where the check was placed + line - the line in file where the check was placed + If a padding_size was supplied to vpx_memory_tracker_init() + this function will check ea. addr in the list verifying that + addr-padding_size and addr+padding_size is filled with pad_value +*/ +static void memory_tracker_check_integrity(char *file, unsigned int line) +{ + if (memtrack.padding_size) + { + int i, + index = 0; + unsigned char *p_show_me, + * p_show_me2; + unsigned int tempme = memtrack.pad_value, + dead1, + dead2; + unsigned char *x_bounds; + struct mem_block *p = memtrack.head->next; + + while (p) + { + //x_bounds = (unsigned char*)p->addr; + //back up VPX_BYTE_ALIGNMENT + //x_bounds -= memtrack.padding_size; + + if (p->padded) // can the bounds be checked? + { + /*yes, move to the address that was actually allocated + by the vpx_* calls*/ + x_bounds = (unsigned char *)(((size_t *)p->addr)[-1]); + + for (i = 0; i < memtrack.padding_size; i += sizeof(unsigned int)) + { + p_show_me = (x_bounds + i); + p_show_me2 = (unsigned char *)(p->addr + p->size + i); + + MEM_TRACK_MEMCPY(&dead1, p_show_me, sizeof(unsigned int)); + MEM_TRACK_MEMCPY(&dead2, p_show_me2, sizeof(unsigned int)); + + if ((dead1 != tempme) || (dead2 != tempme)) + { + memtrack_log("\n[vpx_mem integrity check failed]:\n" + " index[%d,%d] {%s:%d} addr=0x%x, size=%d," + " file: %s, line: %d c0:0x%x c1:0x%x\n", + index, i, file, line, p->addr, p->size, p->file, + p->line, dead1, dead2); + } + } + } + + ++index; + p = p->next; + } + } +} + +/* + memory_tracker_add(size_t addr, unsigned int size, + char * file, unsigned int line) + Adds an address (addr), it's size, file and line number to our list. + Adjusts the total bytes allocated and max bytes allocated if necessary. + If memory cannot be allocated the list will be destroyed. +*/ +void memory_tracker_add(size_t addr, unsigned int size, + char *file, unsigned int line, + int padded) +{ + if (!memory_tracker_lock_mutex()) + { + struct mem_block *p; + + p = MEM_TRACK_MALLOC(sizeof(struct mem_block)); + + if (p) + { + p->prev = memtrack.tail; + p->prev->next = p; + p->addr = addr; + p->size = size; + p->line = line; + p->file = file; + p->padded = padded; + p->next = NULL; + + memtrack.tail = p; + + memtrack.current_allocated += size; + + if (memtrack.current_allocated > memtrack.max_allocated) + memtrack.max_allocated = memtrack.current_allocated; + + //memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr); + + memory_tracker_unlock_mutex(); + } + else + { + memtrack_log("memory_tracker_add: error allocating memory!\n"); + memory_tracker_unlock_mutex(); + vpx_memory_tracker_destroy(); + } + } +} + +/* + memory_tracker_remove(size_t addr) + Removes an address and its corresponding size (if they exist) + from the memory tracker list and adjusts the current number + of bytes allocated. + Return: + 0: on success + -1: if the mutex could not be locked + -2: if the addr was not found in the list +*/ +int memory_tracker_remove(size_t addr) +{ + int ret = -1; + + if (!memory_tracker_lock_mutex()) + { + struct mem_block *p; + + if ((p = memory_tracker_find(addr))) + { + memtrack.current_allocated -= p->size; + + p->prev->next = p->next; + + if (p->next) + p->next->prev = p->prev; + else + memtrack.tail = p->prev; + + ret = 0; + MEM_TRACK_FREE(p); + } + else + { + if (addr) + memtrack_log("memory_tracker_remove(): addr not found in list," + " 0x%.8x\n", addr); + + ret = -2; + } + + memory_tracker_unlock_mutex(); + } + + return ret; +} + +/* + memory_tracker_find(size_t addr) + Finds an address in our addrs list + NOTE: the mutex MUST be locked in the other internal + functions before calling this one. This avoids + the need for repeated locking and unlocking as in Remove + Returns: pointer to the mem block if found, NULL otherwise +*/ +static struct mem_block *memory_tracker_find(size_t addr) +{ + struct mem_block *p = NULL; + + if (memtrack.head) + { + p = memtrack.head->next; + + while (p && (p->addr != addr)) + p = p->next; + } + + return p; +} + + +#if !defined(NO_MUTEX) +/* + memory_tracker_lock_mutex() + Locks the memory tracker mutex with a platform specific call + Returns: + 0: Success + <0: Failure, either the mutex was not initialized + or the call to lock the mutex failed +*/ +static int memory_tracker_lock_mutex() +{ + int ret = -1; + + if (g_b_mem_tracker_inited) + { + +#if HAVE_PTHREAD_H + ret = pthread_mutex_lock(&memtrack.mutex); +#elif defined(WIN32) || defined(_WIN32_WCE) + ret = WaitForSingleObject(memtrack.mutex, INFINITE); +#elif defined(VXWORKS) + ret = sem_take(memtrack.mutex, WAIT_FOREVER); +#endif + + if (ret) + { + memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n"); + } + } + + return ret; +} + +/* + memory_tracker_unlock_mutex() + Unlocks the memory tracker mutex with a platform specific call + Returns: + 0: Success + <0: Failure, either the mutex was not initialized + or the call to unlock the mutex failed +*/ +static int memory_tracker_unlock_mutex() +{ + int ret = -1; + + if (g_b_mem_tracker_inited) + { + +#if HAVE_PTHREAD_H + ret = pthread_mutex_unlock(&memtrack.mutex); +#elif defined(WIN32) || defined(_WIN32_WCE) + ret = !ReleaseMutex(memtrack.mutex); +#elif defined(VXWORKS) + ret = sem_give(memtrack.mutex); +#endif + + if (ret) + { + memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n"); + } + } + + return ret; +} +#endif + +/* + vpx_memory_tracker_set_functions + + Sets the function pointers for the standard library functions. + + Return: + 0: on success + -1: if the use global function pointers is not set. +*/ +int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l + , mem_track_calloc_func g_calloc_l + , mem_track_realloc_func g_realloc_l + , mem_track_free_func g_free_l + , mem_track_memcpy_func g_memcpy_l + , mem_track_memset_func g_memset_l + , mem_track_memmove_func g_memmove_l) +{ +#if USE_GLOBAL_FUNCTION_POINTERS + + if (g_malloc_l) + g_malloc = g_malloc_l; + + if (g_calloc_l) + g_calloc = g_calloc_l; + + if (g_realloc_l) + g_realloc = g_realloc_l; + + if (g_free_l) + g_free = g_free_l; + + if (g_memcpy_l) + g_memcpy = g_memcpy_l; + + if (g_memset_l) + g_memset = g_memset_l; + + if (g_memmove_l) + g_memmove = g_memmove_l; + + return 0; +#else + (void)g_malloc_l; + (void)g_calloc_l; + (void)g_realloc_l; + (void)g_free_l; + (void)g_memcpy_l; + (void)g_memset_l; + (void)g_memmove_l; + return -1; +#endif +} diff --git a/vpx_ports/arm.h b/vpx_ports/arm.h new file mode 100644 index 0000000..525a764 --- /dev/null +++ b/vpx_ports/arm.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_PORTS_ARM_H +#define VPX_PORTS_ARM_H +#include +#include "vpx_config.h" + +/*ARMv5TE "Enhanced DSP" instructions.*/ +#define HAS_EDSP 0x01 +/*ARMv6 "Parallel" or "Media" instructions.*/ +#define HAS_MEDIA 0x02 +/*ARMv7 optional NEON instructions.*/ +#define HAS_NEON 0x04 + +int arm_cpu_caps(void); + +#endif + diff --git a/vpx_ports/arm_cpudetect.c b/vpx_ports/arm_cpudetect.c new file mode 100644 index 0000000..ebe428d --- /dev/null +++ b/vpx_ports/arm_cpudetect.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include "arm.h" + +static int arm_cpu_env_flags(int *flags) +{ + char *env; + env = getenv("VPX_SIMD_CAPS"); + if (env && *env) + { + *flags = (int)strtol(env, NULL, 0); + return 0; + } + *flags = 0; + return -1; +} + +static int arm_cpu_env_mask(void) +{ + char *env; + env = getenv("VPX_SIMD_CAPS_MASK"); + return env && *env ? (int)strtol(env, NULL, 0) : ~0; +} + + +#if defined(_MSC_VER) +/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/ +#define WIN32_LEAN_AND_MEAN +#define WIN32_EXTRA_LEAN +#include + +int arm_cpu_caps(void) +{ + int flags; + int mask; + if (!arm_cpu_env_flags(&flags)) + { + return flags; + } + mask = arm_cpu_env_mask(); + /* MSVC has no inline __asm support for ARM, but it does let you __emit + * instructions via their assembled hex code. + * All of these instructions should be essentially nops. + */ +#if defined(HAVE_EDSP) + if (mask & HAS_EDSP) + { + __try + { + /*PLD [r13]*/ + __emit(0xF5DDF000); + flags |= HAS_EDSP; + } + __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) + { + /*Ignore exception.*/ + } + } +#if defined(HAVE_MEDIA) + if (mask & HAS_MEDIA) + __try + { + /*SHADD8 r3,r3,r3*/ + __emit(0xE6333F93); + flags |= HAS_MEDIA; + } + __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) + { + /*Ignore exception.*/ + } + } +#if defined(HAVE_NEON) + if (mask & HAS_NEON) + { + __try + { + /*VORR q0,q0,q0*/ + __emit(0xF2200150); + flags |= HAS_NEON; + } + __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) + { + /*Ignore exception.*/ + } + } +#endif +#endif +#endif + return flags & mask; +} + +#elif defined(__linux__) +#if defined(__ANDROID__) +#include + +int arm_cpu_caps(void) +{ + int flags; + int mask; + uint64_t features; + if (!arm_cpu_env_flags(&flags)) + { + return flags; + } + mask = arm_cpu_env_mask(); + features = android_getCpuFeatures(); + +#if defined(HAVE_EDSP) + flags |= HAS_EDSP; +#endif +#if defined(HAVE_MEDIA) + flags |= HAS_MEDIA; +#endif +#if defined(HAVE_NEON) + if (features & ANDROID_CPU_ARM_FEATURE_NEON) + flags |= HAS_NEON; +#endif + return flags & mask; +} +#else // !defined(__ANDROID__) +#include + +int arm_cpu_caps(void) +{ + FILE *fin; + int flags; + int mask; + if (!arm_cpu_env_flags(&flags)) + { + return flags; + } + mask = arm_cpu_env_mask(); + /* Reading /proc/self/auxv would be easier, but that doesn't work reliably + * on Android. + * This also means that detection will fail in Scratchbox. + */ + fin = fopen("/proc/cpuinfo","r"); + if(fin != NULL) + { + /* 512 should be enough for anybody (it's even enough for all the flags + * that x86 has accumulated... so far). + */ + char buf[512]; + while (fgets(buf, 511, fin) != NULL) + { +#if defined(HAVE_EDSP) || defined(HAVE_NEON) + if (memcmp(buf, "Features", 8) == 0) + { + char *p; +#if defined(HAVE_EDSP) + p=strstr(buf, " edsp"); + if (p != NULL && (p[5] == ' ' || p[5] == '\n')) + { + flags |= HAS_EDSP; + } +#if defined(HAVE_NEON) + p = strstr(buf, " neon"); + if (p != NULL && (p[5] == ' ' || p[5] == '\n')) + { + flags |= HAS_NEON; + } +#endif +#endif + } +#endif +#if defined(HAVE_MEDIA) + if (memcmp(buf, "CPU architecture:",17) == 0){ + int version; + version = atoi(buf+17); + if (version >= 6) + { + flags |= HAS_MEDIA; + } + } +#endif + } + fclose(fin); + } + return flags & mask; +} +#endif // defined(__linux__) +#elif !CONFIG_RUNTIME_CPU_DETECT + +int arm_cpu_caps(void) +{ + int flags; + int mask; + if (!arm_cpu_env_flags(&flags)) + { + return flags; + } + mask = arm_cpu_env_mask(); +#if defined(HAVE_EDSP) + flags |= HAS_EDSP; +#endif +#if defined(HAVE_MEDIA) + flags |= HAS_MEDIA; +#endif +#if defined(HAVE_NEON) + flags |= HAS_NEON; +#endif + return flags & mask; +} + +#else +#error "--enable-runtime-cpu-detect selected, but no CPU detection method " \ + "available for your platform. Reconfigure without --enable-runtime-cpu-detect." +#endif diff --git a/vpx_ports/asm_offsets.h b/vpx_ports/asm_offsets.h new file mode 100644 index 0000000..d3b4fc7 --- /dev/null +++ b/vpx_ports/asm_offsets.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_PORTS_ASM_OFFSETS_H +#define VPX_PORTS_ASM_OFFSETS_H + +#include + +#define ct_assert(name,cond) \ + static void assert_##name(void) UNUSED;\ + static void assert_##name(void) {switch(0){case 0:case !!(cond):;}} + +#if INLINE_ASM +#define DEFINE(sym, val) asm("\n" #sym " EQU %0" : : "i" (val)); +#define BEGIN int main(void) { +#define END return 0; } +#else +#define DEFINE(sym, val) int sym = val; +#define BEGIN +#define END +#endif + +#endif /* VPX_PORTS_ASM_OFFSETS_H */ diff --git a/vpx_ports/emms.asm b/vpx_ports/emms.asm new file mode 100644 index 0000000..306e235 --- /dev/null +++ b/vpx_ports/emms.asm @@ -0,0 +1,38 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +section .text + global sym(vpx_reset_mmx_state) +sym(vpx_reset_mmx_state): + emms + ret + + +%ifidn __OUTPUT_FORMAT__,x64 +global sym(vpx_winx64_fldcw) +sym(vpx_winx64_fldcw): + sub rsp, 8 + mov [rsp], rcx ; win x64 specific + fldcw [rsp] + add rsp, 8 + ret + + +global sym(vpx_winx64_fstcw) +sym(vpx_winx64_fstcw): + sub rsp, 8 + fstcw [rsp] + mov rax, [rsp] + add rsp, 8 + ret +%endif diff --git a/vpx_ports/mem.h b/vpx_ports/mem.h new file mode 100644 index 0000000..29e507f --- /dev/null +++ b/vpx_ports/mem.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_PORTS_MEM_H +#define VPX_PORTS_MEM_H +#include "vpx_config.h" +#include "vpx/vpx_integer.h" + +#if (defined(__GNUC__) && __GNUC__) || defined(__SUNPRO_C) +#define DECLARE_ALIGNED(n,typ,val) typ val __attribute__ ((aligned (n))) +#elif defined(_MSC_VER) +#define DECLARE_ALIGNED(n,typ,val) __declspec(align(n)) typ val +#else +#warning No alignment directives known for this compiler. +#define DECLARE_ALIGNED(n,typ,val) typ val +#endif +#endif + + +/* Declare an aligned array on the stack, for situations where the stack + * pointer may not have the alignment we expect. Creates an array with a + * modified name, then defines val to be a pointer, and aligns that pointer + * within the array. + */ +#define DECLARE_ALIGNED_ARRAY(a,typ,val,n)\ +typ val##_[(n)+(a)/sizeof(typ)+1];\ +typ *val = (typ*)((((intptr_t)val##_)+(a)-1)&((intptr_t)-(a))) + + +/* Indicates that the usage of the specified variable has been audited to assure + * that it's safe to use uninitialized. Silences 'may be used uninitialized' + * warnings on gcc. + */ +#if defined(__GNUC__) && __GNUC__ +#define UNINITIALIZED_IS_SAFE(x) x=x +#else +#define UNINITIALIZED_IS_SAFE(x) x +#endif diff --git a/vpx_ports/mem_ops.h b/vpx_ports/mem_ops.h new file mode 100644 index 0000000..0e52368 --- /dev/null +++ b/vpx_ports/mem_ops.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* \file + * \brief Provides portable memory access primitives + * + * This function provides portable primitives for getting and setting of + * signed and unsigned integers in 16, 24, and 32 bit sizes. The operations + * can be performed on unaligned data regardless of hardware support for + * unaligned accesses. + * + * The type used to pass the integral values may be changed by defining + * MEM_VALUE_T with the appropriate type. The type given must be an integral + * numeric type. + * + * The actual functions instantiated have the MEM_VALUE_T type name pasted + * on to the symbol name. This allows the developer to instantiate these + * operations for multiple types within the same translation unit. This is + * of somewhat questionable utility, but the capability exists nonetheless. + * Users not making use of this functionality should call the functions + * without the type name appended, and the preprocessor will take care of + * it. + * + * NOTE: This code is not supported on platforms where char > 1 octet ATM. + */ + +#ifndef MAU_T +/* Minimum Access Unit for this target */ +#define MAU_T unsigned char +#endif + +#ifndef MEM_VALUE_T +#define MEM_VALUE_T int +#endif + +#undef MEM_VALUE_T_SZ_BITS +#define MEM_VALUE_T_SZ_BITS (sizeof(MEM_VALUE_T) << 3) + +#undef mem_ops_wrap_symbol +#define mem_ops_wrap_symbol(fn) mem_ops_wrap_symbol2(fn, MEM_VALUE_T) +#undef mem_ops_wrap_symbol2 +#define mem_ops_wrap_symbol2(fn,typ) mem_ops_wrap_symbol3(fn,typ) +#undef mem_ops_wrap_symbol3 +#define mem_ops_wrap_symbol3(fn,typ) fn##_as_##typ + +/* + * Include aligned access routines + */ +#define INCLUDED_BY_MEM_OPS_H +#include "mem_ops_aligned.h" +#undef INCLUDED_BY_MEM_OPS_H + +#undef mem_get_be16 +#define mem_get_be16 mem_ops_wrap_symbol(mem_get_be16) +static unsigned MEM_VALUE_T mem_get_be16(const void *vmem) +{ + unsigned MEM_VALUE_T val; + const MAU_T *mem = (const MAU_T *)vmem; + + val = mem[0] << 8; + val |= mem[1]; + return val; +} + +#undef mem_get_be24 +#define mem_get_be24 mem_ops_wrap_symbol(mem_get_be24) +static unsigned MEM_VALUE_T mem_get_be24(const void *vmem) +{ + unsigned MEM_VALUE_T val; + const MAU_T *mem = (const MAU_T *)vmem; + + val = mem[0] << 16; + val |= mem[1] << 8; + val |= mem[2]; + return val; +} + +#undef mem_get_be32 +#define mem_get_be32 mem_ops_wrap_symbol(mem_get_be32) +static unsigned MEM_VALUE_T mem_get_be32(const void *vmem) +{ + unsigned MEM_VALUE_T val; + const MAU_T *mem = (const MAU_T *)vmem; + + val = mem[0] << 24; + val |= mem[1] << 16; + val |= mem[2] << 8; + val |= mem[3]; + return val; +} + +#undef mem_get_le16 +#define mem_get_le16 mem_ops_wrap_symbol(mem_get_le16) +static unsigned MEM_VALUE_T mem_get_le16(const void *vmem) +{ + unsigned MEM_VALUE_T val; + const MAU_T *mem = (const MAU_T *)vmem; + + val = mem[1] << 8; + val |= mem[0]; + return val; +} + +#undef mem_get_le24 +#define mem_get_le24 mem_ops_wrap_symbol(mem_get_le24) +static unsigned MEM_VALUE_T mem_get_le24(const void *vmem) +{ + unsigned MEM_VALUE_T val; + const MAU_T *mem = (const MAU_T *)vmem; + + val = mem[2] << 16; + val |= mem[1] << 8; + val |= mem[0]; + return val; +} + +#undef mem_get_le32 +#define mem_get_le32 mem_ops_wrap_symbol(mem_get_le32) +static unsigned MEM_VALUE_T mem_get_le32(const void *vmem) +{ + unsigned MEM_VALUE_T val; + const MAU_T *mem = (const MAU_T *)vmem; + + val = mem[3] << 24; + val |= mem[2] << 16; + val |= mem[1] << 8; + val |= mem[0]; + return val; +} + +#define mem_get_s_generic(end,sz) \ + static signed MEM_VALUE_T mem_get_s##end##sz(const void *vmem) {\ + const MAU_T *mem = (const MAU_T*)vmem;\ + signed MEM_VALUE_T val = mem_get_##end##sz(mem);\ + return (val << (MEM_VALUE_T_SZ_BITS - sz)) >> (MEM_VALUE_T_SZ_BITS - sz);\ + } + +#undef mem_get_sbe16 +#define mem_get_sbe16 mem_ops_wrap_symbol(mem_get_sbe16) +mem_get_s_generic(be, 16); + +#undef mem_get_sbe24 +#define mem_get_sbe24 mem_ops_wrap_symbol(mem_get_sbe24) +mem_get_s_generic(be, 24); + +#undef mem_get_sbe32 +#define mem_get_sbe32 mem_ops_wrap_symbol(mem_get_sbe32) +mem_get_s_generic(be, 32); + +#undef mem_get_sle16 +#define mem_get_sle16 mem_ops_wrap_symbol(mem_get_sle16) +mem_get_s_generic(le, 16); + +#undef mem_get_sle24 +#define mem_get_sle24 mem_ops_wrap_symbol(mem_get_sle24) +mem_get_s_generic(le, 24); + +#undef mem_get_sle32 +#define mem_get_sle32 mem_ops_wrap_symbol(mem_get_sle32) +mem_get_s_generic(le, 32); + +#undef mem_put_be16 +#define mem_put_be16 mem_ops_wrap_symbol(mem_put_be16) +static void mem_put_be16(void *vmem, MEM_VALUE_T val) +{ + MAU_T *mem = (MAU_T *)vmem; + + mem[0] = (val >> 8) & 0xff; + mem[1] = (val >> 0) & 0xff; +} + +#undef mem_put_be24 +#define mem_put_be24 mem_ops_wrap_symbol(mem_put_be24) +static void mem_put_be24(void *vmem, MEM_VALUE_T val) +{ + MAU_T *mem = (MAU_T *)vmem; + + mem[0] = (val >> 16) & 0xff; + mem[1] = (val >> 8) & 0xff; + mem[2] = (val >> 0) & 0xff; +} + +#undef mem_put_be32 +#define mem_put_be32 mem_ops_wrap_symbol(mem_put_be32) +static void mem_put_be32(void *vmem, MEM_VALUE_T val) +{ + MAU_T *mem = (MAU_T *)vmem; + + mem[0] = (val >> 24) & 0xff; + mem[1] = (val >> 16) & 0xff; + mem[2] = (val >> 8) & 0xff; + mem[3] = (val >> 0) & 0xff; +} + +#undef mem_put_le16 +#define mem_put_le16 mem_ops_wrap_symbol(mem_put_le16) +static void mem_put_le16(void *vmem, MEM_VALUE_T val) +{ + MAU_T *mem = (MAU_T *)vmem; + + mem[0] = (val >> 0) & 0xff; + mem[1] = (val >> 8) & 0xff; +} + +#undef mem_put_le24 +#define mem_put_le24 mem_ops_wrap_symbol(mem_put_le24) +static void mem_put_le24(void *vmem, MEM_VALUE_T val) +{ + MAU_T *mem = (MAU_T *)vmem; + + mem[0] = (val >> 0) & 0xff; + mem[1] = (val >> 8) & 0xff; + mem[2] = (val >> 16) & 0xff; +} + +#undef mem_put_le32 +#define mem_put_le32 mem_ops_wrap_symbol(mem_put_le32) +static void mem_put_le32(void *vmem, MEM_VALUE_T val) +{ + MAU_T *mem = (MAU_T *)vmem; + + mem[0] = (val >> 0) & 0xff; + mem[1] = (val >> 8) & 0xff; + mem[2] = (val >> 16) & 0xff; + mem[3] = (val >> 24) & 0xff; +} diff --git a/vpx_ports/mem_ops_aligned.h b/vpx_ports/mem_ops_aligned.h new file mode 100644 index 0000000..0fbba65 --- /dev/null +++ b/vpx_ports/mem_ops_aligned.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* \file + * \brief Provides portable memory access primitives for operating on aligned + * data + * + * This file is split from mem_ops.h for easier maintenance. See mem_ops.h + * for a more detailed description of these primitives. + */ +#ifndef INCLUDED_BY_MEM_OPS_H +#error Include mem_ops.h, not mem_ops_aligned.h directly. +#endif + +/* Architectures that provide instructions for doing this byte swapping + * could redefine these macros. + */ +#define swap_endian_16(val,raw) do {\ + val = ((raw>>8) & 0x00ff) \ + | ((raw<<8) & 0xff00);\ + } while(0) +#define swap_endian_32(val,raw) do {\ + val = ((raw>>24) & 0x000000ff) \ + | ((raw>>8) & 0x0000ff00) \ + | ((raw<<8) & 0x00ff0000) \ + | ((raw<<24) & 0xff000000); \ + } while(0) +#define swap_endian_16_se(val,raw) do {\ + swap_endian_16(val,raw);\ + val = ((val << 16) >> 16);\ + } while(0) +#define swap_endian_32_se(val,raw) swap_endian_32(val,raw) + +#define mem_get_ne_aligned_generic(end,sz) \ + static unsigned MEM_VALUE_T mem_get_##end##sz##_aligned(const void *vmem) {\ + const uint##sz##_t *mem = (const uint##sz##_t *)vmem;\ + return *mem;\ + } + +#define mem_get_sne_aligned_generic(end,sz) \ + static signed MEM_VALUE_T mem_get_s##end##sz##_aligned(const void *vmem) {\ + const int##sz##_t *mem = (const int##sz##_t *)vmem;\ + return *mem;\ + } + +#define mem_get_se_aligned_generic(end,sz) \ + static unsigned MEM_VALUE_T mem_get_##end##sz##_aligned(const void *vmem) {\ + const uint##sz##_t *mem = (const uint##sz##_t *)vmem;\ + unsigned MEM_VALUE_T val, raw = *mem;\ + swap_endian_##sz(val,raw);\ + return val;\ + } + +#define mem_get_sse_aligned_generic(end,sz) \ + static signed MEM_VALUE_T mem_get_s##end##sz##_aligned(const void *vmem) {\ + const int##sz##_t *mem = (const int##sz##_t *)vmem;\ + unsigned MEM_VALUE_T val, raw = *mem;\ + swap_endian_##sz##_se(val,raw);\ + return val;\ + } + +#define mem_put_ne_aligned_generic(end,sz) \ + static void mem_put_##end##sz##_aligned(void *vmem, MEM_VALUE_T val) {\ + uint##sz##_t *mem = (uint##sz##_t *)vmem;\ + *mem = (uint##sz##_t)val;\ + } + +#define mem_put_se_aligned_generic(end,sz) \ + static void mem_put_##end##sz##_aligned(void *vmem, MEM_VALUE_T val) {\ + uint##sz##_t *mem = (uint##sz##_t *)vmem, raw;\ + swap_endian_##sz(raw,val);\ + *mem = (uint##sz##_t)raw;\ + } + +#include "vpx_config.h" +#if CONFIG_BIG_ENDIAN +#define mem_get_be_aligned_generic(sz) mem_get_ne_aligned_generic(be,sz) +#define mem_get_sbe_aligned_generic(sz) mem_get_sne_aligned_generic(be,sz) +#define mem_get_le_aligned_generic(sz) mem_get_se_aligned_generic(le,sz) +#define mem_get_sle_aligned_generic(sz) mem_get_sse_aligned_generic(le,sz) +#define mem_put_be_aligned_generic(sz) mem_put_ne_aligned_generic(be,sz) +#define mem_put_le_aligned_generic(sz) mem_put_se_aligned_generic(le,sz) +#else +#define mem_get_be_aligned_generic(sz) mem_get_se_aligned_generic(be,sz) +#define mem_get_sbe_aligned_generic(sz) mem_get_sse_aligned_generic(be,sz) +#define mem_get_le_aligned_generic(sz) mem_get_ne_aligned_generic(le,sz) +#define mem_get_sle_aligned_generic(sz) mem_get_sne_aligned_generic(le,sz) +#define mem_put_be_aligned_generic(sz) mem_put_se_aligned_generic(be,sz) +#define mem_put_le_aligned_generic(sz) mem_put_ne_aligned_generic(le,sz) +#endif + +#undef mem_get_be16_aligned +#define mem_get_be16_aligned mem_ops_wrap_symbol(mem_get_be16_aligned) +mem_get_be_aligned_generic(16); + +#undef mem_get_be32_aligned +#define mem_get_be32_aligned mem_ops_wrap_symbol(mem_get_be32_aligned) +mem_get_be_aligned_generic(32); + +#undef mem_get_le16_aligned +#define mem_get_le16_aligned mem_ops_wrap_symbol(mem_get_le16_aligned) +mem_get_le_aligned_generic(16); + +#undef mem_get_le32_aligned +#define mem_get_le32_aligned mem_ops_wrap_symbol(mem_get_le32_aligned) +mem_get_le_aligned_generic(32); + +#undef mem_get_sbe16_aligned +#define mem_get_sbe16_aligned mem_ops_wrap_symbol(mem_get_sbe16_aligned) +mem_get_sbe_aligned_generic(16); + +#undef mem_get_sbe32_aligned +#define mem_get_sbe32_aligned mem_ops_wrap_symbol(mem_get_sbe32_aligned) +mem_get_sbe_aligned_generic(32); + +#undef mem_get_sle16_aligned +#define mem_get_sle16_aligned mem_ops_wrap_symbol(mem_get_sle16_aligned) +mem_get_sle_aligned_generic(16); + +#undef mem_get_sle32_aligned +#define mem_get_sle32_aligned mem_ops_wrap_symbol(mem_get_sle32_aligned) +mem_get_sle_aligned_generic(32); + +#undef mem_put_be16_aligned +#define mem_put_be16_aligned mem_ops_wrap_symbol(mem_put_be16_aligned) +mem_put_be_aligned_generic(16); + +#undef mem_put_be32_aligned +#define mem_put_be32_aligned mem_ops_wrap_symbol(mem_put_be32_aligned) +mem_put_be_aligned_generic(32); + +#undef mem_put_le16_aligned +#define mem_put_le16_aligned mem_ops_wrap_symbol(mem_put_le16_aligned) +mem_put_le_aligned_generic(16); + +#undef mem_put_le32_aligned +#define mem_put_le32_aligned mem_ops_wrap_symbol(mem_put_le32_aligned) +mem_put_le_aligned_generic(32); + +#undef mem_get_ne_aligned_generic +#undef mem_get_se_aligned_generic +#undef mem_get_sne_aligned_generic +#undef mem_get_sse_aligned_generic +#undef mem_put_ne_aligned_generic +#undef mem_put_se_aligned_generic +#undef swap_endian_16 +#undef swap_endian_32 +#undef swap_endian_16_se +#undef swap_endian_32_se diff --git a/vpx_ports/vpx_timer.h b/vpx_ports/vpx_timer.h new file mode 100644 index 0000000..d07e086 --- /dev/null +++ b/vpx_ports/vpx_timer.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_TIMER_H +#define VPX_TIMER_H +#include "vpx/vpx_integer.h" + +#if CONFIG_OS_SUPPORT + +#if defined(_WIN32) +/* + * Win32 specific includes + */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +/* + * POSIX specific includes + */ +#include + +/* timersub is not provided by msys at this time. */ +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif +#endif + + +struct vpx_usec_timer +{ +#if defined(_WIN32) + LARGE_INTEGER begin, end; +#else + struct timeval begin, end; +#endif +}; + + +static void +vpx_usec_timer_start(struct vpx_usec_timer *t) +{ +#if defined(_WIN32) + QueryPerformanceCounter(&t->begin); +#else + gettimeofday(&t->begin, NULL); +#endif +} + + +static void +vpx_usec_timer_mark(struct vpx_usec_timer *t) +{ +#if defined(_WIN32) + QueryPerformanceCounter(&t->end); +#else + gettimeofday(&t->end, NULL); +#endif +} + + +static int64_t +vpx_usec_timer_elapsed(struct vpx_usec_timer *t) +{ +#if defined(_WIN32) + LARGE_INTEGER freq, diff; + + diff.QuadPart = t->end.QuadPart - t->begin.QuadPart; + + QueryPerformanceFrequency(&freq); + return diff.QuadPart * 1000000 / freq.QuadPart; +#else + struct timeval diff; + + timersub(&t->end, &t->begin, &diff); + return diff.tv_sec * 1000000 + diff.tv_usec; +#endif +} + +#else /* CONFIG_OS_SUPPORT = 0*/ + +/* Empty timer functions if CONFIG_OS_SUPPORT = 0 */ +#ifndef timersub +#define timersub(a, b, result) +#endif + +struct vpx_usec_timer +{ + void *dummy; +}; + +static void +vpx_usec_timer_start(struct vpx_usec_timer *t) { } + +static void +vpx_usec_timer_mark(struct vpx_usec_timer *t) { } + +static long +vpx_usec_timer_elapsed(struct vpx_usec_timer *t) { return 0; } + +#endif /* CONFIG_OS_SUPPORT */ + +#endif diff --git a/vpx_ports/vpxtypes.h b/vpx_ports/vpxtypes.h new file mode 100644 index 0000000..f2fb089 --- /dev/null +++ b/vpx_ports/vpxtypes.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __VPXTYPES_H__ +#define __VPXTYPES_H__ + +#include "vpx_config.h" + +//#include +#ifdef _MSC_VER +# include +typedef SSIZE_T ssize_t; +#endif + +#if defined(HAVE_STDINT_H) && HAVE_STDINT_H +/* C99 types are preferred to vpx integer types */ +# include +#endif + +/*!\defgroup basetypes Base Types + @{*/ +#if !defined(HAVE_STDINT_H) && !defined(INT_T_DEFINED) +# ifdef STRICTTYPES +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +# else +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +# endif +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#endif + +typedef int8_t vpxs8; +typedef uint8_t vpxu8; +typedef int16_t vpxs16; +typedef uint16_t vpxu16; +typedef int32_t vpxs32; +typedef uint32_t vpxu32; +typedef int32_t vpxbool; + +enum {vpxfalse, vpxtrue}; + +/*!\def OTC + \brief a macro suitable for declaring a constant #vpxtc*/ +/*!\def VPXTC + \brief printf format string suitable for printing an #vpxtc*/ +#ifdef UNICODE +# ifdef NO_WCHAR +# error "no non-wchar support added yet" +# else +# include +typedef wchar_t vpxtc; +# define OTC(str) L ## str +# define VPXTC "ls" +# endif /*NO_WCHAR*/ +#else +typedef char vpxtc; +# define OTC(str) (vpxtc*)str +# define VPXTC "s" +#endif /*UNICODE*/ +/*@} end - base types*/ + +/*!\addtogroup basetypes + @{*/ +/*!\def VPX64 + \brief printf format string suitable for printing an #vpxs64*/ +#if defined(HAVE_STDINT_H) +# define VPX64 PRId64 +typedef int64_t vpxs64; +#elif defined(HASLONGLONG) +# undef PRId64 +# define PRId64 "lld" +# define VPX64 PRId64 +typedef long long vpxs64; +#elif defined(WIN32) || defined(_WIN32_WCE) +# undef PRId64 +# define PRId64 "I64d" +# define VPX64 PRId64 +typedef __int64 vpxs64; +typedef unsigned __int64 vpxu64; +#elif defined(__uClinux__) && defined(CHIP_DM642) +# include +# undef PRId64 +# define PRId64 "lld" +# define VPX64 PRId64 +typedef long vpxs64; +#else +# error "64 bit integer type undefined for this platform!" +#endif +#if !defined(HAVE_STDINT_H) && !defined(INT_T_DEFINED) +typedef vpxs64 int64_t; +typedef vpxu64 uint64_t; +#endif +/*!@} end - base types*/ + +/*!\ingroup basetypes + \brief Common return type*/ +typedef enum +{ + VPX_NOT_FOUND = -404, + VPX_BUFFER_EMPTY = -202, + VPX_BUFFER_FULL = -201, + + VPX_CONNREFUSED = -102, + VPX_TIMEDOUT = -101, + VPX_WOULDBLOCK = -100, + + VPX_NET_ERROR = -9, + VPX_INVALID_VERSION = -8, + VPX_INPROGRESS = -7, + VPX_NOT_SUPP = -6, + VPX_NO_MEM = -3, + VPX_INVALID_PARAMS = -2, + VPX_ERROR = -1, + VPX_OK = 0, + VPX_DONE = 1 +} vpxsc; + +#if defined(WIN32) || defined(_WIN32_WCE) +# define DLLIMPORT __declspec(dllimport) +# define DLLEXPORT __declspec(dllexport) +# define DLLLOCAL +#elif defined(LINUX) +# define DLLIMPORT +/*visibility attribute support is available in 3.4 and later. + see: http://gcc.gnu.org/wiki/Visibility for more info*/ +# if defined(__GNUC__) && ((__GNUC__<<16|(__GNUC_MINOR__&0xff)) >= (3<<16|4)) +# define GCC_HASCLASSVISIBILITY +# endif /*defined(__GNUC__) && __GNUC_PREREQ(3,4)*/ +# ifdef GCC_HASCLASSVISIBILITY +# define DLLEXPORT __attribute__ ((visibility("default"))) +# define DLLLOCAL __attribute__ ((visibility("hidden"))) +# else +# define DLLEXPORT +# define DLLLOCAL +# endif /*GCC_HASCLASSVISIBILITY*/ +#endif /*platform ifdefs*/ + +#endif /*__VPXTYPES_H__*/ + +#undef VPXAPI +/*!\def VPXAPI + \brief library calling convention/storage class attributes. + + Specifies whether the function is imported through a dll + or is from a static library.*/ +#ifdef VPXDLL +# ifdef VPXDLLEXPORT +# define VPXAPI DLLEXPORT +# else +# define VPXAPI DLLIMPORT +# endif /*VPXDLLEXPORT*/ +#else +# define VPXAPI +#endif /*VPXDLL*/ diff --git a/vpx_ports/x86.h b/vpx_ports/x86.h new file mode 100644 index 0000000..1341c7f --- /dev/null +++ b/vpx_ports/x86.h @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_PORTS_X86_H +#define VPX_PORTS_X86_H +#include +#include "vpx_config.h" + +typedef enum +{ + VPX_CPU_UNKNOWN = -1, + VPX_CPU_AMD, + VPX_CPU_AMD_OLD, + VPX_CPU_CENTAUR, + VPX_CPU_CYRIX, + VPX_CPU_INTEL, + VPX_CPU_NEXGEN, + VPX_CPU_NSC, + VPX_CPU_RISE, + VPX_CPU_SIS, + VPX_CPU_TRANSMETA, + VPX_CPU_TRANSMETA_OLD, + VPX_CPU_UMC, + VPX_CPU_VIA, + + VPX_CPU_LAST +} vpx_cpu_t; + +#if defined(__GNUC__) && __GNUC__ +#if ARCH_X86_64 +#define cpuid(func,ax,bx,cx,dx)\ + __asm__ __volatile__ (\ + "cpuid \n\t" \ + : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) \ + : "a" (func)); +#else +#define cpuid(func,ax,bx,cx,dx)\ + __asm__ __volatile__ (\ + "mov %%ebx, %%edi \n\t" \ + "cpuid \n\t" \ + "xchg %%edi, %%ebx \n\t" \ + : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \ + : "a" (func)); +#endif +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#if ARCH_X86_64 +#define cpuid(func,ax,bx,cx,dx)\ + asm volatile (\ + "xchg %rsi, %rbx \n\t" \ + "cpuid \n\t" \ + "movl %ebx, %edi \n\t" \ + "xchg %rsi, %rbx \n\t" \ + : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \ + : "a" (func)); +#else +#define cpuid(func,ax,bx,cx,dx)\ + asm volatile (\ + "pushl %ebx \n\t" \ + "cpuid \n\t" \ + "movl %ebx, %edi \n\t" \ + "popl %ebx \n\t" \ + : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \ + : "a" (func)); +#endif +#else +#if ARCH_X86_64 +void __cpuid(int CPUInfo[4], int info_type); +#pragma intrinsic(__cpuid) +#define cpuid(func,a,b,c,d) do{\ + int regs[4];\ + __cpuid(regs,func); a=regs[0]; b=regs[1]; c=regs[2]; d=regs[3];\ + } while(0) +#else +#define cpuid(func,a,b,c,d)\ + __asm mov eax, func\ + __asm cpuid\ + __asm mov a, eax\ + __asm mov b, ebx\ + __asm mov c, ecx\ + __asm mov d, edx +#endif +#endif + +#define HAS_MMX 0x01 +#define HAS_SSE 0x02 +#define HAS_SSE2 0x04 +#define HAS_SSE3 0x08 +#define HAS_SSSE3 0x10 +#define HAS_SSE4_1 0x20 +#ifndef BIT +#define BIT(n) (1< +; This macro aligns the stack to the given alignment (in bytes). The stack +; is left such that the previous value of the stack pointer is the first +; argument on the stack (ie, the inverse of this macro is 'pop rsp.') +; This macro uses one temporary register, which is not preserved, and thus +; must be specified as an argument. +%macro ALIGN_STACK 2 + mov %2, rsp + and rsp, -%1 + lea rsp, [rsp - (%1 - REG_SZ_BYTES)] + push %2 +%endmacro + + +; +; The Microsoft assembler tries to impose a certain amount of type safety in +; its register usage. YASM doesn't recognize these directives, so we just +; %define them away to maintain as much compatibility as possible with the +; original inline assembler we're porting from. +; +%idefine PTR +%idefine XMMWORD +%idefine MMWORD + +; PIC macros +; +%if ABI_IS_32BIT + %if CONFIG_PIC=1 + %ifidn __OUTPUT_FORMAT__,elf32 + %define GET_GOT_SAVE_ARG 1 + %define WRT_PLT wrt ..plt + %macro GET_GOT 1 + extern _GLOBAL_OFFSET_TABLE_ + push %1 + call %%get_got + %%sub_offset: + jmp %%exitGG + %%get_got: + mov %1, [esp] + add %1, _GLOBAL_OFFSET_TABLE_ + $$ - %%sub_offset wrt ..gotpc + ret + %%exitGG: + %undef GLOBAL + %define GLOBAL(x) x + %1 wrt ..gotoff + %undef RESTORE_GOT + %define RESTORE_GOT pop %1 + %endmacro + %elifidn __OUTPUT_FORMAT__,macho32 + %define GET_GOT_SAVE_ARG 1 + %macro GET_GOT 1 + push %1 + call %%get_got + %%get_got: + pop %1 + %undef GLOBAL + %define GLOBAL(x) x + %1 - %%get_got + %undef RESTORE_GOT + %define RESTORE_GOT pop %1 + %endmacro + %endif + %endif + %define HIDDEN_DATA(x) x +%else + %macro GET_GOT 1 + %endmacro + %define GLOBAL(x) rel x + %ifidn __OUTPUT_FORMAT__,elf64 + %define WRT_PLT wrt ..plt + %define HIDDEN_DATA(x) x:data hidden + %else + %define HIDDEN_DATA(x) x + %endif +%endif +%ifnmacro GET_GOT + %macro GET_GOT 1 + %endmacro + %define GLOBAL(x) x +%endif +%ifndef RESTORE_GOT +%define RESTORE_GOT +%endif +%ifndef WRT_PLT +%define WRT_PLT +%endif + +%if ABI_IS_32BIT + %macro SHADOW_ARGS_TO_STACK 1 + %endm + %define UNSHADOW_ARGS +%else +%ifidn __OUTPUT_FORMAT__,x64 + %macro SHADOW_ARGS_TO_STACK 1 ; argc + %if %1 > 0 + mov arg(0),rcx + %endif + %if %1 > 1 + mov arg(1),rdx + %endif + %if %1 > 2 + mov arg(2),r8 + %endif + %if %1 > 3 + mov arg(3),r9 + %endif + %endm +%else + %macro SHADOW_ARGS_TO_STACK 1 ; argc + %if %1 > 0 + push rdi + %endif + %if %1 > 1 + push rsi + %endif + %if %1 > 2 + push rdx + %endif + %if %1 > 3 + push rcx + %endif + %if %1 > 4 + push r8 + %endif + %if %1 > 5 + push r9 + %endif + %if %1 > 6 + %assign i %1-6 + %assign off 16 + %rep i + mov rax,[rbp+off] + push rax + %assign off off+8 + %endrep + %endif + %endm +%endif + %define UNSHADOW_ARGS mov rsp, rbp +%endif + +; Win64 ABI requires that XMM6:XMM15 are callee saved +; SAVE_XMM n, [u] +; store registers 6-n on the stack +; if u is specified, use unaligned movs. +; Win64 ABI requires 16 byte stack alignment, but then pushes an 8 byte return +; value. Typically we follow this up with 'push rbp' - re-aligning the stack - +; but in some cases this is not done and unaligned movs must be used. +%ifidn __OUTPUT_FORMAT__,x64 +%macro SAVE_XMM 1-2 a + %if %1 < 6 + %error Only xmm registers 6-15 must be preserved + %else + %assign last_xmm %1 + %define movxmm movdq %+ %2 + %assign xmm_stack_space ((last_xmm - 5) * 16) + sub rsp, xmm_stack_space + %assign i 6 + %rep (last_xmm - 5) + movxmm [rsp + ((i - 6) * 16)], xmm %+ i + %assign i i+1 + %endrep + %endif +%endmacro +%macro RESTORE_XMM 0 + %ifndef last_xmm + %error RESTORE_XMM must be paired with SAVE_XMM n + %else + %assign i last_xmm + %rep (last_xmm - 5) + movxmm xmm %+ i, [rsp +((i - 6) * 16)] + %assign i i-1 + %endrep + add rsp, xmm_stack_space + ; there are a couple functions which return from multiple places. + ; otherwise, we could uncomment these: + ; %undef last_xmm + ; %undef xmm_stack_space + ; %undef movxmm + %endif +%endmacro +%else +%macro SAVE_XMM 1-2 +%endmacro +%macro RESTORE_XMM 0 +%endmacro +%endif + +; Name of the rodata section +; +; .rodata seems to be an elf-ism, as it doesn't work on OSX. +; +%ifidn __OUTPUT_FORMAT__,macho64 +%define SECTION_RODATA section .text +%elifidn __OUTPUT_FORMAT__,macho32 +%macro SECTION_RODATA 0 +section .text +%endmacro +%elifidn __OUTPUT_FORMAT__,aout +%define SECTION_RODATA section .data +%else +%define SECTION_RODATA section .rodata +%endif + + +; Tell GNU ld that we don't require an executable stack. +%ifidn __OUTPUT_FORMAT__,elf32 +section .note.GNU-stack noalloc noexec nowrite progbits +section .text +%elifidn __OUTPUT_FORMAT__,elf64 +section .note.GNU-stack noalloc noexec nowrite progbits +section .text +%endif + diff --git a/vpx_ports/x86_cpuid.c b/vpx_ports/x86_cpuid.c new file mode 100644 index 0000000..ce64033 --- /dev/null +++ b/vpx_ports/x86_cpuid.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include "x86.h" + +struct cpuid_vendors +{ + char vendor_string[12]; + vpx_cpu_t vendor_id; +}; + +static struct cpuid_vendors cpuid_vendor_list[VPX_CPU_LAST] = +{ + { "AuthenticAMD", VPX_CPU_AMD }, + { "AMDisbetter!", VPX_CPU_AMD_OLD }, + { "CentaurHauls", VPX_CPU_CENTAUR }, + { "CyrixInstead", VPX_CPU_CYRIX }, + { "GenuineIntel", VPX_CPU_INTEL }, + { "NexGenDriven", VPX_CPU_NEXGEN }, + { "Geode by NSC", VPX_CPU_NSC }, + { "RiseRiseRise", VPX_CPU_RISE }, + { "SiS SiS SiS ", VPX_CPU_SIS }, + { "GenuineTMx86", VPX_CPU_TRANSMETA }, + { "TransmetaCPU", VPX_CPU_TRANSMETA_OLD }, + { "UMC UMC UMC ", VPX_CPU_UMC }, + { "VIA VIA VIA ", VPX_CPU_VIA }, +}; + +vpx_cpu_t vpx_x86_vendor(void) +{ + unsigned int reg_eax; + unsigned int vs[3]; + int i; + + /* Get the Vendor String from the CPU */ + cpuid(0, reg_eax, vs[0], vs[2], vs[1]); + + for (i = 0; i < VPX_CPU_LAST; i++) + { + if (strncmp ((const char *)vs, cpuid_vendor_list[i].vendor_string, 12) == 0) + return (cpuid_vendor_list[i].vendor_id); + } + + return VPX_CPU_UNKNOWN; +} diff --git a/vpx_scale/arm/neon/vp8_vpxyv12_copy_y_neon.asm b/vpx_scale/arm/neon/vp8_vpxyv12_copy_y_neon.asm new file mode 100644 index 0000000..9189641 --- /dev/null +++ b/vpx_scale/arm/neon/vp8_vpxyv12_copy_y_neon.asm @@ -0,0 +1,122 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_yv12_copy_y_neon| + + ARM + REQUIRE8 + PRESERVE8 + + INCLUDE asm_com_offsets.asm + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;void vpxyv12_copy_y_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc) +|vp8_yv12_copy_y_neon| PROC + push {r4 - r11, lr} + vpush {d8-d15} + + ldr r4, [r0, #yv12_buffer_config_y_height] + ldr r5, [r0, #yv12_buffer_config_y_width] + ldr r6, [r0, #yv12_buffer_config_y_stride] + ldr r7, [r1, #yv12_buffer_config_y_stride] + ldr r2, [r0, #yv12_buffer_config_y_buffer] ;srcptr1 + ldr r3, [r1, #yv12_buffer_config_y_buffer] ;dstptr1 + + ; copy two rows at one time + mov lr, r4, lsr #1 + +cp_src_to_dst_height_loop1 + mov r8, r2 + mov r9, r3 + add r10, r2, r6 + add r11, r3, r7 + movs r12, r5, lsr #7 + ble extra_copy_needed ; y_width < 128 + +cp_src_to_dst_width_loop1 + vld1.8 {q0, q1}, [r8]! + vld1.8 {q8, q9}, [r10]! + vld1.8 {q2, q3}, [r8]! + vld1.8 {q10, q11}, [r10]! + vld1.8 {q4, q5}, [r8]! + vld1.8 {q12, q13}, [r10]! + vld1.8 {q6, q7}, [r8]! + vld1.8 {q14, q15}, [r10]! + + subs r12, r12, #1 + + vst1.8 {q0, q1}, [r9]! + vst1.8 {q8, q9}, [r11]! + vst1.8 {q2, q3}, [r9]! + vst1.8 {q10, q11}, [r11]! + vst1.8 {q4, q5}, [r9]! + vst1.8 {q12, q13}, [r11]! + vst1.8 {q6, q7}, [r9]! + vst1.8 {q14, q15}, [r11]! + + bne cp_src_to_dst_width_loop1 + + subs lr, lr, #1 + add r2, r2, r6, lsl #1 + add r3, r3, r7, lsl #1 + + bne cp_src_to_dst_height_loop1 + +extra_copy_needed + ands r10, r5, #0x7f ;check to see if extra copy is needed + sub r11, r5, r10 + ldr r2, [r0, #yv12_buffer_config_y_buffer] ;srcptr1 + ldr r3, [r1, #yv12_buffer_config_y_buffer] ;dstptr1 + bne extra_cp_src_to_dst_width1 +end_of_cp_src_to_dst1 + + vpop {d8 - d15} + pop {r4-r11, pc} + +;============================= +extra_cp_src_to_dst_width1 + add r2, r2, r11 + add r3, r3, r11 + add r0, r8, r6 + add r11, r9, r7 + + mov lr, r4, lsr #1 +extra_cp_src_to_dst_height_loop1 + mov r8, r2 + mov r9, r3 + add r0, r8, r6 + add r11, r9, r7 + + mov r12, r10 + +extra_cp_src_to_dst_width_loop1 + vld1.8 {q0}, [r8]! + vld1.8 {q1}, [r0]! + + subs r12, r12, #16 + + vst1.8 {q0}, [r9]! + vst1.8 {q1}, [r11]! + bne extra_cp_src_to_dst_width_loop1 + + subs lr, lr, #1 + + add r2, r2, r6, lsl #1 + add r3, r3, r7, lsl #1 + + bne extra_cp_src_to_dst_height_loop1 + + b end_of_cp_src_to_dst1 + + ENDP + + END diff --git a/vpx_scale/arm/neon/vp8_vpxyv12_copyframe_func_neon.asm b/vpx_scale/arm/neon/vp8_vpxyv12_copyframe_func_neon.asm new file mode 100644 index 0000000..e55d076 --- /dev/null +++ b/vpx_scale/arm/neon/vp8_vpxyv12_copyframe_func_neon.asm @@ -0,0 +1,233 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_yv12_copy_frame_func_neon| + ARM + REQUIRE8 + PRESERVE8 + + INCLUDE asm_com_offsets.asm + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;void vp8_yv12_copy_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, +; YV12_BUFFER_CONFIG *dst_ybc); + +|vp8_yv12_copy_frame_func_neon| PROC + push {r4 - r11, lr} + vpush {d8 - d15} + + sub sp, sp, #16 + + ;Copy Y plane + ldr r8, [r0, #yv12_buffer_config_u_buffer] ;srcptr1 + ldr r9, [r1, #yv12_buffer_config_u_buffer] ;srcptr1 + ldr r10, [r0, #yv12_buffer_config_v_buffer] ;srcptr1 + ldr r11, [r1, #yv12_buffer_config_v_buffer] ;srcptr1 + + ldr r4, [r0, #yv12_buffer_config_y_height] + ldr r5, [r0, #yv12_buffer_config_y_width] + ldr r6, [r0, #yv12_buffer_config_y_stride] + ldr r7, [r1, #yv12_buffer_config_y_stride] + ldr r2, [r0, #yv12_buffer_config_y_buffer] ;srcptr1 + ldr r3, [r1, #yv12_buffer_config_y_buffer] ;dstptr1 + + str r8, [sp] + str r9, [sp, #4] + str r10, [sp, #8] + str r11, [sp, #12] + + ; copy two rows at one time + mov lr, r4, lsr #1 + +cp_src_to_dst_height_loop + mov r8, r2 + mov r9, r3 + add r10, r2, r6 + add r11, r3, r7 + movs r12, r5, lsr #7 + ble extra_cp_needed ; y_width < 128 + +cp_src_to_dst_width_loop + vld1.8 {q0, q1}, [r8]! + vld1.8 {q8, q9}, [r10]! + vld1.8 {q2, q3}, [r8]! + vld1.8 {q10, q11}, [r10]! + vld1.8 {q4, q5}, [r8]! + vld1.8 {q12, q13}, [r10]! + vld1.8 {q6, q7}, [r8]! + vld1.8 {q14, q15}, [r10]! + + subs r12, r12, #1 + + vst1.8 {q0, q1}, [r9]! + vst1.8 {q8, q9}, [r11]! + vst1.8 {q2, q3}, [r9]! + vst1.8 {q10, q11}, [r11]! + vst1.8 {q4, q5}, [r9]! + vst1.8 {q12, q13}, [r11]! + vst1.8 {q6, q7}, [r9]! + vst1.8 {q14, q15}, [r11]! + + bne cp_src_to_dst_width_loop + + subs lr, lr, #1 + add r2, r2, r6, lsl #1 + add r3, r3, r7, lsl #1 + + bne cp_src_to_dst_height_loop + +extra_cp_needed + ands r10, r5, #0x7f ;check to see if extra copy is needed + sub r11, r5, r10 + ldr r2, [r0, #yv12_buffer_config_y_buffer] ;srcptr1 + ldr r3, [r1, #yv12_buffer_config_y_buffer] ;dstptr1 + bne extra_cp_src_to_dst_width +end_of_cp_src_to_dst + +;Copy U & V planes + ldr r2, [sp] ;srcptr1 + ldr r3, [sp, #4] ;dstptr1 + mov r4, r4, lsr #1 ;src uv_height + mov r5, r5, lsr #1 ;src uv_width + mov r6, r6, lsr #1 ;src uv_stride + mov r7, r7, lsr #1 ;dst uv_stride + + mov r1, #2 + +cp_uv_loop + + ;copy two rows at one time + mov lr, r4, lsr #1 + +cp_src_to_dst_height_uv_loop + mov r8, r2 + mov r9, r3 + add r10, r2, r6 + add r11, r3, r7 + movs r12, r5, lsr #6 + ble extra_uv_cp_needed + +cp_src_to_dst_width_uv_loop + vld1.8 {q0, q1}, [r8]! + vld1.8 {q8, q9}, [r10]! + vld1.8 {q2, q3}, [r8]! + vld1.8 {q10, q11}, [r10]! + + subs r12, r12, #1 + + vst1.8 {q0, q1}, [r9]! + vst1.8 {q8, q9}, [r11]! + vst1.8 {q2, q3}, [r9]! + vst1.8 {q10, q11}, [r11]! + + bne cp_src_to_dst_width_uv_loop + + subs lr, lr, #1 + add r2, r2, r6, lsl #1 + add r3, r3, r7, lsl #1 + + bne cp_src_to_dst_height_uv_loop + +extra_uv_cp_needed + ands r10, r5, #0x3f ;check to see if extra copy is needed + sub r11, r5, r10 + ldr r2, [sp] ;srcptr1 + ldr r3, [sp, #4] ;dstptr1 + bne extra_cp_src_to_dst_uv_width +end_of_cp_src_to_dst_uv + + subs r1, r1, #1 + + addne sp, sp, #8 + + ldrne r2, [sp] ;srcptr1 + ldrne r3, [sp, #4] ;dstptr1 + + bne cp_uv_loop + + add sp, sp, #8 + + vpop {d8 - d15} + pop {r4 - r11, pc} + +;============================= +extra_cp_src_to_dst_width + add r2, r2, r11 + add r3, r3, r11 + add r0, r8, r6 + add r11, r9, r7 + + mov lr, r4, lsr #1 +extra_cp_src_to_dst_height_loop + mov r8, r2 + mov r9, r3 + add r0, r8, r6 + add r11, r9, r7 + + mov r12, r10 + +extra_cp_src_to_dst_width_loop + vld1.8 {q0}, [r8]! + vld1.8 {q1}, [r0]! + + subs r12, r12, #16 + + vst1.8 {q0}, [r9]! + vst1.8 {q1}, [r11]! + bne extra_cp_src_to_dst_width_loop + + subs lr, lr, #1 + + add r2, r2, r6, lsl #1 + add r3, r3, r7, lsl #1 + + bne extra_cp_src_to_dst_height_loop + + b end_of_cp_src_to_dst + +;================================= +extra_cp_src_to_dst_uv_width + add r2, r2, r11 + add r3, r3, r11 + add r0, r8, r6 + add r11, r9, r7 + + mov lr, r4, lsr #1 +extra_cp_src_to_dst_height_uv_loop + mov r8, r2 + mov r9, r3 + add r0, r8, r6 + add r11, r9, r7 + + mov r12, r10 + +extra_cp_src_to_dst_width_uv_loop + vld1.8 {d0}, [r8]! + vld1.8 {d1}, [r0]! + + subs r12, r12, #8 + + vst1.8 {d0}, [r9]! + vst1.8 {d1}, [r11]! + bne extra_cp_src_to_dst_width_uv_loop + + subs lr, lr, #1 + + add r2, r2, r6, lsl #1 + add r3, r3, r7, lsl #1 + + bne extra_cp_src_to_dst_height_uv_loop + + b end_of_cp_src_to_dst_uv + + ENDP + END diff --git a/vpx_scale/arm/neon/vp8_vpxyv12_copysrcframe_func_neon.asm b/vpx_scale/arm/neon/vp8_vpxyv12_copysrcframe_func_neon.asm new file mode 100644 index 0000000..ec64dbc --- /dev/null +++ b/vpx_scale/arm/neon/vp8_vpxyv12_copysrcframe_func_neon.asm @@ -0,0 +1,258 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_yv12_copy_src_frame_func_neon| + ARM + REQUIRE8 + PRESERVE8 + + INCLUDE asm_com_offsets.asm + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: This function is used to copy source data in src_buffer[i] at beginning of +;the encoding. The buffer has a width and height of cpi->oxcf.Width and cpi->oxcf.Height, +;which can be ANY numbers(NOT always multiples of 16 or 4). + +;void vp8_yv12_copy_src_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); + +|vp8_yv12_copy_src_frame_func_neon| PROC + push {r4 - r11, lr} + vpush {d8 - d15} + + ;Copy Y plane + ldr r4, [r0, #yv12_buffer_config_y_height] + ldr r5, [r0, #yv12_buffer_config_y_width] + ldr r6, [r0, #yv12_buffer_config_y_stride] + ldr r7, [r1, #yv12_buffer_config_y_stride] + ldr r2, [r0, #yv12_buffer_config_y_buffer] ;srcptr1 + ldr r3, [r1, #yv12_buffer_config_y_buffer] ;dstptr1 + + add r10, r2, r6 ;second row src + add r11, r3, r7 ;second row dst + mov r6, r6, lsl #1 + mov r7, r7, lsl #1 + sub r6, r6, r5 ;adjust stride + sub r7, r7, r5 + + ; copy two rows at one time + mov lr, r4, lsr #1 + +cp_src_to_dst_height_loop + mov r12, r5 + +cp_width_128_loop + vld1.8 {q0, q1}, [r2]! + vld1.8 {q4, q5}, [r10]! + vld1.8 {q2, q3}, [r2]! + vld1.8 {q6, q7}, [r10]! + vld1.8 {q8, q9}, [r2]! + vld1.8 {q12, q13}, [r10]! + vld1.8 {q10, q11}, [r2]! + vld1.8 {q14, q15}, [r10]! + sub r12, r12, #128 + cmp r12, #128 + vst1.8 {q0, q1}, [r3]! + vst1.8 {q4, q5}, [r11]! + vst1.8 {q2, q3}, [r3]! + vst1.8 {q6, q7}, [r11]! + vst1.8 {q8, q9}, [r3]! + vst1.8 {q12, q13}, [r11]! + vst1.8 {q10, q11}, [r3]! + vst1.8 {q14, q15}, [r11]! + bhs cp_width_128_loop + + cmp r12, #0 + beq cp_width_done + +cp_width_8_loop + vld1.8 {d0}, [r2]! + vld1.8 {d1}, [r10]! + sub r12, r12, #8 + cmp r12, #8 + vst1.8 {d0}, [r3]! + vst1.8 {d1}, [r11]! + bhs cp_width_8_loop + + cmp r12, #0 + beq cp_width_done + +cp_width_1_loop + ldrb r8, [r2], #1 + subs r12, r12, #1 + strb r8, [r3], #1 + ldrb r8, [r10], #1 + strb r8, [r11], #1 + bne cp_width_1_loop + +cp_width_done + subs lr, lr, #1 + add r2, r2, r6 + add r3, r3, r7 + add r10, r10, r6 + add r11, r11, r7 + bne cp_src_to_dst_height_loop + +;copy last line for Y if y_height is odd + tst r4, #1 + beq cp_width_done_1 + mov r12, r5 + +cp_width_128_loop_1 + vld1.8 {q0, q1}, [r2]! + vld1.8 {q2, q3}, [r2]! + vld1.8 {q8, q9}, [r2]! + vld1.8 {q10, q11}, [r2]! + sub r12, r12, #128 + cmp r12, #128 + vst1.8 {q0, q1}, [r3]! + vst1.8 {q2, q3}, [r3]! + vst1.8 {q8, q9}, [r3]! + vst1.8 {q10, q11}, [r3]! + bhs cp_width_128_loop_1 + + cmp r12, #0 + beq cp_width_done_1 + +cp_width_8_loop_1 + vld1.8 {d0}, [r2]! + sub r12, r12, #8 + cmp r12, #8 + vst1.8 {d0}, [r3]! + bhs cp_width_8_loop_1 + + cmp r12, #0 + beq cp_width_done_1 + +cp_width_1_loop_1 + ldrb r8, [r2], #1 + subs r12, r12, #1 + strb r8, [r3], #1 + bne cp_width_1_loop_1 +cp_width_done_1 + +;Copy U & V planes + ldr r4, [r0, #yv12_buffer_config_uv_height] + ldr r5, [r0, #yv12_buffer_config_uv_width] + ldr r6, [r0, #yv12_buffer_config_uv_stride] + ldr r7, [r1, #yv12_buffer_config_uv_stride] + ldr r2, [r0, #yv12_buffer_config_u_buffer] ;srcptr1 + ldr r3, [r1, #yv12_buffer_config_u_buffer] ;dstptr1 + + add r10, r2, r6 ;second row src + add r11, r3, r7 ;second row dst + mov r6, r6, lsl #1 + mov r7, r7, lsl #1 + sub r6, r6, r5 ;adjust stride + sub r7, r7, r5 + + mov r9, #2 + +cp_uv_loop + ;copy two rows at one time + mov lr, r4, lsr #1 + +cp_src_to_dst_height_uv_loop + mov r12, r5 + +cp_width_uv_64_loop + vld1.8 {q0, q1}, [r2]! + vld1.8 {q4, q5}, [r10]! + vld1.8 {q2, q3}, [r2]! + vld1.8 {q6, q7}, [r10]! + sub r12, r12, #64 + cmp r12, #64 + vst1.8 {q0, q1}, [r3]! + vst1.8 {q4, q5}, [r11]! + vst1.8 {q2, q3}, [r3]! + vst1.8 {q6, q7}, [r11]! + bhs cp_width_uv_64_loop + + cmp r12, #0 + beq cp_width_uv_done + +cp_width_uv_8_loop + vld1.8 {d0}, [r2]! + vld1.8 {d1}, [r10]! + sub r12, r12, #8 + cmp r12, #8 + vst1.8 {d0}, [r3]! + vst1.8 {d1}, [r11]! + bhs cp_width_uv_8_loop + + cmp r12, #0 + beq cp_width_uv_done + +cp_width_uv_1_loop + ldrb r8, [r2], #1 + subs r12, r12, #1 + strb r8, [r3], #1 + ldrb r8, [r10], #1 + strb r8, [r11], #1 + bne cp_width_uv_1_loop + +cp_width_uv_done + subs lr, lr, #1 + add r2, r2, r6 + add r3, r3, r7 + add r10, r10, r6 + add r11, r11, r7 + bne cp_src_to_dst_height_uv_loop + +;copy last line for U & V if uv_height is odd + tst r4, #1 + beq cp_width_uv_done_1 + mov r12, r5 + +cp_width_uv_64_loop_1 + vld1.8 {q0, q1}, [r2]! + vld1.8 {q2, q3}, [r2]! + sub r12, r12, #64 + cmp r12, #64 + vst1.8 {q0, q1}, [r3]! + vst1.8 {q2, q3}, [r3]! + bhs cp_width_uv_64_loop_1 + + cmp r12, #0 + beq cp_width_uv_done_1 + +cp_width_uv_8_loop_1 + vld1.8 {d0}, [r2]! + sub r12, r12, #8 + cmp r12, #8 + vst1.8 {d0}, [r3]! + bhs cp_width_uv_8_loop_1 + + cmp r12, #0 + beq cp_width_uv_done_1 + +cp_width_uv_1_loop_1 + ldrb r8, [r2], #1 + subs r12, r12, #1 + strb r8, [r3], #1 + bne cp_width_uv_1_loop_1 +cp_width_uv_done_1 + + subs r9, r9, #1 + ldrne r2, [r0, #yv12_buffer_config_v_buffer] ;srcptr1 + ldrne r3, [r1, #yv12_buffer_config_v_buffer] ;dstptr1 + ldrne r10, [r0, #yv12_buffer_config_uv_stride] + ldrne r11, [r1, #yv12_buffer_config_uv_stride] + + addne r10, r2, r10 ;second row src + addne r11, r3, r11 ;second row dst + + bne cp_uv_loop + + vpop {d8 - d15} + pop {r4 - r11, pc} + + ENDP + END diff --git a/vpx_scale/arm/neon/vp8_vpxyv12_extendframeborders_neon.asm b/vpx_scale/arm/neon/vp8_vpxyv12_extendframeborders_neon.asm new file mode 100644 index 0000000..ebc4242 --- /dev/null +++ b/vpx_scale/arm/neon/vp8_vpxyv12_extendframeborders_neon.asm @@ -0,0 +1,308 @@ +; +; Copyright (c) 2010 The WebM project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license +; that can be found in the LICENSE file in the root of the source +; tree. An additional intellectual property rights grant can be found +; in the file PATENTS. All contributing project authors may +; be found in the AUTHORS file in the root of the source tree. +; + + + EXPORT |vp8_yv12_extend_frame_borders_neon| + ARM + REQUIRE8 + PRESERVE8 + + INCLUDE asm_com_offsets.asm + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_yv12_extend_frame_borders_neon (YV12_BUFFER_CONFIG *ybf); +; we depend on VP8BORDERINPIXELS being 32 + +|vp8_yv12_extend_frame_borders_neon| PROC + push {r4 - r10, lr} + vpush {d8 - d15} + + ; Border = 32 + ldr r3, [r0, #yv12_buffer_config_y_width] ; plane_width + ldr r1, [r0, #yv12_buffer_config_y_buffer] ; src_ptr1 + ldr r4, [r0, #yv12_buffer_config_y_height] ; plane_height + ldr lr, [r0, #yv12_buffer_config_y_stride] ; plane_stride + +; Border copy for Y plane +; copy the left and right most columns out + add r6, r1, r3 ; dest_ptr2 = src_ptr2 + 1 (src_ptr1 + plane_width) + sub r2, r6, #1 ; src_ptr2 = src_ptr1 + plane_width - 1 + sub r5, r1, #32 ; dest_ptr1 = src_ptr1 - Border + + mov r12, r4, lsr #2 ; plane_height / 4 + +copy_left_right_y + vld1.8 {d0[], d1[]}, [r1], lr + vld1.8 {d4[], d5[]}, [r2], lr + vld1.8 {d8[], d9[]}, [r1], lr + vld1.8 {d12[], d13[]}, [r2], lr + vld1.8 {d16[], d17[]}, [r1], lr + vld1.8 {d20[], d21[]}, [r2], lr + vld1.8 {d24[], d25[]}, [r1], lr + vld1.8 {d28[], d29[]}, [r2], lr + + vmov q1, q0 + vmov q3, q2 + vmov q5, q4 + vmov q7, q6 + vmov q9, q8 + vmov q11, q10 + vmov q13, q12 + vmov q15, q14 + + subs r12, r12, #1 + + vst1.8 {q0, q1}, [r5], lr + vst1.8 {q2, q3}, [r6], lr + vst1.8 {q4, q5}, [r5], lr + vst1.8 {q6, q7}, [r6], lr + vst1.8 {q8, q9}, [r5], lr + vst1.8 {q10, q11}, [r6], lr + vst1.8 {q12, q13}, [r5], lr + vst1.8 {q14, q15}, [r6], lr + + bne copy_left_right_y + +;Now copy the top and bottom source lines into each line of the respective borders + ldr r1, [r0, #yv12_buffer_config_y_buffer] ; y_buffer + mul r8, r4, lr ; plane_height * plane_stride + + ; copy width is plane_stride + movs r12, lr, lsr #7 ; plane_stride / 128 + + sub r1, r1, #32 ; src_ptr1 = y_buffer - Border + add r6, r1, r8 ; dest_ptr2 = src_ptr2 - plane_stride (src_ptr1 + (plane_height * plane_stride)) + sub r2, r6, lr ; src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride + sub r5, r1, lr, asl #5 ; dest_ptr1 = src_ptr1 - (Border * plane_stride) + ble extra_y_copy_needed ; plane stride < 128 + +copy_top_bottom_y + vld1.8 {q0, q1}, [r1]! + vld1.8 {q8, q9}, [r2]! + vld1.8 {q2, q3}, [r1]! + vld1.8 {q10, q11}, [r2]! + vld1.8 {q4, q5}, [r1]! + vld1.8 {q12, q13}, [r2]! + vld1.8 {q6, q7}, [r1]! + vld1.8 {q14, q15}, [r2]! + + mov r7, #32 ; Border + +top_bottom_32 + subs r7, r7, #1 + + vst1.8 {q0, q1}, [r5]! + vst1.8 {q8, q9}, [r6]! + vst1.8 {q2, q3}, [r5]! + vst1.8 {q10, q11}, [r6]! + vst1.8 {q4, q5}, [r5]! + vst1.8 {q12, q13}, [r6]! + vst1.8 {q6, q7}, [r5]! + vst1.8 {q14, q15}, [r6]! + + add r5, r5, lr ; dest_ptr1 += plane_stride + sub r5, r5, #128 ; dest_ptr1 -= 128 + add r6, r6, lr ; dest_ptr2 += plane_stride + sub r6, r6, #128 ; dest_ptr2 -= 128 + + bne top_bottom_32 + + sub r5, r1, lr, asl #5 ; src_ptr1 - (Border* plane_stride) + add r6, r2, lr ; src_ptr2 + plane_stride + + subs r12, r12, #1 + bne copy_top_bottom_y + +extra_y_copy_needed + mov r7, lr, lsr #4 ; check to see if extra copy is needed + ands r7, r7, #0x7 + bne extra_top_bottom_y +end_of_border_copy_y + +;Border copy for U, V planes +; Border = 16 + ldr r7, [r0, #yv12_buffer_config_u_buffer] ; src_ptr1 + ldr lr, [r0, #yv12_buffer_config_uv_stride] ; plane_stride + ldr r3, [r0, #yv12_buffer_config_uv_width] ; plane_width + ldr r4, [r0, #yv12_buffer_config_uv_height] ; plane_height + + mov r10, #2 + +;copy the left and right most columns out +border_copy_uv + mov r1, r7 ; src_ptr1 needs to be saved for second half of loop + sub r5, r1, #16 ; dest_ptr1 = src_ptr1 - Border + add r6, r1, r3 ; dest_ptr2 = src_ptr2 + 1 (src_ptr1 + plane_width) + sub r2, r6, #1 ; src_ptr2 = src_ptr1 + plane_width - 1 + + mov r12, r4, lsr #3 ; plane_height / 8 + +copy_left_right_uv + vld1.8 {d0[], d1[]}, [r1], lr + vld1.8 {d2[], d3[]}, [r2], lr + vld1.8 {d4[], d5[]}, [r1], lr + vld1.8 {d6[], d7[]}, [r2], lr + vld1.8 {d8[], d9[]}, [r1], lr + vld1.8 {d10[], d11[]}, [r2], lr + vld1.8 {d12[], d13[]}, [r1], lr + vld1.8 {d14[], d15[]}, [r2], lr + vld1.8 {d16[], d17[]}, [r1], lr + vld1.8 {d18[], d19[]}, [r2], lr + vld1.8 {d20[], d21[]}, [r1], lr + vld1.8 {d22[], d23[]}, [r2], lr + vld1.8 {d24[], d25[]}, [r1], lr + vld1.8 {d26[], d27[]}, [r2], lr + vld1.8 {d28[], d29[]}, [r1], lr + vld1.8 {d30[], d31[]}, [r2], lr + + subs r12, r12, #1 + + vst1.8 {q0}, [r5], lr + vst1.8 {q1}, [r6], lr + vst1.8 {q2}, [r5], lr + vst1.8 {q3}, [r6], lr + vst1.8 {q4}, [r5], lr + vst1.8 {q5}, [r6], lr + vst1.8 {q6}, [r5], lr + vst1.8 {q7}, [r6], lr + vst1.8 {q8}, [r5], lr + vst1.8 {q9}, [r6], lr + vst1.8 {q10}, [r5], lr + vst1.8 {q11}, [r6], lr + vst1.8 {q12}, [r5], lr + vst1.8 {q13}, [r6], lr + vst1.8 {q14}, [r5], lr + vst1.8 {q15}, [r6], lr + + bne copy_left_right_uv + +;Now copy the top and bottom source lines into each line of the respective borders + mov r1, r7 + mul r8, r4, lr ; plane_height * plane_stride + movs r12, lr, lsr #6 ; plane_stride / 64 + + sub r1, r1, #16 ; src_ptr1 = u_buffer - Border + add r6, r1, r8 ; dest_ptr2 = src_ptr2 + plane_stride (src_ptr1 + (plane_height * plane_stride) + sub r2, r6, lr ; src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride + sub r5, r1, lr, asl #4 ; dest_ptr1 = src_ptr1 - (Border * plane_stride) + ble extra_uv_copy_needed ; plane_stride < 64 + +copy_top_bottom_uv + vld1.8 {q0, q1}, [r1]! + vld1.8 {q8, q9}, [r2]! + vld1.8 {q2, q3}, [r1]! + vld1.8 {q10, q11}, [r2]! + + mov r7, #16 ; Border + +top_bottom_16 + subs r7, r7, #1 + + vst1.8 {q0, q1}, [r5]! + vst1.8 {q8, q9}, [r6]! + vst1.8 {q2, q3}, [r5]! + vst1.8 {q10, q11}, [r6]! + + add r5, r5, lr ; dest_ptr1 += plane_stride + sub r5, r5, #64 + add r6, r6, lr ; dest_ptr2 += plane_stride + sub r6, r6, #64 + + bne top_bottom_16 + + sub r5, r1, lr, asl #4 ; dest_ptr1 = src_ptr1 - (Border * plane_stride) + add r6, r2, lr ; dest_ptr2 = src_ptr2 + plane_stride + + subs r12, r12, #1 + bne copy_top_bottom_uv +extra_uv_copy_needed + mov r7, lr, lsr #3 ; check to see if extra copy is needed + ands r7, r7, #0x7 + bne extra_top_bottom_uv + +end_of_border_copy_uv + subs r10, r10, #1 + ldrne r7, [r0, #yv12_buffer_config_v_buffer] ; src_ptr1 + bne border_copy_uv + + vpop {d8 - d15} + pop {r4 - r10, pc} + +;;;;;;;;;;;;;;;;;;;;;; +extra_top_bottom_y + vld1.8 {q0}, [r1]! + vld1.8 {q2}, [r2]! + + mov r9, #4 ; 32 >> 3 + +extra_top_bottom_32 + subs r9, r9, #1 + + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + vst1.8 {q0}, [r5], lr + vst1.8 {q2}, [r6], lr + bne extra_top_bottom_32 + + sub r5, r1, lr, asl #5 ; src_ptr1 - (Border * plane_stride) + add r6, r2, lr ; src_ptr2 + plane_stride + subs r7, r7, #1 + bne extra_top_bottom_y + + b end_of_border_copy_y + +extra_top_bottom_uv + vld1.8 {d0}, [r1]! + vld1.8 {d8}, [r2]! + + mov r9, #2 ; 16 >> 3 + +extra_top_bottom_16 + subs r9, r9, #1 + + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + vst1.8 {d0}, [r5], lr + vst1.8 {d8}, [r6], lr + bne extra_top_bottom_16 + + sub r5, r1, lr, asl #4 ; src_ptr1 - (Border * plane_stride) + add r6, r2, lr ; src_ptr2 + plane_stride + subs r7, r7, #1 + bne extra_top_bottom_uv + + b end_of_border_copy_uv + + ENDP + END diff --git a/vpx_scale/arm/neon/yv12extend_arm.c b/vpx_scale/arm/neon/yv12extend_arm.c new file mode 100644 index 0000000..7529fc6 --- /dev/null +++ b/vpx_scale/arm/neon/yv12extend_arm.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_scale/vpxscale.h" + +extern void vp8_yv12_copy_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, + YV12_BUFFER_CONFIG *dst_ybc); + +void vp8_yv12_copy_frame_neon(YV12_BUFFER_CONFIG *src_ybc, + YV12_BUFFER_CONFIG *dst_ybc) +{ + vp8_yv12_copy_frame_func_neon(src_ybc, dst_ybc); + + vp8_yv12_extend_frame_borders_neon(dst_ybc); +} diff --git a/vpx_scale/generic/bicubic_scaler.c b/vpx_scale/generic/bicubic_scaler.c new file mode 100644 index 0000000..4468e9d --- /dev/null +++ b/vpx_scale/generic/bicubic_scaler.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include +#include +#include +#include "vpx_mem/vpx_mem.h" +#include "vpxscale_arbitrary.h" + +#define FIXED_POINT + +#define MAX_IN_WIDTH 800 +#define MAX_IN_HEIGHT 600 +#define MAX_OUT_WIDTH 800 +#define MAX_OUT_HEIGHT 600 +#define MAX_OUT_DIMENSION ((MAX_OUT_WIDTH > MAX_OUT_HEIGHT) ? \ + MAX_OUT_WIDTH : MAX_OUT_HEIGHT) + +BICUBIC_SCALER_STRUCT g_b_scaler; +static int g_first_time = 1; + +#pragma DATA_SECTION(g_hbuf, "VP6_HEAP") +#pragma DATA_ALIGN (g_hbuf, 32); +unsigned char g_hbuf[MAX_OUT_DIMENSION]; + +#pragma DATA_SECTION(g_hbuf_uv, "VP6_HEAP") +#pragma DATA_ALIGN (g_hbuf_uv, 32); +unsigned char g_hbuf_uv[MAX_OUT_DIMENSION]; + + +#ifdef FIXED_POINT +static int a_i = 0.6 * 65536; +#else +static float a = -0.6; +#endif + +#ifdef FIXED_POINT +// 3 2 +// C0 = a*t - a*t +// +static short c0_fixed(unsigned int t) +{ + // put t in Q16 notation + unsigned short v1, v2; + + // Q16 + v1 = (a_i * t) >> 16; + v1 = (v1 * t) >> 16; + + // Q16 + v2 = (a_i * t) >> 16; + v2 = (v2 * t) >> 16; + v2 = (v2 * t) >> 16; + + // Q12 + return -((v1 - v2) >> 4); +} + +// 2 3 +// C1 = a*t + (3-2*a)*t - (2-a)*t +// +static short c1_fixed(unsigned int t) +{ + unsigned short v1, v2, v3; + unsigned short two, three; + + // Q16 + v1 = (a_i * t) >> 16; + + // Q13 + two = 2 << 13; + v2 = two - (a_i >> 3); + v2 = (v2 * t) >> 16; + v2 = (v2 * t) >> 16; + v2 = (v2 * t) >> 16; + + // Q13 + three = 3 << 13; + v3 = three - (2 * (a_i >> 3)); + v3 = (v3 * t) >> 16; + v3 = (v3 * t) >> 16; + + // Q12 + return (((v1 >> 3) - v2 + v3) >> 1); + +} + +// 2 3 +// C2 = 1 - (3-a)*t + (2-a)*t +// +static short c2_fixed(unsigned int t) +{ + unsigned short v1, v2, v3; + unsigned short two, three; + + // Q13 + v1 = 1 << 13; + + // Q13 + three = 3 << 13; + v2 = three - (a_i >> 3); + v2 = (v2 * t) >> 16; + v2 = (v2 * t) >> 16; + + // Q13 + two = 2 << 13; + v3 = two - (a_i >> 3); + v3 = (v3 * t) >> 16; + v3 = (v3 * t) >> 16; + v3 = (v3 * t) >> 16; + + // Q12 + return (v1 - v2 + v3) >> 1; +} + +// 2 3 +// C3 = a*t - 2*a*t + a*t +// +static short c3_fixed(unsigned int t) +{ + int v1, v2, v3; + + // Q16 + v1 = (a_i * t) >> 16; + + // Q15 + v2 = 2 * (a_i >> 1); + v2 = (v2 * t) >> 16; + v2 = (v2 * t) >> 16; + + // Q16 + v3 = (a_i * t) >> 16; + v3 = (v3 * t) >> 16; + v3 = (v3 * t) >> 16; + + // Q12 + return ((v2 - (v1 >> 1) - (v3 >> 1)) >> 3); +} +#else +// 3 2 +// C0 = -a*t + a*t +// +float C0(float t) +{ + return -a * t * t * t + a * t * t; +} + +// 2 3 +// C1 = -a*t + (2*a+3)*t - (a+2)*t +// +float C1(float t) +{ + return -(a + 2.0f) * t * t * t + (2.0f * a + 3.0f) * t * t - a * t; +} + +// 2 3 +// C2 = 1 - (a+3)*t + (a+2)*t +// +float C2(float t) +{ + return (a + 2.0f) * t * t * t - (a + 3.0f) * t * t + 1.0f; +} + +// 2 3 +// C3 = a*t - 2*a*t + a*t +// +float C3(float t) +{ + return a * t * t * t - 2.0f * a * t * t + a * t; +} +#endif + +#if 0 +int compare_real_fixed() +{ + int i, errors = 0; + float mult = 1.0 / 10000.0; + unsigned int fixed_mult = mult * 4294967296;//65536; + unsigned int phase_offset_int; + float phase_offset_real; + + for (i = 0; i < 10000; i++) + { + int fixed0, fixed1, fixed2, fixed3, fixed_total; + int real0, real1, real2, real3, real_total; + + phase_offset_real = (float)i * mult; + phase_offset_int = (fixed_mult * i) >> 16; +// phase_offset_int = phase_offset_real * 65536; + + fixed0 = c0_fixed(phase_offset_int); + real0 = C0(phase_offset_real) * 4096.0; + + if ((abs(fixed0) > (abs(real0) + 1)) || (abs(fixed0) < (abs(real0) - 1))) + errors++; + + fixed1 = c1_fixed(phase_offset_int); + real1 = C1(phase_offset_real) * 4096.0; + + if ((abs(fixed1) > (abs(real1) + 1)) || (abs(fixed1) < (abs(real1) - 1))) + errors++; + + fixed2 = c2_fixed(phase_offset_int); + real2 = C2(phase_offset_real) * 4096.0; + + if ((abs(fixed2) > (abs(real2) + 1)) || (abs(fixed2) < (abs(real2) - 1))) + errors++; + + fixed3 = c3_fixed(phase_offset_int); + real3 = C3(phase_offset_real) * 4096.0; + + if ((abs(fixed3) > (abs(real3) + 1)) || (abs(fixed3) < (abs(real3) - 1))) + errors++; + + fixed_total = fixed0 + fixed1 + fixed2 + fixed3; + real_total = real0 + real1 + real2 + real3; + + if ((fixed_total > 4097) || (fixed_total < 4094)) + errors ++; + + if ((real_total > 4097) || (real_total < 4095)) + errors ++; + } + + return errors; +} +#endif + +// Find greatest common denominator between two integers. Method used here is +// slow compared to Euclid's algorithm, but does not require any division. +int gcd(int a, int b) +{ + // Problem with this algorithm is that if a or b = 0 this function + // will never exit. Don't want to return 0 because any computation + // that was based on a common denoninator and tried to reduce by + // dividing by 0 would fail. Best solution that could be thought of + // would to be fail by returing a 1; + if (a <= 0 || b <= 0) + return 1; + + while (a != b) + { + if (b > a) + b = b - a; + else + { + int tmp = a;//swap large and + a = b; //small + b = tmp; + } + } + + return b; +} + +void bicubic_coefficient_init() +{ + vpx_memset(&g_b_scaler, 0, sizeof(BICUBIC_SCALER_STRUCT)); + g_first_time = 0; +} + +void bicubic_coefficient_destroy() +{ + if (!g_first_time) + { + vpx_free(g_b_scaler.l_w); + + vpx_free(g_b_scaler.l_h); + + vpx_free(g_b_scaler.l_h_uv); + + vpx_free(g_b_scaler.c_w); + + vpx_free(g_b_scaler.c_h); + + vpx_free(g_b_scaler.c_h_uv); + + vpx_memset(&g_b_scaler, 0, sizeof(BICUBIC_SCALER_STRUCT)); + } +} + +// Create the coeffients that will be used for the cubic interpolation. +// Because scaling does not have to be equal in the vertical and horizontal +// regimes the phase offsets will be different. There are 4 coefficents +// for each point, two on each side. The layout is that there are the +// 4 coefficents for each phase in the array and then the next phase. +int bicubic_coefficient_setup(int in_width, int in_height, int out_width, int out_height) +{ + int i; +#ifdef FIXED_POINT + int phase_offset_int; + unsigned int fixed_mult; + int product_val = 0; +#else + float phase_offset; +#endif + int gcd_w, gcd_h, gcd_h_uv, d_w, d_h, d_h_uv; + + if (g_first_time) + bicubic_coefficient_init(); + + + // check to see if the coefficents have already been set up correctly + if ((in_width == g_b_scaler.in_width) && (in_height == g_b_scaler.in_height) + && (out_width == g_b_scaler.out_width) && (out_height == g_b_scaler.out_height)) + return 0; + + g_b_scaler.in_width = in_width; + g_b_scaler.in_height = in_height; + g_b_scaler.out_width = out_width; + g_b_scaler.out_height = out_height; + + // Don't want to allow crazy scaling, just try and prevent a catastrophic + // failure here. Want to fail after setting the member functions so if + // if the scaler is called the member functions will not scale. + if (out_width <= 0 || out_height <= 0) + return -1; + + // reduce in/out width and height ratios using the gcd + gcd_w = gcd(out_width, in_width); + gcd_h = gcd(out_height, in_height); + gcd_h_uv = gcd(out_height, in_height / 2); + + // the numerator width and height are to be saved in + // globals so they can be used during the scaling process + // without having to be recalculated. + g_b_scaler.nw = out_width / gcd_w; + d_w = in_width / gcd_w; + + g_b_scaler.nh = out_height / gcd_h; + d_h = in_height / gcd_h; + + g_b_scaler.nh_uv = out_height / gcd_h_uv; + d_h_uv = (in_height / 2) / gcd_h_uv; + + // allocate memory for the coefficents + vpx_free(g_b_scaler.l_w); + + vpx_free(g_b_scaler.l_h); + + vpx_free(g_b_scaler.l_h_uv); + + g_b_scaler.l_w = (short *)vpx_memalign(32, out_width * 2); + g_b_scaler.l_h = (short *)vpx_memalign(32, out_height * 2); + g_b_scaler.l_h_uv = (short *)vpx_memalign(32, out_height * 2); + + vpx_free(g_b_scaler.c_w); + + vpx_free(g_b_scaler.c_h); + + vpx_free(g_b_scaler.c_h_uv); + + g_b_scaler.c_w = (short *)vpx_memalign(32, g_b_scaler.nw * 4 * 2); + g_b_scaler.c_h = (short *)vpx_memalign(32, g_b_scaler.nh * 4 * 2); + g_b_scaler.c_h_uv = (short *)vpx_memalign(32, g_b_scaler.nh_uv * 4 * 2); + + g_b_scaler.hbuf = g_hbuf; + g_b_scaler.hbuf_uv = g_hbuf_uv; + + // Set up polyphase filter taps. This needs to be done before + // the scaling because of the floating point math required. The + // coefficients are multiplied by 2^12 so that fixed point math + // can be used in the main scaling loop. +#ifdef FIXED_POINT + fixed_mult = (1.0 / (float)g_b_scaler.nw) * 4294967296; + + product_val = 0; + + for (i = 0; i < g_b_scaler.nw; i++) + { + if (product_val > g_b_scaler.nw) + product_val -= g_b_scaler.nw; + + phase_offset_int = (fixed_mult * product_val) >> 16; + + g_b_scaler.c_w[i*4] = c3_fixed(phase_offset_int); + g_b_scaler.c_w[i*4+1] = c2_fixed(phase_offset_int); + g_b_scaler.c_w[i*4+2] = c1_fixed(phase_offset_int); + g_b_scaler.c_w[i*4+3] = c0_fixed(phase_offset_int); + + product_val += d_w; + } + + + fixed_mult = (1.0 / (float)g_b_scaler.nh) * 4294967296; + + product_val = 0; + + for (i = 0; i < g_b_scaler.nh; i++) + { + if (product_val > g_b_scaler.nh) + product_val -= g_b_scaler.nh; + + phase_offset_int = (fixed_mult * product_val) >> 16; + + g_b_scaler.c_h[i*4] = c0_fixed(phase_offset_int); + g_b_scaler.c_h[i*4+1] = c1_fixed(phase_offset_int); + g_b_scaler.c_h[i*4+2] = c2_fixed(phase_offset_int); + g_b_scaler.c_h[i*4+3] = c3_fixed(phase_offset_int); + + product_val += d_h; + } + + fixed_mult = (1.0 / (float)g_b_scaler.nh_uv) * 4294967296; + + product_val = 0; + + for (i = 0; i < g_b_scaler.nh_uv; i++) + { + if (product_val > g_b_scaler.nh_uv) + product_val -= g_b_scaler.nh_uv; + + phase_offset_int = (fixed_mult * product_val) >> 16; + + g_b_scaler.c_h_uv[i*4] = c0_fixed(phase_offset_int); + g_b_scaler.c_h_uv[i*4+1] = c1_fixed(phase_offset_int); + g_b_scaler.c_h_uv[i*4+2] = c2_fixed(phase_offset_int); + g_b_scaler.c_h_uv[i*4+3] = c3_fixed(phase_offset_int); + + product_val += d_h_uv; + } + +#else + + for (i = 0; i < g_nw; i++) + { + phase_offset = (float)((i * d_w) % g_nw) / (float)g_nw; + g_c_w[i*4] = (C3(phase_offset) * 4096.0); + g_c_w[i*4+1] = (C2(phase_offset) * 4096.0); + g_c_w[i*4+2] = (C1(phase_offset) * 4096.0); + g_c_w[i*4+3] = (C0(phase_offset) * 4096.0); + } + + for (i = 0; i < g_nh; i++) + { + phase_offset = (float)((i * d_h) % g_nh) / (float)g_nh; + g_c_h[i*4] = (C0(phase_offset) * 4096.0); + g_c_h[i*4+1] = (C1(phase_offset) * 4096.0); + g_c_h[i*4+2] = (C2(phase_offset) * 4096.0); + g_c_h[i*4+3] = (C3(phase_offset) * 4096.0); + } + + for (i = 0; i < g_nh_uv; i++) + { + phase_offset = (float)((i * d_h_uv) % g_nh_uv) / (float)g_nh_uv; + g_c_h_uv[i*4] = (C0(phase_offset) * 4096.0); + g_c_h_uv[i*4+1] = (C1(phase_offset) * 4096.0); + g_c_h_uv[i*4+2] = (C2(phase_offset) * 4096.0); + g_c_h_uv[i*4+3] = (C3(phase_offset) * 4096.0); + } + +#endif + + // Create an array that corresponds input lines to output lines. + // This doesn't require floating point math, but it does require + // a division and because hardware division is not present that + // is a call. + for (i = 0; i < out_width; i++) + { + g_b_scaler.l_w[i] = (i * d_w) / g_b_scaler.nw; + + if ((g_b_scaler.l_w[i] + 2) <= in_width) + g_b_scaler.max_usable_out_width = i; + + } + + for (i = 0; i < out_height + 1; i++) + { + g_b_scaler.l_h[i] = (i * d_h) / g_b_scaler.nh; + g_b_scaler.l_h_uv[i] = (i * d_h_uv) / g_b_scaler.nh_uv; + } + + return 0; +} + +int bicubic_scale(int in_width, int in_height, int in_stride, + int out_width, int out_height, int out_stride, + unsigned char *input_image, unsigned char *output_image) +{ + short *RESTRICT l_w, * RESTRICT l_h; + short *RESTRICT c_w, * RESTRICT c_h; + unsigned char *RESTRICT ip, * RESTRICT op; + unsigned char *RESTRICT hbuf; + int h, w, lw, lh; + int temp_sum; + int phase_offset_w, phase_offset_h; + + c_w = g_b_scaler.c_w; + c_h = g_b_scaler.c_h; + + op = output_image; + + l_w = g_b_scaler.l_w; + l_h = g_b_scaler.l_h; + + phase_offset_h = 0; + + for (h = 0; h < out_height; h++) + { + // select the row to work on + lh = l_h[h]; + ip = input_image + (in_stride * lh); + + // vp8_filter the row vertically into an temporary buffer. + // If the phase offset == 0 then all the multiplication + // is going to result in the output equalling the input. + // So instead point the temporary buffer to the input. + // Also handle the boundry condition of not being able to + // filter that last lines. + if (phase_offset_h && (lh < in_height - 2)) + { + hbuf = g_b_scaler.hbuf; + + for (w = 0; w < in_width; w++) + { + temp_sum = c_h[phase_offset_h*4+3] * ip[w - in_stride]; + temp_sum += c_h[phase_offset_h*4+2] * ip[w]; + temp_sum += c_h[phase_offset_h*4+1] * ip[w + in_stride]; + temp_sum += c_h[phase_offset_h*4] * ip[w + 2*in_stride]; + + hbuf[w] = temp_sum >> 12; + } + } + else + hbuf = ip; + + // increase the phase offset for the next time around. + if (++phase_offset_h >= g_b_scaler.nh) + phase_offset_h = 0; + + // now filter and expand it horizontally into the final + // output buffer + phase_offset_w = 0; + + for (w = 0; w < out_width; w++) + { + // get the index to use to expand the image + lw = l_w[w]; + + temp_sum = c_w[phase_offset_w*4] * hbuf[lw - 1]; + temp_sum += c_w[phase_offset_w*4+1] * hbuf[lw]; + temp_sum += c_w[phase_offset_w*4+2] * hbuf[lw + 1]; + temp_sum += c_w[phase_offset_w*4+3] * hbuf[lw + 2]; + temp_sum = temp_sum >> 12; + + if (++phase_offset_w >= g_b_scaler.nw) + phase_offset_w = 0; + + // boundry conditions + if ((lw + 2) >= in_width) + temp_sum = hbuf[lw]; + + if (lw == 0) + temp_sum = hbuf[0]; + + op[w] = temp_sum; + } + + op += out_stride; + } + + return 0; +} + +void bicubic_scale_frame_reset() +{ + g_b_scaler.out_width = 0; + g_b_scaler.out_height = 0; +} + +void bicubic_scale_frame(YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst, + int new_width, int new_height) +{ + + dst->y_width = new_width; + dst->y_height = new_height; + dst->uv_width = new_width / 2; + dst->uv_height = new_height / 2; + + dst->y_stride = dst->y_width; + dst->uv_stride = dst->uv_width; + + bicubic_scale(src->y_width, src->y_height, src->y_stride, + new_width, new_height, dst->y_stride, + src->y_buffer, dst->y_buffer); + + bicubic_scale(src->uv_width, src->uv_height, src->uv_stride, + new_width / 2, new_height / 2, dst->uv_stride, + src->u_buffer, dst->u_buffer); + + bicubic_scale(src->uv_width, src->uv_height, src->uv_stride, + new_width / 2, new_height / 2, dst->uv_stride, + src->v_buffer, dst->v_buffer); +} diff --git a/vpx_scale/generic/gen_scalers.c b/vpx_scale/generic/gen_scalers.c new file mode 100644 index 0000000..9beb162 --- /dev/null +++ b/vpx_scale/generic/gen_scalers.c @@ -0,0 +1,956 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_scale/vpxscale.h" +#include "vpx_mem/vpx_mem.h" +/**************************************************************************** +* Imports +****************************************************************************/ + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_4_5_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 4 to 5. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_horizontal_line_4_5_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned i; + unsigned int a, b, c; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width - 4; i += 4) + { + a = src[0]; + b = src[1]; + des [0] = (unsigned char) a; + des [1] = (unsigned char)((a * 51 + 205 * b + 128) >> 8); + c = src[2] * 154; + a = src[3]; + des [2] = (unsigned char)((b * 102 + c + 128) >> 8); + des [3] = (unsigned char)((c + 102 * a + 128) >> 8); + b = src[4]; + des [4] = (unsigned char)((a * 205 + 51 * b + 128) >> 8); + + src += 4; + des += 5; + } + + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a * 51 + 205 * b + 128) >> 8); + c = src[2] * 154; + a = src[3]; + des [2] = (unsigned char)((b * 102 + c + 128) >> 8); + des [3] = (unsigned char)((c + 102 * a + 128) >> 8); + des [4] = (unsigned char)(a); + +} + +/**************************************************************************** + * + * ROUTINE : vp8_vertical_band_4_5_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales vertical band of pixels by scale 4 to 5. The + * height of the band scaled is 4-pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. + * + ****************************************************************************/ +void vp8_vertical_band_4_5_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c, d; + unsigned char *des = dest; + + for (i = 0; i < dest_width; i++) + { + a = des [0]; + b = des [dest_pitch]; + + des[dest_pitch] = (unsigned char)((a * 51 + 205 * b + 128) >> 8); + + c = des[dest_pitch*2] * 154; + d = des[dest_pitch*3]; + + des [dest_pitch*2] = (unsigned char)((b * 102 + c + 128) >> 8); + des [dest_pitch*3] = (unsigned char)((c + 102 * d + 128) >> 8); + + /* First line in next band */ + a = des [dest_pitch * 5]; + des [dest_pitch * 4] = (unsigned char)((d * 205 + 51 * a + 128) >> 8); + + des ++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_last_vertical_band_4_5_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales last vertical band of pixels by scale 4 to 5. The + * height of the band scaled is 4-pixels. + * + * SPECIAL NOTES : The routine does not have available the first line of + * the band below the current band, since this is the + * last band. + * + ****************************************************************************/ +void vp8_last_vertical_band_4_5_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c, d; + unsigned char *des = dest; + + for (i = 0; i < dest_width; ++i) + { + a = des[0]; + b = des[dest_pitch]; + + des[dest_pitch] = (unsigned char)((a * 51 + 205 * b + 128) >> 8); + + c = des[dest_pitch*2] * 154; + d = des[dest_pitch*3]; + + des [dest_pitch*2] = (unsigned char)((b * 102 + c + 128) >> 8); + des [dest_pitch*3] = (unsigned char)((c + 102 * d + 128) >> 8); + + /* No other line for interplation of this line, so .. */ + des[dest_pitch*4] = (unsigned char) d; + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_2_3_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 2 to 3. + * + * SPECIAL NOTES : None. + * + * + ****************************************************************************/ +void vp8_horizontal_line_2_3_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width - 2; i += 2) + { + a = src[0]; + b = src[1]; + c = src[2]; + + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a * 85 + 171 * b + 128) >> 8); + des [2] = (unsigned char)((b * 171 + 85 * c + 128) >> 8); + + src += 2; + des += 3; + } + + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a * 85 + 171 * b + 128) >> 8); + des [2] = (unsigned char)(b); +} + + +/**************************************************************************** + * + * ROUTINE : vp8_vertical_band_2_3_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales vertical band of pixels by scale 2 to 3. The + * height of the band scaled is 2-pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. + * + ****************************************************************************/ +void vp8_vertical_band_2_3_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + + for (i = 0; i < dest_width; i++) + { + a = des [0]; + b = des [dest_pitch]; + c = des[dest_pitch*3]; + des [dest_pitch ] = (unsigned char)((a * 85 + 171 * b + 128) >> 8); + des [dest_pitch*2] = (unsigned char)((b * 171 + 85 * c + 128) >> 8); + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_last_vertical_band_2_3_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales last vertical band of pixels by scale 2 to 3. The + * height of the band scaled is 2-pixels. + * + * SPECIAL NOTES : The routine does not have available the first line of + * the band below the current band, since this is the + * last band. + * + ****************************************************************************/ +void vp8_last_vertical_band_2_3_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b; + unsigned char *des = dest; + + for (i = 0; i < dest_width; ++i) + { + a = des [0]; + b = des [dest_pitch]; + + des [dest_pitch ] = (unsigned char)((a * 85 + 171 * b + 128) >> 8); + des [dest_pitch*2] = (unsigned char)(b); + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_3_5_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 3 to 5. + * + * SPECIAL NOTES : None. + * + * + ****************************************************************************/ +void vp8_horizontal_line_3_5_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width - 3; i += 3) + { + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a * 102 + 154 * b + 128) >> 8); + + c = src[2] ; + des [2] = (unsigned char)((b * 205 + c * 51 + 128) >> 8); + des [3] = (unsigned char)((b * 51 + c * 205 + 128) >> 8); + + a = src[3]; + des [4] = (unsigned char)((c * 154 + a * 102 + 128) >> 8); + + src += 3; + des += 5; + } + + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + + des [1] = (unsigned char)((a * 102 + 154 * b + 128) >> 8); + c = src[2] ; + des [2] = (unsigned char)((b * 205 + c * 51 + 128) >> 8); + des [3] = (unsigned char)((b * 51 + c * 205 + 128) >> 8); + + des [4] = (unsigned char)(c); +} + +/**************************************************************************** + * + * ROUTINE : vp8_vertical_band_3_5_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales vertical band of pixels by scale 3 to 5. The + * height of the band scaled is 3-pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. + * + ****************************************************************************/ +void vp8_vertical_band_3_5_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + + for (i = 0; i < dest_width; i++) + { + a = des [0]; + b = des [dest_pitch]; + des [dest_pitch] = (unsigned char)((a * 102 + 154 * b + 128) >> 8); + + c = des[dest_pitch*2]; + des [dest_pitch*2] = (unsigned char)((b * 205 + c * 51 + 128) >> 8); + des [dest_pitch*3] = (unsigned char)((b * 51 + c * 205 + 128) >> 8); + + /* First line in next band... */ + a = des [dest_pitch * 5]; + des [dest_pitch * 4] = (unsigned char)((c * 154 + a * 102 + 128) >> 8); + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_last_vertical_band_3_5_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales last vertical band of pixels by scale 3 to 5. The + * height of the band scaled is 3-pixels. + * + * SPECIAL NOTES : The routine does not have available the first line of + * the band below the current band, since this is the + * last band. + * + ****************************************************************************/ +void vp8_last_vertical_band_3_5_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + + for (i = 0; i < dest_width; ++i) + { + a = des [0]; + b = des [dest_pitch]; + + des [ dest_pitch ] = (unsigned char)((a * 102 + 154 * b + 128) >> 8); + + c = des[dest_pitch*2]; + des [dest_pitch*2] = (unsigned char)((b * 205 + c * 51 + 128) >> 8); + des [dest_pitch*3] = (unsigned char)((b * 51 + c * 205 + 128) >> 8); + + /* No other line for interplation of this line, so .. */ + des [ dest_pitch * 4 ] = (unsigned char)(c) ; + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_3_4_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 3 to 4. + * + * SPECIAL NOTES : None. + * + * + ****************************************************************************/ +void vp8_horizontal_line_3_4_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width - 3; i += 3) + { + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a * 64 + b * 192 + 128) >> 8); + + c = src[2]; + des [2] = (unsigned char)((b + c + 1) >> 1); + + a = src[3]; + des [3] = (unsigned char)((c * 192 + a * 64 + 128) >> 8); + + src += 3; + des += 4; + } + + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a * 64 + b * 192 + 128) >> 8); + + c = src[2] ; + des [2] = (unsigned char)((b + c + 1) >> 1); + des [3] = (unsigned char)(c); +} + +/**************************************************************************** + * + * ROUTINE : vp8_vertical_band_3_4_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales vertical band of pixels by scale 3 to 4. The + * height of the band scaled is 3-pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. + * + ****************************************************************************/ +void vp8_vertical_band_3_4_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + + for (i = 0; i < dest_width; i++) + { + a = des [0]; + b = des [dest_pitch]; + des [dest_pitch] = (unsigned char)((a * 64 + b * 192 + 128) >> 8); + + c = des[dest_pitch*2]; + des [dest_pitch*2] = (unsigned char)((b + c + 1) >> 1); + + /* First line in next band... */ + a = des [dest_pitch*4]; + des [dest_pitch*3] = (unsigned char)((c * 192 + a * 64 + 128) >> 8); + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_last_vertical_band_3_4_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales last vertical band of pixels by scale 3 to 4. The + * height of the band scaled is 3-pixels. + * + * SPECIAL NOTES : The routine does not have available the first line of + * the band below the current band, since this is the + * last band. + * + ****************************************************************************/ +void vp8_last_vertical_band_3_4_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c; + unsigned char *des = dest; + + for (i = 0; i < dest_width; ++i) + { + a = des [0]; + b = des [dest_pitch]; + + des [dest_pitch] = (unsigned char)((a * 64 + b * 192 + 128) >> 8); + + c = des[dest_pitch*2]; + des [dest_pitch*2] = (unsigned char)((b + c + 1) >> 1); + + /* No other line for interplation of this line, so .. */ + des [dest_pitch*3] = (unsigned char)(c); + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_1_2_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 1 to 2. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_horizontal_line_1_2_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned int i; + unsigned int a, b; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width - 1; i += 1) + { + a = src[0]; + b = src[1]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)((a + b + 1) >> 1); + src += 1; + des += 2; + } + + a = src[0]; + des [0] = (unsigned char)(a); + des [1] = (unsigned char)(a); +} + +/**************************************************************************** + * + * ROUTINE : vp8_vertical_band_1_2_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales vertical band of pixels by scale 1 to 2. The + * height of the band scaled is 1-pixel. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. + * + ****************************************************************************/ +void vp8_vertical_band_1_2_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b; + unsigned char *des = dest; + + for (i = 0; i < dest_width; i++) + { + a = des [0]; + b = des [dest_pitch * 2]; + + des[dest_pitch] = (unsigned char)((a + b + 1) >> 1); + + des++; + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_last_vertical_band_1_2_scale_c + * + * INPUTS : unsigned char *dest : Pointer to destination data. + * unsigned int dest_pitch : Stride of destination data. + * unsigned int dest_width : Width of destination data. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Scales last vertical band of pixels by scale 1 to 2. The + * height of the band scaled is 1-pixel. + * + * SPECIAL NOTES : The routine does not have available the first line of + * the band below the current band, since this is the + * last band. + * + ****************************************************************************/ +void vp8_last_vertical_band_1_2_scale_c(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned char *des = dest; + + for (i = 0; i < dest_width; ++i) + { + des[dest_pitch] = des[0]; + des++; + } +} + + + + + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_4_5_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 4 to 5. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_horizontal_line_5_4_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned i; + unsigned int a, b, c, d, e; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width; i += 5) + { + a = src[0]; + b = src[1]; + c = src[2]; + d = src[3]; + e = src[4]; + + des[0] = (unsigned char) a; + des[1] = (unsigned char)((b * 192 + c * 64 + 128) >> 8); + des[2] = (unsigned char)((c * 128 + d * 128 + 128) >> 8); + des[3] = (unsigned char)((d * 64 + e * 192 + 128) >> 8); + + src += 5; + des += 4; + } +} + + + + +void vp8_vertical_band_5_4_scale_c(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c, d, e; + unsigned char *des = dest; + unsigned char *src = source; + + for (i = 0; i < dest_width; i++) + { + + a = src[0 * src_pitch]; + b = src[1 * src_pitch]; + c = src[2 * src_pitch]; + d = src[3 * src_pitch]; + e = src[4 * src_pitch]; + + des[0 * dest_pitch] = (unsigned char) a; + des[1 * dest_pitch] = (unsigned char)((b * 192 + c * 64 + 128) >> 8); + des[2 * dest_pitch] = (unsigned char)((c * 128 + d * 128 + 128) >> 8); + des[3 * dest_pitch] = (unsigned char)((d * 64 + e * 192 + 128) >> 8); + + src ++; + des ++; + + } +} + + +/*7*************************************************************************** + * + * ROUTINE : vp8_horizontal_line_3_5_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 3 to 5. + * + * SPECIAL NOTES : None. + * + * + ****************************************************************************/ +void vp8_horizontal_line_5_3_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned int i; + unsigned int a, b, c, d , e; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width; i += 5) + { + a = src[0]; + b = src[1]; + c = src[2]; + d = src[3]; + e = src[4]; + + des[0] = (unsigned char) a; + des[1] = (unsigned char)((b * 85 + c * 171 + 128) >> 8); + des[2] = (unsigned char)((d * 171 + e * 85 + 128) >> 8); + + src += 5; + des += 3; + } + +} + +void vp8_vertical_band_5_3_scale_c(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + unsigned int i; + unsigned int a, b, c, d, e; + unsigned char *des = dest; + unsigned char *src = source; + + for (i = 0; i < dest_width; i++) + { + + a = src[0 * src_pitch]; + b = src[1 * src_pitch]; + c = src[2 * src_pitch]; + d = src[3 * src_pitch]; + e = src[4 * src_pitch]; + + des[0 * dest_pitch] = (unsigned char) a; + des[1 * dest_pitch] = (unsigned char)((b * 85 + c * 171 + 128) >> 8); + des[2 * dest_pitch] = (unsigned char)((d * 171 + e * 85 + 128) >> 8); + + src ++; + des ++; + + } +} + +/**************************************************************************** + * + * ROUTINE : vp8_horizontal_line_1_2_scale_c + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 1 to 2. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_horizontal_line_2_1_scale_c +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + unsigned int i; + unsigned int a; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for (i = 0; i < source_width; i += 2) + { + a = src[0]; + des [0] = (unsigned char)(a); + src += 2; + des += 1; + } + + + +} +void vp8_vertical_band_2_1_scale_c(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + (void) dest_pitch; + (void) src_pitch; + vpx_memcpy(dest, source, dest_width); +} + +void vp8_vertical_band_2_1_scale_i_c(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + int i; + int temp; + int width = dest_width; + + (void) dest_pitch; + + for (i = 0; i < width; i++) + { + temp = 8; + temp += source[i-(int)src_pitch] * 3; + temp += source[i] * 10; + temp += source[i+src_pitch] * 3; + temp >>= 4 ; + dest[i] = (unsigned char)(temp); + } + +} diff --git a/vpx_scale/generic/vpxscale.c b/vpx_scale/generic/vpxscale.c new file mode 100644 index 0000000..c02e4ff --- /dev/null +++ b/vpx_scale/generic/vpxscale.c @@ -0,0 +1,1059 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** + * + * Module Title : scale.c + * + * Description : Image scaling functions. + * + ***************************************************************************/ + +/**************************************************************************** +* Header Files +****************************************************************************/ +#include "vpx_rtcd.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_scale/yv12config.h" +#include "vpx_scale/scale_mode.h" + +typedef struct +{ + int expanded_frame_width; + int expanded_frame_height; + + int HScale; + int HRatio; + int VScale; + int VRatio; + + YV12_BUFFER_CONFIG *src_yuv_config; + YV12_BUFFER_CONFIG *dst_yuv_config; + +} SCALE_VARS; + +/**************************************************************************** + * + * ROUTINE : horizontal_line_copy + * + * INPUTS : None + * + * + * OUTPUTS : None. + * + * RETURNS : None + * + * FUNCTION : 1 to 1 scaling up for a horizontal line of pixles + * + * SPECIAL NOTES : None. + * + * ERRORS : None. + * + ****************************************************************************/ +static +void horizontal_line_copy( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + (void) dest_width; + + duck_memcpy(dest, source, source_width); +} +/**************************************************************************** + * + * ROUTINE : null_scale + * + * INPUTS : None + * + * + * OUTPUTS : None. + * + * RETURNS : None + * + * FUNCTION : 1 to 1 scaling up for a vertical band + * + * SPECIAL NOTES : None. + * + * ERRORS : None. + * + ****************************************************************************/ +static +void null_scale( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + (void) dest; + (void) dest_pitch; + (void) dest_width; + + return; +} + +/**************************************************************************** + * + * ROUTINE : scale1d_2t1_i + * + * INPUTS : const unsigned char *source : Pointer to data to be scaled. + * int source_step : Number of pixels to step on in source. + * unsigned int source_scale : Scale for source (UNUSED). + * unsigned int source_length : Length of source (UNUSED). + * unsigned char *dest : Pointer to output data array. + * int dest_step : Number of pixels to step on in destination. + * unsigned int dest_scale : Scale for destination (UNUSED). + * unsigned int dest_length : Length of destination. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs 2-to-1 interpolated scaling. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void scale1d_2t1_i +( + const unsigned char *source, + int source_step, + unsigned int source_scale, + unsigned int source_length, + unsigned char *dest, + int dest_step, + unsigned int dest_scale, + unsigned int dest_length +) +{ + unsigned int i, j; + unsigned int temp; + int source_pitch = source_step; + (void) source_length; + (void) source_scale; + (void) dest_scale; + + source_step *= 2; + dest[0] = source[0]; + + for (i = dest_step, j = source_step; i < dest_length * dest_step; i += dest_step, j += source_step) + { + temp = 8; + temp += 3 * source[j-source_pitch]; + temp += 10 * source[j]; + temp += 3 * source[j+source_pitch]; + temp >>= 4; + dest[i] = (char)(temp); + } +} + +/**************************************************************************** + * + * ROUTINE : scale1d_2t1_ps + * + * INPUTS : const unsigned char *source : Pointer to data to be scaled. + * int source_step : Number of pixels to step on in source. + * unsigned int source_scale : Scale for source (UNUSED). + * unsigned int source_length : Length of source (UNUSED). + * unsigned char *dest : Pointer to output data array. + * int dest_step : Number of pixels to step on in destination. + * unsigned int dest_scale : Scale for destination (UNUSED). + * unsigned int dest_length : Length of destination. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs 2-to-1 point subsampled scaling. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void scale1d_2t1_ps +( + const unsigned char *source, + int source_step, + unsigned int source_scale, + unsigned int source_length, + unsigned char *dest, + int dest_step, + unsigned int dest_scale, + unsigned int dest_length +) +{ + unsigned int i, j; + + (void) source_length; + (void) source_scale; + (void) dest_scale; + + source_step *= 2; + j = 0; + + for (i = 0; i < dest_length * dest_step; i += dest_step, j += source_step) + dest[i] = source[j]; +} +/**************************************************************************** + * + * ROUTINE : scale1d_c + * + * INPUTS : const unsigned char *source : Pointer to data to be scaled. + * int source_step : Number of pixels to step on in source. + * unsigned int source_scale : Scale for source. + * unsigned int source_length : Length of source (UNUSED). + * unsigned char *dest : Pointer to output data array. + * int dest_step : Number of pixels to step on in destination. + * unsigned int dest_scale : Scale for destination. + * unsigned int dest_length : Length of destination. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs linear interpolation in one dimension. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void scale1d_c +( + const unsigned char *source, + int source_step, + unsigned int source_scale, + unsigned int source_length, + unsigned char *dest, + int dest_step, + unsigned int dest_scale, + unsigned int dest_length +) +{ + unsigned int i; + unsigned int round_value = dest_scale / 2; + unsigned int left_modifier = dest_scale; + unsigned int right_modifier = 0; + unsigned char left_pixel = *source; + unsigned char right_pixel = *(source + source_step); + + (void) source_length; + + /* These asserts are needed if there are boundary issues... */ + /*assert ( dest_scale > source_scale );*/ + /*assert ( (source_length-1) * dest_scale >= (dest_length-1) * source_scale );*/ + + for (i = 0; i < dest_length * dest_step; i += dest_step) + { + dest[i] = (char)((left_modifier * left_pixel + right_modifier * right_pixel + round_value) / dest_scale); + + right_modifier += source_scale; + + while (right_modifier > dest_scale) + { + right_modifier -= dest_scale; + source += source_step; + left_pixel = *source; + right_pixel = *(source + source_step); + } + + left_modifier = dest_scale - right_modifier; + } +} + +/**************************************************************************** + * + * ROUTINE : Scale2D + * + * INPUTS : const unsigned char *source : Pointer to data to be scaled. + * int source_pitch : Stride of source image. + * unsigned int source_width : Width of input image. + * unsigned int source_height : Height of input image. + * unsigned char *dest : Pointer to output data array. + * int dest_pitch : Stride of destination image. + * unsigned int dest_width : Width of destination image. + * unsigned int dest_height : Height of destination image. + * unsigned char *temp_area : Pointer to temp work area. + * unsigned char temp_area_height : Height of temp work area. + * unsigned int hscale : Horizontal scale factor numerator. + * unsigned int hratio : Horizontal scale factor denominator. + * unsigned int vscale : Vertical scale factor numerator. + * unsigned int vratio : Vertical scale factor denominator. + * unsigned int interlaced : Interlace flag. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs 2-tap linear interpolation in two dimensions. + * + * SPECIAL NOTES : Expansion is performed one band at a time to help with + * caching. + * + ****************************************************************************/ +static +void Scale2D +( + /*const*/ + unsigned char *source, + int source_pitch, + unsigned int source_width, + unsigned int source_height, + unsigned char *dest, + int dest_pitch, + unsigned int dest_width, + unsigned int dest_height, + unsigned char *temp_area, + unsigned char temp_area_height, + unsigned int hscale, + unsigned int hratio, + unsigned int vscale, + unsigned int vratio, + unsigned int interlaced +) +{ + /*unsigned*/ + int i, j, k; + int bands; + int dest_band_height; + int source_band_height; + + typedef void (*Scale1D)(const unsigned char * source, int source_step, unsigned int source_scale, unsigned int source_length, + unsigned char * dest, int dest_step, unsigned int dest_scale, unsigned int dest_length); + + Scale1D Scale1Dv = scale1d_c; + Scale1D Scale1Dh = scale1d_c; + + void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *, unsigned int) = NULL; + void (*vert_band_scale)(unsigned char *, unsigned int, unsigned char *, unsigned int, unsigned int) = NULL; + + int ratio_scalable = 1; + int interpolation = 0; + + unsigned char *source_base; /* = (unsigned char *) ((source_pitch >= 0) ? source : (source + ((source_height-1) * source_pitch))); */ + unsigned char *line_src; + + + source_base = (unsigned char *)source; + + if (source_pitch < 0) + { + int offset; + + offset = (source_height - 1); + offset *= source_pitch; + + source_base += offset; + } + + /* find out the ratio for each direction */ + switch (hratio * 10 / hscale) + { + case 8: + /* 4-5 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_5_4_scale; + break; + case 6: + /* 3-5 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_5_3_scale; + break; + case 5: + /* 1-2 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_2_1_scale; + break; + default: + /* The ratio is not acceptable now */ + /* throw("The ratio is not acceptable for now!"); */ + ratio_scalable = 0; + break; + } + + switch (vratio * 10 / vscale) + { + case 8: + /* 4-5 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_5_4_scale; + source_band_height = 5; + dest_band_height = 4; + break; + case 6: + /* 3-5 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_5_3_scale; + source_band_height = 5; + dest_band_height = 3; + break; + case 5: + /* 1-2 Scale in vertical direction */ + + if (interlaced) + { + /* if the content is interlaced, point sampling is used */ + vert_band_scale = vp8_vertical_band_2_1_scale; + } + else + { + + interpolation = 1; + /* if the content is progressive, interplo */ + vert_band_scale = vp8_vertical_band_2_1_scale_i; + + } + + source_band_height = 2; + dest_band_height = 1; + break; + default: + /* The ratio is not acceptable now */ + /* throw("The ratio is not acceptable for now!"); */ + ratio_scalable = 0; + break; + } + + if (ratio_scalable) + { + if (source_height == dest_height) + { + /* for each band of the image */ + for (k = 0; k < (int)dest_height; k++) + { + horiz_line_scale(source, source_width, dest, dest_width); + source += source_pitch; + dest += dest_pitch; + } + + return; + } + + if (interpolation) + { + if (source < source_base) + source = source_base; + + horiz_line_scale(source, source_width, temp_area, dest_width); + } + + for (k = 0; k < (int)(dest_height + dest_band_height - 1) / dest_band_height; k++) + { + /* scale one band horizontally */ + for (i = 0; i < source_band_height; i++) + { + /* Trap case where we could read off the base of the source buffer */ + + line_src = (unsigned char *)source + i * source_pitch; + + if (line_src < source_base) + line_src = source_base; + + horiz_line_scale(line_src, source_width, + temp_area + (i + 1)*dest_pitch, dest_width); + } + + /* Vertical scaling is in place */ + vert_band_scale(temp_area + dest_pitch, dest_pitch, dest, dest_pitch, dest_width); + + if (interpolation) + vpx_memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_width); + + /* Next band... */ + source += (unsigned long) source_band_height * source_pitch; + dest += (unsigned long) dest_band_height * dest_pitch; + } + + return; + } + + if (hscale == 2 && hratio == 1) + Scale1Dh = scale1d_2t1_ps; + + if (vscale == 2 && vratio == 1) + { + if (interlaced) + Scale1Dv = scale1d_2t1_ps; + else + Scale1Dv = scale1d_2t1_i; + } + + if (source_height == dest_height) + { + /* for each band of the image */ + for (k = 0; k < (int)dest_height; k++) + { + Scale1Dh(source, 1, hscale, source_width + 1, dest, 1, hratio, dest_width); + source += source_pitch; + dest += dest_pitch; + } + + return; + } + + if (dest_height > source_height) + { + dest_band_height = temp_area_height - 1; + source_band_height = dest_band_height * source_height / dest_height; + } + else + { + source_band_height = temp_area_height - 1; + dest_band_height = source_band_height * vratio / vscale; + } + + /* first row needs to be done so that we can stay one row ahead for vertical zoom */ + Scale1Dh(source, 1, hscale, source_width + 1, temp_area, 1, hratio, dest_width); + + /* for each band of the image */ + bands = (dest_height + dest_band_height - 1) / dest_band_height; + + for (k = 0; k < bands; k++) + { + /* scale one band horizontally */ + for (i = 1; i < source_band_height + 1; i++) + { + if (k * source_band_height + i < (int) source_height) + { + Scale1Dh(source + i * source_pitch, 1, hscale, source_width + 1, + temp_area + i * dest_pitch, 1, hratio, dest_width); + } + else /* Duplicate the last row */ + { + /* copy temp_area row 0 over from last row in the past */ + duck_memcpy(temp_area + i * dest_pitch, temp_area + (i - 1)*dest_pitch, dest_pitch); + } + } + + /* scale one band vertically */ + for (j = 0; j < (int)dest_width; j++) + { + Scale1Dv(&temp_area[j], dest_pitch, vscale, source_band_height + 1, + &dest[j], dest_pitch, vratio, dest_band_height); + } + + /* copy temp_area row 0 over from last row in the past */ + duck_memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_pitch); + + /* move to the next band */ + source += source_band_height * source_pitch; + dest += dest_band_height * dest_pitch; + } +} + +/**************************************************************************** + * + * ROUTINE : + * + * INPUTS : YV12_BUFFER_CONFIG *src : Pointer to frame to be scaled. + * YV12_BUFFER_CONFIG *dst : Pointer to buffer to hold scaled frame. + * unsigned char *temp_area : Pointer to temp work area. + * unsigned char temp_area_height : Height of temp work area. + * unsigned int hscale : Horizontal scale factor numerator. + * unsigned int hratio : Horizontal scale factor denominator. + * unsigned int vscale : Vertical scale factor numerator. + * unsigned int vratio : Vertical scale factor denominator. + * unsigned int interlaced : Interlace flag. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs 2-tap linear interpolation in two dimensions. + * + * SPECIAL NOTES : Expansion is performed one band at a time to help with + * caching. + * + ****************************************************************************/ +void vp8_scale_frame +( + YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst, + unsigned char *temp_area, + unsigned char temp_height, + unsigned int hscale, + unsigned int hratio, + unsigned int vscale, + unsigned int vratio, + unsigned int interlaced +) +{ + int i; + int dw = (hscale - 1 + src->y_width * hratio) / hscale; + int dh = (vscale - 1 + src->y_height * vratio) / vscale; + + /* call our internal scaling routines!! */ + Scale2D((unsigned char *) src->y_buffer, src->y_stride, src->y_width, src->y_height, + (unsigned char *) dst->y_buffer, dst->y_stride, dw, dh, + temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced); + + if (dw < (int)dst->y_width) + for (i = 0; i < dh; i++) + duck_memset(dst->y_buffer + i * dst->y_stride + dw - 1, dst->y_buffer[i*dst->y_stride+dw-2], dst->y_width - dw + 1); + + if (dh < (int)dst->y_height) + for (i = dh - 1; i < (int)dst->y_height; i++) + duck_memcpy(dst->y_buffer + i * dst->y_stride, dst->y_buffer + (dh - 2) * dst->y_stride, dst->y_width + 1); + + Scale2D((unsigned char *) src->u_buffer, src->uv_stride, src->uv_width, src->uv_height, + (unsigned char *) dst->u_buffer, dst->uv_stride, dw / 2, dh / 2, + temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced); + + if (dw / 2 < (int)dst->uv_width) + for (i = 0; i < dst->uv_height; i++) + duck_memset(dst->u_buffer + i * dst->uv_stride + dw / 2 - 1, dst->u_buffer[i*dst->uv_stride+dw/2-2], dst->uv_width - dw / 2 + 1); + + if (dh / 2 < (int)dst->uv_height) + for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++) + duck_memcpy(dst->u_buffer + i * dst->uv_stride, dst->u_buffer + (dh / 2 - 2)*dst->uv_stride, dst->uv_width); + + Scale2D((unsigned char *) src->v_buffer, src->uv_stride, src->uv_width, src->uv_height, + (unsigned char *) dst->v_buffer, dst->uv_stride, dw / 2, dh / 2, + temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced); + + if (dw / 2 < (int)dst->uv_width) + for (i = 0; i < dst->uv_height; i++) + duck_memset(dst->v_buffer + i * dst->uv_stride + dw / 2 - 1, dst->v_buffer[i*dst->uv_stride+dw/2-2], dst->uv_width - dw / 2 + 1); + + if (dh / 2 < (int) dst->uv_height) + for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++) + duck_memcpy(dst->v_buffer + i * dst->uv_stride, dst->v_buffer + (dh / 2 - 2)*dst->uv_stride, dst->uv_width); +} +/**************************************************************************** + * + * ROUTINE : any_ratio_2d_scale + * + * INPUTS : SCALE_INSTANCE *si : Pointer to post-processor instance (NOT USED). + * const unsigned char *source : Pointer to source image. + * unsigned int source_pitch : Stride of source image. + * unsigned int source_width : Width of source image. + * unsigned int source_height : Height of source image (NOT USED). + * unsigned char *dest : Pointer to destination image. + * unsigned int dest_pitch : Stride of destination image. + * unsigned int dest_width : Width of destination image. + * unsigned int dest_height : Height of destination image. + * + * OUTPUTS : None. + * + * RETURNS : int: 1 if image scaled, 0 if image could not be scaled. + * + * FUNCTION : Scale the image with changing apect ratio. + * + * SPECIAL NOTES : This scaling is a bi-linear scaling. Need to re-work the + * whole function for new scaling algorithm. + * + ****************************************************************************/ +static +int any_ratio_2d_scale +( + SCALE_VARS *si, + const unsigned char *source, + int source_pitch, + unsigned int source_width, + unsigned int source_height, + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width, + unsigned int dest_height +) +{ + unsigned int i, k; + unsigned int src_band_height = 0; + unsigned int dest_band_height = 0; + + /* suggested scale factors */ + int hs = si->HScale; + int hr = si->HRatio; + int vs = si->VScale; + int vr = si->VRatio; + + /* assume the ratios are scalable instead of should be centered */ + int ratio_scalable = 1; + + const unsigned char *source_base = ((source_pitch >= 0) ? source : (source + ((source_height - 1) * source_pitch))); + const unsigned char *line_src; + + void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *, unsigned int) = NULL; + void (*vert_band_scale)(unsigned char *, unsigned int, unsigned int) = NULL; + void (*last_vert_band_scale)(unsigned char *, unsigned int, unsigned int) = NULL; + + (void) si; + + /* find out the ratio for each direction */ + switch (hr * 30 / hs) + { + case 24: + /* 4-5 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_4_5_scale; + break; + case 22: + /* 3-4 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_3_4_scale; + break; + + case 20: + /* 4-5 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_2_3_scale; + break; + case 18: + /* 3-5 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_3_5_scale; + break; + case 15: + /* 1-2 Scale in Width direction */ + horiz_line_scale = vp8_horizontal_line_1_2_scale; + break; + case 30: + /* no scale in Width direction */ + horiz_line_scale = horizontal_line_copy; + break; + default: + /* The ratio is not acceptable now */ + /* throw("The ratio is not acceptable for now!"); */ + ratio_scalable = 0; + break; + } + + switch (vr * 30 / vs) + { + case 24: + /* 4-5 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_4_5_scale; + last_vert_band_scale = vp8_last_vertical_band_4_5_scale; + src_band_height = 4; + dest_band_height = 5; + break; + case 22: + /* 3-4 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_3_4_scale; + last_vert_band_scale = vp8_last_vertical_band_3_4_scale; + src_band_height = 3; + dest_band_height = 4; + break; + case 20: + /* 2-3 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_2_3_scale; + last_vert_band_scale = vp8_last_vertical_band_2_3_scale; + src_band_height = 2; + dest_band_height = 3; + break; + case 18: + /* 3-5 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_3_5_scale; + last_vert_band_scale = vp8_last_vertical_band_3_5_scale; + src_band_height = 3; + dest_band_height = 5; + break; + case 15: + /* 1-2 Scale in vertical direction */ + vert_band_scale = vp8_vertical_band_1_2_scale; + last_vert_band_scale = vp8_last_vertical_band_1_2_scale; + src_band_height = 1; + dest_band_height = 2; + break; + case 30: + /* no scale in Width direction */ + vert_band_scale = null_scale; + last_vert_band_scale = null_scale; + src_band_height = 4; + dest_band_height = 4; + break; + default: + /* The ratio is not acceptable now */ + /* throw("The ratio is not acceptable for now!"); */ + ratio_scalable = 0; + break; + } + + if (ratio_scalable == 0) + return ratio_scalable; + + horiz_line_scale(source, source_width, dest, dest_width); + + /* except last band */ + for (k = 0; k < (dest_height + dest_band_height - 1) / dest_band_height - 1; k++) + { + /* scale one band horizontally */ + for (i = 1; i < src_band_height; i++) + { + /* Trap case where we could read off the base of the source buffer */ + line_src = source + i * source_pitch; + + if (line_src < source_base) + line_src = source_base; + + horiz_line_scale(line_src, source_width, + dest + i * dest_pitch, dest_width); + } + + /* first line of next band */ + /* Trap case where we could read off the base of the source buffer */ + line_src = source + src_band_height * source_pitch; + + if (line_src < source_base) + line_src = source_base; + + horiz_line_scale(line_src, source_width, + dest + dest_band_height * dest_pitch, + dest_width); + + /* Vertical scaling is in place */ + vert_band_scale(dest, dest_pitch, dest_width); + + /* Next band... */ + source += src_band_height * source_pitch; + dest += dest_band_height * dest_pitch; + } + + /* scale one band horizontally */ + for (i = 1; i < src_band_height; i++) + { + /* Trap case where we could read off the base of the source buffer */ + line_src = source + i * source_pitch; + + if (line_src < source_base) + line_src = source_base; + + horiz_line_scale(line_src, source_width, + dest + i * dest_pitch, + dest_width); + } + + /* Vertical scaling is in place */ + last_vert_band_scale(dest, dest_pitch, dest_width); + + return ratio_scalable; +} + +/**************************************************************************** + * + * ROUTINE : any_ratio_frame_scale + * + * INPUTS : SCALE_INSTANCE *si : Pointer to post-processor instance (NOT USED). + * unsigned char *frame_buffer : Pointer to source image. + * int YOffset : Offset from start of buffer to Y samples. + * int UVOffset : Offset from start of buffer to UV samples. + * + * OUTPUTS : None. + * + * RETURNS : int: 1 if image scaled, 0 if image could not be scaled. + * + * FUNCTION : Scale the image with changing apect ratio. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +int any_ratio_frame_scale(SCALE_VARS *scale_vars, int YOffset, int UVOffset) +{ + int i; + int ew; + int eh; + + /* suggested scale factors */ + int hs = scale_vars->HScale; + int hr = scale_vars->HRatio; + int vs = scale_vars->VScale; + int vr = scale_vars->VRatio; + + int ratio_scalable = 1; + + int sw = (scale_vars->expanded_frame_width * hr + hs - 1) / hs; + int sh = (scale_vars->expanded_frame_height * vr + vs - 1) / vs; + int dw = scale_vars->expanded_frame_width; + int dh = scale_vars->expanded_frame_height; + YV12_BUFFER_CONFIG *src_yuv_config = scale_vars->src_yuv_config; + YV12_BUFFER_CONFIG *dst_yuv_config = scale_vars->dst_yuv_config; + + if (hr == 3) + ew = (sw + 2) / 3 * 3 * hs / hr; + else + ew = (sw + 7) / 8 * 8 * hs / hr; + + if (vr == 3) + eh = (sh + 2) / 3 * 3 * vs / vr; + else + eh = (sh + 7) / 8 * 8 * vs / vr; + + ratio_scalable = any_ratio_2d_scale(scale_vars, + (const unsigned char *)src_yuv_config->y_buffer, + src_yuv_config->y_stride, sw, sh, + (unsigned char *) dst_yuv_config->y_buffer + YOffset, + dst_yuv_config->y_stride, dw, dh); + + for (i = 0; i < eh; i++) + duck_memset(dst_yuv_config->y_buffer + YOffset + i * dst_yuv_config->y_stride + dw, 0, ew - dw); + + for (i = dh; i < eh; i++) + duck_memset(dst_yuv_config->y_buffer + YOffset + i * dst_yuv_config->y_stride, 0, ew); + + if (ratio_scalable == 0) + return ratio_scalable; + + sw = (sw + 1) >> 1; + sh = (sh + 1) >> 1; + dw = (dw + 1) >> 1; + dh = (dh + 1) >> 1; + + any_ratio_2d_scale(scale_vars, + (const unsigned char *)src_yuv_config->u_buffer, + src_yuv_config->y_stride / 2, sw, sh, + (unsigned char *)dst_yuv_config->u_buffer + UVOffset, + dst_yuv_config->uv_stride, dw, dh); + + any_ratio_2d_scale(scale_vars, + (const unsigned char *)src_yuv_config->v_buffer, + src_yuv_config->y_stride / 2, sw, sh, + (unsigned char *)dst_yuv_config->v_buffer + UVOffset, + dst_yuv_config->uv_stride, dw, dh); + + return ratio_scalable; +} + +/**************************************************************************** + * + * ROUTINE : center_image + * + * INPUTS : SCALE_INSTANCE *si : Pointer to post-processor instance. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Centers the image without scaling in the output buffer. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static void +center_image(YV12_BUFFER_CONFIG *src_yuv_config, YV12_BUFFER_CONFIG *dst_yuv_config) +{ + int i; + int row_offset, col_offset; + unsigned char *src_data_pointer; + unsigned char *dst_data_pointer; + + /* center values */ + row_offset = (dst_yuv_config->y_height - src_yuv_config->y_height) / 2; + col_offset = (dst_yuv_config->y_width - src_yuv_config->y_width) / 2; + + /* Y's */ + src_data_pointer = src_yuv_config->y_buffer; + dst_data_pointer = (unsigned char *)dst_yuv_config->y_buffer + (row_offset * dst_yuv_config->y_stride) + col_offset; + + for (i = 0; i < src_yuv_config->y_height; i++) + { + duck_memcpy(dst_data_pointer, src_data_pointer, src_yuv_config->y_width); + dst_data_pointer += dst_yuv_config->y_stride; + src_data_pointer += src_yuv_config->y_stride; + } + + row_offset /= 2; + col_offset /= 2; + + /* U's */ + src_data_pointer = src_yuv_config->u_buffer; + dst_data_pointer = (unsigned char *)dst_yuv_config->u_buffer + (row_offset * dst_yuv_config->uv_stride) + col_offset; + + for (i = 0; i < src_yuv_config->uv_height; i++) + { + duck_memcpy(dst_data_pointer, src_data_pointer, src_yuv_config->uv_width); + dst_data_pointer += dst_yuv_config->uv_stride; + src_data_pointer += src_yuv_config->uv_stride; + } + + /* V's */ + src_data_pointer = src_yuv_config->v_buffer; + dst_data_pointer = (unsigned char *)dst_yuv_config->v_buffer + (row_offset * dst_yuv_config->uv_stride) + col_offset; + + for (i = 0; i < src_yuv_config->uv_height; i++) + { + duck_memcpy(dst_data_pointer, src_data_pointer, src_yuv_config->uv_width); + dst_data_pointer += dst_yuv_config->uv_stride; + src_data_pointer += src_yuv_config->uv_stride; + } +} + +/**************************************************************************** + * + * ROUTINE : scale_or_center + * + * INPUTS : SCALE_INSTANCE *si : Pointer to post-processor instance. + * + * + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Decides to scale or center image in scale buffer for blit + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void +vp8_yv12_scale_or_center +( + YV12_BUFFER_CONFIG *src_yuv_config, + YV12_BUFFER_CONFIG *dst_yuv_config, + int expanded_frame_width, + int expanded_frame_height, + int scaling_mode, + int HScale, + int HRatio, + int VScale, + int VRatio +) +{ + /*if ( ppi->post_processing_level ) + update_umvborder ( ppi, frame_buffer );*/ + + + switch (scaling_mode) + { + case SCALE_TO_FIT: + case MAINTAIN_ASPECT_RATIO: + { + SCALE_VARS scale_vars; + /* center values */ +#if 1 + int row = (dst_yuv_config->y_height - expanded_frame_height) / 2; + int col = (dst_yuv_config->y_width - expanded_frame_width) / 2; + /*int YOffset = row * dst_yuv_config->y_width + col; + int UVOffset = (row>>1) * dst_yuv_config->uv_width + (col>>1);*/ + int YOffset = row * dst_yuv_config->y_stride + col; + int UVOffset = (row >> 1) * dst_yuv_config->uv_stride + (col >> 1); +#else + int row = (src_yuv_config->y_height - expanded_frame_height) / 2; + int col = (src_yuv_config->y_width - expanded_frame_width) / 2; + int YOffset = row * src_yuv_config->y_width + col; + int UVOffset = (row >> 1) * src_yuv_config->uv_width + (col >> 1); +#endif + + scale_vars.dst_yuv_config = dst_yuv_config; + scale_vars.src_yuv_config = src_yuv_config; + scale_vars.HScale = HScale; + scale_vars.HRatio = HRatio; + scale_vars.VScale = VScale; + scale_vars.VRatio = VRatio; + scale_vars.expanded_frame_width = expanded_frame_width; + scale_vars.expanded_frame_height = expanded_frame_height; + + /* perform center and scale */ + any_ratio_frame_scale(&scale_vars, YOffset, UVOffset); + + break; + } + case CENTER: + center_image(src_yuv_config, dst_yuv_config); + break; + + default: + break; + } +} diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c new file mode 100644 index 0000000..eff594e --- /dev/null +++ b/vpx_scale/generic/yv12config.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +#include "vpx_mem/vpx_mem.h" + +/**************************************************************************** +* Exports +****************************************************************************/ + +/**************************************************************************** + * + ****************************************************************************/ +int +vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) +{ + if (ybf) + { + vpx_free(ybf->buffer_alloc); + + /* buffer_alloc isn't accessed by most functions. Rather y_buffer, + u_buffer and v_buffer point to buffer_alloc and are used. Clear out + all of this so that a freed pointer isn't inadvertently used */ + vpx_memset (ybf, 0, sizeof (YV12_BUFFER_CONFIG)); + } + else + { + return -1; + } + + return 0; +} + +/**************************************************************************** + * + ****************************************************************************/ +int +vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border) +{ +/*NOTE:*/ + + if (ybf) + { + int y_stride = ((width + 2 * border) + 31) & ~31; + int yplane_size = (height + 2 * border) * y_stride; + int uv_width = width >> 1; + int uv_height = height >> 1; + /** There is currently a bunch of code which assumes + * uv_stride == y_stride/2, so enforce this here. */ + int uv_stride = y_stride >> 1; + int uvplane_size = (uv_height + border) * uv_stride; + + vp8_yv12_de_alloc_frame_buffer(ybf); + + /** Only support allocating buffers that have a height and width that + * are multiples of 16, and a border that's a multiple of 32. + * The border restriction is required to get 16-byte alignment of the + * start of the chroma rows without intoducing an arbitrary gap + * between planes, which would break the semantics of things like + * vpx_img_set_rect(). */ + if ((width & 0xf) | (height & 0xf) | (border & 0x1f)) + return -3; + + ybf->y_width = width; + ybf->y_height = height; + ybf->y_stride = y_stride; + + ybf->uv_width = uv_width; + ybf->uv_height = uv_height; + ybf->uv_stride = uv_stride; + + ybf->border = border; + ybf->frame_size = yplane_size + 2 * uvplane_size; + + ybf->buffer_alloc = (unsigned char *) vpx_memalign(32, ybf->frame_size); + + if (ybf->buffer_alloc == NULL) + return -1; + + ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; + ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2 * uv_stride) + border / 2; + ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2 * uv_stride) + border / 2; + + ybf->corrupted = 0; /* assume not currupted by errors */ + } + else + { + return -2; + } + + return 0; +} diff --git a/vpx_scale/generic/yv12extend.c b/vpx_scale/generic/yv12extend.c new file mode 100644 index 0000000..638633b --- /dev/null +++ b/vpx_scale/generic/yv12extend.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_scale/vpxscale.h" + +/**************************************************************************** +* Exports +****************************************************************************/ + +/**************************************************************************** + * + ****************************************************************************/ +void +vp8_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf) +{ + int i; + unsigned char *src_ptr1, *src_ptr2; + unsigned char *dest_ptr1, *dest_ptr2; + + unsigned int Border; + int plane_stride; + int plane_height; + int plane_width; + + /***********/ + /* Y Plane */ + /***********/ + Border = ybf->border; + plane_stride = ybf->y_stride; + plane_height = ybf->y_height; + plane_width = ybf->y_width; + + /* copy the left and right most columns out */ + src_ptr1 = ybf->y_buffer; + src_ptr2 = src_ptr1 + plane_width - 1; + dest_ptr1 = src_ptr1 - Border; + dest_ptr2 = src_ptr2 + 1; + + for (i = 0; i < plane_height; i++) + { + vpx_memset(dest_ptr1, src_ptr1[0], Border); + vpx_memset(dest_ptr2, src_ptr2[0], Border); + src_ptr1 += plane_stride; + src_ptr2 += plane_stride; + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + /* Now copy the top and bottom source lines into each line of the respective borders */ + src_ptr1 = ybf->y_buffer - Border; + src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride; + dest_ptr1 = src_ptr1 - (Border * plane_stride); + dest_ptr2 = src_ptr2 + plane_stride; + + for (i = 0; i < (int)Border; i++) + { + vpx_memcpy(dest_ptr1, src_ptr1, plane_stride); + vpx_memcpy(dest_ptr2, src_ptr2, plane_stride); + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + + /***********/ + /* U Plane */ + /***********/ + plane_stride = ybf->uv_stride; + plane_height = ybf->uv_height; + plane_width = ybf->uv_width; + Border /= 2; + + /* copy the left and right most columns out */ + src_ptr1 = ybf->u_buffer; + src_ptr2 = src_ptr1 + plane_width - 1; + dest_ptr1 = src_ptr1 - Border; + dest_ptr2 = src_ptr2 + 1; + + for (i = 0; i < plane_height; i++) + { + vpx_memset(dest_ptr1, src_ptr1[0], Border); + vpx_memset(dest_ptr2, src_ptr2[0], Border); + src_ptr1 += plane_stride; + src_ptr2 += plane_stride; + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + /* Now copy the top and bottom source lines into each line of the respective borders */ + src_ptr1 = ybf->u_buffer - Border; + src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride; + dest_ptr1 = src_ptr1 - (Border * plane_stride); + dest_ptr2 = src_ptr2 + plane_stride; + + for (i = 0; i < (int)(Border); i++) + { + vpx_memcpy(dest_ptr1, src_ptr1, plane_stride); + vpx_memcpy(dest_ptr2, src_ptr2, plane_stride); + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + /***********/ + /* V Plane */ + /***********/ + + /* copy the left and right most columns out */ + src_ptr1 = ybf->v_buffer; + src_ptr2 = src_ptr1 + plane_width - 1; + dest_ptr1 = src_ptr1 - Border; + dest_ptr2 = src_ptr2 + 1; + + for (i = 0; i < plane_height; i++) + { + vpx_memset(dest_ptr1, src_ptr1[0], Border); + vpx_memset(dest_ptr2, src_ptr2[0], Border); + src_ptr1 += plane_stride; + src_ptr2 += plane_stride; + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + /* Now copy the top and bottom source lines into each line of the respective borders */ + src_ptr1 = ybf->v_buffer - Border; + src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride; + dest_ptr1 = src_ptr1 - (Border * plane_stride); + dest_ptr2 = src_ptr2 + plane_stride; + + for (i = 0; i < (int)(Border); i++) + { + vpx_memcpy(dest_ptr1, src_ptr1, plane_stride); + vpx_memcpy(dest_ptr2, src_ptr2, plane_stride); + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } +} + + +static void +extend_frame_borders_yonly_c(YV12_BUFFER_CONFIG *ybf) +{ + int i; + unsigned char *src_ptr1, *src_ptr2; + unsigned char *dest_ptr1, *dest_ptr2; + + unsigned int Border; + int plane_stride; + int plane_height; + int plane_width; + + /***********/ + /* Y Plane */ + /***********/ + Border = ybf->border; + plane_stride = ybf->y_stride; + plane_height = ybf->y_height; + plane_width = ybf->y_width; + + /* copy the left and right most columns out */ + src_ptr1 = ybf->y_buffer; + src_ptr2 = src_ptr1 + plane_width - 1; + dest_ptr1 = src_ptr1 - Border; + dest_ptr2 = src_ptr2 + 1; + + for (i = 0; i < plane_height; i++) + { + vpx_memset(dest_ptr1, src_ptr1[0], Border); + vpx_memset(dest_ptr2, src_ptr2[0], Border); + src_ptr1 += plane_stride; + src_ptr2 += plane_stride; + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + /* Now copy the top and bottom source lines into each line of the respective borders */ + src_ptr1 = ybf->y_buffer - Border; + src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride; + dest_ptr1 = src_ptr1 - (Border * plane_stride); + dest_ptr2 = src_ptr2 + plane_stride; + + for (i = 0; i < (int)Border; i++) + { + vpx_memcpy(dest_ptr1, src_ptr1, plane_stride); + vpx_memcpy(dest_ptr2, src_ptr2, plane_stride); + dest_ptr1 += plane_stride; + dest_ptr2 += plane_stride; + } + + plane_stride /= 2; + plane_height /= 2; + plane_width /= 2; + Border /= 2; + +} + + + +/**************************************************************************** + * + * ROUTINE : vp8_yv12_copy_frame + * + * INPUTS : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies the source image into the destination image and + * updates the destination's UMV borders. + * + * SPECIAL NOTES : The frames are assumed to be identical in size. + * + ****************************************************************************/ +void +vp8_yv12_copy_frame_c(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc) +{ + int row; + unsigned char *source, *dest; + + source = src_ybc->y_buffer; + dest = dst_ybc->y_buffer; + + for (row = 0; row < src_ybc->y_height; row++) + { + vpx_memcpy(dest, source, src_ybc->y_width); + source += src_ybc->y_stride; + dest += dst_ybc->y_stride; + } + + source = src_ybc->u_buffer; + dest = dst_ybc->u_buffer; + + for (row = 0; row < src_ybc->uv_height; row++) + { + vpx_memcpy(dest, source, src_ybc->uv_width); + source += src_ybc->uv_stride; + dest += dst_ybc->uv_stride; + } + + source = src_ybc->v_buffer; + dest = dst_ybc->v_buffer; + + for (row = 0; row < src_ybc->uv_height; row++) + { + vpx_memcpy(dest, source, src_ybc->uv_width); + source += src_ybc->uv_stride; + dest += dst_ybc->uv_stride; + } + + vp8_yv12_extend_frame_borders_c(dst_ybc); +} + +void vp8_yv12_copy_y_c(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc) +{ + int row; + unsigned char *source, *dest; + + + source = src_ybc->y_buffer; + dest = dst_ybc->y_buffer; + + for (row = 0; row < src_ybc->y_height; row++) + { + vpx_memcpy(dest, source, src_ybc->y_width); + source += src_ybc->y_stride; + dest += dst_ybc->y_stride; + } +} diff --git a/vpx_scale/generic/yv12extend_generic.h b/vpx_scale/generic/yv12extend_generic.h new file mode 100644 index 0000000..cc2a554 --- /dev/null +++ b/vpx_scale/generic/yv12extend_generic.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef YV12_EXTEND_GENERIC_H +#define YV12_EXTEND_GENERIC_H + +#include "vpx_scale/yv12config.h" + + void vp8_yv12_extend_frame_borders(YV12_BUFFER_CONFIG *ybf); + + /* Copy Y,U,V buffer data from src to dst, filling border of dst as well. */ + void vp8_yv12_copy_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); + + /* Copy Y buffer data from src_ybc to dst_ybc without filling border data */ + void vp8_yv12_copy_y_c(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); + +#endif /* YV12_EXTEND_GENERIC_H */ diff --git a/vpx_scale/include/generic/vpxscale_arbitrary.h b/vpx_scale/include/generic/vpxscale_arbitrary.h new file mode 100644 index 0000000..39de181 --- /dev/null +++ b/vpx_scale/include/generic/vpxscale_arbitrary.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef __VPX_SCALE_ARBITRARY_H__ +#define __VPX_SCALE_ARBITRARY_H__ + +#include "vpx_scale/yv12config.h" + +typedef struct +{ + int in_width; + int in_height; + + int out_width; + int out_height; + int max_usable_out_width; + + // numerator for the width and height + int nw; + int nh; + int nh_uv; + + // output to input correspondance array + short *l_w; + short *l_h; + short *l_h_uv; + + // polyphase coefficients + short *c_w; + short *c_h; + short *c_h_uv; + + // buffer for horizontal filtering. + unsigned char *hbuf; + unsigned char *hbuf_uv; +} BICUBIC_SCALER_STRUCT; + +int bicubic_coefficient_setup(int in_width, int in_height, int out_width, int out_height); +int bicubic_scale(int in_width, int in_height, int in_stride, + int out_width, int out_height, int out_stride, + unsigned char *input_image, unsigned char *output_image); +void bicubic_scale_frame_reset(); +void bicubic_scale_frame(YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst, + int new_width, int new_height); +void bicubic_coefficient_init(); +void bicubic_coefficient_destroy(); + +#endif /* __VPX_SCALE_ARBITRARY_H__ */ diff --git a/vpx_scale/include/generic/vpxscale_depricated.h b/vpx_scale/include/generic/vpxscale_depricated.h new file mode 100644 index 0000000..3f7fe0f --- /dev/null +++ b/vpx_scale/include/generic/vpxscale_depricated.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : postp.h +* +* Description : Post processor interface +* +****************************************************************************/ +#ifndef VPXSCALE_H +#define VPXSCALE_H + +extern void (*vp8_vertical_band_4_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width); +extern void (*vp8_last_vertical_band_4_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width); +extern void (*vp8_vertical_band_3_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width); +extern void (*vp8_last_vertical_band_3_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width); +extern void (*vp8_horizontal_line_1_2_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width); +extern void (*vp8_horizontal_line_3_5_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width); +extern void (*vp8_horizontal_line_4_5_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width); +extern void (*vp8_vertical_band_1_2_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width); +extern void (*vp8_last_vertical_band_1_2_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width); + +extern void dmachine_specific_config(int mmx_enabled, int xmm_enabled, int wmt_enabled); + +#endif diff --git a/vpx_scale/scale_mode.h b/vpx_scale/scale_mode.h new file mode 100644 index 0000000..1476e64 --- /dev/null +++ b/vpx_scale/scale_mode.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** +* +***************************************************************************** +*/ + +#ifndef SCALE_MODE_H +#define SCALE_MODE_H + +typedef enum +{ + MAINTAIN_ASPECT_RATIO = 0x0, + SCALE_TO_FIT = 0x1, + CENTER = 0x2, + OTHER = 0x3 +} SCALE_MODE; + + +#endif diff --git a/vpx_scale/vpx_scale.mk b/vpx_scale/vpx_scale.mk new file mode 100644 index 0000000..dc89478 --- /dev/null +++ b/vpx_scale/vpx_scale.mk @@ -0,0 +1,18 @@ +SCALE_SRCS-yes += vpx_scale.mk +SCALE_SRCS-yes += scale_mode.h +SCALE_SRCS-yes += yv12config.h +SCALE_SRCS-yes += vpxscale.h +SCALE_SRCS-yes += generic/vpxscale.c +SCALE_SRCS-yes += generic/yv12config.c +SCALE_SRCS-yes += generic/yv12extend.c +SCALE_SRCS-yes += generic/yv12extend_generic.h +SCALE_SRCS-$(CONFIG_SPATIAL_RESAMPLING) += generic/gen_scalers.c + +#neon +SCALE_SRCS-$(HAVE_NEON) += arm/neon/vp8_vpxyv12_copyframe_func_neon$(ASM) +SCALE_SRCS-$(HAVE_NEON) += arm/neon/vp8_vpxyv12_copy_y_neon$(ASM) +SCALE_SRCS-$(HAVE_NEON) += arm/neon/vp8_vpxyv12_copysrcframe_func_neon$(ASM) +SCALE_SRCS-$(HAVE_NEON) += arm/neon/vp8_vpxyv12_extendframeborders_neon$(ASM) +SCALE_SRCS-$(HAVE_NEON) += arm/neon/yv12extend_arm.c + +SCALE_SRCS-no += $(SCALE_SRCS_REMOVE-yes) diff --git a/vpx_scale/vpxscale.h b/vpx_scale/vpxscale.h new file mode 100644 index 0000000..8919a24 --- /dev/null +++ b/vpx_scale/vpxscale.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPXSCALE_H +#define VPXSCALE_H + +#include "vpx_scale/yv12config.h" + +extern void vp8_yv12_scale_or_center +( + YV12_BUFFER_CONFIG *src_yuv_config, + YV12_BUFFER_CONFIG *dst_yuv_config, + int expanded_frame_width, + int expanded_frame_height, + int scaling_mode, + int HScale, + int HRatio, + int VScale, + int VRatio +); +extern void vp8_scale_frame +( + YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst, + unsigned char *temp_area, + unsigned char temp_height, + unsigned int hscale, + unsigned int hratio, + unsigned int vscale, + unsigned int vratio, + unsigned int interlaced +); + +#endif diff --git a/vpx_scale/win32/scaleopt.c b/vpx_scale/win32/scaleopt.c new file mode 100644 index 0000000..3711fe5 --- /dev/null +++ b/vpx_scale/win32/scaleopt.c @@ -0,0 +1,1750 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : scaleopt.cpp +* +* Description : Optimized scaling functions +* +****************************************************************************/ +#include "pragmas.h" + + + +/**************************************************************************** +* Module Statics +****************************************************************************/ +__declspec(align(16)) const static unsigned short one_fifth[] = { 51, 51, 51, 51 }; +__declspec(align(16)) const static unsigned short two_fifths[] = { 102, 102, 102, 102 }; +__declspec(align(16)) const static unsigned short three_fifths[] = { 154, 154, 154, 154 }; +__declspec(align(16)) const static unsigned short four_fifths[] = { 205, 205, 205, 205 }; +__declspec(align(16)) const static unsigned short round_values[] = { 128, 128, 128, 128 }; +__declspec(align(16)) const static unsigned short four_ones[] = { 1, 1, 1, 1}; +__declspec(align(16)) const static unsigned short const45_2[] = {205, 154, 102, 51 }; +__declspec(align(16)) const static unsigned short const45_1[] = { 51, 102, 154, 205 }; +__declspec(align(16)) const static unsigned char mask45[] = { 0, 0, 0, 0, 0, 0, 255, 0}; +__declspec(align(16)) const static unsigned short const35_2[] = { 154, 51, 205, 102 }; +__declspec(align(16)) const static unsigned short const35_1[] = { 102, 205, 51, 154 }; + + + +#include "vpx_scale/vpxscale.h" +#include "vpx_mem/vpx_mem.h" + +/**************************************************************************** + * + * ROUTINE : horizontal_line_3_5_scale_mmx + * + * INPUTS : const unsigned char *source : + * unsigned int source_width : + * unsigned char *dest : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 3 to 5 up-scaling of a horizontal line of pixels. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void horizontal_line_3_5_scale_mmx +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + (void) dest_width; + + __asm + { + + push ebx + + mov esi, source + mov edi, dest + + mov ecx, source_width + lea edx, [esi+ecx-3]; + + movq mm5, const35_1 // mm5 = 66 xx cd xx 33 xx 9a xx + movq mm6, const35_2 // mm6 = 9a xx 33 xx cd xx 66 xx + + movq mm4, round_values // mm4 = 80 xx 80 xx 80 xx 80 xx + pxor mm7, mm7 // clear mm7 + + horiz_line_3_5_loop: + + mov eax, DWORD PTR [esi] // eax = 00 01 02 03 + mov ebx, eax + + and ebx, 0xffff00 // ebx = xx 01 02 xx + mov ecx, eax // ecx = 00 01 02 03 + + and eax, 0xffff0000 // eax = xx xx 02 03 + xor ecx, eax // ecx = 00 01 xx xx + + shr ebx, 8 // ebx = 01 02 xx xx + or eax, ebx // eax = 01 02 02 03 + + shl ebx, 16 // ebx = xx xx 01 02 + movd mm1, eax // mm1 = 01 02 02 03 xx xx xx xx + + or ebx, ecx // ebx = 00 01 01 02 + punpcklbw mm1, mm7 // mm1 = 01 xx 02 xx 02 xx 03 xx + + movd mm0, ebx // mm0 = 00 01 01 02 + pmullw mm1, mm6 // + + punpcklbw mm0, mm7 // mm0 = 00 xx 01 xx 01 xx 02 xx + pmullw mm0, mm5 // + + mov [edi], ebx // writeoutput 00 xx xx xx + add esi, 3 + + add edi, 5 + paddw mm0, mm1 + + paddw mm0, mm4 + psrlw mm0, 8 + + cmp esi, edx + packuswb mm0, mm7 + + movd DWORD Ptr [edi-4], mm0 + jl horiz_line_3_5_loop + +//Exit: + mov eax, DWORD PTR [esi] // eax = 00 01 02 03 + mov ebx, eax + + and ebx, 0xffff00 // ebx = xx 01 02 xx + mov ecx, eax // ecx = 00 01 02 03 + + and eax, 0xffff0000 // eax = xx xx 02 03 + xor ecx, eax // ecx = 00 01 xx xx + + shr ebx, 8 // ebx = 01 02 xx xx + or eax, ebx // eax = 01 02 02 03 + + shl eax, 8 // eax = xx 01 02 02 + and eax, 0xffff0000 // eax = xx xx 02 02 + + or eax, ebx // eax = 01 02 02 02 + + shl ebx, 16 // ebx = xx xx 01 02 + movd mm1, eax // mm1 = 01 02 02 02 xx xx xx xx + + or ebx, ecx // ebx = 00 01 01 02 + punpcklbw mm1, mm7 // mm1 = 01 xx 02 xx 02 xx 02 xx + + movd mm0, ebx // mm0 = 00 01 01 02 + pmullw mm1, mm6 // + + punpcklbw mm0, mm7 // mm0 = 00 xx 01 xx 01 xx 02 xx + pmullw mm0, mm5 // + + mov [edi], ebx // writeoutput 00 xx xx xx + paddw mm0, mm1 + + paddw mm0, mm4 + psrlw mm0, 8 + + packuswb mm0, mm7 + movd DWORD Ptr [edi+1], mm0 + + pop ebx + + } + +} + + +/**************************************************************************** + * + * ROUTINE : horizontal_line_4_5_scale_mmx + * + * INPUTS : const unsigned char *source : + * unsigned int source_width : + * unsigned char *dest : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 4 to 5 up-scaling of a horizontal line of pixels. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void horizontal_line_4_5_scale_mmx +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + (void)dest_width; + + __asm + { + + mov esi, source + mov edi, dest + + mov ecx, source_width + lea edx, [esi+ecx-8]; + + movq mm5, const45_1 // mm5 = 33 xx 66 xx 9a xx cd xx + movq mm6, const45_2 // mm6 = cd xx 9a xx 66 xx 33 xx + + movq mm4, round_values // mm4 = 80 xx 80 xx 80 xx 80 xx + pxor mm7, mm7 // clear mm7 + + horiz_line_4_5_loop: + + movq mm0, QWORD PTR [esi] // mm0 = 00 01 02 03 04 05 06 07 + movq mm1, QWORD PTR [esi+1]; // mm1 = 01 02 03 04 05 06 07 08 + + movq mm2, mm0 // mm2 = 00 01 02 03 04 05 06 07 + movq mm3, mm1 // mm3 = 01 02 03 04 05 06 07 08 + + movd DWORD PTR [edi], mm0 // write output 00 xx xx xx + punpcklbw mm0, mm7 // mm0 = 00 xx 01 xx 02 xx 03 xx + + punpcklbw mm1, mm7 // mm1 = 01 xx 02 xx 03 xx 04 xx + pmullw mm0, mm5 // 00* 51 01*102 02*154 03*205 + + pmullw mm1, mm6 // 01*205 02*154 03*102 04* 51 + punpckhbw mm2, mm7 // mm2 = 04 xx 05 xx 06 xx 07 xx + + movd DWORD PTR [edi+5], mm2 // write ouput 05 xx xx xx + pmullw mm2, mm5 // 04* 51 05*102 06*154 07*205 + + punpckhbw mm3, mm7 // mm3 = 05 xx 06 xx 07 xx 08 xx + pmullw mm3, mm6 // 05*205 06*154 07*102 08* 51 + + paddw mm0, mm1 // added round values + paddw mm0, mm4 + + psrlw mm0, 8 // output: 01 xx 02 xx 03 xx 04 xx + packuswb mm0, mm7 + + movd DWORD PTR [edi+1], mm0 // write output 01 02 03 04 + add edi, 10 + + add esi, 8 + paddw mm2, mm3 // + + paddw mm2, mm4 // added round values + cmp esi, edx + + psrlw mm2, 8 + packuswb mm2, mm7 + + movd DWORD PTR [edi-4], mm2 // writeoutput 06 07 08 09 + jl horiz_line_4_5_loop + +//Exit: + movq mm0, [esi] // mm0 = 00 01 02 03 04 05 06 07 + movq mm1, mm0 // mm1 = 00 01 02 03 04 05 06 07 + + movq mm2, mm0 // mm2 = 00 01 02 03 04 05 06 07 + psrlq mm1, 8 // mm1 = 01 02 03 04 05 06 07 00 + + movq mm3, mask45 // mm3 = 00 00 00 00 00 00 ff 00 + pand mm3, mm1 // mm3 = 00 00 00 00 00 00 07 00 + + psllq mm3, 8 // mm3 = 00 00 00 00 00 00 00 07 + por mm1, mm3 // mm1 = 01 02 03 04 05 06 07 07 + + movq mm3, mm1 + + movd DWORD PTR [edi], mm0 // write output 00 xx xx xx + punpcklbw mm0, mm7 // mm0 = 00 xx 01 xx 02 xx 03 xx + + punpcklbw mm1, mm7 // mm1 = 01 xx 02 xx 03 xx 04 xx + pmullw mm0, mm5 // 00* 51 01*102 02*154 03*205 + + pmullw mm1, mm6 // 01*205 02*154 03*102 04* 51 + punpckhbw mm2, mm7 // mm2 = 04 xx 05 xx 06 xx 07 xx + + movd DWORD PTR [edi+5], mm2 // write ouput 05 xx xx xx + pmullw mm2, mm5 // 04* 51 05*102 06*154 07*205 + + punpckhbw mm3, mm7 // mm3 = 05 xx 06 xx 07 xx 08 xx + pmullw mm3, mm6 // 05*205 06*154 07*102 07* 51 + + paddw mm0, mm1 // added round values + paddw mm0, mm4 + + psrlw mm0, 8 // output: 01 xx 02 xx 03 xx 04 xx + packuswb mm0, mm7 // 01 02 03 04 xx xx xx xx + + movd DWORD PTR [edi+1], mm0 // write output 01 02 03 04 + paddw mm2, mm3 // + + paddw mm2, mm4 // added round values + psrlw mm2, 8 + + packuswb mm2, mm7 + movd DWORD PTR [edi+6], mm2 // writeoutput 06 07 08 09 + + + } +} + +/**************************************************************************** + * + * ROUTINE : vertical_band_4_5_scale_mmx + * + * INPUTS : unsigned char *dest : + * unsigned int dest_pitch : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 4 to 5 up-scaling of a 4 pixel high band of pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. The function also has a "C" only + * version. + * + ****************************************************************************/ +static +void vertical_band_4_5_scale_mmx +( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + __asm + { + + mov esi, dest // Get the source and destination pointer + mov ecx, dest_pitch // Get the pitch size + + lea edi, [esi+ecx*2] // tow lines below + add edi, ecx // three lines below + + pxor mm7, mm7 // clear out mm7 + mov edx, dest_width // Loop counter + + vs_4_5_loop: + + movq mm0, QWORD ptr [esi] // src[0]; + movq mm1, QWORD ptr [esi+ecx] // src[1]; + + movq mm2, mm0 // Make a copy + punpcklbw mm0, mm7 // unpack low to word + + movq mm5, one_fifth + punpckhbw mm2, mm7 // unpack high to word + + pmullw mm0, mm5 // a * 1/5 + + movq mm3, mm1 // make a copy + punpcklbw mm1, mm7 // unpack low to word + + pmullw mm2, mm5 // a * 1/5 + movq mm6, four_fifths // constan + + movq mm4, mm1 // copy of low b + pmullw mm4, mm6 // b * 4/5 + + punpckhbw mm3, mm7 // unpack high to word + movq mm5, mm3 // copy of high b + + pmullw mm5, mm6 // b * 4/5 + paddw mm0, mm4 // a * 1/5 + b * 4/5 + + paddw mm2, mm5 // a * 1/5 + b * 4/5 + paddw mm0, round_values // + 128 + + paddw mm2, round_values // + 128 + psrlw mm0, 8 + + psrlw mm2, 8 + packuswb mm0, mm2 // des [1] + + movq QWORD ptr [esi+ecx], mm0 // write des[1] + movq mm0, [esi+ecx*2] // mm0 = src[2] + + // mm1, mm3 --- Src[1] + // mm0 --- Src[2] + // mm7 for unpacking + + movq mm5, two_fifths + movq mm2, mm0 // make a copy + + pmullw mm1, mm5 // b * 2/5 + movq mm6, three_fifths + + + punpcklbw mm0, mm7 // unpack low to word + pmullw mm3, mm5 // b * 2/5 + + movq mm4, mm0 // make copy of c + punpckhbw mm2, mm7 // unpack high to word + + pmullw mm4, mm6 // c * 3/5 + movq mm5, mm2 + + pmullw mm5, mm6 // c * 3/5 + paddw mm1, mm4 // b * 2/5 + c * 3/5 + + paddw mm3, mm5 // b * 2/5 + c * 3/5 + paddw mm1, round_values // + 128 + + paddw mm3, round_values // + 128 + psrlw mm1, 8 + + psrlw mm3, 8 + packuswb mm1, mm3 // des[2] + + movq QWORD ptr [esi+ecx*2], mm1 // write des[2] + movq mm1, [edi] // mm1=Src[3]; + + // mm0, mm2 --- Src[2] + // mm1 --- Src[3] + // mm6 --- 3/5 + // mm7 for unpacking + + pmullw mm0, mm6 // c * 3/5 + movq mm5, two_fifths // mm5 = 2/5 + + movq mm3, mm1 // make a copy + pmullw mm2, mm6 // c * 3/5 + + punpcklbw mm1, mm7 // unpack low + movq mm4, mm1 // make a copy + + punpckhbw mm3, mm7 // unpack high + pmullw mm4, mm5 // d * 2/5 + + movq mm6, mm3 // make a copy + pmullw mm6, mm5 // d * 2/5 + + paddw mm0, mm4 // c * 3/5 + d * 2/5 + paddw mm2, mm6 // c * 3/5 + d * 2/5 + + paddw mm0, round_values // + 128 + paddw mm2, round_values // + 128 + + psrlw mm0, 8 + psrlw mm2, 8 + + packuswb mm0, mm2 // des[3] + movq QWORD ptr [edi], mm0 // write des[3] + + // mm1, mm3 --- Src[3] + // mm7 -- cleared for unpacking + + movq mm0, [edi+ecx*2] // mm0, Src[0] of the next group + + movq mm5, four_fifths // mm5 = 4/5 + pmullw mm1, mm5 // d * 4/5 + + movq mm6, one_fifth // mm6 = 1/5 + movq mm2, mm0 // make a copy + + pmullw mm3, mm5 // d * 4/5 + punpcklbw mm0, mm7 // unpack low + + pmullw mm0, mm6 // an * 1/5 + punpckhbw mm2, mm7 // unpack high + + paddw mm1, mm0 // d * 4/5 + an * 1/5 + pmullw mm2, mm6 // an * 1/5 + + paddw mm3, mm2 // d * 4/5 + an * 1/5 + paddw mm1, round_values // + 128 + + paddw mm3, round_values // + 128 + psrlw mm1, 8 + + psrlw mm3, 8 + packuswb mm1, mm3 // des[4] + + movq QWORD ptr [edi+ecx], mm1 // write des[4] + + add edi, 8 + add esi, 8 + + sub edx, 8 + jg vs_4_5_loop + } +} + +/**************************************************************************** + * + * ROUTINE : last_vertical_band_4_5_scale_mmx + * + * INPUTS : unsigned char *dest : + * unsigned int dest_pitch : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : None + * + * FUNCTION : 4 to 5 up-scaling of the last 4-pixel high band in an image. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. The function also has an "C" only + * version. + * + ****************************************************************************/ +static +void last_vertical_band_4_5_scale_mmx +( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + __asm + { + mov esi, dest // Get the source and destination pointer + mov ecx, dest_pitch // Get the pitch size + + lea edi, [esi+ecx*2] // tow lines below + add edi, ecx // three lines below + + pxor mm7, mm7 // clear out mm7 + mov edx, dest_width // Loop counter + + last_vs_4_5_loop: + + movq mm0, QWORD ptr [esi] // src[0]; + movq mm1, QWORD ptr [esi+ecx] // src[1]; + + movq mm2, mm0 // Make a copy + punpcklbw mm0, mm7 // unpack low to word + + movq mm5, one_fifth + punpckhbw mm2, mm7 // unpack high to word + + pmullw mm0, mm5 // a * 1/5 + + movq mm3, mm1 // make a copy + punpcklbw mm1, mm7 // unpack low to word + + pmullw mm2, mm5 // a * 1/5 + movq mm6, four_fifths // constan + + movq mm4, mm1 // copy of low b + pmullw mm4, mm6 // b * 4/5 + + punpckhbw mm3, mm7 // unpack high to word + movq mm5, mm3 // copy of high b + + pmullw mm5, mm6 // b * 4/5 + paddw mm0, mm4 // a * 1/5 + b * 4/5 + + paddw mm2, mm5 // a * 1/5 + b * 4/5 + paddw mm0, round_values // + 128 + + paddw mm2, round_values // + 128 + psrlw mm0, 8 + + psrlw mm2, 8 + packuswb mm0, mm2 // des [1] + + movq QWORD ptr [esi+ecx], mm0 // write des[1] + movq mm0, [esi+ecx*2] // mm0 = src[2] + + // mm1, mm3 --- Src[1] + // mm0 --- Src[2] + // mm7 for unpacking + + movq mm5, two_fifths + movq mm2, mm0 // make a copy + + pmullw mm1, mm5 // b * 2/5 + movq mm6, three_fifths + + + punpcklbw mm0, mm7 // unpack low to word + pmullw mm3, mm5 // b * 2/5 + + movq mm4, mm0 // make copy of c + punpckhbw mm2, mm7 // unpack high to word + + pmullw mm4, mm6 // c * 3/5 + movq mm5, mm2 + + pmullw mm5, mm6 // c * 3/5 + paddw mm1, mm4 // b * 2/5 + c * 3/5 + + paddw mm3, mm5 // b * 2/5 + c * 3/5 + paddw mm1, round_values // + 128 + + paddw mm3, round_values // + 128 + psrlw mm1, 8 + + psrlw mm3, 8 + packuswb mm1, mm3 // des[2] + + movq QWORD ptr [esi+ecx*2], mm1 // write des[2] + movq mm1, [edi] // mm1=Src[3]; + + movq QWORD ptr [edi+ecx], mm1 // write des[4]; + + // mm0, mm2 --- Src[2] + // mm1 --- Src[3] + // mm6 --- 3/5 + // mm7 for unpacking + + pmullw mm0, mm6 // c * 3/5 + movq mm5, two_fifths // mm5 = 2/5 + + movq mm3, mm1 // make a copy + pmullw mm2, mm6 // c * 3/5 + + punpcklbw mm1, mm7 // unpack low + movq mm4, mm1 // make a copy + + punpckhbw mm3, mm7 // unpack high + pmullw mm4, mm5 // d * 2/5 + + movq mm6, mm3 // make a copy + pmullw mm6, mm5 // d * 2/5 + + paddw mm0, mm4 // c * 3/5 + d * 2/5 + paddw mm2, mm6 // c * 3/5 + d * 2/5 + + paddw mm0, round_values // + 128 + paddw mm2, round_values // + 128 + + psrlw mm0, 8 + psrlw mm2, 8 + + packuswb mm0, mm2 // des[3] + movq QWORD ptr [edi], mm0 // write des[3] + + // mm1, mm3 --- Src[3] + // mm7 -- cleared for unpacking + add edi, 8 + add esi, 8 + + sub edx, 8 + jg last_vs_4_5_loop + } +} + +/**************************************************************************** + * + * ROUTINE : vertical_band_3_5_scale_mmx + * + * INPUTS : unsigned char *dest : + * unsigned int dest_pitch : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 3 to 5 up-scaling of a 3-pixel high band of pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. The function also has an "C" only + * version. + * + ****************************************************************************/ +static +void vertical_band_3_5_scale_mmx +( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + __asm + { + mov esi, dest // Get the source and destination pointer + mov ecx, dest_pitch // Get the pitch size + + lea edi, [esi+ecx*2] // tow lines below + add edi, ecx // three lines below + + pxor mm7, mm7 // clear out mm7 + mov edx, dest_width // Loop counter + + vs_3_5_loop: + + movq mm0, QWORD ptr [esi] // src[0]; + movq mm1, QWORD ptr [esi+ecx] // src[1]; + + movq mm2, mm0 // Make a copy + punpcklbw mm0, mm7 // unpack low to word + + movq mm5, two_fifths // mm5 = 2/5 + punpckhbw mm2, mm7 // unpack high to word + + pmullw mm0, mm5 // a * 2/5 + + movq mm3, mm1 // make a copy + punpcklbw mm1, mm7 // unpack low to word + + pmullw mm2, mm5 // a * 2/5 + movq mm6, three_fifths // mm6 = 3/5 + + movq mm4, mm1 // copy of low b + pmullw mm4, mm6 // b * 3/5 + + punpckhbw mm3, mm7 // unpack high to word + movq mm5, mm3 // copy of high b + + pmullw mm5, mm6 // b * 3/5 + paddw mm0, mm4 // a * 2/5 + b * 3/5 + + paddw mm2, mm5 // a * 2/5 + b * 3/5 + paddw mm0, round_values // + 128 + + paddw mm2, round_values // + 128 + psrlw mm0, 8 + + psrlw mm2, 8 + packuswb mm0, mm2 // des [1] + + movq QWORD ptr [esi+ecx], mm0 // write des[1] + movq mm0, [esi+ecx*2] // mm0 = src[2] + + // mm1, mm3 --- Src[1] + // mm0 --- Src[2] + // mm7 for unpacking + + movq mm4, mm1 // b low + pmullw mm1, four_fifths // b * 4/5 low + + movq mm5, mm3 // b high + pmullw mm3, four_fifths // b * 4/5 high + + movq mm2, mm0 // c + pmullw mm4, one_fifth // b * 1/5 + + punpcklbw mm0, mm7 // c low + pmullw mm5, one_fifth // b * 1/5 + + movq mm6, mm0 // make copy of c low + punpckhbw mm2, mm7 // c high + + pmullw mm6, one_fifth // c * 1/5 low + movq mm7, mm2 // make copy of c high + + pmullw mm7, one_fifth // c * 1/5 high + paddw mm1, mm6 // b * 4/5 + c * 1/5 low + + paddw mm3, mm7 // b * 4/5 + c * 1/5 high + movq mm6, mm0 // make copy of c low + + pmullw mm6, four_fifths // c * 4/5 low + movq mm7, mm2 // make copy of c high + + pmullw mm7, four_fifths // c * 4/5 high + + paddw mm4, mm6 // b * 1/5 + c * 4/5 low + paddw mm5, mm7 // b * 1/5 + c * 4/5 high + + paddw mm1, round_values // + 128 + paddw mm3, round_values // + 128 + + psrlw mm1, 8 + psrlw mm3, 8 + + packuswb mm1, mm3 // des[2] + movq QWORD ptr [esi+ecx*2], mm1 // write des[2] + + paddw mm4, round_values // + 128 + paddw mm5, round_values // + 128 + + psrlw mm4, 8 + psrlw mm5, 8 + + packuswb mm4, mm5 // des[3] + movq QWORD ptr [edi], mm4 // write des[3] + + // mm0, mm2 --- Src[3] + + pxor mm7, mm7 // clear mm7 for unpacking + movq mm1, [edi+ecx*2] // mm1 = Src[0] of the next group + + movq mm5, three_fifths // mm5 = 3/5 + pmullw mm0, mm5 // d * 3/5 + + movq mm6, two_fifths // mm6 = 2/5 + movq mm3, mm1 // make a copy + + pmullw mm2, mm5 // d * 3/5 + punpcklbw mm1, mm7 // unpack low + + pmullw mm1, mm6 // an * 2/5 + punpckhbw mm3, mm7 // unpack high + + paddw mm0, mm1 // d * 3/5 + an * 2/5 + pmullw mm3, mm6 // an * 2/5 + + paddw mm2, mm3 // d * 3/5 + an * 2/5 + paddw mm0, round_values // + 128 + + paddw mm2, round_values // + 128 + psrlw mm0, 8 + + psrlw mm2, 8 + packuswb mm0, mm2 // des[4] + + movq QWORD ptr [edi+ecx], mm0 // write des[4] + + add edi, 8 + add esi, 8 + + sub edx, 8 + jg vs_3_5_loop + } +} + +/**************************************************************************** + * + * ROUTINE : last_vertical_band_3_5_scale_mmx + * + * INPUTS : unsigned char *dest : + * unsigned int dest_pitch : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 3 to 5 up-scaling of a 3-pixel high band of pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. The function also has an "C" only + * version. + * + ****************************************************************************/ +static +void last_vertical_band_3_5_scale_mmx +( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + __asm + { + mov esi, dest // Get the source and destination pointer + mov ecx, dest_pitch // Get the pitch size + + lea edi, [esi+ecx*2] // tow lines below + add edi, ecx // three lines below + + pxor mm7, mm7 // clear out mm7 + mov edx, dest_width // Loop counter + + + last_vs_3_5_loop: + + movq mm0, QWORD ptr [esi] // src[0]; + movq mm1, QWORD ptr [esi+ecx] // src[1]; + + movq mm2, mm0 // Make a copy + punpcklbw mm0, mm7 // unpack low to word + + movq mm5, two_fifths // mm5 = 2/5 + punpckhbw mm2, mm7 // unpack high to word + + pmullw mm0, mm5 // a * 2/5 + + movq mm3, mm1 // make a copy + punpcklbw mm1, mm7 // unpack low to word + + pmullw mm2, mm5 // a * 2/5 + movq mm6, three_fifths // mm6 = 3/5 + + movq mm4, mm1 // copy of low b + pmullw mm4, mm6 // b * 3/5 + + punpckhbw mm3, mm7 // unpack high to word + movq mm5, mm3 // copy of high b + + pmullw mm5, mm6 // b * 3/5 + paddw mm0, mm4 // a * 2/5 + b * 3/5 + + paddw mm2, mm5 // a * 2/5 + b * 3/5 + paddw mm0, round_values // + 128 + + paddw mm2, round_values // + 128 + psrlw mm0, 8 + + psrlw mm2, 8 + packuswb mm0, mm2 // des [1] + + movq QWORD ptr [esi+ecx], mm0 // write des[1] + movq mm0, [esi+ecx*2] // mm0 = src[2] + + + + // mm1, mm3 --- Src[1] + // mm0 --- Src[2] + // mm7 for unpacking + + movq mm4, mm1 // b low + pmullw mm1, four_fifths // b * 4/5 low + + movq QWORD ptr [edi+ecx], mm0 // write des[4] + + movq mm5, mm3 // b high + pmullw mm3, four_fifths // b * 4/5 high + + movq mm2, mm0 // c + pmullw mm4, one_fifth // b * 1/5 + + punpcklbw mm0, mm7 // c low + pmullw mm5, one_fifth // b * 1/5 + + movq mm6, mm0 // make copy of c low + punpckhbw mm2, mm7 // c high + + pmullw mm6, one_fifth // c * 1/5 low + movq mm7, mm2 // make copy of c high + + pmullw mm7, one_fifth // c * 1/5 high + paddw mm1, mm6 // b * 4/5 + c * 1/5 low + + paddw mm3, mm7 // b * 4/5 + c * 1/5 high + movq mm6, mm0 // make copy of c low + + pmullw mm6, four_fifths // c * 4/5 low + movq mm7, mm2 // make copy of c high + + pmullw mm7, four_fifths // c * 4/5 high + + paddw mm4, mm6 // b * 1/5 + c * 4/5 low + paddw mm5, mm7 // b * 1/5 + c * 4/5 high + + paddw mm1, round_values // + 128 + paddw mm3, round_values // + 128 + + psrlw mm1, 8 + psrlw mm3, 8 + + packuswb mm1, mm3 // des[2] + movq QWORD ptr [esi+ecx*2], mm1 // write des[2] + + paddw mm4, round_values // + 128 + paddw mm5, round_values // + 128 + + psrlw mm4, 8 + psrlw mm5, 8 + + packuswb mm4, mm5 // des[3] + movq QWORD ptr [edi], mm4 // write des[3] + + // mm0, mm2 --- Src[3] + + add edi, 8 + add esi, 8 + + sub edx, 8 + jg last_vs_3_5_loop + } +} + +/**************************************************************************** + * + * ROUTINE : vertical_band_1_2_scale_mmx + * + * INPUTS : unsigned char *dest : + * unsigned int dest_pitch : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 1 to 2 up-scaling of a band of pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. The function also has an "C" only + * version. + * + ****************************************************************************/ +static +void vertical_band_1_2_scale_mmx +( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + __asm + { + + mov esi, dest // Get the source and destination pointer + mov ecx, dest_pitch // Get the pitch size + + pxor mm7, mm7 // clear out mm7 + mov edx, dest_width // Loop counter + + vs_1_2_loop: + + movq mm0, [esi] // get Src[0] + movq mm1, [esi + ecx * 2] // get Src[1] + + movq mm2, mm0 // make copy before unpack + movq mm3, mm1 // make copy before unpack + + punpcklbw mm0, mm7 // low Src[0] + movq mm6, four_ones // mm6= 1, 1, 1, 1 + + punpcklbw mm1, mm7 // low Src[1] + paddw mm0, mm1 // low (a + b) + + punpckhbw mm2, mm7 // high Src[0] + paddw mm0, mm6 // low (a + b + 1) + + punpckhbw mm3, mm7 + paddw mm2, mm3 // high (a + b ) + + psraw mm0, 1 // low (a + b +1 )/2 + paddw mm2, mm6 // high (a + b + 1) + + psraw mm2, 1 // high (a + b + 1)/2 + packuswb mm0, mm2 // pack results + + movq [esi+ecx], mm0 // write out eight bytes + add esi, 8 + + sub edx, 8 + jg vs_1_2_loop + } + +} + +/**************************************************************************** + * + * ROUTINE : last_vertical_band_1_2_scale_mmx + * + * INPUTS : unsigned char *dest : + * unsigned int dest_pitch : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 1 to 2 up-scaling of band of pixels. + * + * SPECIAL NOTES : The routine uses the first line of the band below + * the current band. The function also has an "C" only + * version. + * + ****************************************************************************/ +static +void last_vertical_band_1_2_scale_mmx +( + unsigned char *dest, + unsigned int dest_pitch, + unsigned int dest_width +) +{ + __asm + { + mov esi, dest // Get the source and destination pointer + mov ecx, dest_pitch // Get the pitch size + + mov edx, dest_width // Loop counter + + last_vs_1_2_loop: + + movq mm0, [esi] // get Src[0] + movq [esi+ecx], mm0 // write out eight bytes + + add esi, 8 + sub edx, 8 + + jg last_vs_1_2_loop + } +} + +/**************************************************************************** + * + * ROUTINE : horizontal_line_1_2_scale + * + * INPUTS : const unsigned char *source : + * unsigned int source_width : + * unsigned char *dest : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 1 to 2 up-scaling of a horizontal line of pixels. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void horizontal_line_1_2_scale_mmx +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + (void) dest_width; + + __asm + { + mov esi, source + mov edi, dest + + pxor mm7, mm7 + movq mm6, four_ones + + mov ecx, source_width + + hs_1_2_loop: + + movq mm0, [esi] + movq mm1, [esi+1] + + movq mm2, mm0 + movq mm3, mm1 + + movq mm4, mm0 + punpcklbw mm0, mm7 + + punpcklbw mm1, mm7 + paddw mm0, mm1 + + paddw mm0, mm6 + punpckhbw mm2, mm7 + + punpckhbw mm3, mm7 + paddw mm2, mm3 + + paddw mm2, mm6 + psraw mm0, 1 + + psraw mm2, 1 + packuswb mm0, mm2 + + movq mm2, mm4 + punpcklbw mm2, mm0 + + movq [edi], mm2 + punpckhbw mm4, mm0 + + movq [edi+8], mm4 + add esi, 8 + + add edi, 16 + sub ecx, 8 + + cmp ecx, 8 + jg hs_1_2_loop + +// last eight pixel + + movq mm0, [esi] + movq mm1, mm0 + + movq mm2, mm0 + movq mm3, mm1 + + psrlq mm1, 8 + psrlq mm3, 56 + + psllq mm3, 56 + por mm1, mm3 + + movq mm3, mm1 + movq mm4, mm0 + + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + + paddw mm0, mm1 + paddw mm0, mm6 + + punpckhbw mm2, mm7 + punpckhbw mm3, mm7 + + paddw mm2, mm3 + paddw mm2, mm6 + + psraw mm0, 1 + psraw mm2, 1 + + packuswb mm0, mm2 + movq mm2, mm4 + + punpcklbw mm2, mm0 + movq [edi], mm2 + + punpckhbw mm4, mm0 + movq [edi+8], mm4 + } +} + + + + + +__declspec(align(16)) const static unsigned short const54_2[] = { 0, 64, 128, 192 }; +__declspec(align(16)) const static unsigned short const54_1[] = {256, 192, 128, 64 }; + + +/**************************************************************************** + * + * ROUTINE : horizontal_line_5_4_scale_mmx + * + * INPUTS : const unsigned char *source : Pointer to source data. + * unsigned int source_width : Stride of source. + * unsigned char *dest : Pointer to destination data. + * unsigned int dest_width : Stride of destination (NOT USED). + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Copies horizontal line of pixels from source to + * destination scaling up by 4 to 5. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void horizontal_line_5_4_scale_mmx +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + /* + unsigned i; + unsigned int a, b, c, d, e; + unsigned char *des = dest; + const unsigned char *src = source; + + (void) dest_width; + + for ( i=0; i>8); + des[2] = ((c*128 + d*128 + 128)>>8); + des[3] = ((d* 64 + e*192 + 128)>>8); + + src += 5; + des += 4; + } + */ + (void) dest_width; + + __asm + { + + mov esi, source ; + mov edi, dest ; + + mov ecx, source_width ; + movq mm5, const54_1 ; + + pxor mm7, mm7 ; + movq mm6, const54_2 ; + + movq mm4, round_values ; + lea edx, [esi+ecx] ; + horizontal_line_5_4_loop: + + movq mm0, QWORD PTR [esi] ; + 00 01 02 03 04 05 06 07 + movq mm1, mm0 ; + 00 01 02 03 04 05 06 07 + + psrlq mm0, 8 ; + 01 02 03 04 05 06 07 xx + punpcklbw mm1, mm7 ; + xx 00 xx 01 xx 02 xx 03 + + punpcklbw mm0, mm7 ; + xx 01 xx 02 xx 03 xx 04 + pmullw mm1, mm5 + + pmullw mm0, mm6 + add esi, 5 + + add edi, 4 + paddw mm1, mm0 + + paddw mm1, mm4 + psrlw mm1, 8 + + cmp esi, edx + packuswb mm1, mm7 + + movd DWORD PTR [edi-4], mm1 + + jl horizontal_line_5_4_loop + + } + +} +__declspec(align(16)) const static unsigned short one_fourths[] = { 64, 64, 64, 64 }; +__declspec(align(16)) const static unsigned short two_fourths[] = { 128, 128, 128, 128 }; +__declspec(align(16)) const static unsigned short three_fourths[] = { 192, 192, 192, 192 }; + +static +void vertical_band_5_4_scale_mmx(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + + __asm + { + push ebx + + mov esi, source // Get the source and destination pointer + mov ecx, src_pitch // Get the pitch size + + mov edi, dest // tow lines below + pxor mm7, mm7 // clear out mm7 + + mov edx, dest_pitch // Loop counter + mov ebx, dest_width + + vs_5_4_loop: + + movd mm0, DWORD ptr [esi] // src[0]; + movd mm1, DWORD ptr [esi+ecx] // src[1]; + + movd mm2, DWORD ptr [esi+ecx*2] + lea eax, [esi+ecx*2] // + + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + movq mm3, mm2 + pmullw mm1, three_fourths + + pmullw mm2, one_fourths + movd mm4, [eax+ecx] + + pmullw mm3, two_fourths + punpcklbw mm4, mm7 + + movq mm5, mm4 + pmullw mm4, two_fourths + + paddw mm1, mm2 + movd mm6, [eax+ecx*2] + + pmullw mm5, one_fourths + paddw mm1, round_values; + + paddw mm3, mm4 + psrlw mm1, 8 + + punpcklbw mm6, mm7 + paddw mm3, round_values + + pmullw mm6, three_fourths + psrlw mm3, 8 + + packuswb mm1, mm7 + packuswb mm3, mm7 + + movd DWORD PTR [edi], mm0 + movd DWORD PTR [edi+edx], mm1 + + + paddw mm5, mm6 + movd DWORD PTR [edi+edx*2], mm3 + + lea eax, [edi+edx*2] + paddw mm5, round_values + + psrlw mm5, 8 + add edi, 4 + + packuswb mm5, mm7 + movd DWORD PTR [eax+edx], mm5 + + add esi, 4 + sub ebx, 4 + + jg vs_5_4_loop + + pop ebx + } +} + + +__declspec(align(16)) const static unsigned short const53_1[] = { 0, 85, 171, 0 }; +__declspec(align(16)) const static unsigned short const53_2[] = {256, 171, 85, 0 }; + + +static +void horizontal_line_5_3_scale_mmx +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + + (void) dest_width; + __asm + { + + mov esi, source ; + mov edi, dest ; + + mov ecx, source_width ; + movq mm5, const53_1 ; + + pxor mm7, mm7 ; + movq mm6, const53_2 ; + + movq mm4, round_values ; + lea edx, [esi+ecx-5] ; + horizontal_line_5_3_loop: + + movq mm0, QWORD PTR [esi] ; + 00 01 02 03 04 05 06 07 + movq mm1, mm0 ; + 00 01 02 03 04 05 06 07 + + psllw mm0, 8 ; + xx 00 xx 02 xx 04 xx 06 + psrlw mm1, 8 ; + 01 xx 03 xx 05 xx 07 xx + + psrlw mm0, 8 ; + 00 xx 02 xx 04 xx 06 xx + psllq mm1, 16 ; + xx xx 01 xx 03 xx 05 xx + + pmullw mm0, mm6 + + pmullw mm1, mm5 + add esi, 5 + + add edi, 3 + paddw mm1, mm0 + + paddw mm1, mm4 + psrlw mm1, 8 + + cmp esi, edx + packuswb mm1, mm7 + + movd DWORD PTR [edi-3], mm1 + jl horizontal_line_5_3_loop + +//exit condition + movq mm0, QWORD PTR [esi] ; + 00 01 02 03 04 05 06 07 + movq mm1, mm0 ; + 00 01 02 03 04 05 06 07 + + psllw mm0, 8 ; + xx 00 xx 02 xx 04 xx 06 + psrlw mm1, 8 ; + 01 xx 03 xx 05 xx 07 xx + + psrlw mm0, 8 ; + 00 xx 02 xx 04 xx 06 xx + psllq mm1, 16 ; + xx xx 01 xx 03 xx 05 xx + + pmullw mm0, mm6 + + pmullw mm1, mm5 + paddw mm1, mm0 + + paddw mm1, mm4 + psrlw mm1, 8 + + packuswb mm1, mm7 + movd eax, mm1 + + mov edx, eax + shr edx, 16 + + mov WORD PTR[edi], ax + mov BYTE PTR[edi+2], dl + + } + +} + +__declspec(align(16)) const static unsigned short one_thirds[] = { 85, 85, 85, 85 }; +__declspec(align(16)) const static unsigned short two_thirds[] = { 171, 171, 171, 171 }; + +static +void vertical_band_5_3_scale_mmx(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + + __asm + { + push ebx + + mov esi, source // Get the source and destination pointer + mov ecx, src_pitch // Get the pitch size + + mov edi, dest // tow lines below + pxor mm7, mm7 // clear out mm7 + + mov edx, dest_pitch // Loop counter + movq mm5, one_thirds + + movq mm6, two_thirds + mov ebx, dest_width; + + vs_5_3_loop: + + movd mm0, DWORD ptr [esi] // src[0]; + movd mm1, DWORD ptr [esi+ecx] // src[1]; + + movd mm2, DWORD ptr [esi+ecx*2] + lea eax, [esi+ecx*2] // + + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + pmullw mm1, mm5 + pmullw mm2, mm6 + + movd mm3, DWORD ptr [eax+ecx] + movd mm4, DWORD ptr [eax+ecx*2] + + punpcklbw mm3, mm7 + punpcklbw mm4, mm7 + + pmullw mm3, mm6 + pmullw mm4, mm5 + + + movd DWORD PTR [edi], mm0 + paddw mm1, mm2 + + paddw mm1, round_values + psrlw mm1, 8 + + packuswb mm1, mm7 + paddw mm3, mm4 + + paddw mm3, round_values + movd DWORD PTR [edi+edx], mm1 + + psrlw mm3, 8 + packuswb mm3, mm7 + + movd DWORD PTR [edi+edx*2], mm3 + + + add edi, 4 + add esi, 4 + + sub ebx, 4 + jg vs_5_3_loop + + pop ebx + } +} + + + + +/**************************************************************************** + * + * ROUTINE : horizontal_line_2_1_scale + * + * INPUTS : const unsigned char *source : + * unsigned int source_width : + * unsigned char *dest : + * unsigned int dest_width : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : 1 to 2 up-scaling of a horizontal line of pixels. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +static +void horizontal_line_2_1_scale_mmx +( + const unsigned char *source, + unsigned int source_width, + unsigned char *dest, + unsigned int dest_width +) +{ + (void) dest_width; + (void) source_width; + __asm + { + mov esi, source + mov edi, dest + + pxor mm7, mm7 + mov ecx, dest_width + + xor edx, edx + hs_2_1_loop: + + movq mm0, [esi+edx*2] + psllw mm0, 8 + + psrlw mm0, 8 + packuswb mm0, mm7 + + movd DWORD Ptr [edi+edx], mm0; + add edx, 4 + + cmp edx, ecx + jl hs_2_1_loop + + } +} + + + +static +void vertical_band_2_1_scale_mmx(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + (void) dest_pitch; + (void) src_pitch; + vpx_memcpy(dest, source, dest_width); +} + + +__declspec(align(16)) const static unsigned short three_sixteenths[] = { 48, 48, 48, 48 }; +__declspec(align(16)) const static unsigned short ten_sixteenths[] = { 160, 160, 160, 160 }; + +static +void vertical_band_2_1_scale_i_mmx(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) +{ + + (void) dest_pitch; + __asm + { + mov esi, source + mov edi, dest + + mov eax, src_pitch + mov edx, dest_width + + pxor mm7, mm7 + sub esi, eax //back one line + + + lea ecx, [esi+edx]; + movq mm6, round_values; + + movq mm5, three_sixteenths; + movq mm4, ten_sixteenths; + + vs_2_1_i_loop: + movd mm0, [esi] // + movd mm1, [esi+eax] // + + movd mm2, [esi+eax*2] // + punpcklbw mm0, mm7 + + pmullw mm0, mm5 + punpcklbw mm1, mm7 + + pmullw mm1, mm4 + punpcklbw mm2, mm7 + + pmullw mm2, mm5 + paddw mm0, round_values + + paddw mm1, mm2 + paddw mm0, mm1 + + psrlw mm0, 8 + packuswb mm0, mm7 + + movd DWORD PTR [edi], mm0 + add esi, 4 + + add edi, 4; + cmp esi, ecx + jl vs_2_1_i_loop + + } +} + + + +void +register_mmxscalers(void) +{ + vp8_horizontal_line_1_2_scale = horizontal_line_1_2_scale_mmx; + vp8_vertical_band_1_2_scale = vertical_band_1_2_scale_mmx; + vp8_last_vertical_band_1_2_scale = last_vertical_band_1_2_scale_mmx; + vp8_horizontal_line_3_5_scale = horizontal_line_3_5_scale_mmx; + vp8_vertical_band_3_5_scale = vertical_band_3_5_scale_mmx; + vp8_last_vertical_band_3_5_scale = last_vertical_band_3_5_scale_mmx; + vp8_horizontal_line_4_5_scale = horizontal_line_4_5_scale_mmx; + vp8_vertical_band_4_5_scale = vertical_band_4_5_scale_mmx; + vp8_last_vertical_band_4_5_scale = last_vertical_band_4_5_scale_mmx; + + vp8_horizontal_line_3_4_scale = vp8cx_horizontal_line_3_4_scale_c; + vp8_vertical_band_3_4_scale = vp8cx_vertical_band_3_4_scale_c; + vp8_last_vertical_band_3_4_scale = vp8cx_last_vertical_band_3_4_scale_c; + vp8_horizontal_line_2_3_scale = vp8cx_horizontal_line_2_3_scale_c; + vp8_vertical_band_2_3_scale = vp8cx_vertical_band_2_3_scale_c; + vp8_last_vertical_band_2_3_scale = vp8cx_last_vertical_band_2_3_scale_c; + + + + vp8_vertical_band_5_4_scale = vertical_band_5_4_scale_mmx; + vp8_vertical_band_5_3_scale = vertical_band_5_3_scale_mmx; + vp8_vertical_band_2_1_scale = vertical_band_2_1_scale_mmx; + vp8_vertical_band_2_1_scale_i = vertical_band_2_1_scale_i_mmx; + vp8_horizontal_line_2_1_scale = horizontal_line_2_1_scale_mmx; + vp8_horizontal_line_5_3_scale = horizontal_line_5_3_scale_mmx; + vp8_horizontal_line_5_4_scale = horizontal_line_5_4_scale_mmx; + + + + +} diff --git a/vpx_scale/win32/scalesystemdependent.c b/vpx_scale/win32/scalesystemdependent.c new file mode 100644 index 0000000..19e61c3 --- /dev/null +++ b/vpx_scale/win32/scalesystemdependent.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : system_dependent.c +* +* Description : Miscellaneous system dependent functions +* +****************************************************************************/ + +/**************************************************************************** +* Header Files +****************************************************************************/ +#include "vpx_scale/vpxscale.h" +#include "cpuidlib.h" + +/**************************************************************************** +* Imports +*****************************************************************************/ +extern void register_generic_scalers(void); +extern void register_mmxscalers(void); + +/**************************************************************************** + * + * ROUTINE : post_proc_machine_specific_config + * + * INPUTS : UINT32 Version : Codec version number. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Checks for machine specifc features such as MMX support + * sets appropriate flags and function pointers. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void +vp8_scale_machine_specific_config(void) +{ + // If MMX supported then set to use MMX versions of functions else + // use original 'C' versions. + int mmx_enabled; + int xmm_enabled; + int wmt_enabled; + + vpx_get_processor_flags(&mmx_enabled, &xmm_enabled, &wmt_enabled); + + if (mmx_enabled || xmm_enabled || wmt_enabled) + { + register_mmxscalers(); + } + else + { + vp8_horizontal_line_1_2_scale = vp8cx_horizontal_line_1_2_scale_c; + vp8_vertical_band_1_2_scale = vp8cx_vertical_band_1_2_scale_c; + vp8_last_vertical_band_1_2_scale = vp8cx_last_vertical_band_1_2_scale_c; + vp8_horizontal_line_3_5_scale = vp8cx_horizontal_line_3_5_scale_c; + vp8_vertical_band_3_5_scale = vp8cx_vertical_band_3_5_scale_c; + vp8_last_vertical_band_3_5_scale = vp8cx_last_vertical_band_3_5_scale_c; + vp8_horizontal_line_3_4_scale = vp8cx_horizontal_line_3_4_scale_c; + vp8_vertical_band_3_4_scale = vp8cx_vertical_band_3_4_scale_c; + vp8_last_vertical_band_3_4_scale = vp8cx_last_vertical_band_3_4_scale_c; + vp8_horizontal_line_2_3_scale = vp8cx_horizontal_line_2_3_scale_c; + vp8_vertical_band_2_3_scale = vp8cx_vertical_band_2_3_scale_c; + vp8_last_vertical_band_2_3_scale = vp8cx_last_vertical_band_2_3_scale_c; + vp8_horizontal_line_4_5_scale = vp8cx_horizontal_line_4_5_scale_c; + vp8_vertical_band_4_5_scale = vp8cx_vertical_band_4_5_scale_c; + vp8_last_vertical_band_4_5_scale = vp8cx_last_vertical_band_4_5_scale_c; + + + vp8_vertical_band_5_4_scale = vp8cx_vertical_band_5_4_scale_c; + vp8_vertical_band_5_3_scale = vp8cx_vertical_band_5_3_scale_c; + vp8_vertical_band_2_1_scale = vp8cx_vertical_band_2_1_scale_c; + vp8_vertical_band_2_1_scale_i = vp8cx_vertical_band_2_1_scale_i_c; + vp8_horizontal_line_2_1_scale = vp8cx_horizontal_line_2_1_scale_c; + vp8_horizontal_line_5_3_scale = vp8cx_horizontal_line_5_3_scale_c; + vp8_horizontal_line_5_4_scale = vp8cx_horizontal_line_5_4_scale_c; + + } +} diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h new file mode 100644 index 0000000..800f700 --- /dev/null +++ b/vpx_scale/yv12config.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef YV12_CONFIG_H +#define YV12_CONFIG_H +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VP7BORDERINPIXELS 48 +#define VP8BORDERINPIXELS 32 + + /************************************* + For INT_YUV: + + Y = (R+G*2+B)/4; + U = (R-B)/2; + V = (G*2 - R - B)/4; + And + R = Y+U-V; + G = Y+V; + B = Y-U-V; + ************************************/ + typedef enum + { + REG_YUV = 0, /* Regular yuv */ + INT_YUV = 1 /* The type of yuv that can be tranfer to and from RGB through integer transform */ + } + YUV_TYPE; + + typedef struct yv12_buffer_config + { + int y_width; + int y_height; + int y_stride; +/* int yinternal_width; */ + + int uv_width; + int uv_height; + int uv_stride; +/* int uvinternal_width; */ + + unsigned char *y_buffer; + unsigned char *u_buffer; + unsigned char *v_buffer; + + unsigned char *buffer_alloc; + int border; + int frame_size; + YUV_TYPE clrtype; + + int corrupted; + int flags; + } YV12_BUFFER_CONFIG; + + int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border); + int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf); + +#ifdef __cplusplus +} +#endif + + +#endif /*YV12_CONFIG_H*/ diff --git a/vpxdec.c b/vpxdec.c new file mode 100644 index 0000000..4482f3d --- /dev/null +++ b/vpxdec.c @@ -0,0 +1,1154 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This is a simple program that reads ivf files and decodes them + * using the new interface. Decoded frames are output as YV12 raw. + */ +#include +#include +#include +#include +#include + +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "vpx_config.h" +#include "vpx/vpx_decoder.h" +#include "vpx_ports/vpx_timer.h" +#if CONFIG_VP8_DECODER +#include "vpx/vp8dx.h" +#endif +#if CONFIG_MD5 +#include "md5_utils.h" +#endif +#include "tools_common.h" +#include "nestegg/include/nestegg/nestegg.h" + +#if CONFIG_OS_SUPPORT +#if defined(_MSC_VER) +#include +#define snprintf _snprintf +#define isatty _isatty +#define fileno _fileno +#else +#include +#endif +#endif + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + +static const char *exec_name; + +#define VP8_FOURCC (0x00385056) +static const struct +{ + char const *name; + const vpx_codec_iface_t *iface; + unsigned int fourcc; + unsigned int fourcc_mask; +} ifaces[] = +{ +#if CONFIG_VP8_DECODER + {"vp8", &vpx_codec_vp8_dx_algo, VP8_FOURCC, 0x00FFFFFF}, +#endif +}; + +#include "args.h" +static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, + "Codec to use"); +static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, + "Output raw YV12 frames"); +static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, + "Output raw I420 frames"); +static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0, + "Flip the chroma planes in the output"); +static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0, + "Don't process the decoded frames"); +static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0, + "Show progress after each frame decodes"); +static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1, + "Stop decoding after n frames"); +static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0, + "Postprocess decoded frames"); +static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0, + "Show timing summary"); +static const arg_def_t outputfile = ARG_DEF("o", "output", 1, + "Output file name pattern (see below)"); +static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, + "Max threads to use"); +static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, + "Show version string"); +static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, + "Enable decoder error-concealment"); + + +#if CONFIG_MD5 +static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, + "Compute the MD5 sum of the decoded frame"); +#endif +static const arg_def_t *all_args[] = +{ + &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, + &progressarg, &limitarg, &postprocarg, &summaryarg, &outputfile, + &threadsarg, &verbosearg, +#if CONFIG_MD5 + &md5arg, +#endif + &error_concealment, + NULL +}; + +#if CONFIG_VP8_DECODER +static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1, + "Enable VP8 postproc add noise"); +static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0, + "Enable VP8 deblocking"); +static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1, + "Enable VP8 demacroblocking, w/ level"); +static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1, + "Enable VP8 visible debug info"); +static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1, + "Display only selected reference frame per macro block"); +static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1, + "Display only selected macro block modes"); +static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1, + "Display only selected block modes"); +static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1, + "Draw only selected motion vectors"); +static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0, + "Enable multiframe quality enhancement"); + +static const arg_def_t *vp8_pp_args[] = +{ + &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info, + &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe, + NULL +}; +#endif + +static void usage_exit() +{ + int i; + + fprintf(stderr, "Usage: %s filename\n\n" + "Options:\n", exec_name); + arg_show_usage(stderr, all_args); +#if CONFIG_VP8_DECODER + fprintf(stderr, "\nVP8 Postprocessing Options:\n"); + arg_show_usage(stderr, vp8_pp_args); +#endif + fprintf(stderr, + "\nOutput File Patterns:\n\n" + " The -o argument specifies the name of the file(s) to " + "write to. If the\n argument does not include any escape " + "characters, the output will be\n written to a single file. " + "Otherwise, the filename will be calculated by\n expanding " + "the following escape characters:\n" + "\n\t%%w - Frame width" + "\n\t%%h - Frame height" + "\n\t%% - Frame number, zero padded to places (1..9)" + "\n\n Pattern arguments are only supported in conjunction " + "with the --yv12 and\n --i420 options. If the -o option is " + "not specified, the output will be\n directed to stdout.\n" + ); + fprintf(stderr, "\nIncluded decoders:\n\n"); + + for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) + fprintf(stderr, " %-6s - %s\n", + ifaces[i].name, + vpx_codec_iface_name(ifaces[i].iface)); + + exit(EXIT_FAILURE); +} + +void die(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + usage_exit(); +} + +static unsigned int mem_get_le16(const void *vmem) +{ + unsigned int val; + const unsigned char *mem = (const unsigned char *)vmem; + + val = mem[1] << 8; + val |= mem[0]; + return val; +} + +static unsigned int mem_get_le32(const void *vmem) +{ + unsigned int val; + const unsigned char *mem = (const unsigned char *)vmem; + + val = mem[3] << 24; + val |= mem[2] << 16; + val |= mem[1] << 8; + val |= mem[0]; + return val; +} + +enum file_kind +{ + RAW_FILE, + IVF_FILE, + WEBM_FILE +}; + +struct input_ctx +{ + enum file_kind kind; + FILE *infile; + nestegg *nestegg_ctx; + nestegg_packet *pkt; + unsigned int chunk; + unsigned int chunks; + unsigned int video_track; +}; + +#define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t)) +#define RAW_FRAME_HDR_SZ (sizeof(uint32_t)) +static int read_frame(struct input_ctx *input, + uint8_t **buf, + size_t *buf_sz, + size_t *buf_alloc_sz) +{ + char raw_hdr[IVF_FRAME_HDR_SZ]; + size_t new_buf_sz; + FILE *infile = input->infile; + enum file_kind kind = input->kind; + if(kind == WEBM_FILE) + { + if(input->chunk >= input->chunks) + { + unsigned int track; + + do + { + /* End of this packet, get another. */ + if(input->pkt) + nestegg_free_packet(input->pkt); + + if(nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0 + || nestegg_packet_track(input->pkt, &track)) + return 1; + + } while(track != input->video_track); + + if(nestegg_packet_count(input->pkt, &input->chunks)) + return 1; + input->chunk = 0; + } + + if(nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz)) + return 1; + input->chunk++; + + return 0; + } + /* For both the raw and ivf formats, the frame size is the first 4 bytes + * of the frame header. We just need to special case on the header + * size. + */ + else if (fread(raw_hdr, kind==IVF_FILE + ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) + { + if (!feof(infile)) + fprintf(stderr, "Failed to read frame size\n"); + + new_buf_sz = 0; + } + else + { + new_buf_sz = mem_get_le32(raw_hdr); + + if (new_buf_sz > 256 * 1024 * 1024) + { + fprintf(stderr, "Error: Read invalid frame size (%u)\n", + (unsigned int)new_buf_sz); + new_buf_sz = 0; + } + + if (kind == RAW_FILE && new_buf_sz > 256 * 1024) + fprintf(stderr, "Warning: Read invalid frame size (%u)" + " - not a raw file?\n", (unsigned int)new_buf_sz); + + if (new_buf_sz > *buf_alloc_sz) + { + uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz); + + if (new_buf) + { + *buf = new_buf; + *buf_alloc_sz = 2 * new_buf_sz; + } + else + { + fprintf(stderr, "Failed to allocate compressed data buffer\n"); + new_buf_sz = 0; + } + } + } + + *buf_sz = new_buf_sz; + + if (!feof(infile)) + { + if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) + { + fprintf(stderr, "Failed to read full frame\n"); + return 1; + } + + return 0; + } + + return 1; +} + +void *out_open(const char *out_fn, int do_md5) +{ + void *out = NULL; + + if (do_md5) + { +#if CONFIG_MD5 + MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); + (void)out_fn; + MD5Init(md5_ctx); +#endif + } + else + { + FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") + : set_binary_mode(stdout); + + if (!outfile) + { + fprintf(stderr, "Failed to output file"); + exit(EXIT_FAILURE); + } + } + + return out; +} + +void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) +{ + if (do_md5) + { +#if CONFIG_MD5 + MD5Update(out, buf, len); +#endif + } + else + { + if(fwrite(buf, 1, len, out)); + } +} + +void out_close(void *out, const char *out_fn, int do_md5) +{ + if (do_md5) + { +#if CONFIG_MD5 + uint8_t md5[16]; + int i; + + MD5Final(md5, out); + free(out); + + for (i = 0; i < 16; i++) + printf("%02x", md5[i]); + + printf(" %s\n", out_fn); +#endif + } + else + { + fclose(out); + } +} + +unsigned int file_is_ivf(FILE *infile, + unsigned int *fourcc, + unsigned int *width, + unsigned int *height, + unsigned int *fps_den, + unsigned int *fps_num) +{ + char raw_hdr[32]; + int is_ivf = 0; + + if (fread(raw_hdr, 1, 32, infile) == 32) + { + if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' + && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') + { + is_ivf = 1; + + if (mem_get_le16(raw_hdr + 4) != 0) + fprintf(stderr, "Error: Unrecognized IVF version! This file may not" + " decode properly."); + + *fourcc = mem_get_le32(raw_hdr + 8); + *width = mem_get_le16(raw_hdr + 12); + *height = mem_get_le16(raw_hdr + 14); + *fps_num = mem_get_le32(raw_hdr + 16); + *fps_den = mem_get_le32(raw_hdr + 20); + + /* Some versions of vpxenc used 1/(2*fps) for the timebase, so + * we can guess the framerate using only the timebase in this + * case. Other files would require reading ahead to guess the + * timebase, like we do for webm. + */ + if(*fps_num < 1000) + { + /* Correct for the factor of 2 applied to the timebase in the + * encoder. + */ + if(*fps_num&1)*fps_den<<=1; + else *fps_num>>=1; + } + else + { + /* Don't know FPS for sure, and don't have readahead code + * (yet?), so just default to 30fps. + */ + *fps_num = 30; + *fps_den = 1; + } + } + } + + if (!is_ivf) + rewind(infile); + + return is_ivf; +} + + +unsigned int file_is_raw(FILE *infile, + unsigned int *fourcc, + unsigned int *width, + unsigned int *height, + unsigned int *fps_den, + unsigned int *fps_num) +{ + unsigned char buf[32]; + int is_raw = 0; + vpx_codec_stream_info_t si; + + si.sz = sizeof(si); + + if (fread(buf, 1, 32, infile) == 32) + { + int i; + + if(mem_get_le32(buf) < 256 * 1024 * 1024) + for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) + if(!vpx_codec_peek_stream_info(ifaces[i].iface, + buf + 4, 32 - 4, &si)) + { + is_raw = 1; + *fourcc = ifaces[i].fourcc; + *width = si.w; + *height = si.h; + *fps_num = 30; + *fps_den = 1; + break; + } + } + + rewind(infile); + return is_raw; +} + + +static int +nestegg_read_cb(void *buffer, size_t length, void *userdata) +{ + FILE *f = userdata; + + if(fread(buffer, 1, length, f) < length) + { + if (ferror(f)) + return -1; + if (feof(f)) + return 0; + } + return 1; +} + + +static int +nestegg_seek_cb(int64_t offset, int whence, void * userdata) +{ + switch(whence) { + case NESTEGG_SEEK_SET: whence = SEEK_SET; break; + case NESTEGG_SEEK_CUR: whence = SEEK_CUR; break; + case NESTEGG_SEEK_END: whence = SEEK_END; break; + }; + return fseek(userdata, offset, whence)? -1 : 0; +} + + +static int64_t +nestegg_tell_cb(void * userdata) +{ + return ftell(userdata); +} + + +static void +nestegg_log_cb(nestegg * context, unsigned int severity, char const * format, + ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + + +static int +webm_guess_framerate(struct input_ctx *input, + unsigned int *fps_den, + unsigned int *fps_num) +{ + unsigned int i; + uint64_t tstamp=0; + + /* Guess the framerate. Read up to 1 second, or 50 video packets, + * whichever comes first. + */ + for(i=0; tstamp < 1000000000 && i < 50;) + { + nestegg_packet * pkt; + unsigned int track; + + if(nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0) + break; + + nestegg_packet_track(pkt, &track); + if(track == input->video_track) + { + nestegg_packet_tstamp(pkt, &tstamp); + i++; + } + + nestegg_free_packet(pkt); + } + + if(nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) + goto fail; + + *fps_num = (i - 1) * 1000000; + *fps_den = tstamp / 1000; + return 0; +fail: + nestegg_destroy(input->nestegg_ctx); + input->nestegg_ctx = NULL; + rewind(input->infile); + return 1; +} + + +static int +file_is_webm(struct input_ctx *input, + unsigned int *fourcc, + unsigned int *width, + unsigned int *height, + unsigned int *fps_den, + unsigned int *fps_num) +{ + unsigned int i, n; + int track_type = -1; + + nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, + input->infile}; + nestegg_video_params params; + + if(nestegg_init(&input->nestegg_ctx, io, NULL)) + goto fail; + + if(nestegg_track_count(input->nestegg_ctx, &n)) + goto fail; + + for(i=0; inestegg_ctx, i); + + if(track_type == NESTEGG_TRACK_VIDEO) + break; + else if(track_type < 0) + goto fail; + } + + if(nestegg_track_codec_id(input->nestegg_ctx, i) != NESTEGG_CODEC_VP8) + { + fprintf(stderr, "Not VP8 video, quitting.\n"); + exit(1); + } + + input->video_track = i; + + if(nestegg_track_video_params(input->nestegg_ctx, i, ¶ms)) + goto fail; + + *fps_den = 0; + *fps_num = 0; + *fourcc = VP8_FOURCC; + *width = params.width; + *height = params.height; + return 1; +fail: + input->nestegg_ctx = NULL; + rewind(input->infile); + return 0; +} + + +void show_progress(int frame_in, int frame_out, unsigned long dx_time) +{ + fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r", + frame_in, frame_out, dx_time, + (float)frame_out * 1000000.0 / (float)dx_time); +} + + +void generate_filename(const char *pattern, char *out, size_t q_len, + unsigned int d_w, unsigned int d_h, + unsigned int frame_in) +{ + const char *p = pattern; + char *q = out; + + do + { + char *next_pat = strchr(p, '%'); + + if(p == next_pat) + { + size_t pat_len; + + // parse the pattern + q[q_len - 1] = '\0'; + switch(p[1]) + { + case 'w': snprintf(q, q_len - 1, "%d", d_w); break; + case 'h': snprintf(q, q_len - 1, "%d", d_h); break; + case '1': snprintf(q, q_len - 1, "%d", frame_in); break; + case '2': snprintf(q, q_len - 1, "%02d", frame_in); break; + case '3': snprintf(q, q_len - 1, "%03d", frame_in); break; + case '4': snprintf(q, q_len - 1, "%04d", frame_in); break; + case '5': snprintf(q, q_len - 1, "%05d", frame_in); break; + case '6': snprintf(q, q_len - 1, "%06d", frame_in); break; + case '7': snprintf(q, q_len - 1, "%07d", frame_in); break; + case '8': snprintf(q, q_len - 1, "%08d", frame_in); break; + case '9': snprintf(q, q_len - 1, "%09d", frame_in); break; + default: + die("Unrecognized pattern %%%c\n", p[1]); + } + + pat_len = strlen(q); + if(pat_len >= q_len - 1) + die("Output filename too long.\n"); + q += pat_len; + p += 2; + q_len -= pat_len; + } + else + { + size_t copy_len; + + // copy the next segment + if(!next_pat) + copy_len = strlen(p); + else + copy_len = next_pat - p; + + if(copy_len >= q_len - 1) + die("Output filename too long.\n"); + + memcpy(q, p, copy_len); + q[copy_len] = '\0'; + q += copy_len; + p += copy_len; + q_len -= copy_len; + } + } while(*p); +} + + +int main(int argc, const char **argv_) +{ + vpx_codec_ctx_t decoder; + char *fn = NULL; + int i; + uint8_t *buf = NULL; + size_t buf_sz = 0, buf_alloc_sz = 0; + FILE *infile; + int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0; + int stop_after = 0, postproc = 0, summary = 0, quiet = 1; + int ec_enabled = 0; + vpx_codec_iface_t *iface = NULL; + unsigned int fourcc; + unsigned long dx_time = 0; + struct arg arg; + char **argv, **argi, **argj; + const char *outfile_pattern = 0; + char outfile[PATH_MAX]; + int single_file; + int use_y4m = 1; + unsigned int width; + unsigned int height; + unsigned int fps_den; + unsigned int fps_num; + void *out = NULL; + vpx_codec_dec_cfg_t cfg = {0}; +#if CONFIG_VP8_DECODER + vp8_postproc_cfg_t vp8_pp_cfg = {0}; + int vp8_dbg_color_ref_frame = 0; + int vp8_dbg_color_mb_modes = 0; + int vp8_dbg_color_b_modes = 0; + int vp8_dbg_display_mv = 0; +#endif + struct input_ctx input = {0}; + int frames_corrupted = 0; + int dec_flags = 0; + + /* Parse command line */ + exec_name = argv_[0]; + argv = argv_dup(argc - 1, argv_ + 1); + + for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) + { + memset(&arg, 0, sizeof(arg)); + arg.argv_step = 1; + + if (arg_match(&arg, &codecarg, argi)) + { + int j, k = -1; + + for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) + if (!strcmp(ifaces[j].name, arg.val)) + k = j; + + if (k >= 0) + iface = ifaces[k].iface; + else + die("Error: Unrecognized argument (%s) to --codec\n", + arg.val); + } + else if (arg_match(&arg, &outputfile, argi)) + outfile_pattern = arg.val; + else if (arg_match(&arg, &use_yv12, argi)) + { + use_y4m = 0; + flipuv = 1; + } + else if (arg_match(&arg, &use_i420, argi)) + { + use_y4m = 0; + flipuv = 0; + } + else if (arg_match(&arg, &flipuvarg, argi)) + flipuv = 1; + else if (arg_match(&arg, &noblitarg, argi)) + noblit = 1; + else if (arg_match(&arg, &progressarg, argi)) + progress = 1; + else if (arg_match(&arg, &limitarg, argi)) + stop_after = arg_parse_uint(&arg); + else if (arg_match(&arg, &postprocarg, argi)) + postproc = 1; + else if (arg_match(&arg, &md5arg, argi)) + do_md5 = 1; + else if (arg_match(&arg, &summaryarg, argi)) + summary = 1; + else if (arg_match(&arg, &threadsarg, argi)) + cfg.threads = arg_parse_uint(&arg); + else if (arg_match(&arg, &verbosearg, argi)) + quiet = 0; + +#if CONFIG_VP8_DECODER + else if (arg_match(&arg, &addnoise_level, argi)) + { + postproc = 1; + vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; + vp8_pp_cfg.noise_level = arg_parse_uint(&arg); + } + else if (arg_match(&arg, &demacroblock_level, argi)) + { + postproc = 1; + vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; + vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); + } + else if (arg_match(&arg, &deblock, argi)) + { + postproc = 1; + vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK; + } + else if (arg_match(&arg, &mfqe, argi)) + { + postproc = 1; + vp8_pp_cfg.post_proc_flag |= VP8_MFQE; + } + else if (arg_match(&arg, &pp_debug_info, argi)) + { + unsigned int level = arg_parse_uint(&arg); + + postproc = 1; + vp8_pp_cfg.post_proc_flag &= ~0x7; + + if (level) + vp8_pp_cfg.post_proc_flag |= level; + } + else if (arg_match(&arg, &pp_disp_ref_frame, argi)) + { + unsigned int flags = arg_parse_int(&arg); + if (flags) + { + postproc = 1; + vp8_dbg_color_ref_frame = flags; + } + } + else if (arg_match(&arg, &pp_disp_mb_modes, argi)) + { + unsigned int flags = arg_parse_int(&arg); + if (flags) + { + postproc = 1; + vp8_dbg_color_mb_modes = flags; + } + } + else if (arg_match(&arg, &pp_disp_b_modes, argi)) + { + unsigned int flags = arg_parse_int(&arg); + if (flags) + { + postproc = 1; + vp8_dbg_color_b_modes = flags; + } + } + else if (arg_match(&arg, &pp_disp_mvs, argi)) + { + unsigned int flags = arg_parse_int(&arg); + if (flags) + { + postproc = 1; + vp8_dbg_display_mv = flags; + } + } + else if (arg_match(&arg, &error_concealment, argi)) + { + ec_enabled = 1; + } + +#endif + else + argj++; + } + + /* Check for unrecognized options */ + for (argi = argv; *argi; argi++) + if (argi[0][0] == '-' && strlen(argi[0]) > 1) + die("Error: Unrecognized option %s\n", *argi); + + /* Handle non-option arguments */ + fn = argv[0]; + + if (!fn) + usage_exit(); + + /* Open file */ + infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin); + + if (!infile) + { + fprintf(stderr, "Failed to open file '%s'", + strcmp(fn, "-") ? fn : "stdin"); + return EXIT_FAILURE; + } +#if CONFIG_OS_SUPPORT + /* Make sure we don't dump to the terminal, unless forced to with -o - */ + if(!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) + { + fprintf(stderr, + "Not dumping raw video to your terminal. Use '-o -' to " + "override.\n"); + return EXIT_FAILURE; + } +#endif + input.infile = infile; + if(file_is_ivf(infile, &fourcc, &width, &height, &fps_den, + &fps_num)) + input.kind = IVF_FILE; + else if(file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num)) + input.kind = WEBM_FILE; + else if(file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num)) + input.kind = RAW_FILE; + else + { + fprintf(stderr, "Unrecognized input file type.\n"); + return EXIT_FAILURE; + } + + /* If the output file is not set or doesn't have a sequence number in + * it, then we only open it once. + */ + outfile_pattern = outfile_pattern ? outfile_pattern : "-"; + single_file = 1; + { + const char *p = outfile_pattern; + do + { + p = strchr(p, '%'); + if(p && p[1] >= '1' && p[1] <= '9') + { + // pattern contains sequence number, so it's not unique. + single_file = 0; + break; + } + if(p) + p++; + } while(p); + } + + if(single_file && !noblit) + { + generate_filename(outfile_pattern, outfile, sizeof(outfile)-1, + width, height, 0); + out = out_open(outfile, do_md5); + } + + if (use_y4m && !noblit) + { + char buffer[128]; + if (!single_file) + { + fprintf(stderr, "YUV4MPEG2 not supported with output patterns," + " try --i420 or --yv12.\n"); + return EXIT_FAILURE; + } + + if(input.kind == WEBM_FILE) + if(webm_guess_framerate(&input, &fps_den, &fps_num)) + { + fprintf(stderr, "Failed to guess framerate -- error parsing " + "webm file?\n"); + return EXIT_FAILURE; + } + + + /*Note: We can't output an aspect ratio here because IVF doesn't + store one, and neither does VP8. + That will have to wait until these tools support WebM natively.*/ + sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n", + "420jpeg", width, height, fps_num, fps_den, 'p'); + out_put(out, (unsigned char *)buffer, strlen(buffer), do_md5); + } + + /* Try to determine the codec from the fourcc. */ + for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) + if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) + { + vpx_codec_iface_t *ivf_iface = ifaces[i].iface; + + if (iface && iface != ivf_iface) + fprintf(stderr, "Notice -- IVF header indicates codec: %s\n", + ifaces[i].name); + else + iface = ivf_iface; + + break; + } + + dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | + (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); + if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface, &cfg, + dec_flags)) + { + fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (!quiet) + fprintf(stderr, "%s\n", decoder.name); + +#if CONFIG_VP8_DECODER + + if (vp8_pp_cfg.post_proc_flag + && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) + { + fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (vp8_dbg_color_ref_frame + && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) + { + fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (vp8_dbg_color_mb_modes + && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) + { + fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (vp8_dbg_color_b_modes + && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) + { + fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (vp8_dbg_display_mv + && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) + { + fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } +#endif + + /* Decode file */ + while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) + { + vpx_codec_iter_t iter = NULL; + vpx_image_t *img; + struct vpx_usec_timer timer; + int corrupted; + + vpx_usec_timer_start(&timer); + + if (vpx_codec_decode(&decoder, buf, buf_sz, NULL, 0)) + { + const char *detail = vpx_codec_error_detail(&decoder); + fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder)); + + if (detail) + fprintf(stderr, " Additional information: %s\n", detail); + + goto fail; + } + + vpx_usec_timer_mark(&timer); + dx_time += vpx_usec_timer_elapsed(&timer); + + ++frame_in; + + if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) + { + fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n", + vpx_codec_error(&decoder)); + goto fail; + } + frames_corrupted += corrupted; + + if ((img = vpx_codec_get_frame(&decoder, &iter))) + ++frame_out; + + if (progress) + show_progress(frame_in, frame_out, dx_time); + + if (!noblit) + { + if (img) + { + unsigned int y; + char out_fn[PATH_MAX]; + uint8_t *buf; + + if (!single_file) + { + size_t len = sizeof(out_fn)-1; + + out_fn[len] = '\0'; + generate_filename(outfile_pattern, out_fn, len-1, + img->d_w, img->d_h, frame_in); + out = out_open(out_fn, do_md5); + } + else if(use_y4m) + out_put(out, (unsigned char *)"FRAME\n", 6, do_md5); + + buf = img->planes[VPX_PLANE_Y]; + + for (y = 0; y < img->d_h; y++) + { + out_put(out, buf, img->d_w, do_md5); + buf += img->stride[VPX_PLANE_Y]; + } + + buf = img->planes[flipuv?VPX_PLANE_V:VPX_PLANE_U]; + + for (y = 0; y < (1 + img->d_h) / 2; y++) + { + out_put(out, buf, (1 + img->d_w) / 2, do_md5); + buf += img->stride[VPX_PLANE_U]; + } + + buf = img->planes[flipuv?VPX_PLANE_U:VPX_PLANE_V]; + + for (y = 0; y < (1 + img->d_h) / 2; y++) + { + out_put(out, buf, (1 + img->d_w) / 2, do_md5); + buf += img->stride[VPX_PLANE_V]; + } + + if (!single_file) + out_close(out, out_fn, do_md5); + } + } + + if (stop_after && frame_in >= stop_after) + break; + } + + if (summary || progress) + { + show_progress(frame_in, frame_out, dx_time); + fprintf(stderr, "\n"); + } + + if (frames_corrupted) + fprintf(stderr, "WARNING: %d frames corrupted.\n",frames_corrupted); + +fail: + + if (vpx_codec_destroy(&decoder)) + { + fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (single_file && !noblit) + out_close(out, outfile, do_md5); + + if(input.nestegg_ctx) + nestegg_destroy(input.nestegg_ctx); + if(input.kind != WEBM_FILE) + free(buf); + fclose(infile); + free(argv); + + return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/vpxenc.c b/vpxenc.c new file mode 100644 index 0000000..d32b21b --- /dev/null +++ b/vpxenc.c @@ -0,0 +1,2544 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* This is a simple program that encodes YV12 files and generates ivf + * files using the new interface. + */ +#if defined(_WIN32) || !CONFIG_OS_SUPPORT +#define USE_POSIX_MMAP 0 +#else +#define USE_POSIX_MMAP 1 +#endif + +#include +#include +#include +#include +#include +#include +#include "vpx/vpx_encoder.h" +#if USE_POSIX_MMAP +#include +#include +#include +#include +#include +#endif +#include "vpx/vp8cx.h" +#include "vpx_ports/mem_ops.h" +#include "vpx_ports/vpx_timer.h" +#include "tools_common.h" +#include "y4minput.h" +#include "libmkv/EbmlWriter.h" +#include "libmkv/EbmlIDs.h" + +/* Need special handling of these functions on Windows */ +#if defined(_MSC_VER) +/* MSVS doesn't define off_t, and uses _f{seek,tell}i64 */ +typedef __int64 off_t; +#define fseeko _fseeki64 +#define ftello _ftelli64 +#elif defined(_WIN32) +/* MinGW defines off_t as long + and uses f{seek,tell}o64/off64_t for large files */ +#define fseeko fseeko64 +#define ftello ftello64 +#define off_t off64_t +#endif + +#if defined(_MSC_VER) +#define LITERALU64(n) n +#else +#define LITERALU64(n) n##LLU +#endif + +/* We should use 32-bit file operations in WebM file format + * when building ARM executable file (.axf) with RVCT */ +#if !CONFIG_OS_SUPPORT +typedef long off_t; +#define fseeko fseek +#define ftello ftell +#endif + +static const char *exec_name; + +static const struct codec_item +{ + char const *name; + const vpx_codec_iface_t *iface; + unsigned int fourcc; +} codecs[] = +{ +#if CONFIG_VP8_ENCODER + {"vp8", &vpx_codec_vp8_cx_algo, 0x30385056}, +#endif +}; + +static void usage_exit(); + +#define LOG_ERROR(label) do \ +{\ + const char *l=label;\ + va_list ap;\ + va_start(ap, fmt);\ + if(l)\ + fprintf(stderr, "%s: ", l);\ + vfprintf(stderr, fmt, ap);\ + fprintf(stderr, "\n");\ + va_end(ap);\ +} while(0) + +void die(const char *fmt, ...) +{ + LOG_ERROR(NULL); + usage_exit(); +} + + +void fatal(const char *fmt, ...) +{ + LOG_ERROR("Fatal"); + exit(EXIT_FAILURE); +} + + +void warn(const char *fmt, ...) +{ + LOG_ERROR("Warning"); +} + + +static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) +{ + va_list ap; + + va_start(ap, s); + if (ctx->err) + { + const char *detail = vpx_codec_error_detail(ctx); + + vfprintf(stderr, s, ap); + fprintf(stderr, ": %s\n", vpx_codec_error(ctx)); + + if (detail) + fprintf(stderr, " %s\n", detail); + + exit(EXIT_FAILURE); + } +} + +/* This structure is used to abstract the different ways of handling + * first pass statistics. + */ +typedef struct +{ + vpx_fixed_buf_t buf; + int pass; + FILE *file; + char *buf_ptr; + size_t buf_alloc_sz; +} stats_io_t; + +int stats_open_file(stats_io_t *stats, const char *fpf, int pass) +{ + int res; + + stats->pass = pass; + + if (pass == 0) + { + stats->file = fopen(fpf, "wb"); + stats->buf.sz = 0; + stats->buf.buf = NULL, + res = (stats->file != NULL); + } + else + { +#if 0 +#elif USE_POSIX_MMAP + struct stat stat_buf; + int fd; + + fd = open(fpf, O_RDONLY); + stats->file = fdopen(fd, "rb"); + fstat(fd, &stat_buf); + stats->buf.sz = stat_buf.st_size; + stats->buf.buf = mmap(NULL, stats->buf.sz, PROT_READ, MAP_PRIVATE, + fd, 0); + res = (stats->buf.buf != NULL); +#else + size_t nbytes; + + stats->file = fopen(fpf, "rb"); + + if (fseek(stats->file, 0, SEEK_END)) + fatal("First-pass stats file must be seekable!"); + + stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file); + rewind(stats->file); + + stats->buf.buf = malloc(stats->buf_alloc_sz); + + if (!stats->buf.buf) + fatal("Failed to allocate first-pass stats buffer (%lu bytes)", + (unsigned long)stats->buf_alloc_sz); + + nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file); + res = (nbytes == stats->buf.sz); +#endif + } + + return res; +} + +int stats_open_mem(stats_io_t *stats, int pass) +{ + int res; + stats->pass = pass; + + if (!pass) + { + stats->buf.sz = 0; + stats->buf_alloc_sz = 64 * 1024; + stats->buf.buf = malloc(stats->buf_alloc_sz); + } + + stats->buf_ptr = stats->buf.buf; + res = (stats->buf.buf != NULL); + return res; +} + + +void stats_close(stats_io_t *stats, int last_pass) +{ + if (stats->file) + { + if (stats->pass == last_pass) + { +#if 0 +#elif USE_POSIX_MMAP + munmap(stats->buf.buf, stats->buf.sz); +#else + free(stats->buf.buf); +#endif + } + + fclose(stats->file); + stats->file = NULL; + } + else + { + if (stats->pass == last_pass) + free(stats->buf.buf); + } +} + +void stats_write(stats_io_t *stats, const void *pkt, size_t len) +{ + if (stats->file) + { + if(fwrite(pkt, 1, len, stats->file)); + } + else + { + if (stats->buf.sz + len > stats->buf_alloc_sz) + { + size_t new_sz = stats->buf_alloc_sz + 64 * 1024; + char *new_ptr = realloc(stats->buf.buf, new_sz); + + if (new_ptr) + { + stats->buf_ptr = new_ptr + (stats->buf_ptr - (char *)stats->buf.buf); + stats->buf.buf = new_ptr; + stats->buf_alloc_sz = new_sz; + } + else + fatal("Failed to realloc firstpass stats buffer."); + } + + memcpy(stats->buf_ptr, pkt, len); + stats->buf.sz += len; + stats->buf_ptr += len; + } +} + +vpx_fixed_buf_t stats_get(stats_io_t *stats) +{ + return stats->buf; +} + +/* Stereo 3D packed frame format */ +typedef enum stereo_format +{ + STEREO_FORMAT_MONO = 0, + STEREO_FORMAT_LEFT_RIGHT = 1, + STEREO_FORMAT_BOTTOM_TOP = 2, + STEREO_FORMAT_TOP_BOTTOM = 3, + STEREO_FORMAT_RIGHT_LEFT = 11 +} stereo_format_t; + +enum video_file_type +{ + FILE_TYPE_RAW, + FILE_TYPE_IVF, + FILE_TYPE_Y4M +}; + +struct detect_buffer { + char buf[4]; + size_t buf_read; + size_t position; +}; + + +struct input_state +{ + char *fn; + FILE *file; + y4m_input y4m; + struct detect_buffer detect; + enum video_file_type file_type; + unsigned int w; + unsigned int h; + struct vpx_rational framerate; + int use_i420; +}; + + +#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */ +static int read_frame(struct input_state *input, vpx_image_t *img) +{ + FILE *f = input->file; + enum video_file_type file_type = input->file_type; + y4m_input *y4m = &input->y4m; + struct detect_buffer *detect = &input->detect; + int plane = 0; + int shortread = 0; + + if (file_type == FILE_TYPE_Y4M) + { + if (y4m_input_fetch_frame(y4m, f, img) < 1) + return 0; + } + else + { + if (file_type == FILE_TYPE_IVF) + { + char junk[IVF_FRAME_HDR_SZ]; + + /* Skip the frame header. We know how big the frame should be. See + * write_ivf_frame_header() for documentation on the frame header + * layout. + */ + if(fread(junk, 1, IVF_FRAME_HDR_SZ, f)); + } + + for (plane = 0; plane < 3; plane++) + { + unsigned char *ptr; + int w = (plane ? (1 + img->d_w) / 2 : img->d_w); + int h = (plane ? (1 + img->d_h) / 2 : img->d_h); + int r; + + /* Determine the correct plane based on the image format. The for-loop + * always counts in Y,U,V order, but this may not match the order of + * the data on disk. + */ + switch (plane) + { + case 1: + ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U]; + break; + case 2: + ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V]; + break; + default: + ptr = img->planes[plane]; + } + + for (r = 0; r < h; r++) + { + size_t needed = w; + size_t buf_position = 0; + const size_t left = detect->buf_read - detect->position; + if (left > 0) + { + const size_t more = (left < needed) ? left : needed; + memcpy(ptr, detect->buf + detect->position, more); + buf_position = more; + needed -= more; + detect->position += more; + } + if (needed > 0) + { + shortread |= (fread(ptr + buf_position, 1, needed, f) < needed); + } + + ptr += img->stride[plane]; + } + } + } + + return !shortread; +} + + +unsigned int file_is_y4m(FILE *infile, + y4m_input *y4m, + char detect[4]) +{ + if(memcmp(detect, "YUV4", 4) == 0) + { + return 1; + } + return 0; +} + +#define IVF_FILE_HDR_SZ (32) +unsigned int file_is_ivf(struct input_state *input, + unsigned int *fourcc) +{ + char raw_hdr[IVF_FILE_HDR_SZ]; + int is_ivf = 0; + FILE *infile = input->file; + unsigned int *width = &input->w; + unsigned int *height = &input->h; + struct detect_buffer *detect = &input->detect; + + if(memcmp(detect->buf, "DKIF", 4) != 0) + return 0; + + /* See write_ivf_file_header() for more documentation on the file header + * layout. + */ + if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile) + == IVF_FILE_HDR_SZ - 4) + { + { + is_ivf = 1; + + if (mem_get_le16(raw_hdr + 4) != 0) + warn("Unrecognized IVF version! This file may not decode " + "properly."); + + *fourcc = mem_get_le32(raw_hdr + 8); + } + } + + if (is_ivf) + { + *width = mem_get_le16(raw_hdr + 12); + *height = mem_get_le16(raw_hdr + 14); + detect->position = 4; + } + + return is_ivf; +} + + +static void write_ivf_file_header(FILE *outfile, + const vpx_codec_enc_cfg_t *cfg, + unsigned int fourcc, + int frame_cnt) +{ + char header[32]; + + if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) + return; + + header[0] = 'D'; + header[1] = 'K'; + header[2] = 'I'; + header[3] = 'F'; + mem_put_le16(header + 4, 0); /* version */ + mem_put_le16(header + 6, 32); /* headersize */ + mem_put_le32(header + 8, fourcc); /* headersize */ + mem_put_le16(header + 12, cfg->g_w); /* width */ + mem_put_le16(header + 14, cfg->g_h); /* height */ + mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */ + mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */ + mem_put_le32(header + 24, frame_cnt); /* length */ + mem_put_le32(header + 28, 0); /* unused */ + + if(fwrite(header, 1, 32, outfile)); +} + + +static void write_ivf_frame_header(FILE *outfile, + const vpx_codec_cx_pkt_t *pkt) +{ + char header[12]; + vpx_codec_pts_t pts; + + if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) + return; + + pts = pkt->data.frame.pts; + mem_put_le32(header, pkt->data.frame.sz); + mem_put_le32(header + 4, pts & 0xFFFFFFFF); + mem_put_le32(header + 8, pts >> 32); + + if(fwrite(header, 1, 12, outfile)); +} + +static void write_ivf_frame_size(FILE *outfile, size_t size) +{ + char header[4]; + mem_put_le32(header, size); + fwrite(header, 1, 4, outfile); +} + + +typedef off_t EbmlLoc; + + +struct cue_entry +{ + unsigned int time; + uint64_t loc; +}; + + +struct EbmlGlobal +{ + int debug; + + FILE *stream; + int64_t last_pts_ms; + vpx_rational_t framerate; + + /* These pointers are to the start of an element */ + off_t position_reference; + off_t seek_info_pos; + off_t segment_info_pos; + off_t track_pos; + off_t cue_pos; + off_t cluster_pos; + + /* This pointer is to a specific element to be serialized */ + off_t track_id_pos; + + /* These pointers are to the size field of the element */ + EbmlLoc startSegment; + EbmlLoc startCluster; + + uint32_t cluster_timecode; + int cluster_open; + + struct cue_entry *cue_list; + unsigned int cues; + +}; + + +void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) +{ + if(fwrite(buffer_in, 1, len, glob->stream)); +} + +#define WRITE_BUFFER(s) \ +for(i = len-1; i>=0; i--)\ +{ \ + x = *(const s *)buffer_in >> (i * CHAR_BIT); \ + Ebml_Write(glob, &x, 1); \ +} +void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigned long len) +{ + char x; + int i; + + /* buffer_size: + * 1 - int8_t; + * 2 - int16_t; + * 3 - int32_t; + * 4 - int64_t; + */ + switch (buffer_size) + { + case 1: + WRITE_BUFFER(int8_t) + break; + case 2: + WRITE_BUFFER(int16_t) + break; + case 4: + WRITE_BUFFER(int32_t) + break; + case 8: + WRITE_BUFFER(int64_t) + break; + default: + break; + } +} +#undef WRITE_BUFFER + +/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit + * one, but not a 32 bit one. + */ +static void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) +{ + unsigned char sizeSerialized = 4 | 0x80; + Ebml_WriteID(glob, class_id); + Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); + Ebml_Serialize(glob, &ui, sizeof(ui), 4); +} + + +static void +Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, + unsigned long class_id) +{ + //todo this is always taking 8 bytes, this may need later optimization + //this is a key that says length unknown + uint64_t unknownLen = LITERALU64(0x01FFFFFFFFFFFFFF); + + Ebml_WriteID(glob, class_id); + *ebmlLoc = ftello(glob->stream); + Ebml_Serialize(glob, &unknownLen, sizeof(unknownLen), 8); +} + +static void +Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) +{ + off_t pos; + uint64_t size; + + /* Save the current stream pointer */ + pos = ftello(glob->stream); + + /* Calculate the size of this element */ + size = pos - *ebmlLoc - 8; + size |= LITERALU64(0x0100000000000000); + + /* Seek back to the beginning of the element and write the new size */ + fseeko(glob->stream, *ebmlLoc, SEEK_SET); + Ebml_Serialize(glob, &size, sizeof(size), 8); + + /* Reset the stream pointer */ + fseeko(glob->stream, pos, SEEK_SET); +} + + +static void +write_webm_seek_element(EbmlGlobal *ebml, unsigned long id, off_t pos) +{ + uint64_t offset = pos - ebml->position_reference; + EbmlLoc start; + Ebml_StartSubElement(ebml, &start, Seek); + Ebml_SerializeBinary(ebml, SeekID, id); + Ebml_SerializeUnsigned64(ebml, SeekPosition, offset); + Ebml_EndSubElement(ebml, &start); +} + + +static void +write_webm_seek_info(EbmlGlobal *ebml) +{ + + off_t pos; + + /* Save the current stream pointer */ + pos = ftello(ebml->stream); + + if(ebml->seek_info_pos) + fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET); + else + ebml->seek_info_pos = pos; + + { + EbmlLoc start; + + Ebml_StartSubElement(ebml, &start, SeekHead); + write_webm_seek_element(ebml, Tracks, ebml->track_pos); + write_webm_seek_element(ebml, Cues, ebml->cue_pos); + write_webm_seek_element(ebml, Info, ebml->segment_info_pos); + Ebml_EndSubElement(ebml, &start); + } + { + //segment info + EbmlLoc startInfo; + uint64_t frame_time; + char version_string[64]; + + /* Assemble version string */ + if(ebml->debug) + strcpy(version_string, "vpxenc"); + else + { + strcpy(version_string, "vpxenc "); + strncat(version_string, + vpx_codec_version_str(), + sizeof(version_string) - 1 - strlen(version_string)); + } + + frame_time = (uint64_t)1000 * ebml->framerate.den + / ebml->framerate.num; + ebml->segment_info_pos = ftello(ebml->stream); + Ebml_StartSubElement(ebml, &startInfo, Info); + Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); + Ebml_SerializeFloat(ebml, Segment_Duration, + ebml->last_pts_ms + frame_time); + Ebml_SerializeString(ebml, 0x4D80, version_string); + Ebml_SerializeString(ebml, 0x5741, version_string); + Ebml_EndSubElement(ebml, &startInfo); + } +} + + +static void +write_webm_file_header(EbmlGlobal *glob, + const vpx_codec_enc_cfg_t *cfg, + const struct vpx_rational *fps, + stereo_format_t stereo_fmt) +{ + { + EbmlLoc start; + Ebml_StartSubElement(glob, &start, EBML); + Ebml_SerializeUnsigned(glob, EBMLVersion, 1); + Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); //EBML Read Version + Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); //EBML Max ID Length + Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); //EBML Max Size Length + Ebml_SerializeString(glob, DocType, "webm"); //Doc Type + Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); //Doc Type Version + Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); //Doc Type Read Version + Ebml_EndSubElement(glob, &start); + } + { + Ebml_StartSubElement(glob, &glob->startSegment, Segment); //segment + glob->position_reference = ftello(glob->stream); + glob->framerate = *fps; + write_webm_seek_info(glob); + + { + EbmlLoc trackStart; + glob->track_pos = ftello(glob->stream); + Ebml_StartSubElement(glob, &trackStart, Tracks); + { + unsigned int trackNumber = 1; + uint64_t trackID = 0; + + EbmlLoc start; + Ebml_StartSubElement(glob, &start, TrackEntry); + Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); + glob->track_id_pos = ftello(glob->stream); + Ebml_SerializeUnsigned32(glob, TrackUID, trackID); + Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1 + Ebml_SerializeString(glob, CodecID, "V_VP8"); + { + unsigned int pixelWidth = cfg->g_w; + unsigned int pixelHeight = cfg->g_h; + float frameRate = (float)fps->num/(float)fps->den; + + EbmlLoc videoStart; + Ebml_StartSubElement(glob, &videoStart, Video); + Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); + Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); + Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt); + Ebml_SerializeFloat(glob, FrameRate, frameRate); + Ebml_EndSubElement(glob, &videoStart); //Video + } + Ebml_EndSubElement(glob, &start); //Track Entry + } + Ebml_EndSubElement(glob, &trackStart); + } + // segment element is open + } +} + + +static void +write_webm_block(EbmlGlobal *glob, + const vpx_codec_enc_cfg_t *cfg, + const vpx_codec_cx_pkt_t *pkt) +{ + unsigned long block_length; + unsigned char track_number; + unsigned short block_timecode = 0; + unsigned char flags; + int64_t pts_ms; + int start_cluster = 0, is_keyframe; + + /* Calculate the PTS of this frame in milliseconds */ + pts_ms = pkt->data.frame.pts * 1000 + * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; + if(pts_ms <= glob->last_pts_ms) + pts_ms = glob->last_pts_ms + 1; + glob->last_pts_ms = pts_ms; + + /* Calculate the relative time of this block */ + if(pts_ms - glob->cluster_timecode > SHRT_MAX) + start_cluster = 1; + else + block_timecode = pts_ms - glob->cluster_timecode; + + is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY); + if(start_cluster || is_keyframe) + { + if(glob->cluster_open) + Ebml_EndSubElement(glob, &glob->startCluster); + + /* Open the new cluster */ + block_timecode = 0; + glob->cluster_open = 1; + glob->cluster_timecode = pts_ms; + glob->cluster_pos = ftello(glob->stream); + Ebml_StartSubElement(glob, &glob->startCluster, Cluster); //cluster + Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode); + + /* Save a cue point if this is a keyframe. */ + if(is_keyframe) + { + struct cue_entry *cue, *new_cue_list; + + new_cue_list = realloc(glob->cue_list, + (glob->cues+1) * sizeof(struct cue_entry)); + if(new_cue_list) + glob->cue_list = new_cue_list; + else + fatal("Failed to realloc cue list."); + + cue = &glob->cue_list[glob->cues]; + cue->time = glob->cluster_timecode; + cue->loc = glob->cluster_pos; + glob->cues++; + } + } + + /* Write the Simple Block */ + Ebml_WriteID(glob, SimpleBlock); + + block_length = pkt->data.frame.sz + 4; + block_length |= 0x10000000; + Ebml_Serialize(glob, &block_length, sizeof(block_length), 4); + + track_number = 1; + track_number |= 0x80; + Ebml_Write(glob, &track_number, 1); + + Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2); + + flags = 0; + if(is_keyframe) + flags |= 0x80; + if(pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) + flags |= 0x08; + Ebml_Write(glob, &flags, 1); + + Ebml_Write(glob, pkt->data.frame.buf, pkt->data.frame.sz); +} + + +static void +write_webm_file_footer(EbmlGlobal *glob, long hash) +{ + + if(glob->cluster_open) + Ebml_EndSubElement(glob, &glob->startCluster); + + { + EbmlLoc start; + unsigned int i; + + glob->cue_pos = ftello(glob->stream); + Ebml_StartSubElement(glob, &start, Cues); + for(i=0; icues; i++) + { + struct cue_entry *cue = &glob->cue_list[i]; + EbmlLoc start; + + Ebml_StartSubElement(glob, &start, CuePoint); + { + EbmlLoc start; + + Ebml_SerializeUnsigned(glob, CueTime, cue->time); + + Ebml_StartSubElement(glob, &start, CueTrackPositions); + Ebml_SerializeUnsigned(glob, CueTrack, 1); + Ebml_SerializeUnsigned64(glob, CueClusterPosition, + cue->loc - glob->position_reference); + //Ebml_SerializeUnsigned(glob, CueBlockNumber, cue->blockNumber); + Ebml_EndSubElement(glob, &start); + } + Ebml_EndSubElement(glob, &start); + } + Ebml_EndSubElement(glob, &start); + } + + Ebml_EndSubElement(glob, &glob->startSegment); + + /* Patch up the seek info block */ + write_webm_seek_info(glob); + + /* Patch up the track id */ + fseeko(glob->stream, glob->track_id_pos, SEEK_SET); + Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash); + + fseeko(glob->stream, 0, SEEK_END); +} + + +/* Murmur hash derived from public domain reference implementation at + * http://sites.google.com/site/murmurhash/ + */ +static unsigned int murmur ( const void * key, int len, unsigned int seed ) +{ + const unsigned int m = 0x5bd1e995; + const int r = 24; + + unsigned int h = seed ^ len; + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + unsigned int k; + + k = data[0]; + k |= data[1] << 8; + k |= data[2] << 16; + k |= data[3] << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +#include "math.h" + +static double vp8_mse2psnr(double Samples, double Peak, double Mse) +{ + double psnr; + + if ((double)Mse > 0.0) + psnr = 10.0 * log10(Peak * Peak * Samples / Mse); + else + psnr = 60; // Limit to prevent / 0 + + if (psnr > 60) + psnr = 60; + + return psnr; +} + + +#include "args.h" +static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, + "Debug mode (makes output deterministic)"); +static const arg_def_t outputfile = ARG_DEF("o", "output", 1, + "Output filename"); +static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, + "Input file is YV12 "); +static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, + "Input file is I420 (default)"); +static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, + "Codec to use"); +static const arg_def_t passes = ARG_DEF("p", "passes", 1, + "Number of passes (1/2)"); +static const arg_def_t pass_arg = ARG_DEF(NULL, "pass", 1, + "Pass to execute (1/2)"); +static const arg_def_t fpf_name = ARG_DEF(NULL, "fpf", 1, + "First pass statistics file name"); +static const arg_def_t limit = ARG_DEF(NULL, "limit", 1, + "Stop encoding after n input frames"); +static const arg_def_t deadline = ARG_DEF("d", "deadline", 1, + "Deadline per frame (usec)"); +static const arg_def_t best_dl = ARG_DEF(NULL, "best", 0, + "Use Best Quality Deadline"); +static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, + "Use Good Quality Deadline"); +static const arg_def_t rt_dl = ARG_DEF(NULL, "rt", 0, + "Use Realtime Quality Deadline"); +static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, + "Show encoder parameters"); +static const arg_def_t psnrarg = ARG_DEF(NULL, "psnr", 0, + "Show PSNR in status line"); +static const arg_def_t framerate = ARG_DEF(NULL, "fps", 1, + "Stream frame rate (rate/scale)"); +static const arg_def_t use_ivf = ARG_DEF(NULL, "ivf", 0, + "Output IVF (default is WebM)"); +static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0, + "Makes encoder output partitions. Requires IVF output!"); +static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, + "Show quantizer histogram (n-buckets)"); +static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, + "Show rate histogram (n-buckets)"); +static const arg_def_t *main_args[] = +{ + &debugmode, + &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &deadline, + &best_dl, &good_dl, &rt_dl, + &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, &rate_hist_n, + NULL +}; + +static const arg_def_t usage = ARG_DEF("u", "usage", 1, + "Usage profile number to use"); +static const arg_def_t threads = ARG_DEF("t", "threads", 1, + "Max number of threads to use"); +static const arg_def_t profile = ARG_DEF(NULL, "profile", 1, + "Bitstream profile number to use"); +static const arg_def_t width = ARG_DEF("w", "width", 1, + "Frame width"); +static const arg_def_t height = ARG_DEF("h", "height", 1, + "Frame height"); +static const struct arg_enum_list stereo_mode_enum[] = { + {"mono" , STEREO_FORMAT_MONO}, + {"left-right", STEREO_FORMAT_LEFT_RIGHT}, + {"bottom-top", STEREO_FORMAT_BOTTOM_TOP}, + {"top-bottom", STEREO_FORMAT_TOP_BOTTOM}, + {"right-left", STEREO_FORMAT_RIGHT_LEFT}, + {NULL, 0} +}; +static const arg_def_t stereo_mode = ARG_DEF_ENUM(NULL, "stereo-mode", 1, + "Stereo 3D video format", stereo_mode_enum); +static const arg_def_t timebase = ARG_DEF(NULL, "timebase", 1, + "Output timestamp precision (fractional seconds)"); +static const arg_def_t error_resilient = ARG_DEF(NULL, "error-resilient", 1, + "Enable error resiliency features"); +static const arg_def_t lag_in_frames = ARG_DEF(NULL, "lag-in-frames", 1, + "Max number of frames to lag"); + +static const arg_def_t *global_args[] = +{ + &use_yv12, &use_i420, &usage, &threads, &profile, + &width, &height, &stereo_mode, &timebase, &framerate, &error_resilient, + &lag_in_frames, NULL +}; + +static const arg_def_t dropframe_thresh = ARG_DEF(NULL, "drop-frame", 1, + "Temporal resampling threshold (buf %)"); +static const arg_def_t resize_allowed = ARG_DEF(NULL, "resize-allowed", 1, + "Spatial resampling enabled (bool)"); +static const arg_def_t resize_up_thresh = ARG_DEF(NULL, "resize-up", 1, + "Upscale threshold (buf %)"); +static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1, + "Downscale threshold (buf %)"); +static const struct arg_enum_list end_usage_enum[] = { + {"vbr", VPX_VBR}, + {"cbr", VPX_CBR}, + {"cq", VPX_CQ}, + {NULL, 0} +}; +static const arg_def_t end_usage = ARG_DEF_ENUM(NULL, "end-usage", 1, + "Rate control mode", end_usage_enum); +static const arg_def_t target_bitrate = ARG_DEF(NULL, "target-bitrate", 1, + "Bitrate (kbps)"); +static const arg_def_t min_quantizer = ARG_DEF(NULL, "min-q", 1, + "Minimum (best) quantizer"); +static const arg_def_t max_quantizer = ARG_DEF(NULL, "max-q", 1, + "Maximum (worst) quantizer"); +static const arg_def_t undershoot_pct = ARG_DEF(NULL, "undershoot-pct", 1, + "Datarate undershoot (min) target (%)"); +static const arg_def_t overshoot_pct = ARG_DEF(NULL, "overshoot-pct", 1, + "Datarate overshoot (max) target (%)"); +static const arg_def_t buf_sz = ARG_DEF(NULL, "buf-sz", 1, + "Client buffer size (ms)"); +static const arg_def_t buf_initial_sz = ARG_DEF(NULL, "buf-initial-sz", 1, + "Client initial buffer size (ms)"); +static const arg_def_t buf_optimal_sz = ARG_DEF(NULL, "buf-optimal-sz", 1, + "Client optimal buffer size (ms)"); +static const arg_def_t *rc_args[] = +{ + &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh, + &end_usage, &target_bitrate, &min_quantizer, &max_quantizer, + &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz, + NULL +}; + + +static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1, + "CBR/VBR bias (0=CBR, 100=VBR)"); +static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1, + "GOP min bitrate (% of target)"); +static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1, + "GOP max bitrate (% of target)"); +static const arg_def_t *rc_twopass_args[] = +{ + &bias_pct, &minsection_pct, &maxsection_pct, NULL +}; + + +static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1, + "Minimum keyframe interval (frames)"); +static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1, + "Maximum keyframe interval (frames)"); +static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0, + "Disable keyframe placement"); +static const arg_def_t *kf_args[] = +{ + &kf_min_dist, &kf_max_dist, &kf_disabled, NULL +}; + + +#if CONFIG_VP8_ENCODER +static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1, + "Noise sensitivity (frames to blur)"); +static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1, + "Filter sharpness (0-7)"); +static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1, + "Motion detection threshold"); +#endif + +#if CONFIG_VP8_ENCODER +static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1, + "CPU Used (-16..16)"); +#endif + + +#if CONFIG_VP8_ENCODER +static const arg_def_t token_parts = ARG_DEF(NULL, "token-parts", 1, + "Number of token partitions to use, log2"); +static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1, + "Enable automatic alt reference frames"); +static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1, + "AltRef Max Frames"); +static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1, + "AltRef Strength"); +static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1, + "AltRef Type"); +static const struct arg_enum_list tuning_enum[] = { + {"psnr", VP8_TUNE_PSNR}, + {"ssim", VP8_TUNE_SSIM}, + {NULL, 0} +}; +static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1, + "Material to favor", tuning_enum); +static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1, + "Constrained Quality Level"); +static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, + "Max I-frame bitrate (pct)"); + +static const arg_def_t *vp8_args[] = +{ + &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, + &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type, + &tune_ssim, &cq_level, &max_intra_rate_pct, NULL +}; +static const int vp8_arg_ctrl_map[] = +{ + VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, + VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, + VP8E_SET_TOKEN_PARTITIONS, + VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH , VP8E_SET_ARNR_TYPE, + VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, 0 +}; +#endif + +static const arg_def_t *no_args[] = { NULL }; + +static void usage_exit() +{ + int i; + + fprintf(stderr, "Usage: %s -o dst_filename src_filename \n", + exec_name); + + fprintf(stderr, "\nOptions:\n"); + arg_show_usage(stdout, main_args); + fprintf(stderr, "\nEncoder Global Options:\n"); + arg_show_usage(stdout, global_args); + fprintf(stderr, "\nRate Control Options:\n"); + arg_show_usage(stdout, rc_args); + fprintf(stderr, "\nTwopass Rate Control Options:\n"); + arg_show_usage(stdout, rc_twopass_args); + fprintf(stderr, "\nKeyframe Placement Options:\n"); + arg_show_usage(stdout, kf_args); +#if CONFIG_VP8_ENCODER + fprintf(stderr, "\nVP8 Specific Options:\n"); + arg_show_usage(stdout, vp8_args); +#endif + fprintf(stderr, "\nStream timebase (--timebase):\n" + " The desired precision of timestamps in the output, expressed\n" + " in fractional seconds. Default is 1/1000.\n"); + fprintf(stderr, "\n" + "Included encoders:\n" + "\n"); + + for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++) + fprintf(stderr, " %-6s - %s\n", + codecs[i].name, + vpx_codec_iface_name(codecs[i].iface)); + + exit(EXIT_FAILURE); +} + + +#define HIST_BAR_MAX 40 +struct hist_bucket +{ + int low, high, count; +}; + + +static int merge_hist_buckets(struct hist_bucket *bucket, + int *buckets_, + int max_buckets) +{ + int small_bucket = 0, merge_bucket = INT_MAX, big_bucket=0; + int buckets = *buckets_; + int i; + + /* Find the extrema for this list of buckets */ + big_bucket = small_bucket = 0; + for(i=0; i < buckets; i++) + { + if(bucket[i].count < bucket[small_bucket].count) + small_bucket = i; + if(bucket[i].count > bucket[big_bucket].count) + big_bucket = i; + } + + /* If we have too many buckets, merge the smallest with an adjacent + * bucket. + */ + while(buckets > max_buckets) + { + int last_bucket = buckets - 1; + + // merge the small bucket with an adjacent one. + if(small_bucket == 0) + merge_bucket = 1; + else if(small_bucket == last_bucket) + merge_bucket = last_bucket - 1; + else if(bucket[small_bucket - 1].count < bucket[small_bucket + 1].count) + merge_bucket = small_bucket - 1; + else + merge_bucket = small_bucket + 1; + + assert(abs(merge_bucket - small_bucket) <= 1); + assert(small_bucket < buckets); + assert(big_bucket < buckets); + assert(merge_bucket < buckets); + + if(merge_bucket < small_bucket) + { + bucket[merge_bucket].high = bucket[small_bucket].high; + bucket[merge_bucket].count += bucket[small_bucket].count; + } + else + { + bucket[small_bucket].high = bucket[merge_bucket].high; + bucket[small_bucket].count += bucket[merge_bucket].count; + merge_bucket = small_bucket; + } + + assert(bucket[merge_bucket].low != bucket[merge_bucket].high); + + buckets--; + + /* Remove the merge_bucket from the list, and find the new small + * and big buckets while we're at it + */ + big_bucket = small_bucket = 0; + for(i=0; i < buckets; i++) + { + if(i > merge_bucket) + bucket[i] = bucket[i+1]; + + if(bucket[i].count < bucket[small_bucket].count) + small_bucket = i; + if(bucket[i].count > bucket[big_bucket].count) + big_bucket = i; + } + + } + + *buckets_ = buckets; + return bucket[big_bucket].count; +} + + +static void show_histogram(const struct hist_bucket *bucket, + int buckets, + int total, + int scale) +{ + const char *pat1, *pat2; + int i; + + switch((int)(log(bucket[buckets-1].high)/log(10))+1) + { + case 1: + case 2: + pat1 = "%4d %2s: "; + pat2 = "%4d-%2d: "; + break; + case 3: + pat1 = "%5d %3s: "; + pat2 = "%5d-%3d: "; + break; + case 4: + pat1 = "%6d %4s: "; + pat2 = "%6d-%4d: "; + break; + case 5: + pat1 = "%7d %5s: "; + pat2 = "%7d-%5d: "; + break; + case 6: + pat1 = "%8d %6s: "; + pat2 = "%8d-%6d: "; + break; + case 7: + pat1 = "%9d %7s: "; + pat2 = "%9d-%7d: "; + break; + default: + pat1 = "%12d %10s: "; + pat2 = "%12d-%10d: "; + break; + } + + for(i=0; isamples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000; + + // prevent division by zero + if (hist->samples == 0) + hist->samples=1; + + hist->pts = calloc(hist->samples, sizeof(*hist->pts)); + hist->sz = calloc(hist->samples, sizeof(*hist->sz)); + for(i=0; ibucket[i].low = INT_MAX; + hist->bucket[i].high = 0; + hist->bucket[i].count = 0; + } +} + + +static void destroy_rate_histogram(struct rate_hist *hist) +{ + free(hist->pts); + free(hist->sz); +} + + +static void update_rate_histogram(struct rate_hist *hist, + const vpx_codec_enc_cfg_t *cfg, + const vpx_codec_cx_pkt_t *pkt) +{ + int i, idx; + int64_t now, then, sum_sz = 0, avg_bitrate; + + now = pkt->data.frame.pts * 1000 + * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; + + idx = hist->frames++ % hist->samples; + hist->pts[idx] = now; + hist->sz[idx] = pkt->data.frame.sz; + + if(now < cfg->rc_buf_initial_sz) + return; + + then = now; + + /* Sum the size over the past rc_buf_sz ms */ + for(i = hist->frames; i > 0 && hist->frames - i < hist->samples; i--) + { + int i_idx = (i-1) % hist->samples; + + then = hist->pts[i_idx]; + if(now - then > cfg->rc_buf_sz) + break; + sum_sz += hist->sz[i_idx]; + } + + if (now == then) + return; + + avg_bitrate = sum_sz * 8 * 1000 / (now - then); + idx = avg_bitrate * (RATE_BINS/2) / (cfg->rc_target_bitrate * 1000); + if(idx < 0) + idx = 0; + if(idx > RATE_BINS-1) + idx = RATE_BINS-1; + if(hist->bucket[idx].low > avg_bitrate) + hist->bucket[idx].low = avg_bitrate; + if(hist->bucket[idx].high < avg_bitrate) + hist->bucket[idx].high = avg_bitrate; + hist->bucket[idx].count++; + hist->total++; +} + + +static void show_rate_histogram(struct rate_hist *hist, + const vpx_codec_enc_cfg_t *cfg, + int max_buckets) +{ + int i, scale; + int buckets = 0; + + for(i = 0; i < RATE_BINS; i++) + { + if(hist->bucket[i].low == INT_MAX) + continue; + hist->bucket[buckets++] = hist->bucket[i]; + } + + fprintf(stderr, "\nRate (over %dms window):\n", cfg->rc_buf_sz); + scale = merge_hist_buckets(hist->bucket, &buckets, max_buckets); + show_histogram(hist->bucket, buckets, hist->total, scale); +} + +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) +#define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map) + + +/* Configuration elements common to all streams */ +struct global_config +{ + const struct codec_item *codec; + int passes; + int pass; + int usage; + int deadline; + int use_i420; + int verbose; + int limit; + int show_psnr; + int have_framerate; + struct vpx_rational framerate; + int out_part; + int debug; + int show_q_hist_buckets; + int show_rate_hist_buckets; +}; + + +/* Per-stream configuration */ +struct stream_config +{ + struct vpx_codec_enc_cfg cfg; + const char *out_fn; + const char *stats_fn; + stereo_format_t stereo_fmt; + int arg_ctrls[ARG_CTRL_CNT_MAX][2]; + int arg_ctrl_cnt; + int write_webm; + int have_kf_max_dist; +}; + + +struct stream_state +{ + int index; + struct stream_state *next; + struct stream_config config; + FILE *file; + struct rate_hist rate_hist; + EbmlGlobal ebml; + uint32_t hash; + uint64_t psnr_sse_total; + uint64_t psnr_samples_total; + double psnr_totals[4]; + int psnr_count; + int counts[64]; + vpx_codec_ctx_t encoder; + unsigned int frames_out; + uint64_t cx_time; + size_t nbytes; + stats_io_t stats; +}; + + +void validate_positive_rational(const char *msg, + struct vpx_rational *rat) +{ + if (rat->den < 0) + { + rat->num *= -1; + rat->den *= -1; + } + + if (rat->num < 0) + die("Error: %s must be positive\n", msg); + + if (!rat->den) + die("Error: %s has zero denominator\n", msg); +} + + +static void parse_global_config(struct global_config *global, char **argv) +{ + char **argi, **argj; + struct arg arg; + + /* Initialize default parameters */ + memset(global, 0, sizeof(*global)); + global->codec = codecs; + global->passes = 1; + global->use_i420 = 1; + + for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) + { + arg.argv_step = 1; + + if (arg_match(&arg, &codecarg, argi)) + { + int j, k = -1; + + for (j = 0; j < sizeof(codecs) / sizeof(codecs[0]); j++) + if (!strcmp(codecs[j].name, arg.val)) + k = j; + + if (k >= 0) + global->codec = codecs + k; + else + die("Error: Unrecognized argument (%s) to --codec\n", + arg.val); + + } + else if (arg_match(&arg, &passes, argi)) + { + global->passes = arg_parse_uint(&arg); + + if (global->passes < 1 || global->passes > 2) + die("Error: Invalid number of passes (%d)\n", global->passes); + } + else if (arg_match(&arg, &pass_arg, argi)) + { + global->pass = arg_parse_uint(&arg); + + if (global->pass < 1 || global->pass > 2) + die("Error: Invalid pass selected (%d)\n", + global->pass); + } + else if (arg_match(&arg, &usage, argi)) + global->usage = arg_parse_uint(&arg); + else if (arg_match(&arg, &deadline, argi)) + global->deadline = arg_parse_uint(&arg); + else if (arg_match(&arg, &best_dl, argi)) + global->deadline = VPX_DL_BEST_QUALITY; + else if (arg_match(&arg, &good_dl, argi)) + global->deadline = VPX_DL_GOOD_QUALITY; + else if (arg_match(&arg, &rt_dl, argi)) + global->deadline = VPX_DL_REALTIME; + else if (arg_match(&arg, &use_yv12, argi)) + global->use_i420 = 0; + else if (arg_match(&arg, &use_i420, argi)) + global->use_i420 = 1; + else if (arg_match(&arg, &verbosearg, argi)) + global->verbose = 1; + else if (arg_match(&arg, &limit, argi)) + global->limit = arg_parse_uint(&arg); + else if (arg_match(&arg, &psnrarg, argi)) + global->show_psnr = 1; + else if (arg_match(&arg, &framerate, argi)) + { + global->framerate = arg_parse_rational(&arg); + validate_positive_rational(arg.name, &global->framerate); + global->have_framerate = 1; + } + else if (arg_match(&arg,&out_part, argi)) + global->out_part = 1; + else if (arg_match(&arg, &debugmode, argi)) + global->debug = 1; + else if (arg_match(&arg, &q_hist_n, argi)) + global->show_q_hist_buckets = arg_parse_uint(&arg); + else if (arg_match(&arg, &rate_hist_n, argi)) + global->show_rate_hist_buckets = arg_parse_uint(&arg); + else + argj++; + } + + /* Validate global config */ + + if (global->pass) + { + /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ + if (global->pass > global->passes) + { + warn("Assuming --pass=%d implies --passes=%d\n", + global->pass, global->pass); + global->passes = global->pass; + } + } +} + + +void open_input_file(struct input_state *input) +{ + unsigned int fourcc; + + /* Parse certain options from the input file, if possible */ + input->file = strcmp(input->fn, "-") ? fopen(input->fn, "rb") + : set_binary_mode(stdin); + + if (!input->file) + fatal("Failed to open input file"); + + /* For RAW input sources, these bytes will applied on the first frame + * in read_frame(). + */ + input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file); + input->detect.position = 0; + + if (input->detect.buf_read == 4 + && file_is_y4m(input->file, &input->y4m, input->detect.buf)) + { + if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4) >= 0) + { + input->file_type = FILE_TYPE_Y4M; + input->w = input->y4m.pic_w; + input->h = input->y4m.pic_h; + input->framerate.num = input->y4m.fps_n; + input->framerate.den = input->y4m.fps_d; + input->use_i420 = 0; + } + else + fatal("Unsupported Y4M stream."); + } + else if (input->detect.buf_read == 4 && file_is_ivf(input, &fourcc)) + { + input->file_type = FILE_TYPE_IVF; + switch (fourcc) + { + case 0x32315659: + input->use_i420 = 0; + break; + case 0x30323449: + input->use_i420 = 1; + break; + default: + fatal("Unsupported fourcc (%08x) in IVF", fourcc); + } + } + else + { + input->file_type = FILE_TYPE_RAW; + } +} + + +static void close_input_file(struct input_state *input) +{ + fclose(input->file); + if (input->file_type == FILE_TYPE_Y4M) + y4m_input_close(&input->y4m); +} + +static struct stream_state *new_stream(struct global_config *global, + struct stream_state *prev) +{ + struct stream_state *stream; + + stream = calloc(1, sizeof(*stream)); + if(!stream) + fatal("Failed to allocate new stream."); + if(prev) + { + memcpy(stream, prev, sizeof(*stream)); + stream->index++; + prev->next = stream; + } + else + { + vpx_codec_err_t res; + + /* Populate encoder configuration */ + res = vpx_codec_enc_config_default(global->codec->iface, + &stream->config.cfg, + global->usage); + if (res) + fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res)); + + /* Change the default timebase to a high enough value so that the + * encoder will always create strictly increasing timestamps. + */ + stream->config.cfg.g_timebase.den = 1000; + + /* Never use the library's default resolution, require it be parsed + * from the file or set on the command line. + */ + stream->config.cfg.g_w = 0; + stream->config.cfg.g_h = 0; + + /* Initialize remaining stream parameters */ + stream->config.stereo_fmt = STEREO_FORMAT_MONO; + stream->config.write_webm = 1; + stream->ebml.last_pts_ms = -1; + + /* Allows removal of the application version from the EBML tags */ + stream->ebml.debug = global->debug; + } + + /* Output files must be specified for each stream */ + stream->config.out_fn = NULL; + + stream->next = NULL; + return stream; +} + + +static int parse_stream_params(struct global_config *global, + struct stream_state *stream, + char **argv) +{ + char **argi, **argj; + struct arg arg; + static const arg_def_t **ctrl_args = no_args; + static const int *ctrl_args_map = NULL; + struct stream_config *config = &stream->config; + int eos_mark_found = 0; + + /* Handle codec specific options */ + if (global->codec->iface == &vpx_codec_vp8_cx_algo) + { + ctrl_args = vp8_args; + ctrl_args_map = vp8_arg_ctrl_map; + } + + for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) + { + arg.argv_step = 1; + + /* Once we've found an end-of-stream marker (--) we want to continue + * shifting arguments but not consuming them. + */ + if (eos_mark_found) + { + argj++; + continue; + } + else if (!strcmp(*argj, "--")) + { + eos_mark_found = 1; + continue; + } + + if (0); + else if (arg_match(&arg, &outputfile, argi)) + config->out_fn = arg.val; + else if (arg_match(&arg, &fpf_name, argi)) + config->stats_fn = arg.val; + else if (arg_match(&arg, &use_ivf, argi)) + config->write_webm = 0; + else if (arg_match(&arg, &threads, argi)) + config->cfg.g_threads = arg_parse_uint(&arg); + else if (arg_match(&arg, &profile, argi)) + config->cfg.g_profile = arg_parse_uint(&arg); + else if (arg_match(&arg, &width, argi)) + config->cfg.g_w = arg_parse_uint(&arg); + else if (arg_match(&arg, &height, argi)) + config->cfg.g_h = arg_parse_uint(&arg); + else if (arg_match(&arg, &stereo_mode, argi)) + config->stereo_fmt = arg_parse_enum_or_int(&arg); + else if (arg_match(&arg, &timebase, argi)) + { + config->cfg.g_timebase = arg_parse_rational(&arg); + validate_positive_rational(arg.name, &config->cfg.g_timebase); + } + else if (arg_match(&arg, &error_resilient, argi)) + config->cfg.g_error_resilient = arg_parse_uint(&arg); + else if (arg_match(&arg, &lag_in_frames, argi)) + config->cfg.g_lag_in_frames = arg_parse_uint(&arg); + else if (arg_match(&arg, &dropframe_thresh, argi)) + config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg); + else if (arg_match(&arg, &resize_allowed, argi)) + config->cfg.rc_resize_allowed = arg_parse_uint(&arg); + else if (arg_match(&arg, &resize_up_thresh, argi)) + config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg); + else if (arg_match(&arg, &resize_down_thresh, argi)) + config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg); + else if (arg_match(&arg, &end_usage, argi)) + config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); + else if (arg_match(&arg, &target_bitrate, argi)) + config->cfg.rc_target_bitrate = arg_parse_uint(&arg); + else if (arg_match(&arg, &min_quantizer, argi)) + config->cfg.rc_min_quantizer = arg_parse_uint(&arg); + else if (arg_match(&arg, &max_quantizer, argi)) + config->cfg.rc_max_quantizer = arg_parse_uint(&arg); + else if (arg_match(&arg, &undershoot_pct, argi)) + config->cfg.rc_undershoot_pct = arg_parse_uint(&arg); + else if (arg_match(&arg, &overshoot_pct, argi)) + config->cfg.rc_overshoot_pct = arg_parse_uint(&arg); + else if (arg_match(&arg, &buf_sz, argi)) + config->cfg.rc_buf_sz = arg_parse_uint(&arg); + else if (arg_match(&arg, &buf_initial_sz, argi)) + config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg); + else if (arg_match(&arg, &buf_optimal_sz, argi)) + config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg); + else if (arg_match(&arg, &bias_pct, argi)) + { + config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); + + if (global->passes < 2) + warn("option %s ignored in one-pass mode.\n", arg.name); + } + else if (arg_match(&arg, &minsection_pct, argi)) + { + config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); + + if (global->passes < 2) + warn("option %s ignored in one-pass mode.\n", arg.name); + } + else if (arg_match(&arg, &maxsection_pct, argi)) + { + config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); + + if (global->passes < 2) + warn("option %s ignored in one-pass mode.\n", arg.name); + } + else if (arg_match(&arg, &kf_min_dist, argi)) + config->cfg.kf_min_dist = arg_parse_uint(&arg); + else if (arg_match(&arg, &kf_max_dist, argi)) + { + config->cfg.kf_max_dist = arg_parse_uint(&arg); + config->have_kf_max_dist = 1; + } + else if (arg_match(&arg, &kf_disabled, argi)) + config->cfg.kf_mode = VPX_KF_DISABLED; + else + { + int i, match = 0; + + for (i = 0; ctrl_args[i]; i++) + { + if (arg_match(&arg, ctrl_args[i], argi)) + { + int j; + match = 1; + + /* Point either to the next free element or the first + * instance of this control. + */ + for(j=0; jarg_ctrl_cnt; j++) + if(config->arg_ctrls[j][0] == ctrl_args_map[i]) + break; + + /* Update/insert */ + assert(j < ARG_CTRL_CNT_MAX); + if (j < ARG_CTRL_CNT_MAX) + { + config->arg_ctrls[j][0] = ctrl_args_map[i]; + config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg); + if(j == config->arg_ctrl_cnt) + config->arg_ctrl_cnt++; + } + + } + } + + if (!match) + argj++; + } + } + + return eos_mark_found; +} + + +#define FOREACH_STREAM(func)\ +do\ +{\ + struct stream_state *stream;\ +\ + for(stream = streams; stream; stream = stream->next)\ + func;\ +}while(0) + + +static void validate_stream_config(struct stream_state *stream) +{ + struct stream_state *streami; + + if(!stream->config.cfg.g_w || !stream->config.cfg.g_h) + fatal("Stream %d: Specify stream dimensions with --width (-w) " + " and --height (-h)", stream->index); + + for(streami = stream; streami; streami = streami->next) + { + /* All streams require output files */ + if(!streami->config.out_fn) + fatal("Stream %d: Output file is required (specify with -o)", + streami->index); + + /* Check for two streams outputting to the same file */ + if(streami != stream) + { + const char *a = stream->config.out_fn; + const char *b = streami->config.out_fn; + if(!strcmp(a,b) && strcmp(a, "/dev/null") && strcmp(a, ":nul")) + fatal("Stream %d: duplicate output file (from stream %d)", + streami->index, stream->index); + } + + /* Check for two streams sharing a stats file. */ + if(streami != stream) + { + const char *a = stream->config.stats_fn; + const char *b = streami->config.stats_fn; + if(a && b && !strcmp(a,b)) + fatal("Stream %d: duplicate stats file (from stream %d)", + streami->index, stream->index); + } + } +} + + +static void set_stream_dimensions(struct stream_state *stream, + unsigned int w, + unsigned int h) +{ + if ((stream->config.cfg.g_w && stream->config.cfg.g_w != w) + ||(stream->config.cfg.g_h && stream->config.cfg.g_h != h)) + fatal("Stream %d: Resizing not yet supported", stream->index); + stream->config.cfg.g_w = w; + stream->config.cfg.g_h = h; +} + + +static void set_default_kf_interval(struct stream_state *stream, + struct global_config *global) +{ + /* Use a max keyframe interval of 5 seconds, if none was + * specified on the command line. + */ + if (!stream->config.have_kf_max_dist) + { + double framerate = (double)global->framerate.num/global->framerate.den; + if (framerate > 0.0) + stream->config.cfg.kf_max_dist = 5.0*framerate; + } +} + + +static void show_stream_config(struct stream_state *stream, + struct global_config *global, + struct input_state *input) +{ + +#define SHOW(field) \ + fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) + + if(stream->index == 0) + { + fprintf(stderr, "Codec: %s\n", + vpx_codec_iface_name(global->codec->iface)); + fprintf(stderr, "Source file: %s Format: %s\n", input->fn, + input->use_i420 ? "I420" : "YV12"); + } + if(stream->next || stream->index) + fprintf(stderr, "\nStream Index: %d\n", stream->index); + fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); + fprintf(stderr, "Encoder parameters:\n"); + + SHOW(g_usage); + SHOW(g_threads); + SHOW(g_profile); + SHOW(g_w); + SHOW(g_h); + SHOW(g_timebase.num); + SHOW(g_timebase.den); + SHOW(g_error_resilient); + SHOW(g_pass); + SHOW(g_lag_in_frames); + SHOW(rc_dropframe_thresh); + SHOW(rc_resize_allowed); + SHOW(rc_resize_up_thresh); + SHOW(rc_resize_down_thresh); + SHOW(rc_end_usage); + SHOW(rc_target_bitrate); + SHOW(rc_min_quantizer); + SHOW(rc_max_quantizer); + SHOW(rc_undershoot_pct); + SHOW(rc_overshoot_pct); + SHOW(rc_buf_sz); + SHOW(rc_buf_initial_sz); + SHOW(rc_buf_optimal_sz); + SHOW(rc_2pass_vbr_bias_pct); + SHOW(rc_2pass_vbr_minsection_pct); + SHOW(rc_2pass_vbr_maxsection_pct); + SHOW(kf_mode); + SHOW(kf_min_dist); + SHOW(kf_max_dist); +} + + +static void open_output_file(struct stream_state *stream, + struct global_config *global) +{ + const char *fn = stream->config.out_fn; + + stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout); + + if (!stream->file) + fatal("Failed to open output file"); + + if(stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR)) + fatal("WebM output to pipes not supported."); + + if(stream->config.write_webm) + { + stream->ebml.stream = stream->file; + write_webm_file_header(&stream->ebml, &stream->config.cfg, + &global->framerate, + stream->config.stereo_fmt); + } + else + write_ivf_file_header(stream->file, &stream->config.cfg, + global->codec->fourcc, 0); +} + + +static void close_output_file(struct stream_state *stream, + unsigned int fourcc) +{ + if(stream->config.write_webm) + { + write_webm_file_footer(&stream->ebml, stream->hash); + free(stream->ebml.cue_list); + stream->ebml.cue_list = NULL; + } + else + { + if (!fseek(stream->file, 0, SEEK_SET)) + write_ivf_file_header(stream->file, &stream->config.cfg, + fourcc, + stream->frames_out); + } + + fclose(stream->file); +} + + +static void setup_pass(struct stream_state *stream, + struct global_config *global, + int pass) +{ + if (stream->config.stats_fn) + { + if (!stats_open_file(&stream->stats, stream->config.stats_fn, + pass)) + fatal("Failed to open statistics store"); + } + else + { + if (!stats_open_mem(&stream->stats, pass)) + fatal("Failed to open statistics store"); + } + + stream->config.cfg.g_pass = global->passes == 2 + ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS + : VPX_RC_ONE_PASS; + if (pass) + stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); + + stream->cx_time = 0; + stream->nbytes = 0; + stream->frames_out = 0; +} + + +static void initialize_encoder(struct stream_state *stream, + struct global_config *global) +{ + int i; + int flags = 0; + + flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; + flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; + + /* Construct Encoder Context */ + vpx_codec_enc_init(&stream->encoder, global->codec->iface, + &stream->config.cfg, flags); + ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); + + /* Note that we bypass the vpx_codec_control wrapper macro because + * we're being clever to store the control IDs in an array. Real + * applications will want to make use of the enumerations directly + */ + for (i = 0; i < stream->config.arg_ctrl_cnt; i++) + { + int ctrl = stream->config.arg_ctrls[i][0]; + int value = stream->config.arg_ctrls[i][1]; + if (vpx_codec_control_(&stream->encoder, ctrl, value)) + fprintf(stderr, "Error: Tried to set control %d = %d\n", + ctrl, value); + + ctx_exit_on_error(&stream->encoder, "Failed to control codec"); + } +} + + +static void encode_frame(struct stream_state *stream, + struct global_config *global, + struct vpx_image *img, + unsigned int frames_in) +{ + vpx_codec_pts_t frame_start, next_frame_start; + struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; + struct vpx_usec_timer timer; + + frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1) + * global->framerate.den) + / cfg->g_timebase.num / global->framerate.num; + next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in) + * global->framerate.den) + / cfg->g_timebase.num / global->framerate.num; + vpx_usec_timer_start(&timer); + vpx_codec_encode(&stream->encoder, img, frame_start, + next_frame_start - frame_start, + 0, global->deadline); + vpx_usec_timer_mark(&timer); + stream->cx_time += vpx_usec_timer_elapsed(&timer); + ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame", + stream->index); +} + + +static void update_quantizer_histogram(struct stream_state *stream) +{ + if(stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) + { + int q; + + vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q); + ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); + stream->counts[q]++; + } +} + + +static void get_cx_data(struct stream_state *stream, + struct global_config *global, + int *got_data) +{ + const vpx_codec_cx_pkt_t *pkt; + const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; + vpx_codec_iter_t iter = NULL; + + while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) + { + static size_t fsize = 0; + static off_t ivf_header_pos = 0; + + *got_data = 1; + + switch (pkt->kind) + { + case VPX_CODEC_CX_FRAME_PKT: + if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) + { + stream->frames_out++; + } + fprintf(stderr, " %6luF", + (unsigned long)pkt->data.frame.sz); + + update_rate_histogram(&stream->rate_hist, cfg, pkt); + if(stream->config.write_webm) + { + /* Update the hash */ + if(!stream->ebml.debug) + stream->hash = murmur(pkt->data.frame.buf, + pkt->data.frame.sz, stream->hash); + + write_webm_block(&stream->ebml, cfg, pkt); + } + else + { + if (pkt->data.frame.partition_id <= 0) + { + ivf_header_pos = ftello(stream->file); + fsize = pkt->data.frame.sz; + + write_ivf_frame_header(stream->file, pkt); + } + else + { + fsize += pkt->data.frame.sz; + + if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) + { + off_t currpos = ftello(stream->file); + fseeko(stream->file, ivf_header_pos, SEEK_SET); + write_ivf_frame_size(stream->file, fsize); + fseeko(stream->file, currpos, SEEK_SET); + } + } + + fwrite(pkt->data.frame.buf, 1, + pkt->data.frame.sz, stream->file); + } + stream->nbytes += pkt->data.raw.sz; + break; + case VPX_CODEC_STATS_PKT: + stream->frames_out++; + fprintf(stderr, " %6luS", + (unsigned long)pkt->data.twopass_stats.sz); + stats_write(&stream->stats, + pkt->data.twopass_stats.buf, + pkt->data.twopass_stats.sz); + stream->nbytes += pkt->data.raw.sz; + break; + case VPX_CODEC_PSNR_PKT: + + if (global->show_psnr) + { + int i; + + stream->psnr_sse_total += pkt->data.psnr.sse[0]; + stream->psnr_samples_total += pkt->data.psnr.samples[0]; + for (i = 0; i < 4; i++) + { + fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]); + stream->psnr_totals[i] += pkt->data.psnr.psnr[i]; + } + stream->psnr_count++; + } + + break; + default: + break; + } + } +} + + +static void show_psnr(struct stream_state *stream) +{ + int i; + double ovpsnr; + + if (!stream->psnr_count) + return; + + fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index); + ovpsnr = vp8_mse2psnr(stream->psnr_samples_total, 255.0, + stream->psnr_sse_total); + fprintf(stderr, " %.3lf", ovpsnr); + + for (i = 0; i < 4; i++) + { + fprintf(stderr, " %.3lf", stream->psnr_totals[i]/stream->psnr_count); + } + fprintf(stderr, "\n"); +} + + +float usec_to_fps(uint64_t usec, unsigned int frames) +{ + return usec > 0 ? (float)frames * 1000000.0 / (float)usec : 0; +} + + +int main(int argc, const char **argv_) +{ + int pass; + vpx_image_t raw; + int frame_avail, got_data; + + struct input_state input = {0}; + struct global_config global; + struct stream_state *streams = NULL; + char **argv, **argi; + unsigned long cx_time = 0; + int stream_cnt = 0; + + exec_name = argv_[0]; + + if (argc < 3) + usage_exit(); + + /* Setup default input stream settings */ + input.framerate.num = 30; + input.framerate.den = 1; + input.use_i420 = 1; + + /* First parse the global configuration values, because we want to apply + * other parameters on top of the default configuration provided by the + * codec. + */ + argv = argv_dup(argc - 1, argv_ + 1); + parse_global_config(&global, argv); + + { + /* Now parse each stream's parameters. Using a local scope here + * due to the use of 'stream' as loop variable in FOREACH_STREAM + * loops + */ + struct stream_state *stream = NULL; + + do + { + stream = new_stream(&global, stream); + stream_cnt++; + if(!streams) + streams = stream; + } while(parse_stream_params(&global, stream, argv)); + } + + /* Check for unrecognized options */ + for (argi = argv; *argi; argi++) + if (argi[0][0] == '-' && argi[0][1]) + die("Error: Unrecognized option %s\n", *argi); + + /* Handle non-option arguments */ + input.fn = argv[0]; + + if (!input.fn) + usage_exit(); + + for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) + { + int frames_in = 0; + + open_input_file(&input); + + /* If the input file doesn't specify its w/h (raw files), try to get + * the data from the first stream's configuration. + */ + if(!input.w || !input.h) + FOREACH_STREAM({ + if(stream->config.cfg.g_w && stream->config.cfg.g_h) + { + input.w = stream->config.cfg.g_w; + input.h = stream->config.cfg.g_h; + break; + } + }); + + /* Update stream configurations from the input file's parameters */ + FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h)); + FOREACH_STREAM(validate_stream_config(stream)); + + /* Ensure that --passes and --pass are consistent. If --pass is set and + * --passes=2, ensure --fpf was set. + */ + if (global.pass && global.passes == 2) + FOREACH_STREAM({ + if(!stream->config.stats_fn) + die("Stream %d: Must specify --fpf when --pass=%d" + " and --passes=2\n", stream->index, global.pass); + }); + + + /* Use the frame rate from the file only if none was specified + * on the command-line. + */ + if (!global.have_framerate) + global.framerate = input.framerate; + + FOREACH_STREAM(set_default_kf_interval(stream, &global)); + + /* Show configuration */ + if (global.verbose && pass == 0) + FOREACH_STREAM(show_stream_config(stream, &global, &input)); + + if(pass == (global.pass ? global.pass - 1 : 0)) { + if (input.file_type == FILE_TYPE_Y4M) + /*The Y4M reader does its own allocation. + Just initialize this here to avoid problems if we never read any + frames.*/ + memset(&raw, 0, sizeof(raw)); + else + vpx_img_alloc(&raw, + input.use_i420 ? VPX_IMG_FMT_I420 + : VPX_IMG_FMT_YV12, + input.w, input.h, 1); + + FOREACH_STREAM(init_rate_histogram(&stream->rate_hist, + &stream->config.cfg, + &global.framerate)); + } + + FOREACH_STREAM(open_output_file(stream, &global)); + FOREACH_STREAM(setup_pass(stream, &global, pass)); + FOREACH_STREAM(initialize_encoder(stream, &global)); + + frame_avail = 1; + got_data = 0; + + while (frame_avail || got_data) + { + struct vpx_usec_timer timer; + + if (!global.limit || frames_in < global.limit) + { + frame_avail = read_frame(&input, &raw); + + if (frame_avail) + frames_in++; + + if(stream_cnt == 1) + fprintf(stderr, + "\rPass %d/%d frame %4d/%-4d %7"PRId64"B \033[K", + pass + 1, global.passes, frames_in, + streams->frames_out, (int64_t)streams->nbytes); + else + fprintf(stderr, + "\rPass %d/%d frame %4d %7lu %s (%.2f fps)\033[K", + pass + 1, global.passes, frames_in, + cx_time > 9999999 ? cx_time / 1000 : cx_time, + cx_time > 9999999 ? "ms" : "us", + usec_to_fps(cx_time, frames_in)); + + } + else + frame_avail = 0; + + vpx_usec_timer_start(&timer); + FOREACH_STREAM(encode_frame(stream, &global, + frame_avail ? &raw : NULL, + frames_in)); + vpx_usec_timer_mark(&timer); + cx_time += vpx_usec_timer_elapsed(&timer); + + FOREACH_STREAM(update_quantizer_histogram(stream)); + + got_data = 0; + FOREACH_STREAM(get_cx_data(stream, &global, &got_data)); + + fflush(stdout); + } + + if(stream_cnt > 1) + fprintf(stderr, "\n"); + + FOREACH_STREAM(fprintf( + stderr, + "\rPass %d/%d frame %4d/%-4d %7"PRId64"B %7lub/f %7"PRId64"b/s" + " %7"PRId64" %s (%.2f fps)\033[K\n", pass + 1, + global.passes, frames_in, stream->frames_out, (int64_t)stream->nbytes, + frames_in ? (unsigned long)(stream->nbytes * 8 / frames_in) : 0, + frames_in ? (int64_t)stream->nbytes * 8 + * (int64_t)global.framerate.num / global.framerate.den + / frames_in + : 0, + stream->cx_time > 9999999 ? stream->cx_time / 1000 : stream->cx_time, + stream->cx_time > 9999999 ? "ms" : "us", + usec_to_fps(stream->cx_time, frames_in)); + ); + + if (global.show_psnr) + FOREACH_STREAM(show_psnr(stream)); + + FOREACH_STREAM(vpx_codec_destroy(&stream->encoder)); + + close_input_file(&input); + + FOREACH_STREAM(close_output_file(stream, global.codec->fourcc)); + + FOREACH_STREAM(stats_close(&stream->stats, global.passes-1)); + + if (global.pass) + break; + } + + if (global.show_q_hist_buckets) + FOREACH_STREAM(show_q_histogram(stream->counts, + global.show_q_hist_buckets)); + + if (global.show_rate_hist_buckets) + FOREACH_STREAM(show_rate_histogram(&stream->rate_hist, + &stream->config.cfg, + global.show_rate_hist_buckets)); + FOREACH_STREAM(destroy_rate_histogram(&stream->rate_hist)); + + vpx_img_free(&raw); + free(argv); + free(streams); + return EXIT_SUCCESS; +} diff --git a/y4minput.c b/y4minput.c new file mode 100644 index 0000000..dd51421 --- /dev/null +++ b/y4minput.c @@ -0,0 +1,871 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + * Based on code from the OggTheora software codec source code, + * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors. + */ +#include +#include +#include "y4minput.h" + +static int y4m_parse_tags(y4m_input *_y4m,char *_tags){ + int got_w; + int got_h; + int got_fps; + int got_interlace; + int got_par; + int got_chroma; + char *p; + char *q; + got_w=got_h=got_fps=got_interlace=got_par=got_chroma=0; + for(p=_tags;;p=q){ + /*Skip any leading spaces.*/ + while(*p==' ')p++; + /*If that's all we have, stop.*/ + if(p[0]=='\0')break; + /*Find the end of this tag.*/ + for(q=p+1;*q!='\0'&&*q!=' ';q++); + /*Process the tag.*/ + switch(p[0]){ + case 'W':{ + if(sscanf(p+1,"%d",&_y4m->pic_w)!=1)return -1; + got_w=1; + }break; + case 'H':{ + if(sscanf(p+1,"%d",&_y4m->pic_h)!=1)return -1; + got_h=1; + }break; + case 'F':{ + if(sscanf(p+1,"%d:%d",&_y4m->fps_n,&_y4m->fps_d)!=2){ + return -1; + } + got_fps=1; + }break; + case 'I':{ + _y4m->interlace=p[1]; + got_interlace=1; + }break; + case 'A':{ + if(sscanf(p+1,"%d:%d",&_y4m->par_n,&_y4m->par_d)!=2){ + return -1; + } + got_par=1; + }break; + case 'C':{ + if(q-p>16)return -1; + memcpy(_y4m->chroma_type,p+1,q-p-1); + _y4m->chroma_type[q-p-1]='\0'; + got_chroma=1; + }break; + /*Ignore unknown tags.*/ + } + } + if(!got_w||!got_h||!got_fps)return -1; + if(!got_interlace)_y4m->interlace='?'; + if(!got_par)_y4m->par_n=_y4m->par_d=0; + /*Chroma-type is not specified in older files, e.g., those generated by + mplayer.*/ + if(!got_chroma)strcpy(_y4m->chroma_type,"420"); + return 0; +} + + + +/*All anti-aliasing filters in the following conversion functions are based on + one of two window functions: + The 6-tap Lanczos window (for down-sampling and shifts): + sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t) + 0, |t|>=3 + The 4-tap Mitchell window (for up-sampling): + 7|t|^3-12|t|^2+16/3, |t|<1 + -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2 + 0, |t|>=2 + The number of taps is intentionally kept small to reduce computational + overhead and limit ringing. + + The taps from these filters are scaled so that their sum is 1, and the result + is scaled by 128 and rounded to integers to create a filter whose + intermediate values fit inside 16 bits. + Coefficients are rounded in such a way as to ensure their sum is still 128, + which is usually equivalent to normal rounding. + + Conversions which require both horizontal and vertical filtering could + have these steps pipelined, for less memory consumption and better cache + performance, but we do them separately for simplicity.*/ + +#define OC_MINI(_a,_b) ((_a)>(_b)?(_b):(_a)) +#define OC_MAXI(_a,_b) ((_a)<(_b)?(_b):(_a)) +#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c))) + +/*420jpeg chroma samples are sited like: + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + + 420mpeg2 chroma samples are sited like: + Y-------Y-------Y-------Y------- + | | | | + BR | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + Y-------Y-------Y-------Y------- + | | | | + BR | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + + We use a resampling filter to shift the site locations one quarter pixel (at + the chroma plane's resolution) to the right. + The 4:2:2 modes look exactly the same, except there are twice as many chroma + lines, and they are vertically co-sited with the luma samples in both the + mpeg2 and jpeg cases (thus requiring no vertical resampling).*/ +static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst, + const unsigned char *_src,int _c_w,int _c_h){ + int y; + int x; + for(y=0;y<_c_h;y++){ + /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos + window.*/ + for(x=0;x>7,255); + } + for(;x<_c_w-3;x++){ + _dst[x]=(unsigned char)OC_CLAMPI(0,(4*_src[x-2]-17*_src[x-1]+ + 114*_src[x]+35*_src[x+1]-9*_src[x+2]+_src[x+3]+64)>>7,255); + } + for(;x<_c_w;x++){ + _dst[x]=(unsigned char)OC_CLAMPI(0,(4*_src[x-2]-17*_src[x-1]+ + 114*_src[x]+35*_src[OC_MINI(x+1,_c_w-1)]-9*_src[OC_MINI(x+2,_c_w-1)]+ + _src[_c_w-1]+64)>>7,255); + } + _dst+=_c_w; + _src+=_c_w; + } +} + +/*Handles both 422 and 420mpeg2 to 422jpeg and 420jpeg, respectively.*/ +static void y4m_convert_42xmpeg2_42xjpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + int c_w; + int c_h; + int c_sz; + int pli; + /*Skip past the luma data.*/ + _dst+=_y4m->pic_w*_y4m->pic_h; + /*Compute the size of each chroma plane.*/ + c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; + c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; + c_sz=c_w*c_h; + for(pli=1;pli<3;pli++){ + y4m_42xmpeg2_42xjpeg_helper(_dst,_aux,c_w,c_h); + _dst+=c_sz; + _aux+=c_sz; + } +} + +/*This format is only used for interlaced content, but is included for + completeness. + + 420jpeg chroma samples are sited like: + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + + 420paldv chroma samples are sited like: + YR------Y-------YR------Y------- + | | | | + | | | | + | | | | + YB------Y-------YB------Y------- + | | | | + | | | | + | | | | + YR------Y-------YR------Y------- + | | | | + | | | | + | | | | + YB------Y-------YB------Y------- + | | | | + | | | | + | | | | + + We use a resampling filter to shift the site locations one quarter pixel (at + the chroma plane's resolution) to the right. + Then we use another filter to move the C_r location down one quarter pixel, + and the C_b location up one quarter pixel.*/ +static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + unsigned char *tmp; + int c_w; + int c_h; + int c_sz; + int pli; + int y; + int x; + /*Skip past the luma data.*/ + _dst+=_y4m->pic_w*_y4m->pic_h; + /*Compute the size of each chroma plane.*/ + c_w=(_y4m->pic_w+1)/2; + c_h=(_y4m->pic_h+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; + c_sz=c_w*c_h; + tmp=_aux+2*c_sz; + for(pli=1;pli<3;pli++){ + /*First do the horizontal re-sampling. + This is the same as the mpeg2 case, except that after the horizontal + case, we need to apply a second vertical filter.*/ + y4m_42xmpeg2_42xjpeg_helper(tmp,_aux,c_w,c_h); + _aux+=c_sz; + switch(pli){ + case 1:{ + /*Slide C_b up a quarter-pel. + This is the same filter used above, but in the other order.*/ + for(x=0;x>7,255); + } + for(;y>7,255); + } + for(;y>7,255); + } + _dst++; + tmp++; + } + _dst+=c_sz-c_w; + tmp-=c_w; + }break; + case 2:{ + /*Slide C_r down a quarter-pel. + This is the same as the horizontal filter.*/ + for(x=0;x>7,255); + } + for(;y>7,255); + } + for(;y>7,255); + } + _dst++; + tmp++; + } + }break; + } + /*For actual interlaced material, this would have to be done separately on + each field, and the shift amounts would be different. + C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8, + C_b up 1/8 in the bottom field. + The corresponding filters would be: + Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128 + Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/ + } +} + +/*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0. + This is used as a helper by several converation routines.*/ +static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst, + const unsigned char *_src,int _c_w,int _c_h){ + int y; + int x; + /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/ + for(x=0;x<_c_w;x++){ + for(y=0;y>1)*_c_w]=OC_CLAMPI(0,(64*_src[0] + +78*_src[OC_MINI(1,_c_h-1)*_c_w] + -17*_src[OC_MINI(2,_c_h-1)*_c_w] + +3*_src[OC_MINI(3,_c_h-1)*_c_w]+64)>>7,255); + } + for(;y<_c_h-3;y+=2){ + _dst[(y>>1)*_c_w]=OC_CLAMPI(0,(3*(_src[(y-2)*_c_w]+_src[(y+3)*_c_w]) + -17*(_src[(y-1)*_c_w]+_src[(y+2)*_c_w]) + +78*(_src[y*_c_w]+_src[(y+1)*_c_w])+64)>>7,255); + } + for(;y<_c_h;y+=2){ + _dst[(y>>1)*_c_w]=OC_CLAMPI(0,(3*(_src[(y-2)*_c_w] + +_src[(_c_h-1)*_c_w])-17*(_src[(y-1)*_c_w] + +_src[OC_MINI(y+2,_c_h-1)*_c_w]) + +78*(_src[y*_c_w]+_src[OC_MINI(y+1,_c_h-1)*_c_w])+64)>>7,255); + } + _src++; + _dst++; + } +} + +/*420jpeg chroma samples are sited like: + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + + 422jpeg chroma samples are sited like: + Y---BR--Y-------Y---BR--Y------- + | | | | + | | | | + | | | | + Y---BR--Y-------Y---BR--Y------- + | | | | + | | | | + | | | | + Y---BR--Y-------Y---BR--Y------- + | | | | + | | | | + | | | | + Y---BR--Y-------Y---BR--Y------- + | | | | + | | | | + | | | | + + We use a resampling filter to decimate the chroma planes by two in the + vertical direction.*/ +static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + int c_w; + int c_h; + int c_sz; + int dst_c_w; + int dst_c_h; + int dst_c_sz; + int pli; + /*Skip past the luma data.*/ + _dst+=_y4m->pic_w*_y4m->pic_h; + /*Compute the size of each chroma plane.*/ + c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; + c_h=_y4m->pic_h; + dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; + dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; + c_sz=c_w*c_h; + dst_c_sz=dst_c_w*dst_c_h; + for(pli=1;pli<3;pli++){ + y4m_422jpeg_420jpeg_helper(_dst,_aux,c_w,c_h); + _aux+=c_sz; + _dst+=dst_c_sz; + } +} + +/*420jpeg chroma samples are sited like: + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + + 422 chroma samples are sited like: + YBR-----Y-------YBR-----Y------- + | | | | + | | | | + | | | | + YBR-----Y-------YBR-----Y------- + | | | | + | | | | + | | | | + YBR-----Y-------YBR-----Y------- + | | | | + | | | | + | | | | + YBR-----Y-------YBR-----Y------- + | | | | + | | | | + | | | | + + We use a resampling filter to shift the original site locations one quarter + pixel (at the original chroma resolution) to the right. + Then we use a second resampling filter to decimate the chroma planes by two + in the vertical direction.*/ +static void y4m_convert_422_420jpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + unsigned char *tmp; + int c_w; + int c_h; + int c_sz; + int dst_c_h; + int dst_c_sz; + int pli; + /*Skip past the luma data.*/ + _dst+=_y4m->pic_w*_y4m->pic_h; + /*Compute the size of each chroma plane.*/ + c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; + c_h=_y4m->pic_h; + dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; + c_sz=c_w*c_h; + dst_c_sz=c_w*dst_c_h; + tmp=_aux+2*c_sz; + for(pli=1;pli<3;pli++){ + /*In reality, the horizontal and vertical steps could be pipelined, for + less memory consumption and better cache performance, but we do them + separately for simplicity.*/ + /*First do horizontal filtering (convert to 422jpeg)*/ + y4m_42xmpeg2_42xjpeg_helper(tmp,_aux,c_w,c_h); + /*Now do the vertical filtering.*/ + y4m_422jpeg_420jpeg_helper(_dst,tmp,c_w,c_h); + _aux+=c_sz; + _dst+=dst_c_sz; + } +} + +/*420jpeg chroma samples are sited like: + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | BR | | BR | + | | | | + Y-------Y-------Y-------Y------- + | | | | + | | | | + | | | | + + 411 chroma samples are sited like: + YBR-----Y-------Y-------Y------- + | | | | + | | | | + | | | | + YBR-----Y-------Y-------Y------- + | | | | + | | | | + | | | | + YBR-----Y-------Y-------Y------- + | | | | + | | | | + | | | | + YBR-----Y-------Y-------Y------- + | | | | + | | | | + | | | | + + We use a filter to resample at site locations one eighth pixel (at the source + chroma plane's horizontal resolution) and five eighths of a pixel to the + right. + Then we use another filter to decimate the planes by 2 in the vertical + direction.*/ +static void y4m_convert_411_420jpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + unsigned char *tmp; + int c_w; + int c_h; + int c_sz; + int dst_c_w; + int dst_c_h; + int dst_c_sz; + int tmp_sz; + int pli; + int y; + int x; + /*Skip past the luma data.*/ + _dst+=_y4m->pic_w*_y4m->pic_h; + /*Compute the size of each chroma plane.*/ + c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; + c_h=_y4m->pic_h; + dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; + dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; + c_sz=c_w*c_h; + dst_c_sz=dst_c_w*dst_c_h; + tmp_sz=dst_c_w*c_h; + tmp=_aux+2*c_sz; + for(pli=1;pli<3;pli++){ + /*In reality, the horizontal and vertical steps could be pipelined, for + less memory consumption and better cache performance, but we do them + separately for simplicity.*/ + /*First do horizontal filtering (convert to 422jpeg)*/ + for(y=0;y>7,255); + tmp[x<<1|1]=(unsigned char)OC_CLAMPI(0,(47*_aux[0] + +86*_aux[OC_MINI(1,c_w-1)]-5*_aux[OC_MINI(2,c_w-1)]+64)>>7,255); + } + for(;x>7,255); + tmp[x<<1|1]=(unsigned char)OC_CLAMPI(0,(-3*_aux[x-1]+50*_aux[x] + +86*_aux[x+1]-5*_aux[x+2]+64)>>7,255); + } + for(;x>7,255); + if((x<<1|1)>7,255); + } + } + tmp+=dst_c_w; + _aux+=c_w; + } + tmp-=tmp_sz; + /*Now do the vertical filtering.*/ + y4m_422jpeg_420jpeg_helper(_dst,tmp,dst_c_w,c_h); + _dst+=dst_c_sz; + } +} + +/*Convert 444 to 420jpeg.*/ +static void y4m_convert_444_420jpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + unsigned char *tmp; + int c_w; + int c_h; + int c_sz; + int dst_c_w; + int dst_c_h; + int dst_c_sz; + int tmp_sz; + int pli; + int y; + int x; + /*Skip past the luma data.*/ + _dst+=_y4m->pic_w*_y4m->pic_h; + /*Compute the size of each chroma plane.*/ + c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; + c_h=_y4m->pic_h; + dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; + dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; + c_sz=c_w*c_h; + dst_c_sz=dst_c_w*dst_c_h; + tmp_sz=dst_c_w*c_h; + tmp=_aux+2*c_sz; + for(pli=1;pli<3;pli++){ + /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/ + for(y=0;y>1]=OC_CLAMPI(0,(64*_aux[0]+78*_aux[OC_MINI(1,c_w-1)] + -17*_aux[OC_MINI(2,c_w-1)] + +3*_aux[OC_MINI(3,c_w-1)]+64)>>7,255); + } + for(;x>1]=OC_CLAMPI(0,(3*(_aux[x-2]+_aux[x+3]) + -17*(_aux[x-1]+_aux[x+2])+78*(_aux[x]+_aux[x+1])+64)>>7,255); + } + for(;x>1]=OC_CLAMPI(0,(3*(_aux[x-2]+_aux[c_w-1])- + 17*(_aux[x-1]+_aux[OC_MINI(x+2,c_w-1)])+ + 78*(_aux[x]+_aux[OC_MINI(x+1,c_w-1)])+64)>>7,255); + } + tmp+=dst_c_w; + _aux+=c_w; + } + tmp-=tmp_sz; + /*Now do the vertical filtering.*/ + y4m_422jpeg_420jpeg_helper(_dst,tmp,dst_c_w,c_h); + _dst+=dst_c_sz; + } +} + +/*The image is padded with empty chroma components at 4:2:0.*/ +static void y4m_convert_mono_420jpeg(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ + int c_sz; + _dst+=_y4m->pic_w*_y4m->pic_h; + c_sz=((_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h)* + ((_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v); + memset(_dst,128,c_sz*2); +} + +/*No conversion function needed.*/ +static void y4m_convert_null(y4m_input *_y4m,unsigned char *_dst, + unsigned char *_aux){ +} + +int y4m_input_open(y4m_input *_y4m,FILE *_fin,char *_skip,int _nskip){ + char buffer[80]; + int ret; + int i; + /*Read until newline, or 80 cols, whichever happens first.*/ + for(i=0;i<79;i++){ + if(_nskip>0){ + buffer[i]=*_skip++; + _nskip--; + } + else{ + ret=fread(buffer+i,1,1,_fin); + if(ret<1)return -1; + } + if(buffer[i]=='\n')break; + } + /*We skipped too much header data.*/ + if(_nskip>0)return -1; + if(i==79){ + fprintf(stderr,"Error parsing header; not a YUV2MPEG2 file?\n"); + return -1; + } + buffer[i]='\0'; + if(memcmp(buffer,"YUV4MPEG",8)){ + fprintf(stderr,"Incomplete magic for YUV4MPEG file.\n"); + return -1; + } + if(buffer[8]!='2'){ + fprintf(stderr,"Incorrect YUV input file version; YUV4MPEG2 required.\n"); + } + ret=y4m_parse_tags(_y4m,buffer+5); + if(ret<0){ + fprintf(stderr,"Error parsing YUV4MPEG2 header.\n"); + return ret; + } + if(_y4m->interlace=='?'){ + fprintf(stderr,"Warning: Input video interlacing format unknown; " + "assuming progressive scan.\n"); + } + else if(_y4m->interlace!='p'){ + fprintf(stderr,"Input video is interlaced; " + "Only progressive scan handled.\n"); + return -1; + } + if(strcmp(_y4m->chroma_type,"420")==0|| + strcmp(_y4m->chroma_type,"420jpeg")==0){ + _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h + +2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); + /*Natively supported: no conversion required.*/ + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0; + _y4m->convert=y4m_convert_null; + } + else if(strcmp(_y4m->chroma_type,"420mpeg2")==0){ + _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first.*/ + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz= + 2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); + _y4m->convert=y4m_convert_42xmpeg2_42xjpeg; + } + else if(strcmp(_y4m->chroma_type,"420paldv")==0){ + _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first. + We need to make two filter passes, so we need some extra space in the + aux buffer.*/ + _y4m->aux_buf_sz=3*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); + _y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); + _y4m->convert=y4m_convert_42xpaldv_42xjpeg; + } + else if(strcmp(_y4m->chroma_type,"422jpeg")==0){ + _y4m->src_c_dec_h=_y4m->dst_c_dec_h=2; + _y4m->src_c_dec_v=1; + _y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first.*/ + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*_y4m->pic_h; + _y4m->convert=y4m_convert_422jpeg_420jpeg; + } + else if(strcmp(_y4m->chroma_type,"422")==0){ + _y4m->src_c_dec_h=_y4m->dst_c_dec_h=2; + _y4m->src_c_dec_v=1; + _y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first. + We need to make two filter passes, so we need some extra space in the + aux buffer.*/ + _y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*_y4m->pic_h; + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz+((_y4m->pic_w+1)/2)*_y4m->pic_h; + _y4m->convert=y4m_convert_422_420jpeg; + } + else if(strcmp(_y4m->chroma_type,"411")==0){ + _y4m->src_c_dec_h=4; + _y4m->dst_c_dec_h=2; + _y4m->src_c_dec_v=1; + _y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first. + We need to make two filter passes, so we need some extra space in the + aux buffer.*/ + _y4m->aux_buf_read_sz=2*((_y4m->pic_w+3)/4)*_y4m->pic_h; + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz+((_y4m->pic_w+1)/2)*_y4m->pic_h; + _y4m->convert=y4m_convert_411_420jpeg; + } + else if(strcmp(_y4m->chroma_type,"444")==0){ + _y4m->src_c_dec_h=1; + _y4m->dst_c_dec_h=2; + _y4m->src_c_dec_v=1; + _y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first. + We need to make two filter passes, so we need some extra space in the + aux buffer.*/ + _y4m->aux_buf_read_sz=2*_y4m->pic_w*_y4m->pic_h; + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz+((_y4m->pic_w+1)/2)*_y4m->pic_h; + _y4m->convert=y4m_convert_444_420jpeg; + } + else if(strcmp(_y4m->chroma_type,"444alpha")==0){ + _y4m->src_c_dec_h=1; + _y4m->dst_c_dec_h=2; + _y4m->src_c_dec_v=1; + _y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*Chroma filter required: read into the aux buf first. + We need to make two filter passes, so we need some extra space in the + aux buffer. + The extra plane also gets read into the aux buf. + It will be discarded.*/ + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=3*_y4m->pic_w*_y4m->pic_h; + _y4m->convert=y4m_convert_444_420jpeg; + } + else if(strcmp(_y4m->chroma_type,"mono")==0){ + _y4m->src_c_dec_h=_y4m->src_c_dec_v=0; + _y4m->dst_c_dec_h=_y4m->dst_c_dec_v=2; + _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; + /*No extra space required, but we need to clear the chroma planes.*/ + _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0; + _y4m->convert=y4m_convert_mono_420jpeg; + } + else{ + fprintf(stderr,"Unknown chroma sampling type: %s\n",_y4m->chroma_type); + return -1; + } + /*The size of the final frame buffers is always computed from the + destination chroma decimation type.*/ + _y4m->dst_buf_sz=_y4m->pic_w*_y4m->pic_h + +2*((_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h)* + ((_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v); + _y4m->dst_buf=(unsigned char *)malloc(_y4m->dst_buf_sz); + _y4m->aux_buf=(unsigned char *)malloc(_y4m->aux_buf_sz); + return 0; +} + +void y4m_input_close(y4m_input *_y4m){ + free(_y4m->dst_buf); + free(_y4m->aux_buf); +} + +int y4m_input_fetch_frame(y4m_input *_y4m,FILE *_fin,vpx_image_t *_img){ + char frame[6]; + int pic_sz; + int c_w; + int c_h; + int c_sz; + int ret; + /*Read and skip the frame header.*/ + ret=fread(frame,1,6,_fin); + if(ret<6)return 0; + if(memcmp(frame,"FRAME",5)){ + fprintf(stderr,"Loss of framing in Y4M input data\n"); + return -1; + } + if(frame[5]!='\n'){ + char c; + int j; + for(j=0;j<79&&fread(&c,1,1,_fin)&&c!='\n';j++); + if(j==79){ + fprintf(stderr,"Error parsing Y4M frame header\n"); + return -1; + } + } + /*Read the frame data that needs no conversion.*/ + if(fread(_y4m->dst_buf,1,_y4m->dst_buf_read_sz,_fin)!=_y4m->dst_buf_read_sz){ + fprintf(stderr,"Error reading Y4M frame data.\n"); + return -1; + } + /*Read the frame data that does need conversion.*/ + if(fread(_y4m->aux_buf,1,_y4m->aux_buf_read_sz,_fin)!=_y4m->aux_buf_read_sz){ + fprintf(stderr,"Error reading Y4M frame data.\n"); + return -1; + } + /*Now convert the just read frame.*/ + (*_y4m->convert)(_y4m,_y4m->dst_buf,_y4m->aux_buf); + /*Fill in the frame buffer pointers. + We don't use vpx_img_wrap() because it forces padding for odd picture + sizes, which would require a separate fread call for every row.*/ + memset(_img,0,sizeof(*_img)); + /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/ + _img->fmt=IMG_FMT_I420; + _img->w=_img->d_w=_y4m->pic_w; + _img->h=_img->d_h=_y4m->pic_h; + /*This is hard-coded to 4:2:0 for now, as that's all VP8 supports.*/ + _img->x_chroma_shift=1; + _img->y_chroma_shift=1; + _img->bps=12; + /*Set up the buffer pointers.*/ + pic_sz=_y4m->pic_w*_y4m->pic_h; + c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; + c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; + c_sz=c_w*c_h; + _img->stride[PLANE_Y]=_y4m->pic_w; + _img->stride[PLANE_U]=_img->stride[PLANE_V]=c_w; + _img->planes[PLANE_Y]=_y4m->dst_buf; + _img->planes[PLANE_U]=_y4m->dst_buf+pic_sz; + _img->planes[PLANE_V]=_y4m->dst_buf+pic_sz+c_sz; + return 1; +} diff --git a/y4minput.h b/y4minput.h new file mode 100644 index 0000000..1a01bcd --- /dev/null +++ b/y4minput.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + * Based on code from the OggTheora software codec source code, + * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors. + */ +#if !defined(_y4minput_H) +# define _y4minput_H (1) +# include +# include "vpx/vpx_image.h" + + + +typedef struct y4m_input y4m_input; + + + +/*The function used to perform chroma conversion.*/ +typedef void (*y4m_convert_func)(y4m_input *_y4m, + unsigned char *_dst,unsigned char *_src); + + + +struct y4m_input{ + int pic_w; + int pic_h; + int fps_n; + int fps_d; + int par_n; + int par_d; + char interlace; + int src_c_dec_h; + int src_c_dec_v; + int dst_c_dec_h; + int dst_c_dec_v; + char chroma_type[16]; + /*The size of each converted frame buffer.*/ + size_t dst_buf_sz; + /*The amount to read directly into the converted frame buffer.*/ + size_t dst_buf_read_sz; + /*The size of the auxilliary buffer.*/ + size_t aux_buf_sz; + /*The amount to read into the auxilliary buffer.*/ + size_t aux_buf_read_sz; + y4m_convert_func convert; + unsigned char *dst_buf; + unsigned char *aux_buf; +}; + +int y4m_input_open(y4m_input *_y4m,FILE *_fin,char *_skip,int _nskip); +void y4m_input_close(y4m_input *_y4m); +int y4m_input_fetch_frame(y4m_input *_y4m,FILE *_fin,vpx_image_t *img); + +#endif -- 2.7.4